Michele Riva
Michele Riva

Reputation: 562

Merge multiple images in Go

I am trying to merge an array of N images (where N will be a dynamic value) with Go, but I always get a black image as result.

Here you are my code:

package main

import (
    "image"
    "image/draw"
    "image/jpeg"
    "image/png"
    "log"
    "os"
)

func openAndDecode(imgPath string) image.Image {
    img, err := os.Open(imgPath)
    if err != nil {
        log.Fatalf("Failed to open %s", err)
    }

    decoded, err := png.Decode(img)
    if err != nil {
        log.Fatalf("Failed to decode %s", err)
    }
    defer img.Close()

    return decoded
}

func main () {
    var images = [4]string{"background", "shadow", "item1 ", "item2"}
    var decodedImages = [4]*image.RGBA{}

    for i, img := range images {
        decodedImage := openAndDecode("./imgs/" + img + ".png")
        bounds := decodedImage.Bounds()
        newImg := image.NewRGBA(bounds)
        decodedImages[i] = newImg
    }

    bounds := decodedImages[0].Bounds()
    newImage := image.NewRGBA(bounds)

    for _, img := range decodedImages {
        draw.Draw(newImage, img.Bounds(), img, image.ZP, draw.Src)
    }

    result, err := os.Create("result.jpg")
    if err != nil {
        log.Fatalf("Failed to create: %s", err)
    }

    jpeg.Encode(result, newImage, &jpeg.Options{jpeg.DefaultQuality})
    defer result.Close()
}

I am pretty new to Go and I can't find out where I am wrong.

Upvotes: 2

Views: 2521

Answers (1)

icza
icza

Reputation: 417612

In your first loop where you load the images, you also create a new, empty image and you store this empty image in decodedImages. And then you iterate over these empty images and combine them.

Instead you should store the loaded images in decodedImages:

for i, img := range images {
    decodedImages[i] = openAndDecode("./imgs/" + img + ".png")
}

For this to work, declare decodedImages to be a slice of image.Image (since openAndDecode() returns a value of type image.Image):

var decodedImages = make([]image.Image, len(images))

Also, whenever you open a file and check the error, you should defer close it right after so if subsequent code fails, the file would still get closed.

Also to "combine" images with an alpha channel, you should use draw.Over operator. Quoting from the blog post: The Go Blog: The Go image/draw package:

The Over operator performs the natural layering of a source image over a destination image: the change to the destination image is smaller where the source (after masking) is more transparent (that is, has lower alpha). The Src operator merely copies the source (after masking) with no regard for the destination image's original content. For fully opaque source and mask images, the two operators produce the same output, but the Src operator is usually faster.

Upvotes: 5

Related Questions