aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2023-06-06 11:08:56 +0200
committerPřemysl Eric Janouch <p@janouch.name>2023-06-06 12:20:03 +0200
commit6cc4ca1f44278c9821675dd5d1f34aa442c6ce7d (patch)
tree816410c7ebae8caa0d2287a88e8a1c971b3407e5
parent1c25cb411fc4eb9b1cbb11160560155667e30e81 (diff)
downloadfiv-6cc4ca1f44278c9821675dd5d1f34aa442c6ce7d.tar.gz
fiv-6cc4ca1f44278c9821675dd5d1f34aa442c6ce7d.tar.xz
fiv-6cc4ca1f44278c9821675dd5d1f34aa442c6ce7d.zip
Use Little CMS's alpha premultiplication feature
And do a little cleanup.
-rw-r--r--fiv-io.c117
-rw-r--r--fiv-io.h4
2 files changed, 74 insertions, 47 deletions
diff --git a/fiv-io.c b/fiv-io.c
index 3f9ff30..27c8107 100644
--- a/fiv-io.c
+++ b/fiv-io.c
@@ -286,10 +286,15 @@ fiv_io_profile_free(FivIoProfile self)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// TODO(p): In general, try to use CAIRO_FORMAT_RGB30 or CAIRO_FORMAT_RGBA128F.
-#define FIV_IO_LCMS2_ARGB32 \
+#ifndef HAVE_LCMS2
+#define FIV_IO_PROFILE_ARGB32 0
+#define FIV_IO_PROFILE_4X16LE 0
+#else
+#define FIV_IO_PROFILE_ARGB32 \
(G_BYTE_ORDER == G_LITTLE_ENDIAN ? TYPE_BGRA_8 : TYPE_ARGB_8)
-#define FIV_IO_LCMS2_4X16LE \
+#define FIV_IO_PROFILE_4X16LE \
(G_BYTE_ORDER == G_LITTLE_ENDIAN ? TYPE_BGRA_16 : TYPE_BGRA_16_SE)
+#endif
// CAIRO_STRIDE_ALIGNMENT is 4 bytes, so there will be no padding with
// ARGB/BGRA/XRGB/BGRX.
@@ -332,7 +337,7 @@ fiv_io_profile_cmyk(
cmsHTRANSFORM transform = NULL;
if (source && target) {
transform = cmsCreateTransform(source, TYPE_CMYK_8_REV, target,
- FIV_IO_LCMS2_ARGB32, INTENT_PERCEPTUAL, 0);
+ FIV_IO_PROFILE_ARGB32, INTENT_PERCEPTUAL, 0);
}
if (transform) {
cmsDoTransform(transform, data, data, w * h);
@@ -343,16 +348,20 @@ fiv_io_profile_cmyk(
trivial_cmyk_to_host_byte_order_argb(data, w * h);
}
-static void
-fiv_io_profile_xrgb32_direct(unsigned char *data, int w, int h,
- FivIoProfile source, FivIoProfile target)
+static bool
+fiv_io_profile_rgb_direct(unsigned char *data, int w, int h,
+ FivIoProfile source, FivIoProfile target,
+ uint32_t source_format, uint32_t target_format)
{
#ifndef HAVE_LCMS2
(void) data;
(void) w;
(void) h;
(void) source;
+ (void) source_format;
(void) target;
+ (void) target_format;
+ return false;
#else
// TODO(p): We should make this optional.
cmsHPROFILE src_fallback = NULL;
@@ -361,8 +370,8 @@ fiv_io_profile_xrgb32_direct(unsigned char *data, int w, int h,
cmsHTRANSFORM transform = NULL;
if (source && target) {
- transform = cmsCreateTransform(source, FIV_IO_LCMS2_ARGB32, target,
- FIV_IO_LCMS2_ARGB32, INTENT_PERCEPTUAL, 0);
+ transform = cmsCreateTransform(
+ source, source_format, target, target_format, INTENT_PERCEPTUAL, 0);
}
if (transform) {
cmsDoTransform(transform, data, data, w * h);
@@ -370,10 +379,19 @@ fiv_io_profile_xrgb32_direct(unsigned char *data, int w, int h,
}
if (src_fallback)
cmsCloseProfile(src_fallback);
+ return transform != NULL;
#endif
}
static void
+fiv_io_profile_xrgb32_direct(
+ unsigned char *data, int w, int h, FivIoProfile source, FivIoProfile target)
+{
+ fiv_io_profile_rgb_direct(data, w, h, source, target,
+ FIV_IO_PROFILE_ARGB32, FIV_IO_PROFILE_ARGB32);
+}
+
+static void
fiv_io_profile_xrgb32(
cairo_surface_t *surface, FivIoProfile source, FivIoProfile target)
{
@@ -387,36 +405,15 @@ static void
fiv_io_profile_4x16le_direct(
unsigned char *data, int w, int h, FivIoProfile source, FivIoProfile target)
{
-#ifndef HAVE_LCMS2
- (void) data;
- (void) w;
- (void) h;
- (void) source;
- (void) target;
-#else
- // TODO(p): We should make this optional.
- cmsHPROFILE src_fallback = NULL;
- if (target && !source)
- source = src_fallback = cmsCreate_sRGBProfile();
-
- cmsHTRANSFORM transform = NULL;
- if (source && target) {
- transform = cmsCreateTransform(source, FIV_IO_LCMS2_4X16LE, target,
- FIV_IO_LCMS2_4X16LE, INTENT_PERCEPTUAL, 0);
- }
- if (transform) {
- cmsDoTransform(transform, data, data, w * h);
- cmsDeleteTransform(transform);
- }
- if (src_fallback)
- cmsCloseProfile(src_fallback);
-#endif
+ fiv_io_profile_rgb_direct(data, w, h, source, target,
+ FIV_IO_PROFILE_4X16LE, FIV_IO_PROFILE_4X16LE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void
-fiv_io_profile_xrgb32_page(cairo_surface_t *page, FivIoProfile target)
+fiv_io_profile_page(cairo_surface_t *page, FivIoProfile target,
+ void (*frame_cb) (cairo_surface_t *, FivIoProfile, FivIoProfile))
{
GBytes *bytes = NULL;
FivIoProfile source = NULL;
@@ -426,12 +423,15 @@ fiv_io_profile_xrgb32_page(cairo_surface_t *page, FivIoProfile target)
// TODO(p): All animations need to be composited in a linear colour space.
for (cairo_surface_t *frame = page; frame != NULL;
frame = cairo_surface_get_user_data(frame, &fiv_io_key_frame_next))
- fiv_io_profile_xrgb32(frame, source, target);
+ frame_cb(frame, source, target);
if (source)
fiv_io_profile_free(source);
}
+#define fiv_io_profile_xrgb32_page(page, target) \
+ fiv_io_profile_page((page), (target), fiv_io_profile_xrgb32)
+
// TODO(p): Offer better integration, upgrade the bit depth if appropriate.
static cairo_surface_t *
fiv_io_profile_finalize(cairo_surface_t *image, FivIoProfile target)
@@ -451,6 +451,8 @@ fiv_io_profile_finalize(cairo_surface_t *image, FivIoProfile target)
return image;
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
static void
fiv_io_premultiply_argb32(cairo_surface_t *surface)
{
@@ -473,14 +475,45 @@ fiv_io_premultiply_argb32(cairo_surface_t *surface)
}
}
+#if defined HAVE_LCMS2 && LCMS_VERSION >= 2130
+
+#define FIV_IO_PROFILE_ARGB32_PREMUL \
+ (G_BYTE_ORDER == G_LITTLE_ENDIAN ? TYPE_BGRA_8_PREMUL : TYPE_ARGB_8_PREMUL)
+
static void
-fiv_io_premultiply_argb32_page(cairo_surface_t *page)
+fiv_io_profile_argb32_premultiply(cairo_surface_t *surface,
+ FivIoProfile source, FivIoProfile target)
{
+ int w = cairo_image_surface_get_width(surface);
+ int h = cairo_image_surface_get_height(surface);
+ unsigned char *data = cairo_image_surface_get_data(surface);
+ if (cairo_image_surface_get_format(surface) != CAIRO_FORMAT_ARGB32) {
+ fiv_io_profile_xrgb32_direct(data, w, h, source, target);
+ } else if (!fiv_io_profile_rgb_direct(data, w, h, source, target,
+ FIV_IO_PROFILE_ARGB32, FIV_IO_PROFILE_ARGB32_PREMUL)) {
+ g_debug("failed to create a premultiplying transform");
+ fiv_io_premultiply_argb32(surface);
+ }
+}
+
+#define fiv_io_profile_argb32_premultiply_page(page, target) \
+ fiv_io_profile_page((page), (target), fiv_io_profile_argb32_premultiply)
+
+#else // ! HAVE_LCMS2 || LCMS_VERSION < 2130
+
+static void
+fiv_io_profile_argb32_premultiply_page(
+ cairo_surface_t *page, FivIoProfile target)
+{
+ fiv_io_profile_xrgb32_page(page, target);
+
for (cairo_surface_t *frame = page; frame != NULL;
frame = cairo_surface_get_user_data(frame, &fiv_io_key_frame_next))
fiv_io_premultiply_argb32(frame);
}
+#endif // ! HAVE_LCMS2 || LCMS_VERSION < 2130
+
// --- Wuffs -------------------------------------------------------------------
static bool
@@ -1831,10 +1864,8 @@ open_libwebp(
}
WebPDemuxDelete(demux);
- if (ctx->screen_profile) {
- fiv_io_profile_xrgb32_page(result, ctx->screen_profile);
- fiv_io_premultiply_argb32_page(result);
- }
+ if (ctx->screen_profile)
+ fiv_io_profile_argb32_premultiply_page(result, ctx->screen_profile);
fail:
WebPFreeDecBuffer(&config.output);
@@ -3102,12 +3133,10 @@ open_gdkpixbuf(
}
g_object_unref(pixbuf);
- if (custom_argb32) {
- fiv_io_profile_xrgb32_page(surface, ctx->screen_profile);
- fiv_io_premultiply_argb32_page(surface);
- } else {
+ if (custom_argb32)
+ fiv_io_profile_argb32_premultiply_page(surface, ctx->screen_profile);
+ else
surface = fiv_io_profile_finalize(surface, ctx->screen_profile);
- }
return surface;
}
diff --git a/fiv-io.h b/fiv-io.h
index 121f136..582b907 100644
--- a/fiv-io.h
+++ b/fiv-io.h
@@ -24,9 +24,7 @@
// --- Colour management -------------------------------------------------------
-// TODO(p): Make it possible to use Skia's skcms,
-// which also supports premultiplied alpha.
-// NOTE: Little CMS 2.13 already supports premultiplied alpha, too.
+// TODO(p): Make it also possible to use Skia's skcms.
typedef void *FivIoProfile;
FivIoProfile fiv_io_profile_new(const void *data, size_t len);
FivIoProfile fiv_io_profile_new_sRGB(void);