From 8fe5a7dd10d82a1b19a0fd852465619bb08ee0c2 Mon Sep 17 00:00:00 2001 From: GoEdgeLab Date: Fri, 29 Oct 2021 12:19:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81gif=E8=BD=ACwebp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 3 +- go.sum | 2 ++ internal/nodes/http_writer.go | 67 +++++++++++++++++++++++++++++------ 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index e247494..61aaceb 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/andybalholm/brotli v1.0.3 github.com/biessek/golang-ico v0.0.0-20180326222316-d348d9ea4670 github.com/cespare/xxhash v1.1.0 - github.com/chai2010/webp v1.1.0 + github.com/chai2010/webp v1.1.0 // indirect github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f github.com/dop251/goja v0.0.0-20210804101310-32956a348b49 github.com/go-ole/go-ole v1.2.4 // indirect @@ -19,6 +19,7 @@ require ( github.com/iwind/TeaGo v0.0.0-20210628135026-38575a4ab060 github.com/iwind/gofcgi v0.0.0-20210528023741-a92711d45f11 github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3 + github.com/iwind/gowebp v0.0.0-20211029040624-7331ecc78ed8 github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect github.com/lionsoul2014/ip2region v2.2.0-release+incompatible github.com/mattn/go-sqlite3 v2.0.3+incompatible diff --git a/go.sum b/go.sum index a7a9502..8a806d8 100644 --- a/go.sum +++ b/go.sum @@ -82,6 +82,8 @@ github.com/iwind/gofcgi v0.0.0-20210528023741-a92711d45f11 h1:DaQjoWZhLNxjhIXedV github.com/iwind/gofcgi v0.0.0-20210528023741-a92711d45f11/go.mod h1:JtbX20untAjUVjZs1ZBtq80f5rJWvwtQNRL6EnuYRnY= github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3 h1:aBSonas7vFcgTj9u96/bWGILGv1ZbUSTLiOzcI1ZT6c= github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA= +github.com/iwind/gowebp v0.0.0-20211029040624-7331ecc78ed8 h1:AojsHz9Es9B3He2MQQxeRq3TyD//o9huxUo7r1wh44g= +github.com/iwind/gowebp v0.0.0-20211029040624-7331ecc78ed8/go.mod h1:QJBY2txYhLMzwLO29iB5ujDJ3s3V7DsZ582nw4Ss+tM= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e h1:LvL4XsI70QxOGHed6yhQtAU34Kx3Qq2wwBzGFKY8zKk= github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw= diff --git a/internal/nodes/http_writer.go b/internal/nodes/http_writer.go index 249a103..fd32d7d 100644 --- a/internal/nodes/http_writer.go +++ b/internal/nodes/http_writer.go @@ -12,12 +12,13 @@ import ( "github.com/TeaOSLab/EdgeNode/internal/utils" "github.com/andybalholm/brotli" _ "github.com/biessek/golang-ico" - "github.com/chai2010/webp" "github.com/iwind/TeaGo/lists" "github.com/iwind/TeaGo/types" + "github.com/iwind/gowebp" _ "golang.org/x/image/bmp" _ "golang.org/x/image/webp" "image" + "image/gif" _ "image/gif" _ "image/jpeg" _ "image/png" @@ -278,6 +279,9 @@ func (this *HTTPWriter) Close() { // 需要把字节读取出来做备份,防止在image.Decode()过程中丢失 var imageBytes = this.webpBuffer.Bytes() var imageData image.Image + var gifImage *gif.GIF + var isGif = strings.Contains(this.webpOriginContentType, "image/gif") + var err error if this.webpOriginEncoding == "gzip" { this.Header().Del("Content-Encoding") @@ -287,7 +291,11 @@ func (this *HTTPWriter) Close() { defer func() { _ = reader.Close() }() - imageData, _, err = image.Decode(reader) + if isGif { + gifImage, err = gif.DecodeAll(reader) + } else { + imageData, _, err = image.Decode(reader) + } } } else if this.webpOriginEncoding == "deflate" { this.Header().Del("Content-Encoding") @@ -296,14 +304,26 @@ func (this *HTTPWriter) Close() { defer func() { _ = reader.Close() }() - imageData, _, err = image.Decode(reader) + if isGif { + gifImage, err = gif.DecodeAll(reader) + } else { + imageData, _, err = image.Decode(reader) + } } else if this.webpOriginEncoding == "br" { this.Header().Del("Content-Encoding") var reader *brotli.Reader reader = brotli.NewReader(this.webpBuffer) - imageData, _, err = image.Decode(reader) + if isGif { + gifImage, err = gif.DecodeAll(reader) + } else { + imageData, _, err = image.Decode(reader) + } } else { - imageData, _, err = image.Decode(this.webpBuffer) + if isGif { + gifImage, err = gif.DecodeAll(this.webpBuffer) + } else { + imageData, _, err = image.Decode(this.webpBuffer) + } } if err != nil { this.Header().Set("Content-Type", this.webpOriginContentType) @@ -322,11 +342,38 @@ func (this *HTTPWriter) Close() { } this.webpIsWriting = true - err = webp.Encode(this, imageData, &webp.Options{ - Lossless: false, - Quality: f, - Exact: true, - }) + if imageData != nil { + err = gowebp.Encode(this, imageData, &gowebp.Options{ + Lossless: false, + Quality: f, + Exact: true, + }) + } else if gifImage != nil { + anim := gowebp.NewWebpAnimation(gifImage.Config.Width, gifImage.Config.Height, gifImage.LoopCount) + anim.WebPAnimEncoderOptions.SetKmin(9) + anim.WebPAnimEncoderOptions.SetKmax(17) + defer anim.ReleaseMemory() + webpConfig := gowebp.NewWebpConfig() + //webpConfig.SetLossless(1) + webpConfig.SetQuality(f) + + timeline := 0 + + for i, img := range gifImage.Image { + err = anim.AddFrame(img, timeline, webpConfig) + if err != nil { + break + } + timeline += gifImage.Delay[i] * 10 + } + if err == nil { + err = anim.AddFrame(nil, timeline, webpConfig) + + if err == nil { + err = anim.Encode(this) + } + } + } if err != nil { if !this.req.canIgnore(err) { remotelogs.Error("HTTP_WRITER", "encode webp failed: "+err.Error())