aboutsummaryrefslogtreecommitdiff
path: root/fiv-io-profile.c
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2024-01-27 23:09:32 +0100
committerPřemysl Eric Janouch <p@janouch.name>2024-01-27 23:10:32 +0100
commit250f2f0f758a5f3ea0f3174843dbf55fc73b1370 (patch)
tree4e05028c7b620e676a63953622e22883e1a81ad5 /fiv-io-profile.c
parentc6d89361a5e2a46818d67ce4a21856ddecc129a4 (diff)
downloadfiv-250f2f0f758a5f3ea0f3174843dbf55fc73b1370.tar.gz
fiv-250f2f0f758a5f3ea0f3174843dbf55fc73b1370.tar.xz
fiv-250f2f0f758a5f3ea0f3174843dbf55fc73b1370.zip
WIP: Thread-safe colour management
Diffstat (limited to 'fiv-io-profile.c')
-rw-r--r--fiv-io-profile.c109
1 files changed, 85 insertions, 24 deletions
diff --git a/fiv-io-profile.c b/fiv-io-profile.c
index 44eb0bf..387b201 100644
--- a/fiv-io-profile.c
+++ b/fiv-io-profile.c
@@ -30,31 +30,75 @@
#include <lcms2_fast_float.h>
#endif // HAVE_LCMS2_FAST_FLOAT
-// https://github.com/mm2/Little-CMS/issues/430
-static bool g_broken_cms_premul;
+// --- Contexts ----------------------------------------------------------------
-void
-fiv_io_cmm_init(void)
+struct _FivIoCmm {
+ GObject parent_instance;
+#ifdef HAVE_LCMS2
+ cmsContext context;
+
+ // https://github.com/mm2/Little-CMS/issues/430
+ gboolean broken_premul;
+#endif
+};
+
+G_DEFINE_TYPE(FivIoCmm, fiv_io_cmm, G_TYPE_OBJECT)
+
+static void
+fiv_io_cmm_finalize(GObject *gobject)
+{
+ FivIoCmm *self = FIV_IO_CMM(gobject);
+#ifdef HAVE_LCMS2
+ cmsDeleteContext(self->context);
+#endif
+
+ G_OBJECT_CLASS(fiv_io_cmm_parent_class)->finalize(gobject);
+}
+
+static void
+fiv_io_cmm_class_init(FivIoCmmClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = fiv_io_cmm_finalize;
+}
+
+static void
+fiv_io_cmm_init(FivIoCmm *self)
{
- // TODO(p): Use Little CMS with contexts instead.
+ (void) self;
+
+#ifdef HAVE_LCMS2
+ self->context = cmsCreateContext(NULL, self);
+#endif
#ifdef HAVE_LCMS2_FAST_FLOAT
- if (cmsPluginTHR(NULL, cmsFastFloatExtensions()))
- g_broken_cms_premul = LCMS_VERSION <= 2160;
+ if (cmsPluginTHR(self->context, cmsFastFloatExtensions()))
+ self->broken_premul = LCMS_VERSION <= 2160;
#endif // HAVE_LCMS2_FAST_FLOAT
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
FivIoCmm *
fiv_io_cmm_get_default()
{
- // TODO: Maintain a singleton for the NULL cmsContext.
- return NULL;
+ static gsize initialization_value = 0;
+ static FivIoCmm *default_ = NULL;
+ if (g_once_init_enter(&initialization_value)) {
+ gsize setup_value = 1;
+ default_ = g_object_new(FIV_TYPE_IO_CMM, NULL);
+ g_once_init_leave(&initialization_value, setup_value);
+ }
+ return default_;
}
FivIoProfile *
fiv_io_cmm_get_profile(FivIoCmm *self, const void *data, size_t len)
{
+ if (!self)
+ self = fiv_io_cmm_get_default();
+
#ifdef HAVE_LCMS2
- return cmsOpenProfileFromMemTHR(NULL, data, len);
+ return cmsOpenProfileFromMemTHR(self->context, data, len);
#else
(void) data;
(void) len;
@@ -65,8 +109,11 @@ fiv_io_cmm_get_profile(FivIoCmm *self, const void *data, size_t len)
FivIoProfile *
fiv_io_cmm_get_profile_sRGB(FivIoCmm *self)
{
+ if (!self)
+ self = fiv_io_cmm_get_default();
+
#ifdef HAVE_LCMS2
- return cmsCreate_sRGBProfileTHR(NULL);
+ return cmsCreate_sRGBProfileTHR(self->context);
#else
return NULL;
#endif
@@ -76,10 +123,10 @@ FivIoProfile *
fiv_io_cmm_get_profile_parametric(FivIoCmm *self,
double gamma, double whitepoint[2], double primaries[6])
{
-#ifdef HAVE_LCMS2
- // TODO(p): Make sure to use the library in a thread-safe manner.
- cmsContext context = NULL;
+ if (!self)
+ self = fiv_io_cmm_get_default();
+#ifdef HAVE_LCMS2
const cmsCIExyY cmsWP = {whitepoint[0], whitepoint[1], 1.0};
const cmsCIExyYTRIPLE cmsP = {
{primaries[0], primaries[1], 1.0},
@@ -87,12 +134,12 @@ fiv_io_cmm_get_profile_parametric(FivIoCmm *self,
{primaries[4], primaries[5], 1.0},
};
- cmsToneCurve *curve = cmsBuildGamma(context, gamma);
+ cmsToneCurve *curve = cmsBuildGamma(self->context, gamma);
if (!curve)
return NULL;
- cmsHPROFILE profile = cmsCreateRGBProfileTHR(
- context, &cmsWP, &cmsP, (cmsToneCurve *[3]){curve, curve, curve});
+ cmsHPROFILE profile = cmsCreateRGBProfileTHR(self->context,
+ &cmsWP, &cmsP, (cmsToneCurve *[3]){curve, curve, curve});
cmsFreeToneCurve(curve);
return profile;
#else
@@ -119,6 +166,8 @@ fiv_io_cmm_get_profile_from_bytes(FivIoCmm *self, GBytes *bytes)
return fiv_io_cmm_get_profile(self, p, len);
}
+// --- Profiles ----------------------------------------------------------------
+
GBytes *
fiv_io_profile_to_bytes(FivIoProfile *profile)
{
@@ -190,13 +239,18 @@ void
fiv_io_cmm_cmyk(FivIoCmm *self,
FivIoImage *image, FivIoProfile *source, FivIoProfile *target)
{
+ if (!self)
+ self = fiv_io_cmm_get_default();
+
#ifndef HAVE_LCMS2
+ (void) self;
(void) source;
(void) target;
#else
cmsHTRANSFORM transform = NULL;
if (source && target) {
- transform = cmsCreateTransformTHR(NULL, source, TYPE_CMYK_8_REV, target,
+ transform = cmsCreateTransformTHR(self->context,
+ source, TYPE_CMYK_8_REV, target,
FIV_IO_PROFILE_ARGB32, INTENT_PERCEPTUAL, 0);
}
if (transform) {
@@ -215,7 +269,11 @@ 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)
{
+ if (!self)
+ self = fiv_io_cmm_get_default();
+
#ifndef HAVE_LCMS2
+ (void) self;
(void) data;
(void) w;
(void) h;
@@ -228,11 +286,11 @@ fiv_io_cmm_rgb_direct(FivIoCmm *self, unsigned char *data, int w, int h,
// TODO(p): We should make this optional.
cmsHPROFILE src_fallback = NULL;
if (target && !source)
- source = src_fallback = cmsCreate_sRGBProfileTHR(NULL);
+ source = src_fallback = cmsCreate_sRGBProfileTHR(self->context);
cmsHTRANSFORM transform = NULL;
if (source && target) {
- transform = cmsCreateTransformTHR(NULL,
+ transform = cmsCreateTransformTHR(self->context,
source, source_format, target, target_format, INTENT_PERCEPTUAL, 0);
}
if (transform) {
@@ -311,7 +369,7 @@ fiv_io_cmm_argb32(FivIoCmm *self, FivIoImage *image,
{
g_return_if_fail(image->format == CAIRO_FORMAT_ARGB32);
- // TODO: With g_no_cms_premultiplication,
+ // TODO: With self->broken_premul,
// this probably also needs to be wrapped in un-premultiplication.
fiv_io_cmm_rgb_direct(self, image->data, image->width, image->height,
source, target,
@@ -322,9 +380,12 @@ void
fiv_io_cmm_argb32_premultiply(FivIoCmm *self,
FivIoImage *image, FivIoProfile *source, FivIoProfile *target)
{
+ if (!self)
+ self = fiv_io_cmm_get_default();
+
if (image->format != CAIRO_FORMAT_ARGB32) {
fiv_io_cmm_xrgb32(self, image, source, target);
- } else if (g_broken_cms_premul) {
+ } else if (self->broken_premul) {
fiv_io_cmm_xrgb32(self, image, source, target);
fiv_io_premultiply_argb32(image);
} else if (!fiv_io_cmm_rgb_direct(self, image->data,
@@ -338,7 +399,7 @@ fiv_io_cmm_argb32_premultiply(FivIoCmm *self,
#else // ! HAVE_LCMS2 || LCMS_VERSION < 2130
// TODO(p): Unpremultiply, transform, repremultiply. Or require lcms2>=2.13.
-#define fiv_io_profile_argb32(surface, source, target)
+#define fiv_io_cmm_argb32(self, image, source, target)
void
fiv_io_cmm_argb32_premultiply(FivIoCmm *self,
@@ -371,7 +432,7 @@ fiv_io_cmm_any(FivIoCmm *self,
// TODO(p): Offer better integration, upgrade the bit depth if appropriate.
FivIoImage *
-fiv_io_cmm_finalize(FivIoCmm *self, FivIoImage *image, FivIoProfile *target)
+fiv_io_cmm_finish(FivIoCmm *self, FivIoImage *image, FivIoProfile *target)
{
if (!target)
return image;