aboutsummaryrefslogtreecommitdiff
path: root/fiv-io.h
diff options
context:
space:
mode:
Diffstat (limited to 'fiv-io.h')
-rw-r--r--fiv-io.h273
1 files changed, 156 insertions, 117 deletions
diff --git a/fiv-io.h b/fiv-io.h
index 9cbe5d8..a3b482c 100644
--- a/fiv-io.h
+++ b/fiv-io.h
@@ -1,7 +1,7 @@
//
// fiv-io.h: image operations
//
-// Copyright (c) 2021 - 2022, Přemysl Eric Janouch <p@janouch.name>
+// Copyright (c) 2021 - 2024, Přemysl Eric Janouch <p@janouch.name>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted.
@@ -22,18 +22,53 @@
#include <glib.h>
#include <webp/encode.h> // WebPConfig
+typedef enum _FivIoOrientation FivIoOrientation;
+typedef struct _FivIoRenderClosure FivIoRenderClosure;
+typedef struct _FivIoImage FivIoImage;
+typedef struct _FivIoProfile FivIoProfile;
+
// --- Colour management -------------------------------------------------------
+// Note that without a CMM, all FivIoCmm and FivIoProfile will be returned NULL.
+
+GBytes *fiv_io_profile_to_bytes(FivIoProfile *profile);
+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, IO_CMM, GObject)
+
+FivIoCmm *fiv_io_cmm_get_default(void);
-// 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.
-typedef void *FivIoProfile;
-FivIoProfile fiv_io_profile_new(const void *data, size_t len);
-FivIoProfile fiv_io_profile_new_sRGB(void);
-void fiv_io_profile_free(FivIoProfile self);
+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]);
-// From libwebp, verified to exactly match [x * a / 255].
-#define PREMULTIPLY8(a, x) (((uint32_t) (x) * (uint32_t) (a) * 32897U) >> 23)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+void fiv_io_premultiply_argb32(FivIoImage *image);
+
+void fiv_io_cmm_cmyk(FivIoCmm *self,
+ FivIoImage *image, FivIoProfile *source, FivIoProfile *target);
+void fiv_io_cmm_4x16le_direct(FivIoCmm *self, unsigned char *data,
+ int w, int h, FivIoProfile *source, FivIoProfile *target);
+
+void fiv_io_cmm_argb32_premultiply(FivIoCmm *self,
+ FivIoImage *image, FivIoProfile *source, FivIoProfile *target);
+#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_cmm_page(FivIoCmm *self, FivIoImage *page, FivIoProfile *target,
+ void (*frame_cb) (FivIoCmm *,
+ FivIoImage *, FivIoProfile *, FivIoProfile *));
+void fiv_io_cmm_any(FivIoCmm *self,
+ FivIoImage *image, FivIoProfile *source, FivIoProfile *target);
+FivIoImage *fiv_io_cmm_finish(FivIoCmm *self,
+ FivIoImage *image, FivIoProfile *target);
// --- Loading -----------------------------------------------------------------
@@ -41,135 +76,118 @@ extern const char *fiv_io_supported_media_types[];
gchar **fiv_io_all_supported_media_types(void);
-// Userdata are typically attached to all Cairo surfaces in an animation.
-
-/// GBytes with plain Exif/TIFF data.
-extern cairo_user_data_key_t fiv_io_key_exif;
-/// FivIoOrientation, as a uintptr_t.
-extern cairo_user_data_key_t fiv_io_key_orientation;
-/// GBytes with plain ICC profile data.
-extern cairo_user_data_key_t fiv_io_key_icc;
-/// GBytes with plain XMP data.
-extern cairo_user_data_key_t fiv_io_key_xmp;
-/// GBytes with a WebP's THUM chunk, used for our thumbnails.
-extern cairo_user_data_key_t fiv_io_key_thum;
-/// GHashTable with key-value pairs from PNG's tEXt, zTXt, iTXt chunks.
-/// Currently only read by fiv_io_open_png_thumbnail().
-extern cairo_user_data_key_t fiv_io_key_text;
-
-/// The next frame in a sequence, as a surface, in a chain, pre-composited.
-/// There is no wrap-around.
-extern cairo_user_data_key_t fiv_io_key_frame_next;
-/// The previous frame in a sequence, as a surface, in a chain, pre-composited.
-/// This is a weak pointer that wraps around, and needn't be present
-/// for static images.
-extern cairo_user_data_key_t fiv_io_key_frame_previous;
-/// Frame duration in milliseconds as an intptr_t.
-extern cairo_user_data_key_t fiv_io_key_frame_duration;
-/// How many times to repeat the animation, or zero for +inf, as a uintptr_t.
-extern cairo_user_data_key_t fiv_io_key_loops;
-
-/// The first frame of the next page, as a surface, in a chain.
-/// There is no wrap-around.
-extern cairo_user_data_key_t fiv_io_key_page_next;
-/// The first frame of the previous page, as a surface, in a chain.
-/// There is no wrap-around. This is a weak pointer.
-extern cairo_user_data_key_t fiv_io_key_page_previous;
-
-typedef struct _FivIoRenderClosure {
+// https://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf Table 6
+enum _FivIoOrientation {
+ FivIoOrientationUnknown = 0,
+ FivIoOrientation0 = 1,
+ FivIoOrientationMirror0 = 2,
+ FivIoOrientation180 = 3,
+ FivIoOrientationMirror180 = 4,
+ FivIoOrientationMirror270 = 5,
+ FivIoOrientation90 = 6,
+ FivIoOrientationMirror90 = 7,
+ FivIoOrientation270 = 8
+};
+
+// TODO(p): Maybe make FivIoProfile a referencable type,
+// then loaders could store it in their closures.
+struct _FivIoRenderClosure {
/// The rendering is allowed to fail, returning NULL.
- cairo_surface_t *(*render)(struct _FivIoRenderClosure *, double scale);
-} FivIoRenderClosure;
+ FivIoImage *(*render)(
+ FivIoRenderClosure *, FivIoCmm *, FivIoProfile *, double scale);
+ void (*destroy)(FivIoRenderClosure *);
+};
-/// A FivIoRenderClosure for parametrized re-rendering of vector formats.
-/// This is attached at the page level.
-/// The rendered image will not have this key.
-extern cairo_user_data_key_t fiv_io_key_render;
+// Metadata are typically attached to all Cairo surfaces in an animation.
-typedef struct {
- const char *uri; ///< Source URI
- FivIoProfile screen_profile; ///< Target colour space or NULL
- int screen_dpi; ///< Target DPI
- gboolean enhance; ///< Enhance JPEG (currently)
- gboolean first_frame_only; ///< Only interested in the 1st frame
- GPtrArray *warnings; ///< String vector for non-fatal errors
-} FivIoOpenContext;
+struct _FivIoImage {
+ uint8_t *data; ///< Raw image data
+ cairo_format_t format; ///< Data format
+ uint32_t width; ///< Width of the image in pixels
+ uint32_t stride; ///< Row stride in bytes
+ uint32_t height; ///< Height of the image in pixels
-cairo_surface_t *fiv_io_open(const FivIoOpenContext *ctx, GError **error);
-cairo_surface_t *fiv_io_open_from_data(
- const char *data, size_t len, const FivIoOpenContext *ctx, GError **error);
-cairo_surface_t *fiv_io_open_png_thumbnail(const char *path, GError **error);
+ FivIoOrientation orientation; ///< Orientation to use for display
-// --- Thumbnail passing utilities ---------------------------------------------
+ GBytes *exif; ///< Raw Exif/TIFF segment
+ GBytes *icc; ///< Raw ICC profile data
+ GBytes *xmp; ///< Raw XMP data
+ GBytes *thum; ///< WebP THUM chunk, for our thumbnails
-enum { FIV_IO_SERIALIZE_LOW_QUALITY = 1 << 0 };
+ /// GHashTable with key-value pairs from PNG's tEXt, zTXt, iTXt chunks.
+ /// Currently only read by fiv_io_open_png_thumbnail().
+ GHashTable *text;
-void fiv_io_serialize_to_stdout(cairo_surface_t *surface, guint64 user_data);
-cairo_surface_t *fiv_io_deserialize(GBytes *bytes, guint64 *user_data);
+ /// A FivIoRenderClosure for parametrized re-rendering of vector formats.
+ /// This is attached at the page level.
+ FivIoRenderClosure *render;
-// --- Filesystem --------------------------------------------------------------
+ /// The first frame of the next page, in a chain.
+ /// There is no wrap-around.
+ FivIoImage *page_next;
-typedef enum _FivIoModelSort {
- FIV_IO_MODEL_SORT_NAME,
- FIV_IO_MODEL_SORT_MTIME,
- FIV_IO_MODEL_SORT_COUNT,
+ /// The first frame of the previous page, in a chain.
+ /// There is no wrap-around. This is a weak pointer.
+ FivIoImage *page_previous;
- FIV_IO_MODEL_SORT_MIN = 0,
- FIV_IO_MODEL_SORT_MAX = FIV_IO_MODEL_SORT_COUNT - 1
-} FivIoModelSort;
+ /// The next frame in a sequence, in a chain, pre-composited.
+ /// There is no wrap-around.
+ FivIoImage *frame_next;
-#define FIV_TYPE_IO_MODEL (fiv_io_model_get_type())
-G_DECLARE_FINAL_TYPE(FivIoModel, fiv_io_model, FIV, IO_MODEL, GObject)
+ /// The previous frame in a sequence, in a chain, pre-composited.
+ /// This is a weak pointer that wraps around,
+ /// and needn't be present for static images.
+ FivIoImage *frame_previous;
-/// Loads a directory. Clears itself even on failure.
-gboolean fiv_io_model_open(FivIoModel *self, GFile *directory, GError **error);
+ /// Frame duration in milliseconds.
+ int64_t frame_duration;
-/// Returns the current location as a GFile.
-/// There is no ownership transfer, and the object may be NULL.
-GFile *fiv_io_model_get_location(FivIoModel *self);
+ /// How many times to repeat the animation, or zero for +inf.
+ uint64_t loops;
+};
-typedef struct {
- gchar *uri; ///< GIO URI
- gchar *target_uri; ///< GIO URI for any target
- gchar *collate_key; ///< Collate key for the filename
- gint64 mtime_msec; ///< Modification time in milliseconds
-} FivIoModelEntry;
+FivIoImage *fiv_io_image_ref(FivIoImage *image);
+void fiv_io_image_unref(FivIoImage *image);
-const FivIoModelEntry *fiv_io_model_get_files(FivIoModel *self, gsize *len);
-const FivIoModelEntry *fiv_io_model_get_subdirs(FivIoModel *self, gsize *len);
+/// Analogous to cairo_image_surface_create(). May return NULL.
+FivIoImage *fiv_io_image_new(
+ cairo_format_t format, uint32_t width, uint32_t height);
-// --- Export ------------------------------------------------------------------
+/// Return a new Cairo image surface referencing the same data as the image,
+/// eating the reference to it.
+cairo_surface_t *fiv_io_image_to_surface(FivIoImage *image);
-/// Encodes a Cairo surface as a WebP bitstream, following the configuration.
-/// The result needs to be freed using WebPFree/WebPDataClear().
-unsigned char *fiv_io_encode_webp(
- cairo_surface_t *surface, const WebPConfig *config, size_t *len);
+/// Return a new Cairo image surface referencing the same data as the image,
+/// without eating the image's reference.
+cairo_surface_t *fiv_io_image_to_surface_noref(const FivIoImage *image);
-/// Saves the page as a lossless WebP still picture or animation.
-/// If no exact frame is specified, this potentially creates an animation.
-gboolean fiv_io_save(cairo_surface_t *page, cairo_surface_t *frame,
- FivIoProfile target, const char *path, GError **error);
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// --- Metadata ----------------------------------------------------------------
+typedef struct {
+ const char *uri; ///< Source URI
+ FivIoCmm *cmm; ///< Colour management module or NULL
+ FivIoProfile *screen_profile; ///< Target colour space or NULL
+ int screen_dpi; ///< Target DPI
+ gboolean enhance; ///< Enhance JPEG (currently)
+ gboolean first_frame_only; ///< Only interested in the 1st frame
+ GPtrArray *warnings; ///< String vector for non-fatal errors
+} FivIoOpenContext;
-// https://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf Table 6
-typedef enum _FivIoOrientation {
- FivIoOrientationUnknown = 0,
- FivIoOrientation0 = 1,
- FivIoOrientationMirror0 = 2,
- FivIoOrientation180 = 3,
- FivIoOrientationMirror180 = 4,
- FivIoOrientationMirror270 = 5,
- FivIoOrientation90 = 6,
- FivIoOrientationMirror90 = 7,
- FivIoOrientation270 = 8
-} FivIoOrientation;
+FivIoImage *fiv_io_open(const FivIoOpenContext *ctx, GError **error);
+FivIoImage *fiv_io_open_from_data(
+ const char *data, size_t len, const FivIoOpenContext *ctx, GError **error);
-/// Returns a rendering matrix for a surface (user space to pattern space),
+FivIoImage *fiv_io_open_png_thumbnail(const char *path, GError **error);
+
+// --- Metadata ----------------------------------------------------------------
+
+/// Returns a rendering matrix for an image (user space to pattern space),
/// and its target dimensions.
-cairo_matrix_t fiv_io_orientation_apply(cairo_surface_t *surface,
+cairo_matrix_t fiv_io_orientation_apply(const FivIoImage *image,
FivIoOrientation orientation, double *width, double *height);
-void fiv_io_orientation_dimensions(cairo_surface_t *surface,
+cairo_matrix_t fiv_io_orientation_matrix(
+ FivIoOrientation orientation, double width, double height);
+void fiv_io_orientation_dimensions(const FivIoImage *image,
FivIoOrientation orientation, double *width, double *height);
/// Extracts the orientation field from Exif, if there's any.
@@ -177,4 +195,25 @@ FivIoOrientation fiv_io_exif_orientation(const guint8 *exif, gsize len);
/// Save metadata attached by this module in Exiv2 format.
gboolean fiv_io_save_metadata(
- cairo_surface_t *page, const char *path, GError **error);
+ const FivIoImage *page, const char *path, GError **error);
+
+// --- Thumbnail passing utilities ---------------------------------------------
+
+enum { FIV_IO_SERIALIZE_LOW_QUALITY = 1 << 0 };
+
+void fiv_io_serialize_to_stdout(cairo_surface_t *surface, guint64 user_data);
+cairo_surface_t *fiv_io_deserialize(GBytes *bytes, guint64 *user_data);
+
+GBytes *fiv_io_serialize_for_search(cairo_surface_t *surface, GError **error);
+
+// --- Export ------------------------------------------------------------------
+
+/// Encodes an image as a WebP bitstream, following the configuration.
+/// The result needs to be freed using WebPFree/WebPDataClear().
+unsigned char *fiv_io_encode_webp(
+ FivIoImage *image, const WebPConfig *config, size_t *len);
+
+/// Saves the page as a lossless WebP still picture or animation.
+/// If no exact frame is specified, this potentially creates an animation.
+gboolean fiv_io_save(FivIoImage *page, FivIoImage *frame,
+ FivIoProfile *target, const char *path, GError **error);