From c049fb8a282eeed13f73e5ee79e3f38777ac46cf Mon Sep 17 00:00:00 2001 From: DarthSim Date: Sun, 28 Oct 2018 18:05:57 +0600 Subject: [PATCH] Watermark scale --- docs/generating_the_url_advanced.md | 7 +-- docs/watermark.md | 7 +-- process.go | 69 ++++++++++++++++++++++------- processing_options.go | 19 ++++++-- 4 files changed, 77 insertions(+), 25 deletions(-) diff --git a/docs/generating_the_url_advanced.md b/docs/generating_the_url_advanced.md index 8772a051..b8ff1203 100644 --- a/docs/generating_the_url_advanced.md +++ b/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 diff --git a/docs/watermark.md b/docs/watermark.md index 48a04046..657aceea 100644 --- a/docs/watermark.md +++ b/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. diff --git a/process.go b/process.go index b709d8bd..ccbef4a0 100644 --- a/process.go +++ b/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 } } diff --git a/processing_options.go b/processing_options.go index 77e2feee..8d319ca4 100644 --- a/processing_options.go +++ b/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 }