diff --git a/README.md b/README.md index c7702163f..2351ece29 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ imagor supports the following filters: - `sharpen(sigma)` sharpens the image - `strip_exif()` removes Exif metadata from the resulting image - `strip_icc()` removes ICC profile information from the resulting image +- `strip_metadata()` removes all metadata from the resulting image - `upscale()` upscale the image if `fit-in` is used - `watermark(image, x, y, alpha [, w_ratio [, h_ratio]])` adds a watermark to the image. It can be positioned inside the image with the alpha channel specified and optionally resized based on the image size by specifying the ratio - `image` watermark image URI, using the same image loader configured for imagor @@ -811,4 +812,6 @@ Usage of imagor: VIPS enable maximum compression with MozJPEG. Requires mozjpeg to be installed -vips-avif-speed int VIPS avif speed, the lowest is at 0 and the fastest is at 9 (Default 5). + -vips-strip-metadata + VIPS strips all metadata from the resulting image ``` diff --git a/config/vipsconfig/vipsconfig.go b/config/vipsconfig/vipsconfig.go index b3167f22e..377f8d1de 100644 --- a/config/vipsconfig/vipsconfig.go +++ b/config/vipsconfig/vipsconfig.go @@ -36,6 +36,8 @@ func WithVips(fs *flag.FlagSet, cb func() (*zap.Logger, bool)) imagor.Option { "VIPS enable maximum compression with MozJPEG. Requires mozjpeg to be installed") vipsAvifSpeed = fs.Int("vips-avif-speed", 5, "VIPS avif speed, the lowest is at 0 and the fastest is at 9 (Default 5).") + vipsStripMetadata = fs.Bool("vips-strip-metadata", false, + "VIPS strips all metadata from the resulting image") logger, isDebug = cb() ) @@ -54,6 +56,7 @@ func WithVips(fs *flag.FlagSet, cb func() (*zap.Logger, bool)) imagor.Option { vips.WithMaxResolution(*vipsMaxResolution), vips.WithMozJPEG(*vipsMozJPEG), vips.WithAvifSpeed(*vipsAvifSpeed), + vips.WithStripMetadata(*vipsStripMetadata), vips.WithLogger(logger), vips.WithDebug(isDebug), ), diff --git a/testdata/golden/fit-in/67x67/dancing-banana.gif b/testdata/golden/fit-in/67x67/dancing-banana.gif new file mode 100644 index 000000000..124c43634 Binary files /dev/null and b/testdata/golden/fit-in/67x67/dancing-banana.gif differ diff --git a/testdata/golden/fit-in/67x67/demo1.jpg b/testdata/golden/fit-in/67x67/demo1.jpg new file mode 100644 index 000000000..d64c4c6a2 Binary files /dev/null and b/testdata/golden/fit-in/67x67/demo1.jpg differ diff --git a/testdata/golden/fit-in/67x67/demo3.webp b/testdata/golden/fit-in/67x67/demo3.webp new file mode 100644 index 000000000..b37ad27e3 Binary files /dev/null and b/testdata/golden/fit-in/67x67/demo3.webp differ diff --git a/testdata/golden/fit-in/67x67/filters%3Astrip_metadata%28%29/dancing-banana.gif b/testdata/golden/fit-in/67x67/filters%3Astrip_metadata%28%29/dancing-banana.gif new file mode 100644 index 000000000..124c43634 Binary files /dev/null and b/testdata/golden/fit-in/67x67/filters%3Astrip_metadata%28%29/dancing-banana.gif differ diff --git a/testdata/golden/fit-in/67x67/filters%3Astrip_metadata%28%29/demo1.jpg b/testdata/golden/fit-in/67x67/filters%3Astrip_metadata%28%29/demo1.jpg new file mode 100644 index 000000000..d64c4c6a2 Binary files /dev/null and b/testdata/golden/fit-in/67x67/filters%3Astrip_metadata%28%29/demo1.jpg differ diff --git a/testdata/golden/fit-in/67x67/filters%3Astrip_metadata%28%29/demo3.webp b/testdata/golden/fit-in/67x67/filters%3Astrip_metadata%28%29/demo3.webp new file mode 100644 index 000000000..b37ad27e3 Binary files /dev/null and b/testdata/golden/fit-in/67x67/filters%3Astrip_metadata%28%29/demo3.webp differ diff --git a/testdata/golden/fit-in/67x67/filters%3Astrip_metadata%28%29/gopher.tiff b/testdata/golden/fit-in/67x67/filters%3Astrip_metadata%28%29/gopher.tiff new file mode 100644 index 000000000..c4c95a12c Binary files /dev/null and b/testdata/golden/fit-in/67x67/filters%3Astrip_metadata%28%29/gopher.tiff differ diff --git a/testdata/golden/fit-in/67x67/gopher-front.png b/testdata/golden/fit-in/67x67/gopher-front.png new file mode 100644 index 000000000..50ecfc9aa Binary files /dev/null and b/testdata/golden/fit-in/67x67/gopher-front.png differ diff --git a/testdata/golden/fit-in/67x67/gopher.tiff b/testdata/golden/fit-in/67x67/gopher.tiff new file mode 100644 index 000000000..c4c95a12c Binary files /dev/null and b/testdata/golden/fit-in/67x67/gopher.tiff differ diff --git a/vips/option.go b/vips/option.go index df95da666..24c1cf4d3 100644 --- a/vips/option.go +++ b/vips/option.go @@ -44,6 +44,13 @@ func WithMozJPEG(enabled bool) Option { } } +// WithStripMetadata with strip all metadata from image option +func WithStripMetadata(enabled bool) Option { + return func(v *Processor) { + v.StripMetadata = enabled + } +} + // WithAvifSpeed with avif speed option func WithAvifSpeed(avifSpeed int) Option { return func(v *Processor) { diff --git a/vips/option_test.go b/vips/option_test.go index f78d9d100..043525d3b 100644 --- a/vips/option_test.go +++ b/vips/option_test.go @@ -21,6 +21,7 @@ func TestWithOption(t *testing.T) { WithMaxResolution(1666667), WithMozJPEG(true), WithAvifSpeed(9), + WithStripMetadata(true), WithDebug(true), WithMaxAnimationFrames(3), WithDisableFilters("rgb", "fill, watermark"), @@ -38,6 +39,7 @@ func TestWithOption(t *testing.T) { assert.Equal(t, 1666667, v.MaxResolution) assert.Equal(t, 3, v.MaxAnimationFrames) assert.Equal(t, true, v.MozJPEG) + assert.Equal(t, true, v.StripMetadata) assert.Equal(t, 9, v.AvifSpeed) assert.Equal(t, []string{"rgb", "fill", "watermark"}, v.DisableFilters) diff --git a/vips/process.go b/vips/process.go index eb8b0dfb1..9ec92e7d6 100644 --- a/vips/process.go +++ b/vips/process.go @@ -40,6 +40,7 @@ func (v *Processor) Process( stretch = p.Stretch thumbnail = false stripExif bool + stripMetadata = v.StripMetadata orient int img *Image format = ImageTypeUnknown @@ -122,6 +123,8 @@ func (v *Processor) Process( break case "strip_exif": stripExif = true + case "strip_metadata": + stripMetadata = true break } } @@ -313,7 +316,7 @@ func (v *Processor) Process( } format = supportedSaveFormat(format) // convert to supported export format for { - buf, err := v.export(img, format, compression, quality, palette, bitdepth, stripExif) + buf, err := v.export(img, format, compression, quality, palette, bitdepth, stripMetadata) if err != nil { return nil, WrapErr(err) } @@ -575,7 +578,7 @@ func supportedSaveFormat(format ImageType) ImageType { } func (v *Processor) export( - image *Image, format ImageType, compression int, quality int, palette bool, bitdepth int, stripExif bool, + image *Image, format ImageType, compression int, quality int, palette bool, bitdepth int, stripMetadata bool, ) ([]byte, error) { switch format { case ImageTypePNG: @@ -592,13 +595,16 @@ func (v *Processor) export( if compression > 0 { opts.Compression = compression } + if stripMetadata { + opts.StripMetadata = true + } return image.ExportPng(opts) case ImageTypeWEBP: opts := NewWebpExportParams() if quality > 0 { opts.Quality = quality } - if stripExif { + if stripMetadata { opts.StripMetadata = true } return image.ExportWebp(opts) @@ -607,19 +613,25 @@ func (v *Processor) export( if quality > 0 { opts.Quality = quality } + if stripMetadata { + opts.StripMetadata = true + } return image.ExportTiff(opts) case ImageTypeGIF: opts := NewGifExportParams() if quality > 0 { opts.Quality = quality } + if stripMetadata { + opts.StripMetadata = true + } return image.ExportGIF(opts) case ImageTypeAVIF: opts := NewAvifExportParams() if quality > 0 { opts.Quality = quality } - if stripExif { + if stripMetadata { opts.StripMetadata = true } opts.Speed = v.AvifSpeed @@ -650,6 +662,9 @@ func (v *Processor) export( if quality > 0 { opts.Quality = quality } + if stripMetadata { + opts.StripMetadata = true + } return image.ExportJpeg(opts) } } diff --git a/vips/processor.go b/vips/processor.go index a62c66a4f..3456173ff 100644 --- a/vips/processor.go +++ b/vips/processor.go @@ -36,6 +36,7 @@ type Processor struct { MaxResolution int MaxAnimationFrames int MozJPEG bool + StripMetadata bool AvifSpeed int Debug bool @@ -305,7 +306,7 @@ func (v *Processor) FocalThumbnail(img *Image, w, h int, fx, fy float64) (err er imageHeight = float64(img.PageHeight()) } - if float64(w)/float64(h) > float64(imageWidth)/float64(imageHeight) { + if float64(w)/float64(h) > float64(imageWidth)/float64(imageHeight) { if err = img.Thumbnail(w, v.MaxHeight, InterestingNone); err != nil { return } diff --git a/vips/processor_test.go b/vips/processor_test.go index d9d19f1c9..0be7f60a6 100644 --- a/vips/processor_test.go +++ b/vips/processor_test.go @@ -75,6 +75,28 @@ func TestProcessor(t *testing.T) { {name: "meta strip exif", path: "meta/filters:strip_exif()/Canon_40D.jpg"}, }, WithDebug(true), WithLogger(zap.NewExample())) }) + t.Run("vips strip metadata config", func(t *testing.T) { + var resultDir = filepath.Join(testDataDir, "golden") + doGoldenTests(t, resultDir, []test{ + {name: "png", path: "fit-in/67x67/gopher-front.png"}, + {name: "jpeg", path: "fit-in/67x67/demo1.jpg"}, + {name: "webp", path: "fit-in/67x67/demo3.webp", arm64Golden: true}, + {name: "tiff", path: "fit-in/67x67/gopher.tiff"}, + {name: "tiff", path: "fit-in/67x67/dancing-banana.gif"}, + //{name: "avif", path: "fit-in/67x67/gopher-front.avif", checkTypeOnly: true}, + }, WithDebug(true), WithStripMetadata(true), WithLogger(zap.NewExample())) + }) + t.Run("vips strip_metadata filter", func(t *testing.T) { + var resultDir = filepath.Join(testDataDir, "golden") + doGoldenTests(t, resultDir, []test{ + {name: "png", path: "gopher-front.png"}, + {name: "jpeg", path: "fit-in/67x67/filters:strip_metadata()/demo1.jpg"}, + {name: "webp", path: "fit-in/67x67/filters:strip_metadata()/demo3.webp", arm64Golden: true}, + {name: "tiff", path: "fit-in/67x67/filters:strip_metadata()/gopher.tiff"}, + {name: "gif", path: "fit-in/67x67/filters:strip_metadata()/dancing-banana.gif"}, + //{name: "avif", path: "fit-in/67x67/filters:strip_metadata()/gopher-front.avif", checkTypeOnly: true}, + }, WithDebug(true), WithLogger(zap.NewExample())) + }) t.Run("vips operations", func(t *testing.T) { var resultDir = filepath.Join(testDataDir, "golden") doGoldenTests(t, resultDir, []test{