Golang 如何相互连接/附加图像



Go 具有出色的图像处理和数据库,但是我无法从较小的图像创建一个大图像。 有谁知道如何在 Golang 中获取两个 png 或 jpeg 文件并将它们连接起来形成一个包含两个(或多个)文件的大图像?

我目前正在阅读这样的 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 数据连接和/或将其组合成"空"图像感到困惑。

创建一个新的空图像 (NewRGBA),其边界足够大以容纳两个图像。然后使用 Draw 方法在此新大图像的适当部分绘制每个图像。

下面是使用代码的步骤。

加载两个图像。

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

让我们在第一张图像的右侧绘制第二张图像。因此,它的起点应该在(w, 0),其中w是第一个图像的宽度。第一个图像的右下点将是第二个图像的左下点。

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

注意:此大图像将具有第二个图像的高度。如果第一个图像较高,则将被裁剪。

创建新映像。

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)

由于我们创建了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)

如果你把一些东西做成函数,并创建一个结构来理解每个像素,你的生活会容易得多。

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

我为此构建了一个库。

您可以按如下方式使用它;

import gim "github.com/ozankasikci/go-image-merge"
grids := []*gim.Grid{
    {ImageFilePath: "test1.jpg"},
    {ImageFilePath: "test2.png"},
}
// merge the images into a 2x1 grid
rgba, err := gim.New(grids, 2, 1).Merge()
// save the output to jpg or png
file, err := os.Create("file/path.jpg|png")
err = jpeg.Encode(file, rgba, &jpeg.Options{Quality: 80})

https://github.com/ozankasikci/go-image-merge

调整图像大小并连接它们。

import (
    "fmt"
    "github.com/nfnt/resize"
    "image"
    "image/draw"
)
/**
w: resize weight
h: resize height
v: concat dim
images: list
*/
func Concat(w uint, h uint, v bool, images ...image.Image) *image.RGBA {
    var acc uint = 0
    if w == 0 {
        v = false
    } else if h == 0 {
        v = true
    }
    for i, img := range images {
        rimg := resize.Resize(w, h, img, resize.Bilinear)
        if v { // vertical concat, accumulate height
            acc += uint(rimg.Bounds().Dy())
        } else {
            acc += uint(rimg.Bounds().Dx())
        }
        images[i] = rimg
    }
    if v {
        h = acc
    } else {
        w = acc
    }
    r := image.Rectangle{image.Point{0, 0}, image.Point{int(w), int(h)}}
    rgba := image.NewRGBA(r)
    dx := 0
    dy := 0
    for _, img := range images {
        rec := img.Bounds()
        draw.Draw(rgba, image.Rect(dx, dy, dx+rec.Dx(), dy+rec.Dy()), img, image.Point{0, 0}, draw.Src)
        fmt.Println(image.Point{dx, dy})
        if v {
            dy += img.Bounds().Dy()
        } else {
            dx += img.Bounds().Dx()
        }
    }
    return rgba
}

相关内容

  • 没有找到相关文章

最新更新