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.33k stars 1.3k forks source link

Divide Blend #4194

Closed SuggonM closed 2 months ago

SuggonM commented 3 months ago

Feature request

What are you trying to achieve?

Any one of these two blendmodes/filters:

Description

Hello, good day. I see there is a good list of image compositing options in the composite method. There is one for add and multiply, but the interface doesn't provide divide out of the box.

Upon further digging around, it seems that both of these are already implemented in the libvps library as native functions: Divide and Unpremultiply. So any possibility for these being accessible from Sharp interface?

In my specific case, I'm trying to reverse the pre-multiplication of a texture's alpha (PMA is a common pattern in modern games). In theory, a divide operation is able to undo it quite easily, so it would be a perfect fit for this job.

(The unpremultiply linked above is even more straightforward, but usage of such a specific function in case of Sharp is rather rare and perhaps obsolete.)

lovell commented 3 months ago

I'm trying to reverse the pre-multiplication of a texture's alpha

Did you see the premultiplied option of the composite operation?

https://sharp.pixelplumbing.com/api-composite

  .composite([
    { input: 'texture.png', premultipled: true }
  ])

Alternatively, if you're providing raw pixel input, there is a premultiplied constructor property.

https://sharp.pixelplumbing.com/api-constructor

sharp(rawPixelInput, { raw: { width, height, channels, premultiplied: true }})...
SuggonM commented 2 months ago

there is a premultiplied constructor property.

I see, it's possible to leverage Sharp's own underlying algorithms 😄

With that, the final unpremultiply function is looking more elegant now!

async function unpremultiply(sharpInst) {

    const sharpData = await sharpInst.raw().toBuffer({ resolveWithObject: true });
    const buffer = sharpData.data;
    const metadata = sharpData.info;

    const canvasData = {
        ...metadata,
        background: 'transparent',
        premultiplied: true
    };

    const unpremultiplied = sharp(buffer, { raw: canvasData });

    return unpremultiplied;
}