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

Enhancement: support floating-point raw pixel output for LAB/LCH #681

Open btd opened 7 years ago

btd commented 7 years ago

Hi, there.

I am trying to get Lab colors from image using such code:

sharp(buffer, { raw: opts })
      .toColorspace('lab')
      .raw()
      .toBuffer((err, data, info) => {
        if (err) {
          return reject(err);
        }

        resolve(data);
      });
  });

And i am comparing what i get with what i am expecting for example (using image created in Paint 5*5 px):

Color at pixel 15
Sharp LAB: 63 0 40 255
RGBA: 34 177 76 255
Manual LAB: 63.59512302182216 -57.62819968304833 40.96944518661568

So with this result comming question: How to use Lab colorspace produced by sharp? As a result of toBuffer is a Buffer so it cuts floating data and negative numbers, but lab coordinates could be negative (a and b). Maybe there is way to produce Float32Array or something like this? Another question, why result of Lab conversion 4 channels (iirc LAB does not use alpha)?

Thank you for answers.

lovell commented 7 years ago

LAB values should be signed integer values and the readInt8 function will do the bit-shifting for you. From memory, L values are 0 to 100, AB values are -127 to 127. The alpha channel remains 0 to 255 unsigned.

Sharp LAB: 63 0 40 255 Manual LAB: 63.59512302182216 -57.62819968304833 40.96944518661568

How was the A value converted? I'd expect this to be -57 as signed, 199 as unsigned, so this could be a bug.

btd commented 7 years ago

Hm, in some reason i thought i posted my comment.

Anyway. To ge Lab results i used code above and just printed with console.log (it is line with Sharp LAB). As an image i have used this image: _ To get Manual LAB results i used formulas from wikipedia. There is my implementation in gist. Need to call function RGBtoCIELAB({ r: ..., g: ..., b: ... }). I think also your A and B value range should be scaled. If i got math right A should be around -200 to 200 and B from -500 to 500. But in this case we loose precision too match, am i right there?

lovell commented 7 years ago

I agree that when the expected output is raw LAB pixel data via .toColorspace('lab').raw() (and possibly some other colourspaces too, e.g. LCH), the output should be a Buffer containing 32-bit floating point values. I'll have to take a deeper look to see how this might work.

btd commented 7 years ago

Thank you.