diff options
Diffstat (limited to 'fiv-io.h')
-rw-r--r-- | fiv-io.h | 273 |
1 files changed, 156 insertions, 117 deletions
@@ -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); |