From df751774819b8a545e43381c49a5a4dc0b6944fa Mon Sep 17 00:00:00 2001 From: DarthSim Date: Wed, 24 Apr 2024 19:35:16 +0300 Subject: [PATCH] Replace WatermarkOptions.Gravity with GravityReplicate --- options/gravity_options.go | 17 +++++++++ options/processing_options.go | 40 ++++++++++++++------- options/processing_options_test.go | 56 +++++++++++++++++++++++++++++- processing/watermark.go | 10 +++--- 4 files changed, 104 insertions(+), 19 deletions(-) diff --git a/options/gravity_options.go b/options/gravity_options.go index 41ac2759..f454d86e 100644 --- a/options/gravity_options.go +++ b/options/gravity_options.go @@ -19,6 +19,9 @@ const ( GravitySouthEast GravitySmart GravityFocusPoint + + // Watermark gravity types + GravityReplicate ) var gravityTypes = map[string]GravityType{ @@ -33,6 +36,7 @@ var gravityTypes = map[string]GravityType{ "soea": GravitySouthEast, "sm": GravitySmart, "fp": GravityFocusPoint, + "re": GravityReplicate, } var gravityTypesRotationMap = map[int]map[GravityType]GravityType{ @@ -95,6 +99,19 @@ func (gt GravityType) MarshalJSON() ([]byte, error) { return []byte("null"), nil } +func (gt GravityType) OkForCrop() bool { + return gt != GravityUnknown && gt != GravityReplicate +} + +func (gt GravityType) OkForExtend() bool { + return gt.OkForCrop() && gt != GravitySmart +} + +func (gt GravityType) OkForWatermark() bool { + return gt == GravityReplicate || + (gt.OkForExtend() && gt != GravityFocusPoint) +} + type GravityOptions struct { Type GravityType X, Y float64 diff --git a/options/processing_options.go b/options/processing_options.go index 0fc4efef..b9d4fabd 100644 --- a/options/processing_options.go +++ b/options/processing_options.go @@ -54,11 +54,14 @@ type TrimOptions struct { } type WatermarkOptions struct { - Enabled bool - Opacity float64 - Replicate bool - Gravity GravityOptions - Scale float64 + Enabled bool + Opacity float64 + Gravity GravityOptions + Scale float64 +} + +func (wo WatermarkOptions) ShouldReplicate() bool { + return wo.Gravity.Type == GravityReplicate } type ProcessingOptions struct { @@ -139,7 +142,7 @@ func NewProcessingOptions() *ProcessingOptions { Blur: 0, Sharpen: 0, Dpr: 1, - Watermark: WatermarkOptions{Opacity: 1, Replicate: false, Gravity: GravityOptions{Type: GravityCenter}}, + Watermark: WatermarkOptions{Opacity: 1, Gravity: GravityOptions{Type: GravityCenter}}, StripMetadata: config.StripMetadata, KeepCopyright: config.KeepCopyright, StripColorProfile: config.StripColorProfile, @@ -264,8 +267,8 @@ func parseExtend(opts *ExtendOptions, name string, args []string) error { return err } - if opts.Gravity.Type == GravitySmart { - return fmt.Errorf("%s doesn't support smart gravity", name) + if !opts.Gravity.Type.OkForExtend() { + return fmt.Errorf("%s doesn't support %s gravity", name, opts.Gravity.Type) } } @@ -428,7 +431,15 @@ func applyDprOption(po *ProcessingOptions, args []string) error { } func applyGravityOption(po *ProcessingOptions, args []string) error { - return parseGravity(&po.Gravity, args) + if err := parseGravity(&po.Gravity, args); err != nil { + return err + } + + if !po.Gravity.Type.OkForCrop() { + return fmt.Errorf("%s gravity type is not applicable to gravity", po.Gravity.Type) + } + + return nil } func applyCropOption(po *ProcessingOptions, args []string) error { @@ -451,7 +462,12 @@ func applyCropOption(po *ProcessingOptions, args []string) error { } if len(args) > 2 { - return parseGravity(&po.Crop.Gravity, args[2:]) + if err := parseGravity(&po.Crop.Gravity, args[2:]); err != nil { + return err + } + if !po.Crop.Gravity.Type.OkForCrop() { + return fmt.Errorf("%s gravity type is not applicable to crop", po.Crop.Gravity.Type) + } } return nil @@ -715,9 +731,7 @@ func applyWatermarkOption(po *ProcessingOptions, args []string) error { } if len(args) > 1 && len(args[1]) > 0 { - if args[1] == "re" { - po.Watermark.Replicate = true - } else if g, ok := gravityTypes[args[1]]; ok && g != GravityFocusPoint && g != GravitySmart { + if g, ok := gravityTypes[args[1]]; ok && g.OkForWatermark() { po.Watermark.Gravity.Type = g } else { return fmt.Errorf("Invalid watermark position: %s", args[1]) diff --git a/options/processing_options_test.go b/options/processing_options_test.go index c2985bfa..52457b0b 100644 --- a/options/processing_options_test.go +++ b/options/processing_options_test.go @@ -236,6 +236,20 @@ func (s *ProcessingOptionsTestSuite) TestParsePathExtend() { s.Require().InDelta(20.0, po.Extend.Gravity.Y, 0.0001) } +func (s *ProcessingOptionsTestSuite) TestParsePathExtendSmartGravity() { + path := "/extend:1:sm/plain/http://images.dev/lorem/ipsum.jpg" + _, _, err := ParsePath(path, make(http.Header)) + + s.Require().Error(err) +} + +func (s *ProcessingOptionsTestSuite) TestParsePathExtendReplicateGravity() { + path := "/extend:1:re/plain/http://images.dev/lorem/ipsum.jpg" + _, _, err := ParsePath(path, make(http.Header)) + + s.Require().Error(err) +} + func (s *ProcessingOptionsTestSuite) TestParsePathGravity() { path := "/gravity:soea/plain/http://images.dev/lorem/ipsum.jpg" po, _, err := ParsePath(path, make(http.Header)) @@ -245,7 +259,7 @@ func (s *ProcessingOptionsTestSuite) TestParsePathGravity() { s.Require().Equal(GravitySouthEast, po.Gravity.Type) } -func (s *ProcessingOptionsTestSuite) TestParsePathGravityFocuspoint() { +func (s *ProcessingOptionsTestSuite) TestParsePathGravityFocusPoint() { path := "/gravity:fp:0.5:0.75/plain/http://images.dev/lorem/ipsum.jpg" po, _, err := ParsePath(path, make(http.Header)) @@ -256,6 +270,46 @@ func (s *ProcessingOptionsTestSuite) TestParsePathGravityFocuspoint() { s.Require().InDelta(0.75, po.Gravity.Y, 0.0001) } +func (s *ProcessingOptionsTestSuite) TestParsePathGravityReplicate() { + path := "/gravity:re/plain/http://images.dev/lorem/ipsum.jpg" + _, _, err := ParsePath(path, make(http.Header)) + + s.Require().Error(err) +} + +func (s *ProcessingOptionsTestSuite) TestParsePathCrop() { + path := "/crop:100:200/plain/http://images.dev/lorem/ipsum.jpg" + po, _, err := ParsePath(path, make(http.Header)) + + s.Require().NoError(err) + + s.Require().InDelta(100.0, po.Crop.Width, 0.0001) + s.Require().InDelta(200.0, po.Crop.Height, 0.0001) + s.Require().Equal(GravityUnknown, po.Crop.Gravity.Type) + s.Require().InDelta(0.0, po.Crop.Gravity.X, 0.0001) + s.Require().InDelta(0.0, po.Crop.Gravity.Y, 0.0001) +} + +func (s *ProcessingOptionsTestSuite) TestParsePathCropGravity() { + path := "/crop:100:200:nowe:10:20/plain/http://images.dev/lorem/ipsum.jpg" + po, _, err := ParsePath(path, make(http.Header)) + + s.Require().NoError(err) + + s.Require().InDelta(100.0, po.Crop.Width, 0.0001) + s.Require().InDelta(200.0, po.Crop.Height, 0.0001) + s.Require().Equal(GravityNorthWest, po.Crop.Gravity.Type) + s.Require().InDelta(10.0, po.Crop.Gravity.X, 0.0001) + s.Require().InDelta(20.0, po.Crop.Gravity.Y, 0.0001) +} + +func (s *ProcessingOptionsTestSuite) TestParsePathCropGravityReplicate() { + path := "/crop:100:200:re/plain/http://images.dev/lorem/ipsum.jpg" + _, _, err := ParsePath(path, make(http.Header)) + + s.Require().Error(err) +} + func (s *ProcessingOptionsTestSuite) TestParsePathQuality() { path := "/quality:55/plain/http://images.dev/lorem/ipsum.jpg" po, _, err := ParsePath(path, make(http.Header)) diff --git a/processing/watermark.go b/processing/watermark.go index fababa91..7844d4d4 100644 --- a/processing/watermark.go +++ b/processing/watermark.go @@ -36,7 +36,7 @@ func prepareWatermark(wm *vips.Image, wmData *imagedata.ImageData, opts *options po.Height = imath.Max(imath.ScaleToEven(imgHeight, opts.Scale), 1) } - if opts.Replicate { + if opts.ShouldReplicate() { var offX, offY int if math.Abs(opts.Gravity.X) >= 1.0 { @@ -62,7 +62,7 @@ func prepareWatermark(wm *vips.Image, wmData *imagedata.ImageData, opts *options return err } - if opts.Replicate || framesCount > 1 { + if opts.ShouldReplicate() || framesCount > 1 { // We need to copy image if we're going to replicate. // Replication requires image to be read several times, and this requires // random access to pixels @@ -71,7 +71,7 @@ func prepareWatermark(wm *vips.Image, wmData *imagedata.ImageData, opts *options } } - if opts.Replicate { + if opts.ShouldReplicate() { if err := wm.Replicate(imgWidth, imgHeight); err != nil { return err } @@ -111,7 +111,7 @@ func applyWatermark(img *vips.Image, wmData *imagedata.ImageData, opts *options. // If we replicated the watermark and need to apply it to an animated image, // it is faster to replicate the watermark to all the image and apply it single-pass - if opts.Replicate && framesCount > 1 { + if opts.ShouldReplicate() && framesCount > 1 { if err := wm.Replicate(width, height); err != nil { return err } @@ -121,7 +121,7 @@ func applyWatermark(img *vips.Image, wmData *imagedata.ImageData, opts *options. left, top := 0, 0 - if !opts.Replicate { + if !opts.ShouldReplicate() { left, top = calcPosition(width, frameHeight, wm.Width(), wm.Height(), &opts.Gravity, offsetScale, true) }