瀏覽代碼

Implement padding option (#358)

* Implement padding option

* Move padding `embed` to the right place

* Move padding `embed` to the right place

* Use general background option instead of specific padding's one

* Make padding options css-like and fully optional

* Add docs for new padding option

* Return error if padding embed fails

* Make padding outbounds and apply dpr for it

Co-authored-by: Ilya Melnitskiy <melnitskiy_i_m@onyx-team.com>
ILYA 5 年之前
父節點
當前提交
12b415c9bd
共有 3 個文件被更改,包括 90 次插入0 次删除
  1. 18 0
      docs/generating_the_url_advanced.md
  2. 16 0
      process.go
  3. 56 0
      processing_options.go

+ 18 - 0
docs/generating_the_url_advanced.md

@@ -170,6 +170,24 @@ Defines an area of the image to be processed (crop before resize).
 * `width` and `height` define the size of the area. When `width` or `height` is set to `0`, imgproxy will use the full width/height of the source image.
 * `gravity` _(optional)_ accepts the same values as [gravity](#gravity) option. When `gravity` is not set, imgproxy will use the value of the [gravity](#gravity) option.
 
+#### Padding
+
+```
+padding:%top:%right:%bottom:%left
+pd:%top:%right:%bottom:%left
+```
+
+Defines padding size in css manner. All arguments are optional but at least one dimension must be set. Padded space is filled according to [background](#background) option.
+
+* `top` - top padding (and all other sides if they won't be set explicitly);
+* `right` - right padding (and left if it won't be set explicitly);
+* `bottom` - bottom padding;
+* `left` - left padding.
+
+**📝Notes:** 
+* Padding is applied after all image transformations (except watermark) and enlarges generated image which means that if your resize dimensions were 100x200px and you applied `padding:10` option then you will get 120x220px image.
+* Padding follows [dpr](#dpr) option so it will be scaled too if you set it.
+
 #### Trim
 
 ```

+ 16 - 0
process.go

@@ -453,6 +453,22 @@ func transformImage(ctx context.Context, img *vipsImage, data []byte, po *proces
 		}
 	}
 
+	if po.Padding.Enabled {
+		paddingTop := scaleInt(po.Padding.Top, po.Dpr)
+		paddingRight := scaleInt(po.Padding.Right, po.Dpr)
+		paddingBottom := scaleInt(po.Padding.Bottom, po.Dpr)
+		paddingLeft := scaleInt(po.Padding.Left, po.Dpr)
+		if err = img.Embed(
+			img.Width()+paddingLeft+paddingRight,
+			img.Height()+paddingTop+paddingBottom,
+			paddingLeft,
+			paddingTop,
+			po.Background,
+		); err != nil {
+			return err
+		}
+	}
+
 	checkTimeout(ctx)
 
 	if po.Watermark.Enabled && watermark != nil {

+ 56 - 0
processing_options.go

@@ -100,6 +100,14 @@ type cropOptions struct {
 	Gravity gravityOptions
 }
 
+type paddingOptions struct {
+	Enabled bool
+	Top     int
+	Right   int
+	Bottom  int
+	Left    int
+}
+
 type trimOptions struct {
 	Enabled   bool
 	Threshold float64
@@ -126,6 +134,7 @@ type processingOptions struct {
 	Enlarge      bool
 	Extend       extendOptions
 	Crop         cropOptions
+	Padding      paddingOptions
 	Trim         trimOptions
 	Format       imageType
 	Quality      int
@@ -208,6 +217,7 @@ func newProcessingOptions() *processingOptions {
 			Gravity:      gravityOptions{Type: gravityCenter},
 			Enlarge:      false,
 			Extend:       extendOptions{Enabled: false, Gravity: gravityOptions{Type: gravityCenter}},
+			Padding:      paddingOptions{Enabled: false},
 			Trim:         trimOptions{Enabled: false, Threshold: 10, Smart: true},
 			Quality:      conf.Quality,
 			MaxBytes:     0,
@@ -556,6 +566,50 @@ func applyCropOption(po *processingOptions, args []string) error {
 	return nil
 }
 
+func applyPaddingOption(po *processingOptions, args []string) error {
+	nArgs := len(args)
+
+	if nArgs < 1 || nArgs > 4 {
+		return fmt.Errorf("Invalid padding arguments: %v", args)
+	}
+
+	po.Padding.Enabled = true
+
+	if nArgs > 0 && len(args[0]) > 0 {
+		if err := parseDimension(&po.Padding.Top, "padding top (+all)", args[0]); err != nil {
+			return err
+		}
+		po.Padding.Right = po.Padding.Top
+		po.Padding.Bottom = po.Padding.Top
+		po.Padding.Left = po.Padding.Top
+	}
+
+	if nArgs > 1 && len(args[1]) > 0 {
+		if err := parseDimension(&po.Padding.Right, "padding right (+left)", args[1]); err != nil {
+			return err
+		}
+		po.Padding.Left = po.Padding.Right
+	}
+
+	if nArgs > 2 && len(args[2]) > 0 {
+		if err := parseDimension(&po.Padding.Bottom, "padding bottom", args[2]); err != nil {
+			return err
+		}
+	}
+
+	if nArgs > 3 && len(args[3]) > 0 {
+		if err := parseDimension(&po.Padding.Left, "padding left", args[3]); err != nil {
+			return err
+		}
+	}
+
+	if po.Padding.Top == 0 && po.Padding.Right == 0 && po.Padding.Bottom == 0 && po.Padding.Left == 0 {
+		po.Padding.Enabled = false
+	}
+
+	return nil
+}
+
 func applyTrimOption(po *processingOptions, args []string) error {
 	nArgs := len(args)
 
@@ -820,6 +874,8 @@ func applyProcessingOption(po *processingOptions, name string, args []string) er
 		return applyCropOption(po, args)
 	case "trim", "t":
 		return applyTrimOption(po, args)
+	case "padding", "pd":
+		return applyPaddingOption(po, args)
 	case "quality", "q":
 		return applyQualityOption(po, args)
 	case "max_bytes", "mb":