Compare commits

...

2 Commits

Author SHA1 Message Date
1bd5cb02e7
Extract HEIF auxiliary subimages 2021-12-11 17:09:39 +01:00
1cbd0141a1
Clean up 2021-12-11 17:09:39 +01:00

View File

@ -131,6 +131,26 @@ set_error(GError **error, const char *message)
g_set_error_literal(error, FASTIV_IO_ERROR, FASTIV_IO_ERROR_OPEN, message);
}
static bool
try_append_page(cairo_surface_t *surface, cairo_surface_t **result,
cairo_surface_t **result_tail)
{
if (!surface)
return false;
if (*result) {
cairo_surface_set_user_data(*result_tail,
&fastiv_io_key_page_next, surface,
(cairo_destroy_func_t) cairo_surface_destroy);
cairo_surface_set_user_data(surface,
&fastiv_io_key_page_previous, *result_tail, NULL);
*result_tail = surface;
} else {
*result = *result_tail = surface;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static bool
@ -1089,15 +1109,8 @@ open_xcursor(const gchar *data, gsize len, GError **error)
#ifdef HAVE_LIBHEIF //---------------------------------------------------------
static cairo_surface_t *
load_libheif_image(struct heif_context *ctx, heif_item_id id, GError **error)
load_libheif_image(struct heif_image_handle *handle, GError **error)
{
struct heif_image_handle *handle = NULL;
struct heif_error err = heif_context_get_image_handle(ctx, id, &handle);
if (err.code != heif_error_Ok) {
set_error(error, err.message);
return NULL;
}
cairo_surface_t *surface = NULL;
int has_alpha = heif_image_handle_has_alpha_channel(handle);
int bit_depth = heif_image_handle_get_luma_bits_per_pixel(handle);
@ -1111,8 +1124,8 @@ load_libheif_image(struct heif_context *ctx, heif_item_id id, GError **error)
// TODO(p): We can get 16-bit depth, in reality most likely 10-bit.
struct heif_image *image = NULL;
err = heif_decode_image(handle, &image, heif_colorspace_RGB,
heif_chroma_interleaved_RGBA, opts);
struct heif_error err = heif_decode_image(handle, &image,
heif_colorspace_RGB, heif_chroma_interleaved_RGBA, opts);
if (err.code != heif_error_Ok) {
set_error(error, err.message);
goto fail_decode;
@ -1121,7 +1134,6 @@ load_libheif_image(struct heif_context *ctx, heif_item_id id, GError **error)
int w = heif_image_get_width(image, heif_channel_interleaved);
int h = heif_image_get_height(image, heif_channel_interleaved);
// TODO(p): Add more pages with depth, thumbnails, and auxiliary images.
surface = cairo_image_surface_create(
has_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, w, h);
cairo_status_t surface_status = cairo_surface_status(surface);
@ -1202,12 +1214,43 @@ fail_process:
fail_decode:
heif_decoding_options_free(opts);
fail:
heif_image_handle_release(handle);
return surface;
}
static void
load_libheif_aux_images(const gchar *path, struct heif_image_handle *top,
cairo_surface_t **result, cairo_surface_t **result_tail)
{
// Include the depth image, we have no special processing for it now.
int filter = LIBHEIF_AUX_IMAGE_FILTER_OMIT_ALPHA;
int n = heif_image_handle_get_number_of_auxiliary_images(top, filter);
heif_item_id *ids = g_malloc0_n(n, sizeof *ids);
n = heif_image_handle_get_list_of_auxiliary_image_IDs(top, filter, ids, n);
for (int i = 0; i < n; i++) {
struct heif_image_handle *handle = NULL;
struct heif_error err = heif_image_handle_get_auxiliary_image_handle(
top, ids[i], &handle);
if (err.code != heif_error_Ok) {
g_warning("%s: %s", path, err.message);
continue;
}
GError *e = NULL;
if (!try_append_page(
load_libheif_image(handle, &e), result, result_tail)) {
g_warning("%s: %s", path, e->message);
g_error_free(e);
}
heif_image_handle_release(handle);
}
g_free(ids);
}
static cairo_surface_t *
open_libheif(const gchar *data, gsize len, GError **error)
open_libheif(const gchar *data, gsize len, const gchar *path, GError **error)
{
// libheif will throw C++ exceptions on allocation failures.
// The library is generally awful through and through.
@ -1221,35 +1264,33 @@ open_libheif(const gchar *data, gsize len, GError **error)
goto fail_read;
}
// TODO(p): Only fail if there is absolutely nothing to extract,
// see open_libtiff() below.
int n = heif_context_get_number_of_top_level_images(ctx);
heif_item_id *ids = g_malloc0_n(n, sizeof *ids);
n = heif_context_get_list_of_top_level_image_IDs(ctx, ids, n);
for (int i = 0; i < n; i++) {
cairo_surface_t *surface = load_libheif_image(ctx, ids[i], error);
if (!surface) {
if (result) {
cairo_surface_destroy(result);
result = NULL;
}
goto fail_decode;
struct heif_image_handle *handle = NULL;
err = heif_context_get_image_handle(ctx, ids[i], &handle);
if (err.code != heif_error_Ok) {
g_warning("%s: %s", path, err.message);
continue;
}
if (result) {
cairo_surface_set_user_data(result_tail,
&fastiv_io_key_page_next, surface,
(cairo_destroy_func_t) cairo_surface_destroy);
cairo_surface_set_user_data(surface,
&fastiv_io_key_page_previous, result_tail, NULL);
result_tail = surface;
} else {
result = result_tail = surface;
GError *e = NULL;
if (!try_append_page(
load_libheif_image(handle, &e), &result, &result_tail)) {
g_warning("%s: %s", path, e->message);
g_error_free(e);
}
// TODO(p): Possibly add thumbnail images as well.
load_libheif_aux_images(path, handle, &result, &result_tail);
heif_image_handle_release(handle);
}
if (!result) {
g_clear_pointer(&result, cairo_surface_destroy);
set_error(error, "empty or unsupported image");
}
fail_decode:
g_free(ids);
fail_read:
heif_context_free(ctx);
@ -1454,24 +1495,11 @@ open_libtiff(const gchar *data, gsize len, const gchar *path, GError **error)
do {
// We inform about unsupported directories, but do not fail on them.
GError *err = NULL;
cairo_surface_t *surface = load_libtiff_directory(tiff, &err);
if (err) {
if (!try_append_page(
load_libtiff_directory(tiff, &err), &result, &result_tail)) {
g_warning("%s: %s", path, err->message);
g_error_free(err);
}
if (!surface)
continue;
if (result) {
cairo_surface_set_user_data(result_tail,
&fastiv_io_key_page_next, surface,
(cairo_destroy_func_t) cairo_surface_destroy);
cairo_surface_set_user_data(surface,
&fastiv_io_key_page_previous, result_tail, NULL);
result_tail = surface;
} else {
result = result_tail = surface;
}
} while (TIFFReadDirectory(tiff));
TIFFClose(tiff);
@ -1632,7 +1660,7 @@ fastiv_io_open_from_data(const char *data, size_t len, const gchar *path,
}
#endif // HAVE_XCURSOR --------------------------------------------------------
#ifdef HAVE_LIBHEIF //---------------------------------------------------------
if ((surface = open_libheif(data, len, error)))
if ((surface = open_libheif(data, len, path, error)))
break;
if (error) {
g_debug("%s", (*error)->message);