From 85f790fb4bd7985c3d7faf671c6a325fecad2f87 Mon Sep 17 00:00:00 2001 From: DarthSim Date: Wed, 10 May 2023 17:46:02 +0300 Subject: [PATCH] Optimize watermark application --- CHANGELOG.md | 1 + processing/watermark.go | 39 ++++++++++++++++++++++++++------------- vips/vips.c | 8 ++++++-- vips/vips.go | 4 ++-- vips/vips.h | 3 ++- 5 files changed, 37 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54d179ac..f6166b1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Change - Optimized memory buffers pooling for better performance and memory reusage. +- Optimized watermarks application. ## [3.16.1] - 2023-04-26 ### Fix diff --git a/processing/watermark.go b/processing/watermark.go index a92b7656..db5ba841 100644 --- a/processing/watermark.go +++ b/processing/watermark.go @@ -67,17 +67,6 @@ func prepareWatermark(wm *vips.Image, wmData *imagedata.ImageData, opts *options if err := wm.Replicate(imgWidth, imgHeight); err != nil { return err } - } else { - left, top := calcPosition(imgWidth, imgHeight, wm.Width(), wm.Height(), &opts.Gravity, offsetScale, true) - if err := wm.Embed(imgWidth, imgHeight, left, top); err != nil { - return err - } - } - - if framesCount > 1 { - if err := wm.Replicate(imgWidth, imgWidth*framesCount); err != nil { - return err - } } wm.RemoveHeader("palette-bit-depth") @@ -95,14 +84,38 @@ func applyWatermark(img *vips.Image, wmData *imagedata.ImageData, opts *options. width := img.Width() height := img.Height() + frameHeight := height / framesCount - if err := prepareWatermark(wm, wmData, opts, width, height/framesCount, offsetScale, framesCount); err != nil { + if err := prepareWatermark(wm, wmData, opts, width, frameHeight, offsetScale, framesCount); err != nil { return err } opacity := opts.Opacity * config.WatermarkOpacity - return img.ApplyWatermark(wm, opacity) + // If we replicated the watermark and need to apply it to an animated image, + // it is faster to replicate the watermark to all the image and apply it single-pass + if opts.Replicate && framesCount > 1 { + if err := wm.Replicate(width, height); err != nil { + return err + } + + return img.ApplyWatermark(wm, 0, 0, opacity) + } + + left, top := 0, 0 + + if !opts.Replicate { + left, top = calcPosition(width, frameHeight, wm.Width(), wm.Height(), &opts.Gravity, offsetScale, true) + } + + for i := 0; i < framesCount; i++ { + if err := img.ApplyWatermark(wm, left, top, opacity); err != nil { + return err + } + top += frameHeight + } + + return nil } func watermark(pctx *pipelineContext, img *vips.Image, po *options.ProcessingOptions, imgdata *imagedata.ImageData) error { diff --git a/vips/vips.c b/vips/vips.c index cbc59b3f..a56eea6e 100644 --- a/vips/vips.c +++ b/vips/vips.c @@ -531,7 +531,7 @@ vips_embed_go(VipsImage *in, VipsImage **out, int x, int y, int width, int heigh } int -vips_apply_watermark(VipsImage *in, VipsImage *watermark, VipsImage **out, double opacity) { +vips_apply_watermark(VipsImage *in, VipsImage *watermark, VipsImage **out, int left, int top, double opacity) { VipsImage *base = vips_image_new(); VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(base), 7); @@ -559,7 +559,11 @@ vips_apply_watermark(VipsImage *in, VipsImage *watermark, VipsImage **out, doubl int had_alpha = vips_image_hasalpha(in); if ( - vips_composite2(in, watermark, &t[5], VIPS_BLEND_MODE_OVER, "compositing_space", in->Type, NULL) || + vips_composite2( + in, watermark, &t[5], VIPS_BLEND_MODE_OVER, + "x", left, "y", top, "compositing_space", in->Type, + NULL + ) || vips_cast(t[5], &t[6], vips_image_get_format(in), NULL) ) { clear_image(&base); diff --git a/vips/vips.go b/vips/vips.go index 0c44f1cd..39949e33 100644 --- a/vips/vips.go +++ b/vips/vips.go @@ -771,10 +771,10 @@ func (img *Image) Embed(width, height int, offX, offY int) error { return nil } -func (img *Image) ApplyWatermark(wm *Image, opacity float64) error { +func (img *Image) ApplyWatermark(wm *Image, left, top int, opacity float64) error { var tmp *C.VipsImage - if C.vips_apply_watermark(img.VipsImage, wm.VipsImage, &tmp, C.double(opacity)) != 0 { + if C.vips_apply_watermark(img.VipsImage, wm.VipsImage, &tmp, C.int(left), C.int(top), C.double(opacity)) != 0 { return Error() } C.swap_and_clear(&img.VipsImage, tmp) diff --git a/vips/vips.h b/vips/vips.h index 273674fa..7d84539a 100644 --- a/vips/vips.h +++ b/vips/vips.h @@ -67,7 +67,8 @@ int vips_flatten_go(VipsImage *in, VipsImage **out, double r, double g, double b int vips_replicate_go(VipsImage *in, VipsImage **out, int across, int down); int vips_embed_go(VipsImage *in, VipsImage **out, int x, int y, int width, int height); -int vips_apply_watermark(VipsImage *in, VipsImage *watermark, VipsImage **out, double opacity); +int vips_apply_watermark(VipsImage *in, VipsImage *watermark, VipsImage **out, + int left, int top, double opacity); int vips_arrayjoin_go(VipsImage **in, VipsImage **out, int n);