소스 검색

Add extend_aspect_ratio processing option

DarthSim 2 년 전
부모
커밋
4bf1a27abd
6개의 변경된 파일85개의 추가작업 그리고 26개의 파일을 삭제
  1. 2 0
      CHANGELOG.md
  2. 13 0
      docs/generating_the_url.md
  3. 28 16
      options/processing_options.go
  4. 8 5
      processing/crop.go
  5. 33 5
      processing/extend.go
  6. 1 0
      processing/processing.go

+ 2 - 0
CHANGELOG.md

@@ -1,6 +1,8 @@
 # Changelog
 
 ## [Unreleased]
+## Add
+- Add [extend_aspect_ratio](https://docs.imgproxy.net/latest/generating_the_url?id=extend-aspect-ratio) processing option.
 
 ## [3.13.2] - 2023-02-15
 ### Change

+ 13 - 0
docs/generating_the_url.md

@@ -174,6 +174,19 @@ ex:%extend:%gravity
 
 Default: `false:ce:0:0`
 
+### Extend aspect ratio
+
+```
+extend_aspect_ratio:%extend:%gravity
+extend_ar:%extend:%gravity
+exar:%extend:%gravity
+```
+
+* When `extend` is set to `1`, `t` or `true`, imgproxy will extend the image to the requested aspect ratio.
+* `gravity` _(optional)_ accepts the same values as the [gravity](#gravity) option, except `sm`. When `gravity` is not set, imgproxy will use `ce` gravity without offsets.
+
+Default: `false:ce:0:0`
+
 ### Gravity
 
 ```

+ 28 - 16
options/processing_options.go

@@ -70,6 +70,7 @@ type ProcessingOptions struct {
 	Gravity           GravityOptions
 	Enlarge           bool
 	Extend            ExtendOptions
+	ExtendAspectRatio ExtendOptions
 	Crop              CropOptions
 	Padding           PaddingOptions
 	Trim              TrimOptions
@@ -120,6 +121,7 @@ func NewProcessingOptions() *ProcessingOptions {
 		Gravity:           GravityOptions{Type: GravityCenter},
 		Enlarge:           false,
 		Extend:            ExtendOptions{Enabled: false, Gravity: GravityOptions{Type: GravityCenter}},
+		ExtendAspectRatio: ExtendOptions{Enabled: false, Gravity: GravityOptions{Type: GravityCenter}},
 		Padding:           PaddingOptions{Enabled: false},
 		Trim:              TrimOptions{Enabled: false, Threshold: 10, Smart: true},
 		Rotate:            0,
@@ -250,6 +252,26 @@ func parseGravity(g *GravityOptions, args []string) error {
 	return nil
 }
 
+func parseExtend(opts *ExtendOptions, name string, args []string) error {
+	if len(args) > 4 {
+		return fmt.Errorf("Invalid %s arguments: %v", name, args)
+	}
+
+	opts.Enabled = parseBoolOption(args[0])
+
+	if len(args) > 1 {
+		if err := parseGravity(&opts.Gravity, args[1:]); err != nil {
+			return err
+		}
+
+		if opts.Gravity.Type == GravitySmart {
+			return fmt.Errorf("%s doesn't support smart gravity", name)
+		}
+	}
+
+	return nil
+}
+
 func applyWidthOption(po *ProcessingOptions, args []string) error {
 	if len(args) > 1 {
 		return fmt.Errorf("Invalid width arguments: %v", args)
@@ -293,23 +315,11 @@ func applyEnlargeOption(po *ProcessingOptions, args []string) error {
 }
 
 func applyExtendOption(po *ProcessingOptions, args []string) error {
-	if len(args) > 4 {
-		return fmt.Errorf("Invalid extend arguments: %v", args)
-	}
-
-	po.Extend.Enabled = parseBoolOption(args[0])
-
-	if len(args) > 1 {
-		if err := parseGravity(&po.Extend.Gravity, args[1:]); err != nil {
-			return err
-		}
-
-		if po.Extend.Gravity.Type == GravitySmart {
-			return errors.New("extend doesn't support smart gravity")
-		}
-	}
+	return parseExtend(&po.Extend, "extend", args)
+}
 
-	return nil
+func applyExtendAspectRatioOption(po *ProcessingOptions, args []string) error {
+	return parseExtend(&po.ExtendAspectRatio, "extend_aspect_ratio", args)
 }
 
 func applySizeOption(po *ProcessingOptions, args []string) (err error) {
@@ -898,6 +908,8 @@ func applyURLOption(po *ProcessingOptions, name string, args []string) error {
 		return applyEnlargeOption(po, args)
 	case "extend", "ex":
 		return applyExtendOption(po, args)
+	case "extend_aspect_ratio", "extend_ar", "exar":
+		return applyExtendAspectRatioOption(po, args)
 	case "gravity", "g":
 		return applyGravityOption(po, args)
 	case "crop", "c":

+ 8 - 5
processing/crop.go

@@ -56,13 +56,16 @@ func cropToResult(pctx *pipelineContext, img *vips.Image, po *options.Processing
 	resultWidth, resultHeight := resultSize(po)
 
 	if po.ResizingType == options.ResizeFillDown {
-		if resultWidth > img.Width() {
-			resultHeight = imath.Scale(resultHeight, float64(img.Width())/float64(resultWidth))
+		diffW := float64(resultWidth) / float64(img.Width())
+		diffH := float64(resultHeight) / float64(img.Height())
+
+		switch {
+		case diffW > diffH && diffW > 1.0:
+			resultHeight = imath.Scale(img.Width(), float64(resultHeight)/float64(resultWidth))
 			resultWidth = img.Width()
-		}
 
-		if resultHeight > img.Height() {
-			resultWidth = imath.Scale(resultWidth, float64(img.Height())/float64(resultHeight))
+		case diffH > diffW && diffH > 1.0:
+			resultWidth = imath.Scale(img.Height(), float64(resultWidth)/float64(resultHeight))
 			resultHeight = img.Height()
 		}
 	}

+ 33 - 5
processing/extend.go

@@ -2,17 +2,45 @@ package processing
 
 import (
 	"github.com/imgproxy/imgproxy/v3/imagedata"
+	"github.com/imgproxy/imgproxy/v3/imath"
 	"github.com/imgproxy/imgproxy/v3/options"
 	"github.com/imgproxy/imgproxy/v3/vips"
 )
 
-func extend(pctx *pipelineContext, img *vips.Image, po *options.ProcessingOptions, imgdata *imagedata.ImageData) error {
-	resultWidth, resultHeight := resultSize(po)
-
-	if !po.Extend.Enabled || (resultWidth <= img.Width() && resultHeight <= img.Height()) {
+func extendImage(img *vips.Image, resultWidth, resultHeight int, opts *options.ExtendOptions, extendAr bool) error {
+	if !opts.Enabled || (resultWidth <= img.Width() && resultHeight <= img.Height()) {
 		return nil
 	}
 
-	offX, offY := calcPosition(resultWidth, resultHeight, img.Width(), img.Height(), &po.Extend.Gravity, false)
+	if extendAr && resultWidth > img.Width() && resultHeight > img.Height() {
+		diffW := float64(resultWidth) / float64(img.Width())
+		diffH := float64(resultHeight) / float64(img.Height())
+
+		switch {
+		case diffH > diffW:
+			resultHeight = imath.Scale(img.Width(), float64(resultHeight)/float64(resultWidth))
+			resultWidth = img.Width()
+
+		case diffW > diffH:
+			resultWidth = imath.Scale(img.Height(), float64(resultWidth)/float64(resultHeight))
+			resultHeight = img.Height()
+
+		default:
+			// The image has the requested arpect ratio
+			return nil
+		}
+	}
+
+	offX, offY := calcPosition(resultWidth, resultHeight, img.Width(), img.Height(), &opts.Gravity, false)
 	return img.Embed(resultWidth, resultHeight, offX, offY)
 }
+
+func extend(pctx *pipelineContext, img *vips.Image, po *options.ProcessingOptions, imgdata *imagedata.ImageData) error {
+	resultWidth, resultHeight := resultSize(po)
+	return extendImage(img, resultWidth, resultHeight, &po.Extend, false)
+}
+
+func extendAspectRatio(pctx *pipelineContext, img *vips.Image, po *options.ProcessingOptions, imgdata *imagedata.ImageData) error {
+	resultWidth, resultHeight := resultSize(po)
+	return extendImage(img, resultWidth, resultHeight, &po.ExtendAspectRatio, true)
+}

+ 1 - 0
processing/processing.go

@@ -30,6 +30,7 @@ var mainPipeline = pipeline{
 	cropToResult,
 	applyFilters,
 	extend,
+	extendAspectRatio,
 	padding,
 	fixSize,
 	flatten,