Stop abusing Cairo user data, part 1
This commit temporarily breaks multi-page images and animations.
This commit is contained in:
parent
c2e8b65d0f
commit
add96b37a6
226
fiv-io.h
226
fiv-io.h
@ -33,92 +33,6 @@ void fiv_io_profile_free(FivIoProfile self);
|
|||||||
// From libwebp, verified to exactly match [x * a / 255].
|
// From libwebp, verified to exactly match [x * a / 255].
|
||||||
#define PREMULTIPLY8(a, x) (((uint32_t) (x) * (uint32_t) (a) * 32897U) >> 23)
|
#define PREMULTIPLY8(a, x) (((uint32_t) (x) * (uint32_t) (a) * 32897U) >> 23)
|
||||||
|
|
||||||
// --- Loading -----------------------------------------------------------------
|
|
||||||
|
|
||||||
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 {
|
|
||||||
/// The rendering is allowed to fail, returning NULL.
|
|
||||||
cairo_surface_t *(*render)(struct _FivIoRenderClosure *, double scale);
|
|
||||||
} 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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
// --- 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 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);
|
|
||||||
|
|
||||||
/// 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 ----------------------------------------------------------------
|
// --- Metadata ----------------------------------------------------------------
|
||||||
|
|
||||||
// https://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf Table 6
|
// https://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf Table 6
|
||||||
@ -147,3 +61,143 @@ FivIoOrientation fiv_io_exif_orientation(const guint8 *exif, gsize len);
|
|||||||
/// Save metadata attached by this module in Exiv2 format.
|
/// Save metadata attached by this module in Exiv2 format.
|
||||||
gboolean fiv_io_save_metadata(
|
gboolean fiv_io_save_metadata(
|
||||||
cairo_surface_t *page, const char *path, GError **error);
|
cairo_surface_t *page, const char *path, GError **error);
|
||||||
|
|
||||||
|
// --- Loading -----------------------------------------------------------------
|
||||||
|
|
||||||
|
extern const char *fiv_io_supported_media_types[];
|
||||||
|
|
||||||
|
gchar **fiv_io_all_supported_media_types(void);
|
||||||
|
|
||||||
|
typedef struct _FivIoRenderClosure {
|
||||||
|
/// The rendering is allowed to fail, returning NULL.
|
||||||
|
cairo_surface_t *(*render)(struct _FivIoRenderClosure *, double scale);
|
||||||
|
void (*destroy)(struct _FivIoRenderClosure *);
|
||||||
|
} FivIoRenderClosure;
|
||||||
|
|
||||||
|
typedef 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
|
||||||
|
|
||||||
|
FivIoOrientation orientation; ///< Orientation to use for display
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
/// A FivIoRenderClosure for parametrized re-rendering of vector formats.
|
||||||
|
/// This is attached at the page level.
|
||||||
|
FivIoRenderClosure *render;
|
||||||
|
|
||||||
|
/// The first frame of the next page, in a chain.
|
||||||
|
/// There is no wrap-around.
|
||||||
|
struct _FivIoImage *page_next;
|
||||||
|
|
||||||
|
/// The first frame of the previous page, in a chain.
|
||||||
|
/// There is no wrap-around. This is a weak pointer.
|
||||||
|
struct _FivIoImage *page_previous;
|
||||||
|
|
||||||
|
/// The next frame in a sequence, in a chain, pre-composited.
|
||||||
|
/// There is no wrap-around.
|
||||||
|
struct _FivIoImage *frame_next;
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
struct _FivIoImage *frame_previous;
|
||||||
|
|
||||||
|
/// Frame duration in milliseconds.
|
||||||
|
int64_t frame_duration;
|
||||||
|
|
||||||
|
/// How many times to repeat the animation, or zero for +inf.
|
||||||
|
uint64_t loops;
|
||||||
|
} FivIoImage;
|
||||||
|
|
||||||
|
FivIoImage *fiv_io_image_ref(FivIoImage *image);
|
||||||
|
void fiv_io_image_unref(FivIoImage *image);
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
cairo_surface_t *fiv_io_open_png_thumbnail(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 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);
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
@ -137,8 +137,8 @@ render(GFile *target, GBytes *data, gboolean *color_managed, GError **error)
|
|||||||
.warnings = g_ptr_array_new_with_free_func(g_free),
|
.warnings = g_ptr_array_new_with_free_func(g_free),
|
||||||
};
|
};
|
||||||
|
|
||||||
cairo_surface_t *surface = fiv_io_open_from_data(
|
cairo_surface_t *surface = fiv_io_image_to_surface(fiv_io_open_from_data(
|
||||||
g_bytes_get_data(data, NULL), g_bytes_get_size(data), &ctx, error);
|
g_bytes_get_data(data, NULL), g_bytes_get_size(data), &ctx, error));
|
||||||
g_free((gchar *) ctx.uri);
|
g_free((gchar *) ctx.uri);
|
||||||
g_ptr_array_free(ctx.warnings, TRUE);
|
g_ptr_array_free(ctx.warnings, TRUE);
|
||||||
if ((*color_managed = !!ctx.screen_profile))
|
if ((*color_managed = !!ctx.screen_profile))
|
||||||
@ -793,8 +793,8 @@ read_wide_thumbnail(const char *path, const Stat *st, GError **error)
|
|||||||
if (!thumbnail_uri)
|
if (!thumbnail_uri)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
cairo_surface_t *surface =
|
cairo_surface_t *surface = fiv_io_image_to_surface(
|
||||||
fiv_io_open(&(FivIoOpenContext){.uri = thumbnail_uri}, error);
|
fiv_io_open(&(FivIoOpenContext){.uri = thumbnail_uri}, error));
|
||||||
g_free(thumbnail_uri);
|
g_free(thumbnail_uri);
|
||||||
if (!surface)
|
if (!surface)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1374,7 +1374,8 @@ open_without_swapping_in(FivView *self, const char *uri)
|
|||||||
};
|
};
|
||||||
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
cairo_surface_t *surface = fiv_io_open(&ctx, &error);
|
cairo_surface_t *surface =
|
||||||
|
fiv_io_image_to_surface(fiv_io_open(&ctx, &error));
|
||||||
if (error) {
|
if (error) {
|
||||||
g_ptr_array_add(ctx.warnings, g_strdup(error->message));
|
g_ptr_array_add(ctx.warnings, g_strdup(error->message));
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
|
@ -41,14 +41,14 @@ one_file(const char *filename)
|
|||||||
.warnings = g_ptr_array_new_with_free_func(g_free),
|
.warnings = g_ptr_array_new_with_free_func(g_free),
|
||||||
};
|
};
|
||||||
|
|
||||||
cairo_surface_t *loaded_by_us = fiv_io_open(&ctx, NULL);
|
FivIoImage *loaded_by_us = fiv_io_open(&ctx, NULL);
|
||||||
g_clear_object(&file);
|
g_clear_object(&file);
|
||||||
g_free((char *) ctx.uri);
|
g_free((char *) ctx.uri);
|
||||||
g_ptr_array_free(ctx.warnings, TRUE);
|
g_ptr_array_free(ctx.warnings, TRUE);
|
||||||
if (!loaded_by_us)
|
if (!loaded_by_us)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cairo_surface_destroy(loaded_by_us);
|
fiv_io_image_unref(loaded_by_us);
|
||||||
us = timestamp() - since_us;
|
us = timestamp() - since_us;
|
||||||
|
|
||||||
double since_pixbuf = timestamp(), pixbuf = 0;
|
double since_pixbuf = timestamp(), pixbuf = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user