Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Channel excluded from image manipulations, if the channel was joined at later time #4192

Open
SuggonM opened this issue Aug 20, 2024 · 4 comments

Comments

@SuggonM
Copy link

SuggonM commented Aug 20, 2024

I'm not quite sure if the title is accurate to Sharp's internal algorithm, but joinChannel does appear to exhibit an unusual behavior at least somewhere.

As a very simple example to reproduce, I'm extracting all 4 channels as raw from a colorful PNG, then joining those channels into a new instance of image. The expected result should be 1:1 duplicate of the original.

import sharp from 'sharp';

const orig = sharp('./colors.png');

// decompose into individual RGBA channel values
// concept taken from https://github.com/lovell/sharp/issues/1757#issuecomment-503653509
const channels = ['red', 'green', 'blue', 'alpha'];
const decompose = channels.map(
	channel => orig.extractChannel(channel).raw().toBuffer()
);
const [r, g, b, a] = await Promise.all(decompose);

// copy dimensions from original
const { info } = await orig.toBuffer({ resolveWithObject: true });
const metadata = { raw: {
	...info,
	channels: 1,
	background: 'transparent'
}};

// join/compose all 4 decomposed channels to create an original-alike
const dupe = sharp(r, metadata).joinChannel([g, b, a], metadata);

// export
dupe.toFile('./colors-dupe.png');

Things seem to appear nice and fine until this point - the export is still 1:1 with the original. However, any further manipulation on the dupe from here on, will result in only the red channel being affected. As an example, rotating by 90 degrees:

// export
dupe.rotate(90).toFile('./colors-dupe.png');

This is my exact concern, as one would normally expect all 4 channels being manipulated as a whole.

In order to verify it's only the red channel being manipulated:

  1. Open colors-dupe.png in GIMP.
  2. Go to Channels panel (next to Layers panel).
  3. Hide all 3 channels excluding the red.
  4. Result: Only the red channel appears rotated by 90 degrees.
@lovell
Copy link
Owner

lovell commented Aug 20, 2024

Please try something like the following:

// export
- dupe.toFile('./colors-dupe.png');
+ await dupe.toFile('./colors-dupe.png');
// export
- dupe.rotate(90).toFile('./colors-dupe.png');
+ await sharp('./colors-dupe.png').rotate(90).toFile('./colors-dupe-rotated.png');

@SuggonM
Copy link
Author

SuggonM commented Aug 21, 2024

The said change works 👍

@SuggonM
Copy link
Author

SuggonM commented Aug 21, 2024

Although, I can't really say I'm supportive with the idea of having to spawn an extra image and create another sharp instance for it.

Does this mean achieving it is impossible without first exporting into an intermediate file?

(more context would be welcome!)

@SuggonM
Copy link
Author

SuggonM commented Aug 21, 2024

And if not that then, by extension, would it be possible to somewhat work this around using the composite method? Not trying to be troublesome or anything, just looking for different perspectives to achieve things 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants