Browse Source

Allow relative values for `gravity` and `watermark` offsets

DarthSim 1 year ago
parent
commit
8eb04ea98b
4 changed files with 29 additions and 7 deletions
  1. 2 0
      CHANGELOG.md
  2. 4 4
      options/processing_options.go
  3. 13 1
      processing/calc_position.go
  4. 10 2
      processing/scale_on_load.go

+ 2 - 0
CHANGELOG.md

@@ -1,6 +1,8 @@
 # Changelog
 
 ## [Unreleased]
+### Change
+- Allow relative values for `gravity` and `watermark` offsets.
 
 ## [3.21.0] - 2023-11-23
 ### Add

+ 4 - 4
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])
 		}

+ 13 - 1
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

+ 10 - 2
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