Skip to content

Instantly share code, notes, and snippets.

@JokerCatz
Last active December 28, 2021 15:19
Show Gist options
  • Save JokerCatz/2af8ed7c232251d9b861b02c57d378c8 to your computer and use it in GitHub Desktop.
Save JokerCatz/2af8ed7c232251d9b861b02c57d378c8 to your computer and use it in GitHub Desktop.
golang image append , support jpg / png / webp
package main
import (
"bytes"
"fmt"
"image"
"image/draw"
"image/jpeg"
"image/png"
"io/ioutil"
"os"
"golang.org/x/image/webp"
)
// only support jpg , png , webp
// webp only support read
type ImageType int
const (
ImageTypeJPG ImageType = iota + 1
ImageTypePNG
ImageTypeWEBP
)
// ImageTypeFileHead fast filetype check
var ImageTypeFileHead = map[ImageType][]byte{
ImageTypeJPG: {0xFF, 0xD8, 0xFF},
ImageTypePNG: {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A},
ImageTypeWEBP: {0x52, 0x49, 0x46, 0x46},
}
func getImage(filePath string) (img *image.Image, err error) {
var data []byte
data, err = ioutil.ReadFile(filePath)
if err != nil {
return
}
var imageType *ImageType
for tempImageType, tempImageFileHead := range ImageTypeFileHead {
if len(data) < len(tempImageFileHead) {
continue
}
if bytes.Equal(data[:len(tempImageFileHead)], tempImageFileHead) {
imageType = &tempImageType
break
}
}
if imageType == nil {
err = fmt.Errorf("image file not support , file head not match")
return
}
var tempImg image.Image
switch *imageType {
case ImageTypeJPG:
tempImg, err = jpeg.Decode(bytes.NewReader(data))
case ImageTypePNG:
tempImg, err = png.Decode(bytes.NewReader(data))
case ImageTypeWEBP:
tempImg, err = webp.Decode(bytes.NewReader(data))
default:
err = fmt.Errorf("image file not support , file head not match")
}
if err == nil {
img = &tempImg
}
return
}
func saveImage(img image.Image, filePath string, imageType ImageType, jpgQuality *int) (err error) {
f, err := os.Create(filePath)
if err != nil {
return
}
defer f.Close()
switch imageType {
case ImageTypeJPG:
if jpgQuality == nil {
temp := 80 // default 80
jpgQuality = &temp
}
err = jpeg.Encode(f, img, &jpeg.Options{Quality: *jpgQuality})
case ImageTypePNG:
err = png.Encode(f, img)
default:
err = fmt.Errorf("unknow image type to save file")
}
return
}
func mergeImage(fileList []string) (rgbaConvas *image.RGBA64, err error) {
var imageSize image.Point
for index, fileName := range fileList {
var imgP *image.Image
imgP, err = getImage(fileName)
if err != nil {
return
}
img := *imgP
if index == 0 {
imageSize = img.Bounds().Max
rgbaConvas = image.NewRGBA64(image.Rectangle{image.Point{0, 0}, img.Bounds().Max}) // create empty canvas
}
if !img.Bounds().Max.Eq(imageSize) {
tImageSize := img.Bounds().Max
err = fmt.Errorf("image not all match , image(%d:%d) , [%d:%s](%d:%d)", imageSize.X, imageSize.Y, index, fileName, tImageSize.X, tImageSize.Y)
return
}
draw.Draw(rgbaConvas, img.Bounds(), img, image.Point{0, 0}, draw.Over) // draw image to canvas
}
if rgbaConvas == nil {
err = fmt.Errorf("empty canvas")
return
}
return
}
func main() {
img, err := mergeImage([]string{
"layer1.webp", "layer2.png", "layer3.webp", "layer4.png",
})
if err != nil {
fmt.Println("ERR", err)
return
}
err = saveImage(img, "final.png", ImageTypePNG, nil)
if err != nil {
fmt.Println("ERR", err)
return
}
fmt.Println("finished!")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment