2016-03-12 11 views
6

Go hat große Bildbearbeitung und Datenbibliotheken, aber ich habe Probleme, ein großes Bild von kleineren zu erstellen. Weiß jemand, wie man zwei png oder jpeg Dateien in Golang nimmt und sie zu einem großen Bild zusammenfügt, das die zwei (oder mehr) Dateien umfasst?Golang, wie man Bilder miteinander verbindet/verbindet

Ich lese zur Zeit png-Dateien wie so:

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) 

Ich bin verwirrt, wie diese png RGBA-Daten zu nehmen und verketten mit anderen RGBA-Daten und/oder dass kombinieren in ein „leeres“ Bild .

+3

Welche Art von Schwierigkeiten haben Sie? Was hast du bisher versucht? In jedem Fall besteht das allgemeine Prinzip darin, ein neues, großes Zielbild zu erzeugen und dann Pixel von den Quellbildern in das Zielbild zu kopieren. – Aedolon

+0

Nun bis jetzt bin ich nur in der Lage, die Pixeldaten von einem PNG zu nehmen und ein neues RGBA zu bilden und dieses dann intern als ein png zu decodieren, das ich zu OpenGL übergebe. Allerdings bin ich nicht ganz sicher, wie man diese "decodierten" PNG-Daten, die ich aus der PNG-Datei lesen und kopieren/erstellen ein größeres Bild von diesem – efel

Antwort

10

Erstellen Sie ein neues leeres Bild (NewRGBA), das groß genug für beide Bilder ist. Verwenden Sie dann die Methode Draw, um jedes Bild auf geeignete Teile dieses neuen großen Bildes zu zeichnen.

Hier sind Schritte mit Code.

Laden Sie zwei Bilder.

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) 
} 

Lassen Sie uns das zweite Bild auf der rechten Seite des ersten Bildes zeichnen. Der Ausgangspunkt sollte also (w, 0) sein, wobei w die Breite des ersten Bildes ist. Der untere rechte Punkt des ersten Bildes ist der untere linke Punkt des zweiten Bildes.

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

Es sollte in einem Rechteck groß genug sein, um es zu halten.

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

Erstellen Sie nun ein großes Rechteck, das breit genug für beide Bilder ist.

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

Hinweis Dieses große Bild hat die Höhe des zweiten Bildes. Wenn das erste Bild höher ist, wird es beschnitten.

Erstellen Sie ein neues Bild.

rgba := image.NewRGBA(r) 

Jetzt können Sie

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

die beiden Bilder in dieses neue Bild zeichnen Da wir r2 erstellt seine so nach rechts dem ersten Bild, wird zweites Bild nach rechts gezogen werden.

Endlich können Sie es exportieren.

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

Ich mag diese Antwort wirklich, wie es sehr gut formatiert ist, erklärte jeden Abschnitt individuell, prägnant, verwendet eine Menge vorhandener Funktionalität. – efel

+0

efel, danke. sieht aus, als hätte ich zwischen rechts und links verwirrt. bearbeitet, um zu beheben :) –

6

Ihr Leben wäre viel einfacher, wenn Sie ein paar Dinge in Funktionen machen und eine Struktur erstellen, um jedem Pixel einen Sinn zu geben.

// 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

Eine Menge Arbeit ging in diese Antwort, ich mag es auch. Sehr modular. – efel