2016-03-12 33 views
6

Goは素晴らしい画像操作とデータライブラリを持っていますが、小さな画像から大きな画像を作成するのは難しいです。誰かがGolangで2つのpngまたはjpegファイルを取って、2つ(またはそれ以上)のファイルを取り囲む1つの大きなイメージを形成するために連結する方法を知っていますか?画像を連結/追加する方法をGolang

私は現在、そのようなPNGファイルを読んでいる:

imgFile, err := os.Open(path) 
if err != nil { 
    return Image{}, err 
} 
img, _, err := image.Decode(imgFile) 
if err != nil { 
    return Image{}, err 
} 

rgba := image.NewRGBA(img.Bounds()) 
if rgba.Stride != rgba.Rect.Size().X*4 { 
    return Image{}, fmt.Errorf("unsupported stride") 
} 
draw.Draw(rgba, rgba.Bounds(), img, image.Point{0, 0}, draw.Src) 

私はこのPNG形式のRGBAデータを取得し、他のRGBAデータを連結および/または「空」のイメージにそれを結合する方法について混乱しています。

+3

どのような問題がありますか?これまでに何を試しましたか?いずれにしても、一般的な原理は、新しい大きなターゲット画像を作成し、ソース画像からターゲット画像にピクセルをコピーすることです。 – Aedolon

+0

これまでのところ、私はpngからピクセルデータを取り出して新しいRGBAを作成し、それをOpenGLに渡すpngとして内部的にデコードすることしかできませんでした。しかし、私はこの「デコード済み」PNGデータをどのようにして.pngファイルから読み込んでそれから大きな画像をコピー/作成するのかはよく分かりません – efel

答えて

10

両方のイメージを保持するのに十分な境界を持つ新しい空のイメージ(NewRGBA)を作成します。その後、Drawメソッドを使用して、この新しい大きな画像の適切な部分にそれぞれの画像を描画します。

ここにコードの手順があります。

2枚の画像を読み込みます。

imgFile1, err := os.Open("test1.jpg") 
imgFile2, err := os.Open("test2.jpg") 
if err != nil { 
    fmt.Println(err) 
} 
img1, _, err := image.Decode(imgFile1) 
img2, _, err := image.Decode(imgFile2) 
if err != nil { 
    fmt.Println(err) 
} 

最初の画像の右側に2番目の画像を描画しましょう。したがって、開始点は(w, 0)である必要があります。ここで、wは最初の画像の幅です。最初の画像の右下の点は、2番目の画像の左下の点になります。

//starting position of the second image (bottom left) 
sp2 := image.Point{img1.Bounds().Dx(), 0} 

これを保持するのに十分な大きさの矩形にする必要があります。

//new rectangle for the second image 
r2 := image.Rectangle{sp2, sp2.Add(img2.Bounds().Size())} 

ここで、両方の画像を保持するのに十分な広い矩形を作成します。

//rectangle for the big image 
r := image.Rectangle{image.Point{0, 0}, r2.Max} 

メモこの大きな画像は、2番目の画像の高さを持ちます。最初の画像がより高い場合、それは切り取られます。

新しい画像を作成します。

rgba := image.NewRGBA(r) 

今、あなたは

draw.Draw(rgba, img1.Bounds(), img1, image.Point{0, 0}, draw.Src) 
draw.Draw(rgba, r2, img2, image.Point{0, 0}, draw.Src) 

この新しいイメージに2枚の画像を描くことができ、我々はその最初の画像の右側にあるので、r2を作成したので、第二の画像が右に描画されます。

最後にエクスポートすることができます。

out, err := os.Create("./output.jpg") 
if err != nil { 
    fmt.Println(err) 
} 

var opt jpeg.Options 
opt.Quality = 80 

jpeg.Encode(out, rgba, &opt) 
+1

これはとてもうまく書式が設定されているので、個別に、簡潔に、既存の多くの機能を使用しました。 – efel

+0

efel、ありがとう。私は右と左のealiarの間で混乱しているように見えます。修正するために編集: –

6

機能にいくつかのことを加え、各ピクセルを理解するための構造体を作成すると、人生ははるかに簡単になります。

// Create a struct to deal with pixel 
type Pixel struct { 
    Point image.Point 
    Color color.Color 
} 

// Keep it DRY so don't have to repeat opening file and decode 
func OpenAndDecode(filepath string) (image.Image, string, error) { 
    imgFile, err := os.Open(filepath) 
    if err != nil { 
     panic(err) 
    } 
    defer imgFile.Close() 
    img, format, err := image.Decode(imgFile) 
    if err != nil { 
     panic(err) 
    } 
    return img, format, nil 
} 

// Decode image.Image's pixel data into []*Pixel 
func DecodePixelsFromImage(img image.Image, offsetX, offsetY int) []*Pixel { 
    pixels := []*Pixel{} 
    for y := 0; y <= img.Bounds().Max.Y; y++ { 
     for x := 0; x <= img.Bounds().Max.X; x++ { 
      p := &Pixel{ 
       Point: image.Point{x + offsetX, y + offsetY}, 
       Color: img.At(x, y), 
      } 
      pixels = append(pixels, p) 
     } 
    } 
    return pixels 
} 

func main() { 
    img1, _, err := OpenAndDecode("makey.png") 
    if err != nil { 
     panic(err) 
    } 
    img2, _, err := OpenAndDecode("sample.jpg") 
    if err != nil { 
     panic(err) 
    } 
    // collect pixel data from each image 
    pixels1 := DecodePixelsFromImage(img1, 0, 0) 
    // the second image has a Y-offset of img1's max Y (appended at bottom) 
    pixels2 := DecodePixelsFromImage(img2, 0, img1.Bounds().Max.Y) 
    pixelSum := append(pixels1, pixels2...) 

    // Set a new size for the new image equal to the max width 
    // of bigger image and max height of two images combined 
    newRect := image.Rectangle{ 
     Min: img1.Bounds().Min, 
     Max: image.Point{ 
      X: img2.Bounds().Max.X, 
      Y: img2.Bounds().Max.Y + img1.Bounds().Max.Y, 
     }, 
    } 
    finImage := image.NewRGBA(newRect) 
    // This is the cool part, all you have to do is loop through 
    // each Pixel and set the image's color on the go 
    for _, px := range pixelSum { 
      finImage.Set(
       px.Point.X, 
       px.Point.Y, 
       px.Color, 
      ) 
    } 
    draw.Draw(finImage, finImage.Bounds(), finImage, image.Point{0, 0}, draw.Src) 

    // Create a new file and write to it 
    out, err := os.Create("./output.png") 
    if err != nil { 
     panic(err) 
     os.Exit(1) 
    } 
    err = png.Encode(out, finImage) 
    if err != nil { 
     panic(err) 
     os.Exit(1) 
    } 
} 
+2

多くの仕事はこの答えに入った、私はそれも好きです。非常にモジュラー。 – efel

関連する問題