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

Help converting raw input with color-profile to srgb #4195

Open labsforge opened 3 weeks ago

labsforge commented 3 weeks ago

Hi @lovell, I've tryed to all means to get this output image to work, but its getting out of my knowledge to fix it. The goal is to import a psd layer0 pixel data as a raw input to sharp. Everything works fine if the psd is sRGB, but I have here an Adobe RGB psd file, that I can't get it right, the image gets desaturated. I've tryed to export the image from photoshop with Adobe RGB icc embeded, and the jpg colors imports good, the issue is how to initialize the raw with the icc profile. One of the problems, is that psd files uses xmp metadata, and I can use the "withMetadata" because I'm creating a raw, so I created a simple xmpParser to check for the color-profile tag. I'm using ag-psd to read the psd and access the layer0 pixel-data buffer.

"sharp": "0.31.1",
"ag-psd": "20.2.0"
const psdBuffer = fs.readFileSync(photo.localPath);
const psd = readPsd(psdBuffer, { useImageData: true, skipThumbnail: false });
const imageDataBuffer = psd.bitsPerChannel === 16 ? Buffer.from(psd.imageData.data) : psd.imageData.data;

let sharpInstance = sharp(imageDataBuffer, {
  raw: {
    width: psd.imageData.width,
    height: psd.imageData.height,
    channels: 4
  }
});

// Extract XMP metadata
const xmpMetadata = psd.imageResources?.xmpMetadata ? psd.imageResources.xmpMetadata.toString() : null;
if (xmpMetadata) {
  return from(this.extractIccFromPsdXmp(xmpMetadata)).pipe(
    switchMap(iccProfilePath => {
      if (iccProfilePath) {
        return of(sharpInstance.withMetadata({
          icc: iccProfilePath,
        }));
      }
      return of(sharpInstance);
    }),
    catchError(err => of(sharpInstance)),
  );
}        

return of(sharpInstance);
}

I've also tried to add "toColorspace('srgb')" and the result is the same.

Files: https://www.pipebytes.com/zQnyxcio

Am I missing something? Thank you, Rui

labsforge commented 3 weeks ago

I can say that with ".pipelineColorspace('rbg16')" it helps a lot, but not as good as the direct jpg convertion.

lovell commented 3 weeks ago

with ".pipelineColorspace('rbg16')" it helps a lot

Yes, this is a suitable approach when imageDataBuffer is raw Uint16Array (maybe this should be the default?).

"sharp": "0.31.1",

Please upgrade to the latest version for various bug fixes and improvements relating to ICC profiles, including more fine-grained control over output metadata such as withIccProfile.