From 85c0799243f1668d26b39b2626bfd099ac771781 Mon Sep 17 00:00:00 2001 From: nopo Date: Mon, 13 Apr 2026 21:56:22 +0900 Subject: [PATCH 1/4] =?UTF-8?q?Dev:=20Webp=E3=82=92=E3=82=B9=E3=82=BF?= =?UTF-8?q?=E3=83=B3=E3=83=97=E3=81=AE=E7=94=BB=E5=83=8F=E5=BD=A2=E5=BC=8F?= =?UTF-8?q?=E3=81=AB=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- router/consts/mime_types.go | 1 + router/utils/process_image.go | 31 ++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/router/consts/mime_types.go b/router/consts/mime_types.go index 25a9fb24b..c1066564e 100644 --- a/router/consts/mime_types.go +++ b/router/consts/mime_types.go @@ -5,4 +5,5 @@ const ( MimeImageJPEG = "image/jpeg" MimeImageGIF = "image/gif" MimeImageSVG = "image/svg+xml" + MimeImageWebP = "image/webp" ) diff --git a/router/utils/process_image.go b/router/utils/process_image.go index abb9f099f..6d19f4bc5 100644 --- a/router/utils/process_image.go +++ b/router/utils/process_image.go @@ -5,7 +5,8 @@ import ( "bytes" "image/png" "io" - + "github.com/sapphi-red/midec" + _ "github.com/sapphi-red/midec/webp" "github.com/gofrs/uuid" "github.com/labstack/echo/v4" @@ -81,6 +82,34 @@ func saveUploadImage(p imaging.Processor, c echo.Context, m file.Manager, name s args.MimeType = consts.MimeImagePNG args.Thumbnail = img // サムネイル画像より小さいという前提 + case consts.MimeImageWebP: + isAnimated, _ := midec.IsAnimated(src) + if _, seekErr := src.Seek(0, io.SeekStart); seekErr != nil { + return uuid.Nil, herror.InternalServerError(seekErr) + } + if isAnimated { + return uuid.Nil, herror.BadRequest("animated WebP is not supported") + } + img, err := p.Fit(src, maxImageSize, maxImageSize) + if err != nil { + switch err { + case imaging.ErrInvalidImageSrc: + return uuid.Nil, herror.BadRequest(badImage) + case imaging.ErrPixelLimitExceeded: + return uuid.Nil, herror.BadRequest(tooLargeImage) + default: + return uuid.Nil, herror.InternalServerError(err) + } + } + b := bytes.Buffer{} + if err := png.Encode(&b, img); err != nil { + return uuid.Nil, herror.InternalServerError(err) + } + args.Src = bytes.NewReader(b.Bytes()) + args.FileSize = int64(b.Len()) + args.MimeType = consts.MimeImagePNG + args.Thumbnail = img + case consts.MimeImageGIF: // リサイズ b, err := p.FitAnimationGIF(src, maxImageSize, maxImageSize) From d6a7ccdf762ca06ccbfb7d684a9f478e89b6a088 Mon Sep 17 00:00:00 2001 From: nopo Date: Tue, 11 Aug 2026 22:36:58 +0900 Subject: [PATCH 2/4] =?UTF-8?q?Fix:=20WebP=E7=94=BB=E5=83=8F=E5=87=A6?= =?UTF-8?q?=E7=90=86=E3=81=AE=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E6=8C=87?= =?UTF-8?q?=E6=91=98=E3=82=92=E5=8F=8D=E6=98=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- router/utils/process_image.go | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/router/utils/process_image.go b/router/utils/process_image.go index 6d19f4bc5..6715ba466 100644 --- a/router/utils/process_image.go +++ b/router/utils/process_image.go @@ -3,12 +3,13 @@ package utils import ( "bytes" + "errors" "image/png" "io" - "github.com/sapphi-red/midec" - _ "github.com/sapphi-red/midec/webp" + "github.com/gofrs/uuid" "github.com/labstack/echo/v4" + "github.com/sapphi-red/midec" "github.com/traPtitech/traQ/model" "github.com/traPtitech/traQ/router/consts" @@ -61,10 +62,10 @@ func saveUploadImage(p imaging.Processor, c echo.Context, m file.Manager, name s case consts.MimeImagePNG, consts.MimeImageJPEG: img, err := p.Fit(src, maxImageSize, maxImageSize) if err != nil { - switch err { - case imaging.ErrInvalidImageSrc: + switch { + case errors.Is(err, imaging.ErrInvalidImageSrc): return uuid.Nil, herror.BadRequest(badImage) - case imaging.ErrPixelLimitExceeded: + case err == imaging.ErrPixelLimitExceeded: return uuid.Nil, herror.BadRequest(tooLargeImage) default: return uuid.Nil, herror.InternalServerError(err) @@ -72,7 +73,7 @@ func saveUploadImage(p imaging.Processor, c echo.Context, m file.Manager, name s } // PNGに変換 - b := bytes.Buffer{} + var b bytes.Buffer if err := png.Encode(&b, img); err != nil { return uuid.Nil, herror.InternalServerError(err) } @@ -83,25 +84,28 @@ func saveUploadImage(p imaging.Processor, c echo.Context, m file.Manager, name s args.Thumbnail = img // サムネイル画像より小さいという前提 case consts.MimeImageWebP: - isAnimated, _ := midec.IsAnimated(src) - if _, seekErr := src.Seek(0, io.SeekStart); seekErr != nil { - return uuid.Nil, herror.InternalServerError(seekErr) + isAnimated, err := midec.IsAnimated(src) + if _, err := src.Seek(0, io.SeekStart); err != nil { + return uuid.Nil, herror.InternalServerError(err) + } + if err != nil { + return uuid.Nil, herror.BadRequest(badImage) } if isAnimated { return uuid.Nil, herror.BadRequest("animated WebP is not supported") } img, err := p.Fit(src, maxImageSize, maxImageSize) if err != nil { - switch err { - case imaging.ErrInvalidImageSrc: + switch { + case errors.Is(err, imaging.ErrInvalidImageSrc): return uuid.Nil, herror.BadRequest(badImage) - case imaging.ErrPixelLimitExceeded: + case err == imaging.ErrPixelLimitExceeded: return uuid.Nil, herror.BadRequest(tooLargeImage) - default: + default: return uuid.Nil, herror.InternalServerError(err) } } - b := bytes.Buffer{} + var b bytes.Buffer if err := png.Encode(&b, img); err != nil { return uuid.Nil, herror.InternalServerError(err) } @@ -109,7 +113,6 @@ func saveUploadImage(p imaging.Processor, c echo.Context, m file.Manager, name s args.FileSize = int64(b.Len()) args.MimeType = consts.MimeImagePNG args.Thumbnail = img - case consts.MimeImageGIF: // リサイズ b, err := p.FitAnimationGIF(src, maxImageSize, maxImageSize) From ec8b2e1872483503deea398c20cef220f88c6737 Mon Sep 17 00:00:00 2001 From: nopo Date: Wed, 12 Aug 2026 00:23:20 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Fix:=20=E9=9D=99=E6=AD=A2WebP=E7=94=BB?= =?UTF-8?q?=E5=83=8F=E3=82=92WebP=E5=BD=A2=E5=BC=8F=E3=81=AE=E3=81=BE?= =?UTF-8?q?=E3=81=BE=E4=BF=9D=E5=AD=98=E3=80=81APIdocs=E8=BF=BD=E8=A8=98?= =?UTF-8?q?=E3=80=81TODO=E8=A8=98=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/v3-api.yaml | 42 +++++++++++++++++++++++++++-------- go.mod | 1 + go.sum | 2 ++ router/utils/process_image.go | 6 +++-- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/docs/v3-api.yaml b/docs/v3-api.yaml index adbb62c32..1afdf7e0c 100644 --- a/docs/v3-api.yaml +++ b/docs/v3-api.yaml @@ -792,7 +792,7 @@ paths: $ref: "#/components/schemas/PostStampRequest" encoding: file: - contentType: "image/png, image/jpeg, image/gif, image/svg+xml" + contentType: "image/png, image/jpeg, image/gif, image/webp, image/svg+xml" description: "" operationId: createStamp tags: @@ -1084,7 +1084,7 @@ paths: $ref: "#/components/schemas/PutUserIconRequest" encoding: file: - contentType: "image/png, image/jpeg, image/gif" + contentType: "image/png, image/jpeg, image/gif, image/webp" description: "" tags: - group @@ -1704,6 +1704,10 @@ paths: schema: type: string format: binary + image/webp: + schema: + type: string + format: binary image/png: schema: type: string @@ -1737,7 +1741,7 @@ paths: $ref: "#/components/schemas/PutUserIconRequest" encoding: file: - contentType: "image/png, image/jpeg, image/gif" + contentType: "image/png, image/jpeg, image/gif, image/webp" description: "" tags: - webhook @@ -1761,6 +1765,10 @@ paths: schema: type: string format: binary + image/webp: + schema: + type: string + format: binary image/png: schema: type: string @@ -1796,7 +1804,7 @@ paths: $ref: "#/components/schemas/PutUserIconRequest" encoding: file: - contentType: "image/png, image/jpeg, image/gif" + contentType: "image/png, image/jpeg, image/gif, image/webp" tags: - user description: |- @@ -1819,6 +1827,10 @@ paths: schema: type: string format: binary + image/webp: + schema: + type: string + format: binary image/png: schema: type: string @@ -1849,7 +1861,7 @@ paths: $ref: "#/components/schemas/PutUserIconRequest" encoding: file: - contentType: "image/png, image/jpeg, image/gif" + contentType: "image/png, image/jpeg, image/gif, image/webp" tags: - me /users/me/password: @@ -2921,6 +2933,10 @@ paths: schema: type: string format: binary + image/webp: + schema: + type: string + format: binary image/png: schema: type: string @@ -3187,6 +3203,10 @@ paths: schema: type: string format: binary + image/webp: + schema: + type: string + format: binary image/png: schema: type: string @@ -3224,7 +3244,7 @@ paths: $ref: "#/components/schemas/PutUserIconRequest" encoding: file: - contentType: "image/png, image/jpeg, image/gif" + contentType: "image/png, image/jpeg, image/gif, image/webp" tags: - bot description: |- @@ -3967,6 +3987,10 @@ paths: schema: type: string format: binary + image/webp: + schema: + type: string + format: binary image/jpeg: schema: type: string @@ -4003,7 +4027,7 @@ paths: file: type: string format: binary - description: "スタンプ画像(1MBまでのpng, jpeg, gif)" + description: "スタンプ画像(1MBまでのpng, jpeg, gif, 静止webp)" required: - file description: "" @@ -5222,7 +5246,7 @@ components: file: type: string format: binary - description: "スタンプ画像(1MBまでのpng, jpeg, gif)" + description: "スタンプ画像(1MBまでのpng, jpeg, gif, 静止webp)" required: - name - file @@ -5971,7 +5995,7 @@ components: file: type: string format: binary - description: "アイコン画像(2MB,`Config.Imaging.MaxPixels`(default: 2560*1600)までのpng, jpeg, gif)" + description: "アイコン画像(2MB,`Config.Imaging.MaxPixels`(default: 2560*1600)までのpng, jpeg, gif, 静止webp)" required: - file PutMyPasswordRequest: diff --git a/go.mod b/go.mod index 07864198e..e2aa003c6 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ toolchain go1.26.1 require ( cloud.google.com/go/profiler v0.4.3 firebase.google.com/go/v4 v4.19.0 + github.com/HugoSmits86/nativewebp v1.3.0 github.com/MicahParks/jwkset v0.11.0 github.com/NYTimes/gziphandler v1.1.1 github.com/aws/aws-sdk-go-v2 v1.41.1 diff --git a/go.sum b/go.sum index bc1479841..c62c8b887 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0 github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0/go.mod h1:jUZ5LYlw40WMd07qxcQJD5M40aUxrfwqQX1g7zxYnrQ= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo= +github.com/HugoSmits86/nativewebp v1.3.0 h1:n1egtEzSV4KwFtealr7dzdYq1wI/uj/bOQ/QcTcIyVE= +github.com/HugoSmits86/nativewebp v1.3.0/go.mod h1:YNQuWenlVmSUUASVNhTDwf4d7FwYQGbGhklC8p72Vr8= github.com/MicahParks/jwkset v0.11.0 h1:yc0zG+jCvZpWgFDFmvs8/8jqqVBG9oyIbmBtmjOhoyQ= github.com/MicahParks/jwkset v0.11.0/go.mod h1:U2oRhRaLgDCLjtpGL2GseNKGmZtLs/3O7p+OZaL5vo0= github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o= diff --git a/router/utils/process_image.go b/router/utils/process_image.go index 6715ba466..3f43619f4 100644 --- a/router/utils/process_image.go +++ b/router/utils/process_image.go @@ -7,6 +7,7 @@ import ( "image/png" "io" + "github.com/HugoSmits86/nativewebp" "github.com/gofrs/uuid" "github.com/labstack/echo/v4" "github.com/sapphi-red/midec" @@ -91,6 +92,7 @@ func saveUploadImage(p imaging.Processor, c echo.Context, m file.Manager, name s if err != nil { return uuid.Nil, herror.BadRequest(badImage) } + // TODO: アニメーションWebP対応 if isAnimated { return uuid.Nil, herror.BadRequest("animated WebP is not supported") } @@ -106,12 +108,12 @@ func saveUploadImage(p imaging.Processor, c echo.Context, m file.Manager, name s } } var b bytes.Buffer - if err := png.Encode(&b, img); err != nil { + if err := nativewebp.Encode(&b, img, nil); err != nil { return uuid.Nil, herror.InternalServerError(err) } args.Src = bytes.NewReader(b.Bytes()) args.FileSize = int64(b.Len()) - args.MimeType = consts.MimeImagePNG + args.MimeType = consts.MimeImageWebP args.Thumbnail = img case consts.MimeImageGIF: // リサイズ From 4bc806c20489304e91356adb93432fc7b2aec740 Mon Sep 17 00:00:00 2001 From: nopo Date: Fri, 4 Sep 2026 11:12:26 +0900 Subject: [PATCH 4/4] Update process_image.go --- router/utils/process_image.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/router/utils/process_image.go b/router/utils/process_image.go index 9245a8539..644e06cbf 100644 --- a/router/utils/process_image.go +++ b/router/utils/process_image.go @@ -10,7 +10,7 @@ import ( "github.com/HugoSmits86/nativewebp" "github.com/gofrs/uuid" "github.com/labstack/echo/v5" - "github.com/sapphi-red/midec" + "github.com/sapphi-red/midec" "github.com/traPtitech/traQ/model" "github.com/traPtitech/traQ/router/consts"