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
28.87k stars 1.29k forks source link

composing an image from multiple channels data #1757

Open ericblade opened 5 years ago

ericblade commented 5 years ago

What are you trying to achieve? Extracting channels from an image, and re-composing them into a different setup

Have you searched for similar questions? yes

Are you able to provide a standalone code sample that demonstrates this question? yes

Are you able to provide a sample image that helps explain the question? no


I'm not sure if this is something that would warrant a new feature being added, or just some clarification to the documentation, but it took me quite some time (actually reading the test suite, rather than the documentation) to figure out that joinChannel keeps adding new channels to a file, despite the documentation appearing to suggest that if you give it an array form, it might replace/overwrite the channels, since you can specify [ red, green, blue, alpha ] format if your image is RGB.

That is clearly not how it works after reading the test suite.

Perhaps a "replaceChannel" function, or just explaining in joinChannel, that if you want to replace channels, you'll need to compose them together starting from a single channel image.

ericblade commented 5 years ago

This is not ultimately, what my code will look like, i was just trying to get a 1:1 copy of the original image, and it took quite a while to figure out that this was the way. It extracts all the channels from a RGBA image, and then recomposes them back into the same image. Ultimately, it will end up taking the 4 channels from one image, and outputting them into different images in a different combination.

    const width = 64;
    const height = 64;
    const source = sharp({
        create: {
            width,
            height,
            channels: 4,
            background: {
                r: 0,
                g: 127,
                b: 225,
                alpha: 1.0,
            },
        },
    }).png();
    const sourceData = await source.toBuffer();
    source.toFile('./source1.png');
    const r = sharp(sourceData).extractChannel('red').toColorspace('b-w');
    const g = sharp(sourceData).extractChannel('green').toColorspace('b-w');
    const b = sharp(sourceData).extractChannel('blue').toColorspace('b-w');
    const a = sharp(sourceData).extractChannel(3).toColorspace('b-w');
    const rd = await r.raw().toBuffer({ resolveWithObject: true });
    const gd = await g.raw().toBuffer({ resolveWithObject: true });
    const bd = await b.raw().toBuffer({ resolveWithObject: true });
    const ad = await a.raw().toBuffer({ resolveWithObject: true });
    console.warn(rd, gd, bd, ad);
    const dest = sharp(rd.data, { raw: { width, height, channels: 1 } });
    dest.joinChannel([ gd.data, bd.data, ad.data ], { raw: { width, height, channels: 1 }}).png().toFile('./dest.png');
lovell commented 5 years ago

The JSDocs for joinChannel could definitely benefit from some examples to help clarify its use. Happy to accept a PR if you're able.

https://github.com/lovell/sharp/blob/master/lib/channel.js#L80

/cc @mhirsch

ericblade commented 5 years ago

I'm not sure that i'm well qualified enough to improve the doc based just on what I learned from getting what I needed to work... i know enough about it now to get what I needed, but not sure that's comprehensive enough to do it better.

robogeek commented 4 years ago

The application I have in mind involves processing photo's from an infrared camera. A common transformation is to swap the red and blue channels. I tried reading the documentation, it seems like that should be possible, but there isn't enough there to explain how to get there.