Compare commits
2 Commits
f151fcb72b
...
bafad1a67e
Author | SHA1 | Date | |
---|---|---|---|
bafad1a67e | |||
a5f64b1a65 |
62
fastiv-io.c
62
fastiv-io.c
@ -983,6 +983,8 @@ open_xcursor(const gchar *data, gsize len, GError **error)
|
||||
static cairo_surface_t *
|
||||
open_gdkpixbuf(const gchar *data, gsize len, GError **error)
|
||||
{
|
||||
// gdk-pixbuf controls the playback itself, there is no reliable method of
|
||||
// extracting individual frames (due to loops).
|
||||
GInputStream *is = g_memory_input_stream_new_from_data(data, len, NULL);
|
||||
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream(is, NULL, error);
|
||||
g_object_unref(is);
|
||||
@ -991,6 +993,20 @@ open_gdkpixbuf(const gchar *data, gsize len, GError **error)
|
||||
|
||||
cairo_surface_t *surface =
|
||||
gdk_cairo_surface_create_from_pixbuf(pixbuf, 1, NULL);
|
||||
|
||||
// TODO(p): Also pass the pre-decoded Exif "orientation" option,
|
||||
// which is an ASCII digit from 1 to 8.
|
||||
const char *icc_profile = gdk_pixbuf_get_option(pixbuf, "icc-profile");
|
||||
if (icc_profile) {
|
||||
gsize out_len = 0;
|
||||
guchar *raw = g_base64_decode(icc_profile, &out_len);
|
||||
if (raw) {
|
||||
cairo_surface_set_user_data(surface, &fastiv_io_key_icc,
|
||||
g_bytes_new_take(raw, out_len),
|
||||
(cairo_destroy_func_t) g_bytes_unref);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref(pixbuf);
|
||||
return surface;
|
||||
}
|
||||
@ -1107,6 +1123,52 @@ fastiv_io_open_from_data(const char *data, size_t len, const gchar *path,
|
||||
return surface;
|
||||
}
|
||||
|
||||
// --- Metadata ----------------------------------------------------------------
|
||||
|
||||
FastivIoOrientation
|
||||
fastiv_io_exif_orientation(const guint8 *tiff, gsize len)
|
||||
{
|
||||
// libtiff also knows how to do this, but it's not a lot of code.
|
||||
// The "Orientation" tag/field is part of Baseline TIFF 6.0 (1992),
|
||||
// it just so happens that Exif is derived from this format.
|
||||
// There is no other meaningful placement for this than right in IFD0,
|
||||
// describing the main image.
|
||||
const uint8_t *end = tiff + len,
|
||||
le[4] = {'I', 'I', 42, 0},
|
||||
be[4] = {'M', 'M', 0, 42};
|
||||
|
||||
uint16_t (*u16)(const uint8_t *) = NULL;
|
||||
uint32_t (*u32)(const uint8_t *) = NULL;
|
||||
if (tiff + 8 > end) {
|
||||
return FastivIoOrientationUnknown;
|
||||
} else if (!memcmp(tiff, le, sizeof le)) {
|
||||
u16 = wuffs_base__peek_u16le__no_bounds_check;
|
||||
u32 = wuffs_base__peek_u32le__no_bounds_check;
|
||||
} else if (!memcmp(tiff, be, sizeof be)) {
|
||||
u16 = wuffs_base__peek_u16be__no_bounds_check;
|
||||
u32 = wuffs_base__peek_u32be__no_bounds_check;
|
||||
} else {
|
||||
return FastivIoOrientationUnknown;
|
||||
}
|
||||
|
||||
const uint8_t *ifd0 = tiff + u32(tiff + 4);
|
||||
if (ifd0 + 2 > end)
|
||||
return FastivIoOrientationUnknown;
|
||||
|
||||
uint16_t fields = u16(ifd0);
|
||||
enum { BYTE = 1, ASCII, SHORT, LONG, RATIONAL,
|
||||
SBYTE, UNDEFINED, SSHORT, SLONG, SRATIONAL, FLOAT, DOUBLE };
|
||||
enum { Orientation = 274 };
|
||||
for (const guint8 *p = ifd0 + 2; fields-- && p + 12 <= end; p += 12) {
|
||||
uint16_t tag = u16(p), type = u16(p + 2);
|
||||
uint32_t count = u32(p + 4), value = u32(p + 8);
|
||||
if (tag == Orientation && type == SHORT && count == 1 &&
|
||||
value >= 1 && value <= 8)
|
||||
return value;
|
||||
}
|
||||
return FastivIoOrientationUnknown;
|
||||
}
|
||||
|
||||
// --- Thumbnails --------------------------------------------------------------
|
||||
|
||||
GType
|
||||
|
19
fastiv-io.h
19
fastiv-io.h
@ -37,7 +37,7 @@ extern cairo_user_data_key_t fastiv_io_key_icc;
|
||||
extern cairo_user_data_key_t fastiv_io_key_frame_next;
|
||||
/// Frame duration in milliseconds as an intptr_t.
|
||||
extern cairo_user_data_key_t fastiv_io_key_frame_duration;
|
||||
/// How many times to repeat the animation, or zero for +inf, as an uintptr_t.
|
||||
/// How many times to repeat the animation, or zero for +inf, as a uintptr_t.
|
||||
extern cairo_user_data_key_t fastiv_io_key_loops;
|
||||
|
||||
cairo_surface_t *fastiv_io_open(const gchar *path, GError **error);
|
||||
@ -46,6 +46,23 @@ cairo_surface_t *fastiv_io_open_from_data(
|
||||
|
||||
int fastiv_io_filecmp(GFile *f1, GFile *f2);
|
||||
|
||||
// --- Metadata ----------------------------------------------------------------
|
||||
|
||||
// https://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf Table 6
|
||||
typedef enum _FastivIoOrientation {
|
||||
FastivIoOrientationUnknown = 0,
|
||||
FastivIoOrientation0 = 1,
|
||||
FastivIoOrientationMirror0 = 2,
|
||||
FastivIoOrientation180 = 3,
|
||||
FastivIoOrientationMirror180 = 4,
|
||||
FastivIoOrientationMirror90 = 5,
|
||||
FastivIoOrientation90 = 6,
|
||||
FastivIoOrientationMirror270 = 7,
|
||||
FastivIoOrientation270 = 8
|
||||
} FastivIoOrientation;
|
||||
|
||||
FastivIoOrientation fastiv_io_exif_orientation(const guint8 *exif, gsize len);
|
||||
|
||||
// --- Thumbnails --------------------------------------------------------------
|
||||
|
||||
// And this is how you avoid glib-mkenums.
|
||||
|
Loading…
x
Reference in New Issue
Block a user