lovell / sharp

High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, AVIF and TIFF images. Uses the libvips library.
https://sharp.pixelplumbing.com
Apache License 2.0
29.35k stars 1.3k forks source link

Multiply alpha channel (was: Imagemagick's dissolve option) #618

Open davidecantoni opened 8 years ago

davidecantoni commented 8 years ago

Hi @lovell, Does sharp support the option to dissolve a transparent image? I was looking for something similar to imagemagick's dissolve option. I took a look at the docs but could not find anything. What i wanna achieve is to overlay a watermark, which works well but i would also like to dissolve it by ~35%.

return sharp(watermark)
    .resize(width)
    .toBuffer()
    .then((outputBuffer) => {
      return stream.overlayWith(outputBuffer);
    });

stream is the streamed base image and watermark is the watermark png file which i would like to dissolve.

lovell commented 8 years ago

Hello, have you tried adding an alpha transparency channel of the desired opacity to the watermark?

davidecantoni commented 8 years ago

@lovell thank you for your quick answer!

I tried but wasn't successful, this is the current outcome.

download-1

How can i add an alpha transparency channel of the desired opacity to the watermark?

lovell commented 8 years ago

https://github.com/janosgyerik/cheatsheets/wiki/ImageMagick-cheat-sheet

davidecantoni commented 8 years ago

@lovell thank you for the link but i wanna add the opacity via sharpjs and not on the watermark input file itself. The idea behind it is that the watermark can be reused with different dissolve percentages.

lovell commented 8 years ago

If this module were to provide the ability to multiply alpha channel values then it would make sense to allow this for any images, not just those supplied to overlayWith.

I'm happy to accept a PR to implement such an operation and can help with API design. It would need to pretty much do what the *magick command is doing, which is detach the alpha channel, multiply its pixels by a specified value (clipped to a maximum value based on 8 vs 16 bits-per-channel), then re-attach to the original image.

samlin86 commented 6 years ago

Seeing that libvips has released v8.6 at the end of November, I see there was a commit to master that uses this.

What are the chances that an opacity option (1-100%) is available to the overlayWith function? Or is this already available, and if so, how would I access this?

lovell commented 6 years ago

@samlin86 The overlayWith operation will be switching to use the new vips_composite as part of #728 and that will include all the new blend modes.

jcupitt commented 5 years ago
It would need to pretty much do what the *magick command is doing, which is detach the alpha channel, multiply its pixels by a specified value (clipped to a maximum value based on 8 vs 16 bits-per-channel), then re-attach to the original image.

libvips has aslightly neater way of doing this: you can multiply by a vector, with 1.0 for bands you want to leave alone.

In C++ you can write:

rgba_image *= {1.0, 1.0, 1.0, opacity};

I think (?) that'll work in C++11. You might need a cast in there. You'd obviously need to check that it was an RGBA image somewhere.

Colkadome commented 5 years ago

You can multiply the alpha channel using this, where opacity is the alpha channel (0-255).

await sharp(source)
  .composite([{
    input: Buffer.from([255,255,255,128]),
    raw: {
      width: 1,
      height: 1,
      channels: 4
    },
    tile: true,
    blend: 'dest-in'
  }])
  .toBuffer();
tinypoint commented 5 years ago

You can multiply the alpha channel using this, where opacity is the alpha channel (0-255).

await sharp(source)
  .composite([{
    input: Buffer.from([255,255,255,128]),
    raw: {
      width: 1,
      height: 1,
      channels: 4
    },
    tile: true,
    blend: 'dest-in'
  }])
  .toBuffer();

It works!!!

mariusa commented 2 years ago

Coming back to the original request, how to blend a watermark with transparency over a base image? From previous comment, I can't tell if 'source' is watermark or base, nor couldn't figure out how to combine the two. Thanks

jfederer commented 2 years ago

Has this feature ever been added to Sharp?

It seems like it'd be a relatively common image-manipulation task.

I'm using the following code an can't for the life of me figure out how I'd apply the logo watermark at a variable-based opacity level. (the logo opacity will be user-selected, so I can't just modify the logo png.

           overlayImg = await Sharp(sourceImage.Body)
                .composite([{ 
                    input: './lambdas/processNewImage/logos/white.png', 
                    gravity: 'southeast',

                }])
                .toFormat('jpeg').toBuffer();
lovell commented 2 years ago

@jfederer This issue is a future possible enhancement. A PR to implement it is welcome, if you're able.

jfederer commented 2 years ago

Is it not currently possible (even if there isn't an 'easy' way to do it?)? I'm trying to stay with Sharp but I'll have to leave (an re-write a lot of code) for a different library if it doesn't have this functionality.