Merge "fix TIFF encoder regarding rgbA/RGBA"

This commit is contained in:
Pascal Massimino 2017-03-08 08:07:43 +00:00 committed by Gerrit Code Review
commit 18f0dfac82
3 changed files with 62 additions and 7 deletions

View File

@ -332,9 +332,8 @@ int main(int argc, const char *argv[]) {
case BMP: case BMP:
output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR; output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR;
break; break;
case TIFF: // note: force pre-multiplied alpha case TIFF:
output_buffer->colorspace = output_buffer->colorspace = bitstream->has_alpha ? MODE_RGBA : MODE_RGB;
bitstream->has_alpha ? MODE_rgbA : MODE_RGB;
break; break;
case PGM: case PGM:
case RAW_YUV: case RAW_YUV:

View File

@ -361,6 +361,7 @@ int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
const uint8_t* rgba = buffer->u.RGBA.rgba; const uint8_t* rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride; const int stride = buffer->u.RGBA.stride;
const uint8_t bytes_per_px = has_alpha ? 4 : 3; const uint8_t bytes_per_px = has_alpha ? 4 : 3;
const int assoc_alpha = WebPIsPremultipliedMode(buffer->colorspace) ? 1 : 2;
// For non-alpha case, we omit tag 0x152 (ExtraSamples). // For non-alpha case, we omit tag 0x152 (ExtraSamples).
const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES
: NUM_IFD_ENTRIES - 1; : NUM_IFD_ENTRIES - 1;
@ -388,7 +389,8 @@ int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
EXTRA_DATA_OFFSET + 8, 0, 0, 0, EXTRA_DATA_OFFSET + 8, 0, 0, 0,
0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration 0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration
0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch) 0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch)
0x52, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 178: ExtraSamples: rgbA 0x52, 0x01, 3, 0, 1, 0, 0, 0,
assoc_alpha, 0, 0, 0, // 178: ExtraSamples: rgbA/RGBA
0, 0, 0, 0, // 190: IFD terminator 0, 0, 0, 0, // 190: IFD terminator
// EXTRA_DATA_OFFSET: // EXTRA_DATA_OFFSET:
8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample 8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample

View File

@ -116,13 +116,48 @@ static tsize_t MyRead(thandle_t opaque, void* dst, tsize_t size) {
return size; return size;
} }
// Unmultiply Argb data. Taken from dsp/alpha_processing
// (we don't want to force a dependency to a libdspdec library).
#define MFIX 24 // 24bit fixed-point arithmetic
#define HALF ((1u << MFIX) >> 1)
#define KINV_255 ((1u << MFIX) / 255u)
static uint32_t Unmult(uint8_t x, uint32_t mult) {
const uint32_t v = (x * mult + HALF) >> MFIX;
return (v > 255u) ? 255u : v;
}
static WEBP_INLINE uint32_t GetScale(uint32_t a) {
return (255u << MFIX) / a;
}
static void MultARGBRow(uint8_t* ptr, int width) {
int x;
for (x = 0; x < width; ++x, ptr += 4) {
const uint32_t alpha = ptr[3];
if (alpha < 255) {
if (alpha == 0) { // alpha == 0
ptr[0] = ptr[1] = ptr[2] = 0;
} else {
const uint32_t scale = GetScale(alpha);
ptr[0] = Unmult(ptr[0], scale);
ptr[1] = Unmult(ptr[1], scale);
ptr[2] = Unmult(ptr[2], scale);
}
}
}
}
int ReadTIFF(const uint8_t* const data, size_t data_size, int ReadTIFF(const uint8_t* const data, size_t data_size,
WebPPicture* const pic, int keep_alpha, WebPPicture* const pic, int keep_alpha,
Metadata* const metadata) { Metadata* const metadata) {
MyData my_data = { data, (toff_t)data_size, 0 }; MyData my_data = { data, (toff_t)data_size, 0 };
TIFF* tif; TIFF* tif;
uint32 width, height; uint32_t width, height;
uint32* raster; uint16_t samples_per_px = 0;
uint16_t extra_samples = 0;
uint16_t* extra_samples_ptr = NULL;
uint32_t* raster;
int64_t alloc_size; int64_t alloc_size;
int ok = 0; int ok = 0;
tdir_t dircount; tdir_t dircount;
@ -143,17 +178,27 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
"Only the first will be used, %d will be ignored.\n", "Only the first will be used, %d will be ignored.\n",
dircount - 1); dircount - 1);
} }
if (!TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samples_per_px)) {
fprintf(stderr, "Error! Cannot retrieve TIFF samples-per-pixel info.\n");
goto End;
}
if (samples_per_px < 3 || samples_per_px > 4) goto End; // not supported
if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) && if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) &&
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))) { TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))) {
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n"); fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
goto End; goto End;
} }
if (!ImgIoUtilCheckSizeArgumentsOverflow((uint64_t)width * height, if (!ImgIoUtilCheckSizeArgumentsOverflow((uint64_t)width * height,
sizeof(*raster))) { sizeof(*raster))) {
goto End; goto End;
} }
if (!TIFFGetField(tif, TIFFTAG_EXTRASAMPLES,
&extra_samples, &extra_samples_ptr)) {
fprintf(stderr, "Error! Cannot retrieve TIFF ExtraSamples info.\n");
goto End;
}
// _Tiffmalloc uses a signed type for size. // _Tiffmalloc uses a signed type for size.
alloc_size = (int64_t)((uint64_t)width * height * sizeof(*raster)); alloc_size = (int64_t)((uint64_t)width * height * sizeof(*raster));
if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End; if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End;
@ -169,6 +214,15 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
TIFFSwabArrayOfLong(raster, width * height); TIFFSwabArrayOfLong(raster, width * height);
#endif #endif
// if we have an alpha channel, we must un-multiply from rgbA to RGBA
if (samples_per_px > 3 && extra_samples == 1) {
uint32_t y;
uint8_t* tmp = (uint8_t*)raster;
for (y = 0; y < height; ++y) {
MultARGBRow(tmp, width);
tmp += stride;
}
}
ok = keep_alpha ok = keep_alpha
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride) ? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride); : WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);