Browse Source

IMGPROXY_AUTO_ROTATE config and auto_rotate processing option

DarthSim 4 years ago
parent
commit
6da8885605
6 changed files with 37 additions and 7 deletions
  1. 1 0
      CHANGELOG.md
  2. 3 0
      config.go
  3. 1 0
      docs/configuration.md
  4. 9 0
      docs/generating_the_url_advanced.md
  5. 9 7
      process.go
  6. 14 0
      processing_options.go

+ 1 - 0
CHANGELOG.md

@@ -6,6 +6,7 @@
 - Azure Blob Storage support.
 - Azure Blob Storage support.
 - `IMGPROXY_STRIP_COLOR_PROFILE` config and [strip_color_profile](https://docs.imgproxy.net/#/generating_the_url_advanced?id=strip-color-profile) processing option.
 - `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_FORMAT_QUALITY` config.
+- `IMGPROXY_AUTO_ROTATE` config and [auto_rotate](https://docs.imgproxy.net/#/generating_the_url_advanced?id=auto-rotate) processing option.
 - (pro) Remove Adobe Illustrator garbage from SVGs.
 - (pro) Remove Adobe Illustrator garbage from SVGs.
 
 
 ### Changed
 ### Changed

+ 3 - 0
config.go

@@ -229,6 +229,7 @@ type config struct {
 	GZipCompression       int
 	GZipCompression       int
 	StripMetadata         bool
 	StripMetadata         bool
 	StripColorProfile     bool
 	StripColorProfile     bool
+	AutoRotate            bool
 
 
 	EnableWebpDetection bool
 	EnableWebpDetection bool
 	EnforceWebp         bool
 	EnforceWebp         bool
@@ -323,6 +324,7 @@ var conf = config{
 	FormatQuality:                  map[imageType]int{imageTypeAVIF: 50},
 	FormatQuality:                  map[imageType]int{imageTypeAVIF: 50},
 	StripMetadata:                  true,
 	StripMetadata:                  true,
 	StripColorProfile:              true,
 	StripColorProfile:              true,
+	AutoRotate:                     true,
 	UserAgent:                      fmt.Sprintf("imgproxy/%s", version),
 	UserAgent:                      fmt.Sprintf("imgproxy/%s", version),
 	Presets:                        make(presets),
 	Presets:                        make(presets),
 	WatermarkOpacity:               1,
 	WatermarkOpacity:               1,
@@ -383,6 +385,7 @@ func configure() error {
 	intEnvConfig(&conf.GZipCompression, "IMGPROXY_GZIP_COMPRESSION")
 	intEnvConfig(&conf.GZipCompression, "IMGPROXY_GZIP_COMPRESSION")
 	boolEnvConfig(&conf.StripMetadata, "IMGPROXY_STRIP_METADATA")
 	boolEnvConfig(&conf.StripMetadata, "IMGPROXY_STRIP_METADATA")
 	boolEnvConfig(&conf.StripColorProfile, "IMGPROXY_STRIP_COLOR_PROFILE")
 	boolEnvConfig(&conf.StripColorProfile, "IMGPROXY_STRIP_COLOR_PROFILE")
+	boolEnvConfig(&conf.AutoRotate, "IMGPROXY_AUTO_ROTATE")
 
 
 	boolEnvConfig(&conf.EnableWebpDetection, "IMGPROXY_ENABLE_WEBP_DETECTION")
 	boolEnvConfig(&conf.EnableWebpDetection, "IMGPROXY_ENABLE_WEBP_DETECTION")
 	boolEnvConfig(&conf.EnforceWebp, "IMGPROXY_ENFORCE_WEBP")
 	boolEnvConfig(&conf.EnforceWebp, "IMGPROXY_ENFORCE_WEBP")

+ 1 - 0
docs/configuration.md

@@ -325,3 +325,4 @@ imgproxy can send logs to syslog, but this feature is disabled by default. To en
 * `IMGPROXY_DISABLE_SHRINK_ON_LOAD`: when `true`, disables shrink-on-load for JPEG and WebP. Allows to process the whole image in linear colorspace but dramatically slows down resizing and increases memory usage when working with large images.
 * `IMGPROXY_DISABLE_SHRINK_ON_LOAD`: when `true`, disables shrink-on-load for JPEG and WebP. Allows to process the whole image in linear colorspace but dramatically slows down resizing and increases memory usage when working with large images.
 * `IMGPROXY_STRIP_METADATA`: when `true`, imgproxy will strip all metadata (EXIF, IPTC, etc.) from JPEG and WebP output images. Default: `true`.
 * `IMGPROXY_STRIP_METADATA`: when `true`, imgproxy will strip all metadata (EXIF, IPTC, etc.) from JPEG and WebP output images. Default: `true`.
 * `IMGPROXY_STRIP_COLOR_PROFILE`: when `true`, imgproxy will transform the embedded color profile (ICC) to sRGB and remove it from the image. Otherwise, imgproxy will try to keep it as is. Default: `true`.
 * `IMGPROXY_STRIP_COLOR_PROFILE`: when `true`, imgproxy will transform the embedded color profile (ICC) to sRGB and remove it from the image. Otherwise, imgproxy will try to keep it as is. Default: `true`.
+* `IMGPROXY_AUTO_ROTATE`: when `true`, imgproxy will auto rotate images based on the EXIF Orientation parameter (if available in the image meta data). The orientation tag will be removed from the image anyway. Default: `true`.

+ 9 - 0
docs/generating_the_url_advanced.md

@@ -486,6 +486,15 @@ scp:%strip_color_profile
 
 
 When set to `1`, `t` or `true`, imgproxy will transform the embedded color profile (ICC) to sRGB and remove it from the image. Otherwise, imgproxy will try to keep it as is. Normally this is controlled by the [IMGPROXY_STRIP_COLOR_PROFILE](configuration.md#miscellaneous) configuration but this procesing option allows the configuration to be set for each request.
 When set to `1`, `t` or `true`, imgproxy will transform the embedded color profile (ICC) to sRGB and remove it from the image. Otherwise, imgproxy will try to keep it as is. Normally this is controlled by the [IMGPROXY_STRIP_COLOR_PROFILE](configuration.md#miscellaneous) configuration but this procesing option allows the configuration to be set for each request.
 
 
+#### Auto Rotate
+
+```
+auto_rotate:%auto_rotate
+ar:%auto_rotate
+```
+
+When set to `1`, `t` or `true`, imgproxy will automatically rotate images based onon the EXIF Orientation parameter (if available in the image meta data). The orientation tag will be removed from the image anyway. Normally this is controlled by the [IMGPROXY_AUTO_ROTATE](configuration.md#miscellaneous) configuration but this procesing option allows the configuration to be set for each request.
+
 #### Filename
 #### Filename
 
 
 ```
 ```

+ 9 - 7
process.go

@@ -34,13 +34,17 @@ func imageTypeGoodForWeb(imgtype imageType) bool {
 		imgtype != imageTypeBMP
 		imgtype != imageTypeBMP
 }
 }
 
 
-func extractMeta(img *vipsImage) (int, int, int, bool) {
+func extractMeta(img *vipsImage, useOrientation bool) (int, int, int, bool) {
 	width := img.Width()
 	width := img.Width()
 	height := img.Height()
 	height := img.Height()
 
 
 	angle := vipsAngleD0
 	angle := vipsAngleD0
 	flip := false
 	flip := false
 
 
+	if !useOrientation {
+		return width, height, angle, flip
+	}
+
 	orientation := img.Orientation()
 	orientation := img.Orientation()
 
 
 	if orientation >= 5 && orientation <= 8 {
 	if orientation >= 5 && orientation <= 8 {
@@ -321,7 +325,7 @@ func transformImage(ctx context.Context, img *vipsImage, data []byte, po *proces
 		trimmed = true
 		trimmed = true
 	}
 	}
 
 
-	srcWidth, srcHeight, angle, flip := extractMeta(img)
+	srcWidth, srcHeight, angle, flip := extractMeta(img, po.AutoRotate)
 	cropWidth, cropHeight := po.Crop.Width, po.Crop.Height
 	cropWidth, cropHeight := po.Crop.Width, po.Crop.Height
 
 
 	cropGravity := po.Crop.Gravity
 	cropGravity := po.Crop.Gravity
@@ -352,7 +356,7 @@ func transformImage(ctx context.Context, img *vipsImage, data []byte, po *proces
 		}
 		}
 
 
 		// Update scale after scale-on-load
 		// Update scale after scale-on-load
-		newWidth, newHeight, _, _ := extractMeta(img)
+		newWidth, newHeight, _, _ := extractMeta(img, po.AutoRotate)
 		if srcWidth > srcHeight {
 		if srcWidth > srcHeight {
 			scale = float64(srcWidth) * scale / float64(newWidth)
 			scale = float64(srcWidth) * scale / float64(newWidth)
 		} else {
 		} else {
@@ -399,10 +403,8 @@ func transformImage(ctx context.Context, img *vipsImage, data []byte, po *proces
 		return err
 		return err
 	}
 	}
 
 
-	if angle != vipsAngleD0 {
-		if err = img.Rotate(angle); err != nil {
-			return err
-		}
+	if err = img.Rotate(angle); err != nil {
+		return err
 	}
 	}
 
 
 	if flip {
 	if flip {

+ 14 - 0
processing_options.go

@@ -145,6 +145,7 @@ type processingOptions struct {
 	Sharpen           float32
 	Sharpen           float32
 	StripMetadata     bool
 	StripMetadata     bool
 	StripColorProfile bool
 	StripColorProfile bool
+	AutoRotate        bool
 
 
 	CacheBuster string
 	CacheBuster string
 
 
@@ -231,6 +232,7 @@ func newProcessingOptions() *processingOptions {
 			Watermark:         watermarkOptions{Opacity: 1, Replicate: false, Gravity: gravityOptions{Type: gravityCenter}},
 			Watermark:         watermarkOptions{Opacity: 1, Replicate: false, Gravity: gravityOptions{Type: gravityCenter}},
 			StripMetadata:     conf.StripMetadata,
 			StripMetadata:     conf.StripMetadata,
 			StripColorProfile: conf.StripColorProfile,
 			StripColorProfile: conf.StripColorProfile,
+			AutoRotate:        conf.AutoRotate,
 		}
 		}
 	})
 	})
 
 
@@ -886,6 +888,16 @@ func applyStripColorProfileOption(po *processingOptions, args []string) error {
 	return nil
 	return nil
 }
 }
 
 
+func applyAutoRotateOption(po *processingOptions, args []string) error {
+	if len(args) > 1 {
+		return fmt.Errorf("Invalid auto rotate arguments: %v", args)
+	}
+
+	po.AutoRotate = parseBoolOption(args[0])
+
+	return nil
+}
+
 func applyProcessingOption(po *processingOptions, name string, args []string) error {
 func applyProcessingOption(po *processingOptions, name string, args []string) error {
 	switch name {
 	switch name {
 	case "format", "f", "ext":
 	case "format", "f", "ext":
@@ -934,6 +946,8 @@ func applyProcessingOption(po *processingOptions, name string, args []string) er
 		return applyStripMetadataOption(po, args)
 		return applyStripMetadataOption(po, args)
 	case "strip_color_profile", "scp":
 	case "strip_color_profile", "scp":
 		return applyStripColorProfileOption(po, args)
 		return applyStripColorProfileOption(po, args)
+	case "auto_rotate", "ar":
+		return applyAutoRotateOption(po, args)
 	case "filename", "fn":
 	case "filename", "fn":
 		return applyFilenameOption(po, args)
 		return applyFilenameOption(po, args)
 	}
 	}