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
29.39k stars 1.3k forks source link

Improvements to the handling of images with multiple alpha channels #2266

Open webbery opened 4 years ago

webbery commented 4 years ago

Hi, I use sharp v0.25.4. I load a 16bit tiff and want to display on web canvas. Web chanvas require 4 channel containning alpha. In my code, I write it like this:

let {data, info} = await sharp(tiffpath).jpeg({force: true}).ensureAlpha()
          .raw().toBuffer({ resolveWithObject: true })

I see info is still 6 channel but not 4. Then my code throw an error which can not create ImageData. Is it a bug?

lovell commented 4 years ago

Hi, are you able to provide a sample input image?

As an aside, the use of jpeg() in this code sample is ignored as the use of raw() later in the chain takes precedence.

webbery commented 4 years ago

Here is my image. sample.zip Although I can convert 6 channel to 4 channel, I think it's slowly in javscript. It is best to finish this work in C++.

lovell commented 4 years ago

This input TIFF image has 5 channels, RGB and what appears to be two alpha channels, which is unusual.

The raw, uncompressed output pixel data has five channels, for example:

const { info } = await sharp('Shipyard Cranes Masked (8).tif')
  .raw()
  .toBuffer();

produces:

{
  format: 'raw',
  width: 3363,
  height: 4000,
  channels: 5,
  premultiplied: false,
  size: 67260000
}

sharp currently doesn't understand "5 channel RGB" and does not know how treat channels 4 and 5, so using ensureAlpha() with this image adds a 6th channel.

const { info } = await sharp('Shipyard Cranes Masked (8).tif')
  .ensureAlpha()
  .raw()
  .toBuffer();

produces:

{
  format: 'raw',
  width: 3363,
  height: 4000,
  channels: 6,
  premultiplied: false,
  size: 80712000
}

There are two possible improvements here.

  1. ensureAlpha (and removeAlpha) might be able to better detect multiple alpha channels.
  2. raw should ignore/remove secondary alpha channels to meet its documented behaviour of providing RGBA.
JamieVangeysel commented 2 years ago

I don't use ensureAlpha or removeAlpha. For me it would work if the extra alpha channels are just ignored. The easiest way to implement that in code is by adding an option to the constructor ignoreSecondaryAlpha or something like that defaulting to false to not break alrady existing code