diff --git a/CHANGELOG.md b/CHANGELOG.md index 81004896..a1c4fdb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## [Unreleased] +### Change +- Allow relative values for `gravity` and `watermark` offsets. ## [3.21.0] - 2023-11-23 ### Add diff --git a/options/processing_options.go b/options/processing_options.go index 30512e44..71b859f7 100644 --- a/options/processing_options.go +++ b/options/processing_options.go @@ -733,16 +733,16 @@ func applyWatermarkOption(po *ProcessingOptions, args []string) error { } if len(args) > 2 && len(args[2]) > 0 { - if x, err := strconv.Atoi(args[2]); err == nil { - po.Watermark.Gravity.X = float64(x) + if x, err := strconv.ParseFloat(args[2], 64); err == nil { + po.Watermark.Gravity.X = x } else { return fmt.Errorf("Invalid watermark X offset: %s", args[2]) } } if len(args) > 3 && len(args[3]) > 0 { - if y, err := strconv.Atoi(args[3]); err == nil { - po.Watermark.Gravity.Y = float64(y) + if y, err := strconv.ParseFloat(args[3], 64); err == nil { + po.Watermark.Gravity.Y = y } else { return fmt.Errorf("Invalid watermark Y offset: %s", args[3]) } diff --git a/processing/calc_position.go b/processing/calc_position.go index fea7975c..5cf6bf4c 100644 --- a/processing/calc_position.go +++ b/processing/calc_position.go @@ -15,7 +15,19 @@ func calcPosition(width, height, innerWidth, innerHeight int, gravity *options.G left = pointX - innerWidth/2 top = pointY - innerHeight/2 } else { - offX, offY := int(math.RoundToEven(gravity.X*dpr)), int(math.RoundToEven(gravity.Y*dpr)) + var offX, offY int + + if math.Abs(gravity.X) >= 1.0 { + offX = imath.RoundToEven(gravity.X * dpr) + } else { + offX = imath.ScaleToEven(width, gravity.X) + } + + if math.Abs(gravity.Y) >= 1.0 { + offY = imath.RoundToEven(gravity.Y * dpr) + } else { + offY = imath.ScaleToEven(height, gravity.Y) + } left = imath.ShrinkToEven(width-innerWidth+1, 2) + offX top = imath.ShrinkToEven(height-innerHeight+1, 2) + offY diff --git a/processing/scale_on_load.go b/processing/scale_on_load.go index 18f1f976..ab52eb2a 100644 --- a/processing/scale_on_load.go +++ b/processing/scale_on_load.go @@ -103,6 +103,8 @@ func scaleOnLoad(pctx *pipelineContext, img *vips.Image, po *options.ProcessingO pctx.hscale = 1.0 } + // We should crop before scaling, but we scaled the image on load, + // so we need to adjust crop options if pctx.cropWidth > 0 { pctx.cropWidth = imath.Max(1, imath.Shrink(pctx.cropWidth, wpreshrink)) } @@ -110,8 +112,14 @@ func scaleOnLoad(pctx *pipelineContext, img *vips.Image, po *options.ProcessingO pctx.cropHeight = imath.Max(1, imath.Shrink(pctx.cropHeight, hpreshrink)) } if pctx.cropGravity.Type != options.GravityFocusPoint { - pctx.cropGravity.X /= wpreshrink - pctx.cropGravity.Y /= hpreshrink + // Adjust only when crop gravity offsets are absolute + if math.Abs(pctx.cropGravity.X) >= 1.0 { + // Round offsets to prevent turning absolute offsets to relative (ex: 1.0 => 0.5) + pctx.cropGravity.X = math.RoundToEven(pctx.cropGravity.X / wpreshrink) + } + if math.Abs(pctx.cropGravity.Y) >= 1.0 { + pctx.cropGravity.Y = math.RoundToEven(pctx.cropGravity.Y / hpreshrink) + } } return nil