From 39f6be3f64a6c5c0a1ec0ee8a1d905160381b71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Eric=20Janouch?= Date: Sat, 27 Jan 2024 21:42:24 +0100 Subject: WIP: Thread-safe colour management --- fiv-io-profile.c | 55 +++++++++++++++++++++++++++++---------------------- fiv-io.c | 32 +++++++++++++++++++----------- fiv-io.h | 39 ++++++++++++++++++++++++++---------- fiv.c | 2 +- tools/benchmark-raw.c | 2 +- 5 files changed, 83 insertions(+), 47 deletions(-) diff --git a/fiv-io-profile.c b/fiv-io-profile.c index 2c6f345..4e51848 100644 --- a/fiv-io-profile.c +++ b/fiv-io-profile.c @@ -34,7 +34,7 @@ static bool g_broken_cms_premul; void -fiv_io_profile_init(void) +fiv_io_cmm_init(void) { // TODO(p): Use Little CMS with contexts instead. #ifdef HAVE_LCMS2_FAST_FLOAT @@ -43,6 +43,13 @@ fiv_io_profile_init(void) #endif // HAVE_LCMS2_FAST_FLOAT } +FivIoCmm * +fiv_io_cmm_get_default() +{ + // TODO: Maintain a singleton for the NULL cmsContext. + return NULL; +} + FivIoProfile * fiv_io_profile_new(const void *data, size_t len) { @@ -180,7 +187,7 @@ trivial_cmyk_to_host_byte_order_argb(unsigned char *p, int len) } void -fiv_io_profile_cmyk( +fiv_io_cmm_cmyk(FivIoCmm *self, FivIoImage *image, FivIoProfile *source, FivIoProfile *target) { #ifndef HAVE_LCMS2 @@ -204,7 +211,7 @@ fiv_io_profile_cmyk( } static bool -fiv_io_profile_rgb_direct(unsigned char *data, int w, int h, +fiv_io_cmm_rgb_direct(FivIoCmm *self, unsigned char *data, int w, int h, FivIoProfile *source, FivIoProfile *target, uint32_t source_format, uint32_t target_format) { @@ -239,26 +246,26 @@ fiv_io_profile_rgb_direct(unsigned char *data, int w, int h, } static void -fiv_io_profile_xrgb32( +fiv_io_cmm_xrgb32(FivIoCmm *self, FivIoImage *image, FivIoProfile *source, FivIoProfile *target) { - fiv_io_profile_rgb_direct(image->data, image->width, image->height, + fiv_io_cmm_rgb_direct(self, image->data, image->width, image->height, source, target, FIV_IO_PROFILE_ARGB32, FIV_IO_PROFILE_ARGB32); } void -fiv_io_profile_4x16le_direct(unsigned char *data, +fiv_io_cmm_4x16le_direct(FivIoCmm *self, unsigned char *data, int w, int h, FivIoProfile *source, FivIoProfile *target) { - fiv_io_profile_rgb_direct(data, w, h, source, target, + fiv_io_cmm_rgb_direct(self, data, w, h, source, target, FIV_IO_PROFILE_4X16LE, FIV_IO_PROFILE_4X16LE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void -fiv_io_profile_page(FivIoImage *page, FivIoProfile *target, - void (*frame_cb) (FivIoImage *, FivIoProfile *, FivIoProfile *)) +fiv_io_cmm_page(FivIoCmm *self, FivIoImage *page, FivIoProfile *target, + void (*frame_cb) (FivIoCmm *, FivIoImage *, FivIoProfile *, FivIoProfile *)) { FivIoProfile *source = NULL; if (page->icc) @@ -266,7 +273,7 @@ fiv_io_profile_page(FivIoImage *page, FivIoProfile *target, // TODO(p): All animations need to be composited in a linear colour space. for (FivIoImage *frame = page; frame != NULL; frame = frame->frame_next) - frame_cb(frame, source, target); + frame_cb(self, frame, source, target); if (source) fiv_io_profile_free(source); @@ -299,28 +306,28 @@ fiv_io_premultiply_argb32(FivIoImage *image) (G_BYTE_ORDER == G_LITTLE_ENDIAN ? TYPE_BGRA_8_PREMUL : TYPE_ARGB_8_PREMUL) static void -fiv_io_profile_argb32(FivIoImage *image, +fiv_io_cmm_argb32(FivIoCmm *self, FivIoImage *image, FivIoProfile *source, FivIoProfile *target) { g_return_if_fail(image->format == CAIRO_FORMAT_ARGB32); // TODO: With g_no_cms_premultiplication, // this probably also needs to be wrapped in un-premultiplication. - fiv_io_profile_rgb_direct(image->data, image->width, image->height, + fiv_io_cmm_rgb_direct(self, image->data, image->width, image->height, source, target, FIV_IO_PROFILE_ARGB32_PREMUL, FIV_IO_PROFILE_ARGB32_PREMUL); } void -fiv_io_profile_argb32_premultiply( +fiv_io_cmm_argb32_premultiply(FivIoCmm *self, FivIoImage *image, FivIoProfile *source, FivIoProfile *target) { if (image->format != CAIRO_FORMAT_ARGB32) { - fiv_io_profile_xrgb32(image, source, target); + fiv_io_cmm_xrgb32(self, image, source, target); } else if (g_broken_cms_premul) { - fiv_io_profile_xrgb32(image, source, target); + fiv_io_cmm_xrgb32(self, image, source, target); fiv_io_premultiply_argb32(image); - } else if (!fiv_io_profile_rgb_direct(image->data, + } else if (!fiv_io_cmm_rgb_direct(self, image->data, image->width, image->height, source, target, FIV_IO_PROFILE_ARGB32, FIV_IO_PROFILE_ARGB32_PREMUL)) { g_debug("failed to create a premultiplying transform"); @@ -333,11 +340,11 @@ fiv_io_profile_argb32_premultiply( // TODO(p): Unpremultiply, transform, repremultiply. Or require lcms2>=2.13. #define fiv_io_profile_argb32(surface, source, target) -static void -fiv_io_profile_argb32_premultiply( +void +fiv_io_cmm_argb32_premultiply(FivIoCmm *self, FivIoImage *image, FivIoProfile *source, FivIoProfile *target) { - fiv_io_profile_xrgb32(image, source, target); + fiv_io_cmm_xrgb32(self, image, source, target); fiv_io_premultiply_argb32(image); } @@ -346,7 +353,7 @@ fiv_io_profile_argb32_premultiply( // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void -fiv_io_profile_any( +fiv_io_cmm_any(FivIoCmm *self, FivIoImage *image, FivIoProfile *source, FivIoProfile *target) { // TODO(p): Ensure we do colour management early enough, so that @@ -354,9 +361,9 @@ fiv_io_profile_any( // and also for correct alpha compositing. switch (image->format) { break; case CAIRO_FORMAT_RGB24: - fiv_io_profile_xrgb32(image, source, target); + fiv_io_cmm_xrgb32(self, image, source, target); break; case CAIRO_FORMAT_ARGB32: - fiv_io_profile_argb32(image, source, target); + fiv_io_cmm_argb32(self, image, source, target); break; default: g_debug("CM attempted on an unsupported surface format"); } @@ -364,12 +371,12 @@ fiv_io_profile_any( // TODO(p): Offer better integration, upgrade the bit depth if appropriate. FivIoImage * -fiv_io_profile_finalize(FivIoImage *image, FivIoProfile *target) +fiv_io_cmm_finalize(FivIoCmm *self, FivIoImage *image, FivIoProfile *target) { if (!target) return image; for (FivIoImage *page = image; page != NULL; page = page->page_next) - fiv_io_profile_page(page, target, fiv_io_profile_any); + fiv_io_cmm_page(self, page, target, fiv_io_cmm_any); return image; } diff --git a/fiv-io.c b/fiv-io.c index 4fd3d29..f16a245 100644 --- a/fiv-io.c +++ b/fiv-io.c @@ -447,11 +447,12 @@ load_wuffs_frame(struct load_wuffs_frame_context *ctx, GError **error) if (ctx->target) { if (ctx->expand_16_float || ctx->pack_16_10) { - fiv_io_profile_4x16le_direct( + fiv_io_cmm_4x16le_direct(fiv_io_cmm_get_default(), targetbuf, ctx->width, ctx->height, ctx->source, ctx->target); // The first one premultiplies below, the second doesn't need to. } else { - fiv_io_profile_argb32_premultiply(image, ctx->source, ctx->target); + fiv_io_cmm_argb32_premultiply(fiv_io_cmm_get_default(), + image, ctx->source, ctx->target); } } @@ -1263,9 +1264,11 @@ load_jpeg_finalize(FivIoImage *image, bool cmyk, g_bytes_get_data(image->exif, NULL), g_bytes_get_size(image->exif)); if (cmyk) - fiv_io_profile_cmyk(image, source, ctx->screen_profile); + fiv_io_cmm_cmyk(fiv_io_cmm_get_default(), + image, source, ctx->screen_profile); else - fiv_io_profile_any(image, source, ctx->screen_profile); + fiv_io_cmm_any(fiv_io_cmm_get_default(), + image, source, ctx->screen_profile); if (source) fiv_io_profile_free(source); @@ -1666,7 +1669,8 @@ open_libwebp( WebPDemuxDelete(demux); if (ctx->screen_profile) - fiv_io_profile_argb32_premultiply_page(result, ctx->screen_profile); + fiv_io_cmm_argb32_premultiply_page(fiv_io_cmm_get_default(), + result, ctx->screen_profile); fail: WebPFreeDecBuffer(&config.output); @@ -2049,7 +2053,8 @@ open_libraw( out: libraw_close(iprc); - return fiv_io_profile_finalize(result, ctx->screen_profile); + return fiv_io_cmm_finalize(fiv_io_cmm_get_default(), + result, ctx->screen_profile); } #endif // HAVE_LIBRAW --------------------------------------------------------- @@ -2226,7 +2231,8 @@ load_librsvg_render_internal(FivIoRenderClosureLibrsvg *self, double scale, fiv_io_image_unref(image); return NULL; } - return fiv_io_profile_finalize(image, target); + return fiv_io_cmm_finalize(fiv_io_cmm_get_default(), + image, target); } static FivIoImage * @@ -2600,7 +2606,8 @@ open_libheif( g_free(ids); fail_read: heif_context_free(ctx); - return fiv_io_profile_finalize(result, ioctx->screen_profile); + return fiv_io_cmm_finalize(fiv_io_cmm_get_default(), + result, ioctx->screen_profile); } #endif // HAVE_LIBHEIF -------------------------------------------------------- @@ -2831,7 +2838,8 @@ fail: TIFFSetWarningHandlerExt(whe); TIFFSetErrorHandler(eh); TIFFSetWarningHandler(wh); - return fiv_io_profile_finalize(result, ctx->screen_profile); + return fiv_io_cmm_finalize(fiv_io_cmm_get_default(), + result, ctx->screen_profile); } #endif // HAVE_LIBTIFF -------------------------------------------------------- @@ -2926,9 +2934,11 @@ open_gdkpixbuf( g_object_unref(pixbuf); if (custom_argb32) - fiv_io_profile_argb32_premultiply_page(image, ctx->screen_profile); + fiv_io_cmm_argb32_premultiply_page(fiv_io_cmm_get_default(), + image, ctx->screen_profile); else - image = fiv_io_profile_finalize(image, ctx->screen_profile); + image = fiv_io_cmm_finalize(fiv_io_cmm_get_default(), + image, ctx->screen_profile); return image; } diff --git a/fiv-io.h b/fiv-io.h index bb92033..26e1b93 100644 --- a/fiv-io.h +++ b/fiv-io.h @@ -28,7 +28,7 @@ typedef struct _FivIoImage FivIoImage; // --- Colour management ------------------------------------------------------- -void fiv_io_profile_init(void); +void fiv_io_cmm_init(void); // TODO(p): Make it also possible to use Skia's skcms. typedef void *FivIoProfile; @@ -43,23 +43,42 @@ void fiv_io_profile_free(FivIoProfile *self); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#define FIV_TYPE_IO_CMM (fiv_io_cmm_get_type()) +G_DECLARE_FINAL_TYPE(FivIoCmm, fiv_io_cmm, FIV, CMM, GObject) + +FivIoCmm *fiv_io_cmm_get_default(); + +/* +FivIoProfile *fiv_io_cmm_get_profile( + FivIoCmm *self, const void *data, size_t len); +FivIoProfile *fiv_io_cmm_get_profile_from_bytes(FivIoCmm *self, GBytes *bytes); +FivIoProfile *fiv_io_cmm_get_profile_sRGB(FivIoCmm *self); +FivIoProfile *fiv_io_cmm_get_profile_sRGB_gamma(FivIoCmm *self, double gamma); +FivIoProfile *fiv_io_cmm_get_profile_parametric( + FivIoCmm *self, double gamma, double whitepoint[2], double primaries[6]); +*/ + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + void fiv_io_premultiply_argb32(FivIoImage *image); -void fiv_io_profile_cmyk( +void fiv_io_cmm_cmyk(FivIoCmm *self, FivIoImage *image, FivIoProfile *source, FivIoProfile *target); -void fiv_io_profile_4x16le_direct(unsigned char *data, +void fiv_io_cmm_4x16le_direct(FivIoCmm *self, unsigned char *data, int w, int h, FivIoProfile *source, FivIoProfile *target); -void fiv_io_profile_argb32_premultiply( +void fiv_io_cmm_argb32_premultiply(FivIoCmm *self, FivIoImage *image, FivIoProfile *source, FivIoProfile *target); -void fiv_io_profile_page(FivIoImage *page, FivIoProfile *target, - void (*frame_cb) (FivIoImage *, FivIoProfile *, FivIoProfile *)); -#define fiv_io_profile_argb32_premultiply_page(page, target) \ - fiv_io_profile_page((page), (target), fiv_io_profile_argb32_premultiply) +void fiv_io_cmm_page(FivIoCmm *self, FivIoImage *page, FivIoProfile *target, + void (*frame_cb) (FivIoCmm *, + FivIoImage *, FivIoProfile *, FivIoProfile *)); +#define fiv_io_cmm_argb32_premultiply_page(cmm, page, target) \ + fiv_io_cmm_page((cmm), (page), (target), fiv_io_cmm_argb32_premultiply) -void fiv_io_profile_any( +void fiv_io_cmm_any(FivIoCmm *self, FivIoImage *image, FivIoProfile *source, FivIoProfile *target); -FivIoImage *fiv_io_profile_finalize(FivIoImage *image, FivIoProfile *target); +FivIoImage *fiv_io_cmm_finalize( + FivIoCmm *self, FivIoImage *image, FivIoProfile *target); // --- Loading ----------------------------------------------------------------- diff --git a/fiv.c b/fiv.c index f4f612e..1514d4a 100644 --- a/fiv.c +++ b/fiv.c @@ -2583,7 +2583,7 @@ on_app_handle_local_options(G_GNUC_UNUSED GApplication *app, return 0; } - fiv_io_profile_init(); + fiv_io_cmm_init(); // Normalize all arguments to URIs, and run thumbnailing modes first. for (gsize i = 0; o.args && o.args[i]; i++) { diff --git a/tools/benchmark-raw.c b/tools/benchmark-raw.c index 9e1fe41..e1e6ea8 100644 --- a/tools/benchmark-raw.c +++ b/tools/benchmark-raw.c @@ -408,7 +408,7 @@ main(int argc, char *argv[]) // We don't need to call gdk_cairo_surface_create_from_pixbuf() here, // so don't bother initializing GDK. - fiv_io_profile_init(); + fiv_io_cmm_init(); // A mode to just extract all thumbnails to files for closer inspection. extract_mode = !!getenv("BENCHMARK_RAW_EXTRACT"); -- cgit v1.2.3