完成基础版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)
|
f, err := os.Stat(filePath)
|
||||||
return nil == err || os.IsExist(err), (nil == err || os.IsExist(err)) && !f.IsDir()
|
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