Get ICC profile and orientation from libtiff

Pain has been outsourced to someone from the past,
I just blindly trust the orientation mapping.
This commit is contained in:
Přemysl Eric Janouch 2021-11-28 03:37:04 +01:00
parent 666bfc0759
commit d930b2b245
Signed by: p
GPG Key ID: A0420B94F92B9493
1 changed files with 40 additions and 17 deletions

View File

@ -1134,34 +1134,57 @@ load_libtiff_directory(TIFF *tiff, GError **error)
set_error(error, emsg); set_error(error, emsg);
return NULL; return NULL;
} }
cairo_surface_t *surface = NULL;
if (image.width > G_MAXINT || image.height >= G_MAXINT || if (image.width > G_MAXINT || image.height >= G_MAXINT ||
G_MAXUINT32 / image.width < image.height) { G_MAXUINT32 / image.width < image.height) {
set_error(error, "image dimensions too large"); set_error(error, "image dimensions too large");
TIFFRGBAImageEnd(&image); goto fail;
return NULL;
} }
cairo_surface_t *surface = cairo_image_surface_create( surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, image.width, image.height); CAIRO_FORMAT_ARGB32, image.width, image.height);
uint32_t *raster = (uint32_t *) cairo_image_surface_get_data(surface);
image.req_orientation = ORIENTATION_LEFTTOP; image.req_orientation = ORIENTATION_LEFTTOP;
if (TIFFRGBAImageGet(&image, raster, image.width, image.height)) { uint32_t *raster = (uint32_t *) cairo_image_surface_get_data(surface);
// Needs to be converted from ABGR to ARGB for Cairo, if (!TIFFRGBAImageGet(&image, raster, image.width, image.height)) {
// and then premultiplied.
for (uint32_t i = image.width * image.height; i--; ) {
uint32_t pixel = raster[i],
a = TIFFGetA(pixel),
b = TIFFGetB(pixel) * a / 255,
g = TIFFGetG(pixel) * a / 255,
r = TIFFGetR(pixel) * a / 255;
raster[i] = a << 24 | r << 16 | g << 8 | b;
}
cairo_surface_mark_dirty(surface);
} else {
g_clear_pointer(&surface, cairo_surface_destroy); g_clear_pointer(&surface, cairo_surface_destroy);
goto fail;
} }
// Needs to be converted from ABGR to alpha-premultiplied ARGB for Cairo.
for (uint32_t i = image.width * image.height; i--;) {
uint32_t pixel = raster[i],
a = TIFFGetA(pixel),
b = TIFFGetB(pixel) * a / 255,
g = TIFFGetG(pixel) * a / 255,
r = TIFFGetR(pixel) * a / 255;
raster[i] = a << 24 | r << 16 | g << 8 | b;
}
cairo_surface_mark_dirty(surface);
// XXX: The whole file is essentially an Exif, any ideas?
const uint32_t icc_length = 0;
const void *icc_profile = NULL;
if (TIFFGetField(tiff, TIFFTAG_ICCPROFILE, &icc_length, &icc_profile)) {
cairo_surface_set_user_data(surface, &fastiv_io_key_icc,
g_bytes_new(icc_profile, icc_length),
(cairo_destroy_func_t) g_bytes_unref);
}
// Don't ask. The API is high, alright, I'm just not sure about the level.
uint16_t orientation = 0;
if (TIFFGetField(tiff, TIFFTAG_ORIENTATION, &orientation)) {
if (orientation == 5 || orientation == 7)
cairo_surface_set_user_data(surface, &fastiv_io_key_orientation,
(void *) (uintptr_t) 5, NULL);
if (orientation == 6 || orientation == 8)
cairo_surface_set_user_data(surface, &fastiv_io_key_orientation,
(void *) (uintptr_t) 7, NULL);
}
fail:
TIFFRGBAImageEnd(&image); TIFFRGBAImageEnd(&image);
return surface; return surface;
} }