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

Using clone and joinChannel together apply channel operation to all output #4029

Closed
3 tasks done
nzh63 opened this issue Mar 14, 2024 · 2 comments
Closed
3 tasks done

Comments

@nzh63
Copy link

nzh63 commented Mar 14, 2024

Possible bug

Is this a possible bug in a feature of sharp, unrelated to installation?

  • Running npm install sharp completes without error.
  • Running node -e "require('sharp')" completes without error.

If you cannot confirm both of these, please open an installation issue instead.

Are you using the latest version of sharp?

  • I am using the latest version of sharp as reported by npm view sharp dist-tags.latest.

If you cannot confirm this, please upgrade to the latest version and try again before opening an issue.

If you are using another package which depends on a version of sharp that is not the latest, please open an issue against that package instead.

What is the output of running npx envinfo --binaries --system --npmPackages=sharp --npmGlobalPackages=sharp?

  System:
    OS: Windows 11 10.0.22621
    CPU: (16) x64 AMD Ryzen 7 6800H with Radeon Graphics
    Memory: 5.66 GB / 13.69 GB
  Binaries:
    Node: 20.11.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 4.1.1 - C:\Program Files\nodejs\yarn.CMD
    npm: 10.2.4 - C:\Program Files\nodejs\npm.CMD
  npmPackages:
    sharp: ^0.33.2 => 0.33.2

What are the steps to reproduce?

  1. Create a sharp stream, then use clone to create three output.
  2. Apply a joinChannel operation (add a alpha channel) to one of the output.
  3. Use fs.createReadStream to create a readable stream, then pipe it to sharp.
  4. We can observe that the function joinChannel has been applied to all of the output. Every output has an alpha channel.

What is the expected behaviour?

Using joinChannel after clone should only affect one output. The rest outputs should not have an alpha channel.

Please provide a minimal, standalone code sample, without other dependencies, that demonstrates this problem

const fs = require('fs');
const sharp = require('sharp');

(async function () {
  let img = sharp({
    create: {
      width: 1000,
      height: 1000,
      channels: 3,
      background: '#f00'
    }
  });
  await img.toFile('img.png');
  let circle = sharp(Buffer.from('<svg><circle cx="500" cy="500" r="500" fill="white" /></svg>'));
  let alpha = await circle.extractChannel(0).png().toBuffer();

  let sharpStream = sharp();
  sharpStream.clone().grayscale().toFile('img-grayscale.png'); // bug? expect to get a gray rect, but get a gray circle
  sharpStream.clone().joinChannel(alpha).toFile('img-alpha.png'); // ok, get a red circle with alpha channel
  sharpStream.clone().toFile('img-do-nothing.png'); // bug? expect to get a red rect, but get a red circle

  fs.createReadStream('img.png').pipe(sharpStream);
})();

I also try the flowing code. It doesn't work, too.

const sharp = require('sharp');

(async function () {
  let img = sharp({
    create: {
      width: 1000,
      height: 1000,
      channels: 3,
      background: '#f00'
    }
  });
  let circle = sharp(Buffer.from('<svg><circle cx="500" cy="500" r="500" fill="white" /></svg>'));
  let alpha = await circle.extractChannel(0).png().toBuffer();

  await img.clone().grayscale().toFile('img-grayscale.png'); // ok, get a gray rect
  await img.clone().joinChannel(alpha).toFile('img-alpha.png'); // ok, get a red circle with alpha channel
  await img.clone().toFile('img-do-nothing.png'); // bug? expect to get a red rect, but get a red circle
})();

Please provide sample image(s) that help explain this problem

None. All image is create by the code above.

@nzh63 nzh63 added the triage label Mar 14, 2024
@lovell lovell added this to the v0.33.3 milestone Mar 17, 2024
@lovell
Copy link
Owner

lovell commented Mar 17, 2024

Thanks for reporting, I can reproduce this locally. The joinChannel operation stores channels in an array. However during clone() only a shallow copy is taken, leading to the array of channels being shared by all siblings.

Commit 7bc74fe switches to a deep copy and adds a test that would previously have failed.

@lovell
Copy link
Owner

lovell commented Mar 23, 2024

v0.33.3 now available with the fix, thanks again for reporting this.

@lovell lovell closed this as completed Mar 23, 2024
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