2016-03-12 46 views
6

Go ha una grande manipolazione di immagini e librerie di dati, tuttavia ho problemi a creare una grande immagine da quelle più piccole. Qualcuno sa come prendere due file png o jpeg in Golang e concatenarli per formare una grande immagine che comprende i due (o più) file?Golang come concatenare/accodare le immagini l'un l'altro

sto leggendo i file PNG in questo modo:

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) 

Sono confuso su come prendere questi dati RGBA png e concatenare con altri dati RGBA e/o combinare che in un'immagine "vuoto" .

+3

Che tipo di problemi hai? Cosa hai provato fino ad ora? In ogni caso, il principio generale è quello di creare una nuova, grande immagine di destinazione e quindi copiare i pixel dalle immagini di origine nell'immagine di destinazione. – Aedolon

+0

Beh, fino ad ora sono in grado di acquisire i dati dei pixel da un png e formare un nuovo RGBA e quindi decodificarlo internamente come png e passare a OpenGL. Tuttavia, non sono abbastanza sicuro di come prendere questi dati "decodificati" png che ho letto dal file .png e copiare/creare un'immagine più grande da quello – efel

risposta

10

Creare una nuova immagine vuota (NewRGBA) con margini sufficientemente grandi da contenere entrambe le immagini. Quindi utilizzare il metodo Draw per disegnare ogni immagine sulle parti appropriate di questa nuova grande immagine.

Ecco i passaggi con il codice.

Caricare due immagini.

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

Disegniamo la seconda immagine a destra della prima immagine. Quindi il punto di partenza dovrebbe essere (w, 0) dove w corrisponde alla larghezza della prima immagine. Il punto in basso a destra della prima immagine sarà il punto in basso a sinistra del secondo.

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

Dovrebbe essere in un rettangolo abbastanza grande da contenere.

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

Ora creare un rettangolo grande che sia sufficientemente largo da contenere entrambe le immagini.

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

Nota Questa immagine grande avrà l'altezza della seconda immagine. Se la prima immagine è più alta, verrà ritagliata.

Creare una nuova immagine.

rgba := image.NewRGBA(r) 

Ora è possibile disegnare le due immagini in questa nuova immagine

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

Dal momento che abbiamo creato r2 per cui il suo alla destra della prima immagine, seconda immagine saranno attratti verso destra.

Finalmente è possibile esportarlo.

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

Mi piace molto questa risposta in quanto è molto ben formattata, ha spiegato ogni sezione individualmente, conciso, usato molte funzionalità di go esistenti. – efel

+0

efel, grazie. sembra che io abbia confuso tra destra e sinistra ealiar. modificato per risolvere :) –

6

La tua vita sarebbe molto più semplice se crei alcune cose in funzioni e crei una struttura per dare un senso a ciascun pixel.

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

Un sacco di lavoro è andato in questa risposta, mi piace anche. Molto modulare. – efel