Bläddra i källkod

rotate processing option

DarthSim 4 år sedan
förälder
incheckning
e48c557fc4
5 ändrade filer med 59 tillägg och 29 borttagningar
  1. 1 0
      CHANGELOG.md
  2. 13 0
      docs/generating_the_url_advanced.md
  3. 24 21
      process.go
  4. 18 0
      processing_options.go
  5. 3 8
      vips.go

+ 1 - 0
CHANGELOG.md

@@ -7,6 +7,7 @@
 - `IMGPROXY_STRIP_COLOR_PROFILE` config and [strip_color_profile](https://docs.imgproxy.net/#/generating_the_url_advanced?id=strip-color-profile) processing option.
 - `IMGPROXY_FORMAT_QUALITY` config.
 - `IMGPROXY_AUTO_ROTATE` config and [auto_rotate](https://docs.imgproxy.net/#/generating_the_url_advanced?id=auto-rotate) processing option.
+- [rotate](https://docs.imgproxy.net/#/generating_the_url_advanced?id=rotate) processing option.
 - (pro) Remove Adobe Illustrator garbage from SVGs.
 
 ### Changed

+ 13 - 0
docs/generating_the_url_advanced.md

@@ -208,6 +208,19 @@ Removes surrounding background.
 
 **📝Note:** Trimming of animated images is not supported.
 
+#### Rotate
+
+```
+rotate:%angle
+rot:%angle
+```
+
+Rotates the image on the specified angle. The orientation from the image metadata is applied before the rotation unless autorotation is disabled.
+
+**📝Note:** Only 0/90/180/270/etc degrees angles are supported.
+
+Default: 0.
+
 #### Quality
 
 ```

+ 24 - 21
process.go

@@ -34,34 +34,33 @@ func imageTypeGoodForWeb(imgtype imageType) bool {
 		imgtype != imageTypeBMP
 }
 
-func extractMeta(img *vipsImage, useOrientation bool) (int, int, int, bool) {
+func extractMeta(img *vipsImage, baseAngle int, useOrientation bool) (int, int, int, bool) {
 	width := img.Width()
 	height := img.Height()
 
-	angle := vipsAngleD0
+	angle := 0
 	flip := false
 
-	if !useOrientation {
-		return width, height, angle, flip
-	}
+	if useOrientation {
+		orientation := img.Orientation()
 
-	orientation := img.Orientation()
+		if orientation == 3 || orientation == 4 {
+			angle = 180
+		}
+		if orientation == 5 || orientation == 6 {
+			angle = 90
+		}
+		if orientation == 7 || orientation == 8 {
+			angle = 270
+		}
+		if orientation == 2 || orientation == 4 || orientation == 5 || orientation == 7 {
+			flip = true
+		}
+	}
 
-	if orientation >= 5 && orientation <= 8 {
+	if (angle+baseAngle)%180 != 0 {
 		width, height = height, width
 	}
-	if orientation == 3 || orientation == 4 {
-		angle = vipsAngleD180
-	}
-	if orientation == 5 || orientation == 6 {
-		angle = vipsAngleD90
-	}
-	if orientation == 7 || orientation == 8 {
-		angle = vipsAngleD270
-	}
-	if orientation == 2 || orientation == 4 || orientation == 5 || orientation == 7 {
-		flip = true
-	}
 
 	return width, height, angle, flip
 }
@@ -325,7 +324,7 @@ func transformImage(ctx context.Context, img *vipsImage, data []byte, po *proces
 		trimmed = true
 	}
 
-	srcWidth, srcHeight, angle, flip := extractMeta(img, po.AutoRotate)
+	srcWidth, srcHeight, angle, flip := extractMeta(img, po.Rotate, po.AutoRotate)
 	cropWidth, cropHeight := po.Crop.Width, po.Crop.Height
 
 	cropGravity := po.Crop.Gravity
@@ -356,7 +355,7 @@ func transformImage(ctx context.Context, img *vipsImage, data []byte, po *proces
 		}
 
 		// Update scale after scale-on-load
-		newWidth, newHeight, _, _ := extractMeta(img, po.AutoRotate)
+		newWidth, newHeight, _, _ := extractMeta(img, po.Rotate, po.AutoRotate)
 		if srcWidth > srcHeight {
 			scale = float64(srcWidth) * scale / float64(newWidth)
 		} else {
@@ -413,6 +412,10 @@ func transformImage(ctx context.Context, img *vipsImage, data []byte, po *proces
 		}
 	}
 
+	if err = img.Rotate(po.Rotate); err != nil {
+		return err
+	}
+
 	dprWidth := scaleInt(po.Width, po.Dpr)
 	dprHeight := scaleInt(po.Height, po.Dpr)
 

+ 18 - 0
processing_options.go

@@ -136,6 +136,7 @@ type processingOptions struct {
 	Crop              cropOptions
 	Padding           paddingOptions
 	Trim              trimOptions
+	Rotate            int
 	Format            imageType
 	Quality           int
 	MaxBytes          int
@@ -222,6 +223,7 @@ func newProcessingOptions() *processingOptions {
 			Extend:            extendOptions{Enabled: false, Gravity: gravityOptions{Type: gravityCenter}},
 			Padding:           paddingOptions{Enabled: false},
 			Trim:              trimOptions{Enabled: false, Threshold: 10, Smart: true},
+			Rotate:            0,
 			Quality:           0,
 			MaxBytes:          0,
 			Format:            imageTypeUnknown,
@@ -664,6 +666,20 @@ func applyTrimOption(po *processingOptions, args []string) error {
 	return nil
 }
 
+func applyRotateOption(po *processingOptions, args []string) error {
+	if len(args) > 1 {
+		return fmt.Errorf("Invalid rotate arguments: %v", args)
+	}
+
+	if r, err := strconv.Atoi(args[0]); err == nil && r%90 == 0 {
+		po.Rotate = r
+	} else {
+		return fmt.Errorf("Invalid rotation angle: %s", args[0])
+	}
+
+	return nil
+}
+
 func applyQualityOption(po *processingOptions, args []string) error {
 	if len(args) > 1 {
 		return fmt.Errorf("Invalid quality arguments: %v", args)
@@ -924,6 +940,8 @@ func applyProcessingOption(po *processingOptions, name string, args []string) er
 		return applyCropOption(po, args)
 	case "trim", "t":
 		return applyTrimOption(po, args)
+	case "rotate", "rot":
+		return applyRotateOption(po, args)
 	case "padding", "pd":
 		return applyPaddingOption(po, args)
 	case "quality", "q":

+ 3 - 8
vips.go

@@ -38,13 +38,6 @@ var vipsConf struct {
 	WatermarkOpacity      C.double
 }
 
-const (
-	vipsAngleD0   = C.VIPS_ANGLE_D0
-	vipsAngleD90  = C.VIPS_ANGLE_D90
-	vipsAngleD180 = C.VIPS_ANGLE_D180
-	vipsAngleD270 = C.VIPS_ANGLE_D270
-)
-
 func initVips() error {
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
@@ -392,7 +385,9 @@ func (img *vipsImage) Orientation() C.int {
 func (img *vipsImage) Rotate(angle int) error {
 	var tmp *C.VipsImage
 
-	if C.vips_rot_go(img.VipsImage, &tmp, C.VipsAngle(angle)) != 0 {
+	vipsAngle := (angle / 90) % 4
+
+	if C.vips_rot_go(img.VipsImage, &tmp, C.VipsAngle(vipsAngle)) != 0 {
 		return vipsError()
 	}