完成基础版GIF生成,待调优
This commit is contained in:
parent
6601f4e3c7
commit
e2ebb2ad75
29
image/define.go
Normal file
29
image/define.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Package image ...
|
||||
//
|
||||
// Description : image ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2021-11-29 2:27 下午
|
||||
package image
|
||||
|
||||
const (
|
||||
// TypeGIF ...
|
||||
TypeGIF = "gif"
|
||||
// TypePNG ...
|
||||
TypePNG = "png"
|
||||
// TypeJPG ...
|
||||
TypeJPG = "jpg"
|
||||
// TypeJPEG ...
|
||||
TypeJPEG = "jpeg"
|
||||
)
|
||||
|
||||
// ImgInfo ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2:45 下午 2021/11/29
|
||||
type ImgInfo struct {
|
||||
Path string
|
||||
Type string
|
||||
}
|
195
image/gif.go
Normal file
195
image/gif.go
Normal file
@ -0,0 +1,195 @@
|
||||
// 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
|
||||
}
|
24
image/gif_test.go
Normal file
24
image/gif_test.go
Normal file
@ -0,0 +1,24 @@
|
||||
// Package image ...
|
||||
//
|
||||
// Description : image ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2021-11-29 3:10 下午
|
||||
package image
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestGIFConvert_Generate ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 3:10 下午 2021/11/29
|
||||
func TestGIFConvert_Generate(t *testing.T) {
|
||||
sourceImgList := []string{"./test/1.jpeg", "./test/2.jpeg", "./test/3.jpeg", "./test/4.jpeg"}
|
||||
savePath := "./test/test.gif"
|
||||
fmt.Println(GIF.Generate(sourceImgList, savePath))
|
||||
}
|
BIN
image/test/1.jpeg
Normal file
BIN
image/test/1.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 153 KiB |
BIN
image/test/2.jpeg
Normal file
BIN
image/test/2.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 192 KiB |
BIN
image/test/3.jpeg
Normal file
BIN
image/test/3.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 142 KiB |
BIN
image/test/4.jpeg
Normal file
BIN
image/test/4.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 826 KiB |
BIN
image/test/test.gif
Normal file
BIN
image/test/test.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 404 KiB |
13
util/file.go
13
util/file.go
@ -85,3 +85,16 @@ func IsFileExist(filePath string) (bool, bool) {
|
||||
f, err := os.Stat(filePath)
|
||||
return nil == err || os.IsExist(err), (nil == err || os.IsExist(err)) && !f.IsDir()
|
||||
}
|
||||
|
||||
// GetFileType 获取文件类型
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2:30 下午 2021/11/29
|
||||
func GetFileType(fileName string) string {
|
||||
fileArr := strings.Split(fileName, ".")
|
||||
if len(fileArr) < 2 {
|
||||
return ""
|
||||
}
|
||||
return strings.ToLower(fileArr[len(fileArr)-1])
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user