Bläddra i källkod

Watermark scale

DarthSim 6 år sedan
förälder
incheckning
c049fb8a28
4 ändrade filer med 77 tillägg och 25 borttagningar
  1. 4 3
      docs/generating_the_url_advanced.md
  2. 4 3
      docs/watermark.md
  3. 53 16
      process.go
  4. 16 3
      processing_options.go

+ 4 - 3
docs/generating_the_url_advanced.md

@@ -162,8 +162,8 @@ Default: disabled
 ##### Watermark
 
 ```
-watermark:%opacity:%position:%x_offset:%y_offset
-wm:%opacity:%position:%x_offset:%y_offset
+watermark:%opacity:%position:%x_offset:%y_offset:%scale
+wm:%opacity:%position:%x_offset:%y_offset:%scale
 ```
 
 Puts watermark on the processed image.
@@ -180,7 +180,8 @@ Puts watermark on the processed image.
   * `soea`: south-east (bottom-right corner);
   * `sowe`: south-west (bottom-left corner);
   * `re`: replicate watermark to fill the whole image;
-* `x_offset`, `y_offset` - (optional) specify watermark offset by X and Y axes. Not applicable to `re` position.
+* `x_offset`, `y_offset` - (optional) specify watermark offset by X and Y axes. Not applicable to `re` position;
+* `scale` - (optional) floating point number that defines watermark size relative to the resulting image size. When set to `0` or omitted, watermark size won't be changed.
 
 Default: disabled
 

+ 4 - 3
docs/watermark.md

@@ -17,8 +17,8 @@ You can also specify the base opacity of watermark with `IMGPROXY_WATERMARK_OPAC
 Watermarks are only available with [advanced URL format](generating_the_url_advanced.md). Use `watermark` processing option to put the watermark on the processed image:
 
 ```
-watermark:%opacity:%position:%x_offset:%y_offset
-wm:%opacity:%position:%x_offset:%y_offset
+watermark:%opacity:%position:%x_offset:%y_offset:%scale
+wm:%opacity:%position:%x_offset:%y_offset:%scale
 ```
 
 Where arguments are:
@@ -35,4 +35,5 @@ Where arguments are:
   * `soea`: south-east (bottom-right corner);
   * `sowe`: south-west (bottom-left corner);
   * `re`: replicate watermark to fill the whole image;
-* `x_offset`, `y_offset` - (optional) specify watermark offset by X and Y axes. Not applicable to `re` position.
+* `x_offset`, `y_offset` - (optional) specify watermark offset by X and Y axes. Not applicable to `re` position;
+* `scale` - (optional) floating point number that defines watermark size relative to the resulting image size. When set to `0` or omitted, watermark size won't be changed.

+ 53 - 16
process.go

@@ -635,26 +635,25 @@ func vipsImageCopyMemory(img **C.struct__VipsImage) error {
 	return nil
 }
 
-func vipsReplicateWatermark(width, height C.int) (wm *C.struct__VipsImage, err error) {
+func vipsReplicate(img **C.struct__VipsImage, width, height C.int) error {
 	var tmp *C.struct__VipsImage
-	defer C.clear_image(&tmp)
 
-	if C.vips_replicate_go(watermark, &tmp, 1+width/watermark.Xsize, 1+height/watermark.Ysize) != 0 {
-		err = vipsError()
-		return
+	if C.vips_replicate_go(*img, &tmp, 1+width/(*img).Xsize, 1+height/(*img).Ysize) != 0 {
+		return vipsError()
 	}
+	C.swap_and_clear(img, tmp)
 
-	if C.vips_extract_area_go(tmp, &wm, 0, 0, width, height) != 0 {
-		err = vipsError()
-		return
+	if C.vips_extract_area_go(*img, &tmp, 0, 0, width, height) != 0 {
+		return vipsError()
 	}
+	C.swap_and_clear(img, tmp)
 
-	return
+	return nil
 }
 
-func vipsEmbedWatermark(gravity gravityType, width, height C.int, offX, offY C.int) (wm *C.struct__VipsImage, err error) {
-	wmWidth := watermark.Xsize
-	wmHeight := watermark.Ysize
+func vipsEmbed(img **C.struct__VipsImage, gravity gravityType, width, height C.int, offX, offY C.int) error {
+	wmWidth := (*img).Xsize
+	wmHeight := (*img).Ysize
 
 	left := (width-wmWidth+1)/2 + offX
 	top := (height-wmHeight+1)/2 + offY
@@ -687,9 +686,34 @@ func vipsEmbedWatermark(gravity gravityType, width, height C.int, offX, offY C.i
 		top = 0
 	}
 
-	if C.vips_embed_go(watermark, &wm, left, top, width, height) != 0 {
+	var tmp *C.struct__VipsImage
+	if C.vips_embed_go(*img, &tmp, left, top, width, height) != 0 {
+		return vipsError()
+	}
+	C.swap_and_clear(img, tmp)
+
+	return nil
+}
+
+func vipsResizeWatermark(width, height int) (wm *C.struct__VipsImage, err error) {
+	wmW := float64(watermark.Xsize)
+	wmH := float64(watermark.Ysize)
+
+	wr := float64(width) / wmW
+	hr := float64(height) / wmH
+
+	scale := math.Min(wr, hr)
+
+	if wmW*scale < 1 {
+		scale = 1 / wmW
+	}
+
+	if wmH*scale < 1 {
+		scale = 1 / wmH
+	}
+
+	if C.vips_resize_go(watermark, &wm, C.double(scale)) != 0 {
 		err = vipsError()
-		return
 	}
 
 	return
@@ -709,12 +733,25 @@ func vipsApplyWatermark(img **C.struct__VipsImage, opts *watermarkOptions) error
 	imgW := (*img).Xsize
 	imgH := (*img).Ysize
 
+	if opts.Scale == 0 {
+		if wm = C.vips_image_copy_memory(watermark); wm == nil {
+			return vipsError()
+		}
+	} else {
+		wmW := maxInt(int(float64(imgW)*opts.Scale), 1)
+		wmH := maxInt(int(float64(imgH)*opts.Scale), 1)
+
+		if wm, err = vipsResizeWatermark(wmW, wmH); err != nil {
+			return err
+		}
+	}
+
 	if opts.Replicate {
-		if wm, err = vipsReplicateWatermark(imgW, imgH); err != nil {
+		if err = vipsReplicate(&wm, imgW, imgH); err != nil {
 			return err
 		}
 	} else {
-		if wm, err = vipsEmbedWatermark(opts.Gravity, imgW, imgH, C.int(opts.OffsetX), C.int(opts.OffsetY)); err != nil {
+		if err = vipsEmbed(&wm, opts.Gravity, imgW, imgH, C.int(opts.OffsetX), C.int(opts.OffsetY)); err != nil {
 			return err
 		}
 	}

+ 16 - 3
processing_options.go

@@ -103,6 +103,7 @@ type watermarkOptions struct {
 	Gravity   gravityType
 	OffsetX   int
 	OffsetY   int
+	Scale     float64
 }
 
 type processingOptions struct {
@@ -431,6 +432,10 @@ func applyPresetOption(po *processingOptions, args []string) error {
 }
 
 func applyWatermarkOption(po *processingOptions, args []string) error {
+	if len(args) > 7 {
+		return fmt.Errorf("Invalid watermark arguments: %v", args)
+	}
+
 	if o, err := strconv.ParseFloat(args[0], 64); err == nil && o >= 0 && o <= 1 {
 		po.Watermark.Enabled = o > 0
 		po.Watermark.Opacity = o
@@ -438,7 +443,7 @@ func applyWatermarkOption(po *processingOptions, args []string) error {
 		return fmt.Errorf("Invalid watermark opacity: %s", args[0])
 	}
 
-	if len(args) > 1 {
+	if len(args) > 1 && len(args[1]) > 0 {
 		if args[1] == "re" {
 			po.Watermark.Replicate = true
 		} else if g, ok := gravityTypes[args[1]]; ok && g != gravityFocusPoint && g != gravitySmart {
@@ -448,7 +453,7 @@ func applyWatermarkOption(po *processingOptions, args []string) error {
 		}
 	}
 
-	if len(args) > 2 {
+	if len(args) > 2 && len(args[2]) > 0 {
 		if x, err := strconv.Atoi(args[2]); err == nil {
 			po.Watermark.OffsetX = x
 		} else {
@@ -456,7 +461,7 @@ func applyWatermarkOption(po *processingOptions, args []string) error {
 		}
 	}
 
-	if len(args) > 3 {
+	if len(args) > 3 && len(args[3]) > 0 {
 		if y, err := strconv.Atoi(args[3]); err == nil {
 			po.Watermark.OffsetY = y
 		} else {
@@ -464,6 +469,14 @@ func applyWatermarkOption(po *processingOptions, args []string) error {
 		}
 	}
 
+	if len(args) > 4 && len(args[4]) > 0 {
+		if s, err := strconv.ParseFloat(args[4], 64); err == nil && s >= 0 {
+			po.Watermark.Scale = s
+		} else {
+			return fmt.Errorf("Invalid watermark scale: %s", args[4])
+		}
+	}
+
 	return nil
 }