gopkg/image/gif.go

196 lines
3.9 KiB
Go

// Package image ...
//
// Description : GIF相关操作
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2021-11-29 12:43 下午
package image
import (
"errors"
"image"
"image/color"
"image/color/palette"
"image/draw"
"image/gif"
"image/jpeg"
"image/png"
"os"
"git.zhangdeman.cn/zhangdeman/gopkg/util"
)
var (
// GIF ...
GIF *GIFConvert
)
func init() {
GIF = &GIFConvert{}
}
// GIFConvert gif转换
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:44 下午 2021/11/29
type GIFConvert struct {
}
// Generate 生成
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2:13 下午 2021/11/29
func (g *GIFConvert) Generate(sourceImageList []string, savePath string) error {
if len(sourceImageList) == 0 {
return errors.New("source image list is empty")
}
var (
err error
formatImgList []ImgInfo
disposals []byte
images []*image.Paletted
// 播放速度设置 , 100 次多少秒
delays []int
)
if formatImgList, err = g.checkImageType(sourceImageList); nil != err {
return err
}
for _, imgInfo := range formatImgList {
img, gErr := g.loadImage(imgInfo)
if nil != gErr {
return gErr
}
cp := g.getPalette(img)
//cp:=append(palette.WebSafe,color.Transparent)
disposals = append(disposals, gif.DisposalBackground) //透明图片需要设置
p := image.NewPaletted(image.Rect(0, 0, 640, 996), cp)
draw.Draw(p, p.Bounds(), img, image.ZP, draw.Src)
images = append(images, p)
delays = append(delays, 100)
}
gifInstance := &gif.GIF{
Image: images,
Delay: delays,
LoopCount: -1,
Disposal: disposals,
}
f, fErr := os.Create(savePath)
if fErr != nil {
return fErr
}
defer func() { _ = f.Close() }()
return gif.EncodeAll(f, gifInstance)
}
// checkImageType 检测图片类型
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2:16 下午 2021/11/29
func (g *GIFConvert) checkImageType(sourceImageList []string) ([]ImgInfo, error) {
result := make([]ImgInfo, 0)
for _, item := range sourceImageList {
imgType := util.GetFileType(item)
if len(imgType) == 0 {
return result, errors.New(item + " parse img type fail!")
}
result = append(result, ImgInfo{
Path: item,
Type: imgType,
})
}
return result, nil
}
// loadImage 加载图片内容
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2:52 下午 2021/11/29
func (g *GIFConvert) loadImage(imgInfo ImgInfo) (image.Image, error) {
var (
err error
f *os.File
)
if f, err = os.Open(imgInfo.Path); nil != err {
return nil, err
}
defer func() {
_ = f.Close()
}()
switch imgInfo.Type {
case TypePNG:
if img, imgErr := png.Decode(f); nil != err {
return nil, imgErr
} else {
return img, nil
}
case TypeJPEG:
fallthrough
case TypeJPG:
if img, imgErr := jpeg.Decode(f); nil != err {
return nil, imgErr
} else {
return img, nil
}
case TypeGIF:
if img, imgErr := gif.Decode(f); nil != err {
return nil, imgErr
} else {
return img, nil
}
default:
return nil, errors.New(imgInfo.Type + " is not support!")
}
}
// getPalette ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 3:01 下午 2021/11/29
func (g *GIFConvert) getPalette(m image.Image) color.Palette {
p := color.Palette{color.RGBA{0x00, 0x00, 0x00, 0x00}}
p9 := color.Palette(palette.Plan9)
b := m.Bounds()
black := false
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
c := m.At(x, y)
cc := p9.Convert(c)
if cc == p9[0] {
black = true
}
if g.isInPalette(p, cc) == -1 {
p = append(p, cc)
}
}
}
if len(p) < 256 && black == true {
p[0] = color.RGBA{0x00, 0x00, 0x00, 0x00} // transparent
p = append(p, p9[0])
}
return p
}
// isInPalette ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 3:01 下午 2021/11/29
func (g *GIFConvert) isInPalette(p color.Palette, c color.Color) int {
ret := -1
for i, v := range p {
if v == c {
return i
}
}
return ret
}