aboutsummaryrefslogtreecommitdiff
path: root/fiv-io.h
blob: bb92033424e5797b3d13263a8cc81c5c6ee5b422 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
//
// fiv-io.h: image operations
//
// 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.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//

#pragma once

#include <cairo.h>
#include <gio/gio.h>
#include <glib.h>
#include <webp/encode.h>  // WebPConfig

typedef enum _FivIoOrientation FivIoOrientation;
typedef struct _FivIoRenderClosure FivIoRenderClosure;
typedef struct _FivIoImage FivIoImage;

// --- Colour management -------------------------------------------------------

void fiv_io_profile_init(void);

// 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_from_bytes(GBytes *bytes);
FivIoProfile *fiv_io_profile_new_sRGB(void);
FivIoProfile *fiv_io_profile_new_sRGB_gamma(double gamma);
FivIoProfile *fiv_io_profile_new_parametric(
    double gamma, double whitepoint[2], double primaries[6]);
GBytes *fiv_io_profile_to_bytes(FivIoProfile *profile);
void fiv_io_profile_free(FivIoProfile *self);

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

void fiv_io_premultiply_argb32(FivIoImage *image);

void fiv_io_profile_cmyk(
    FivIoImage *image, FivIoProfile *source, FivIoProfile *target);
void fiv_io_profile_4x16le_direct(unsigned char *data,
    int w, int h, FivIoProfile *source, FivIoProfile *target);
void fiv_io_profile_argb32_premultiply(
    FivIoImage *image, FivIoProfile *source, FivIoProfile *target);

void fiv_io_profile_page(FivIoImage *page, FivIoProfile *target,
	void (*frame_cb) (FivIoImage *, FivIoProfile *, FivIoProfile *));
#define fiv_io_profile_argb32_premultiply_page(page, target) \
	fiv_io_profile_page((page), (target), fiv_io_profile_argb32_premultiply)

void fiv_io_profile_any(
	FivIoImage *image, FivIoProfile *source, FivIoProfile *target);
FivIoImage *fiv_io_profile_finalize(FivIoImage *image, FivIoProfile *target);

// --- Loading -----------------------------------------------------------------

extern const char *fiv_io_supported_media_types[];

gchar **fiv_io_all_supported_media_types(void);

// 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.
	FivIoImage *(*render)(FivIoRenderClosure *, FivIoProfile *, double scale);
	void (*destroy)(FivIoRenderClosure *);
};

// Metadata are typically attached to all Cairo surfaces in an animation.

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

	/// GHashTable with key-value pairs from PNG's tEXt, zTXt, iTXt chunks.
	/// Currently only read by fiv_io_open_png_thumbnail().
	GHashTable *text;

	/// 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.
	FivIoImage *page_next;

	/// The first frame of the previous page, in a chain.
	/// There is no wrap-around. This is a weak pointer.
	FivIoImage *page_previous;

	/// The next frame in a sequence, in a chain, pre-composited.
	/// There is no wrap-around.
	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.
	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 *fiv_io_image_ref(FivIoImage *image);
void fiv_io_image_unref(FivIoImage *image);

/// Analogous to cairo_image_surface_create(). May return NULL.
FivIoImage *fiv_io_image_new(
	cairo_format_t format, uint32_t width, uint32_t height);

/// 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);

/// 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);

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

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);

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(const FivIoImage *image,
	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.
FivIoOrientation fiv_io_exif_orientation(const guint8 *exif, gsize len);

/// Save metadata attached by this module in Exiv2 format.
gboolean fiv_io_save_metadata(
	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);