Compare commits
	
		
			2 Commits
		
	
	
		
			7e92011ab2
			...
			1bd5cb02e7
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						1bd5cb02e7
	
				 | 
					
					
						|||
| 
						
						
							
						
						1cbd0141a1
	
				 | 
					
					
						
							
								
								
									
										128
									
								
								fastiv-io.c
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								fastiv-io.c
									
									
									
									
									
								
							@@ -131,6 +131,26 @@ set_error(GError **error, const char *message)
 | 
				
			|||||||
	g_set_error_literal(error, FASTIV_IO_ERROR, FASTIV_IO_ERROR_OPEN, 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
 | 
					static bool
 | 
				
			||||||
@@ -1089,15 +1109,8 @@ open_xcursor(const gchar *data, gsize len, GError **error)
 | 
				
			|||||||
#ifdef HAVE_LIBHEIF  //---------------------------------------------------------
 | 
					#ifdef HAVE_LIBHEIF  //---------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static cairo_surface_t *
 | 
					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;
 | 
						cairo_surface_t *surface = NULL;
 | 
				
			||||||
	int has_alpha = heif_image_handle_has_alpha_channel(handle);
 | 
						int has_alpha = heif_image_handle_has_alpha_channel(handle);
 | 
				
			||||||
	int bit_depth = heif_image_handle_get_luma_bits_per_pixel(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.
 | 
						// TODO(p): We can get 16-bit depth, in reality most likely 10-bit.
 | 
				
			||||||
	struct heif_image *image = NULL;
 | 
						struct heif_image *image = NULL;
 | 
				
			||||||
	err = heif_decode_image(handle, &image, heif_colorspace_RGB,
 | 
						struct heif_error err = heif_decode_image(handle, &image,
 | 
				
			||||||
		heif_chroma_interleaved_RGBA, opts);
 | 
							heif_colorspace_RGB, heif_chroma_interleaved_RGBA, opts);
 | 
				
			||||||
	if (err.code != heif_error_Ok) {
 | 
						if (err.code != heif_error_Ok) {
 | 
				
			||||||
		set_error(error, err.message);
 | 
							set_error(error, err.message);
 | 
				
			||||||
		goto fail_decode;
 | 
							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 w = heif_image_get_width(image, heif_channel_interleaved);
 | 
				
			||||||
	int h = heif_image_get_height(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(
 | 
						surface = cairo_image_surface_create(
 | 
				
			||||||
		has_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, w, h);
 | 
							has_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, w, h);
 | 
				
			||||||
	cairo_status_t surface_status = cairo_surface_status(surface);
 | 
						cairo_status_t surface_status = cairo_surface_status(surface);
 | 
				
			||||||
@@ -1202,12 +1214,43 @@ fail_process:
 | 
				
			|||||||
fail_decode:
 | 
					fail_decode:
 | 
				
			||||||
	heif_decoding_options_free(opts);
 | 
						heif_decoding_options_free(opts);
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
	heif_image_handle_release(handle);
 | 
					 | 
				
			||||||
	return surface;
 | 
						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 *
 | 
					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.
 | 
						// libheif will throw C++ exceptions on allocation failures.
 | 
				
			||||||
	// The library is generally awful through and through.
 | 
						// The library is generally awful through and through.
 | 
				
			||||||
@@ -1221,35 +1264,33 @@ open_libheif(const gchar *data, gsize len, GError **error)
 | 
				
			|||||||
		goto fail_read;
 | 
							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);
 | 
						int n = heif_context_get_number_of_top_level_images(ctx);
 | 
				
			||||||
	heif_item_id *ids = g_malloc0_n(n, sizeof *ids);
 | 
						heif_item_id *ids = g_malloc0_n(n, sizeof *ids);
 | 
				
			||||||
	n = heif_context_get_list_of_top_level_image_IDs(ctx, ids, n);
 | 
						n = heif_context_get_list_of_top_level_image_IDs(ctx, ids, n);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (int i = 0; i < n; i++) {
 | 
						for (int i = 0; i < n; i++) {
 | 
				
			||||||
		cairo_surface_t *surface = load_libheif_image(ctx, ids[i], error);
 | 
							struct heif_image_handle *handle = NULL;
 | 
				
			||||||
		if (!surface) {
 | 
							err = heif_context_get_image_handle(ctx, ids[i], &handle);
 | 
				
			||||||
			if (result) {
 | 
							if (err.code != heif_error_Ok) {
 | 
				
			||||||
				cairo_surface_destroy(result);
 | 
								g_warning("%s: %s", path, err.message);
 | 
				
			||||||
				result = NULL;
 | 
								continue;
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			goto fail_decode;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (result) {
 | 
							GError *e = NULL;
 | 
				
			||||||
			cairo_surface_set_user_data(result_tail,
 | 
							if (!try_append_page(
 | 
				
			||||||
				&fastiv_io_key_page_next, surface,
 | 
									load_libheif_image(handle, &e), &result, &result_tail)) {
 | 
				
			||||||
				(cairo_destroy_func_t) cairo_surface_destroy);
 | 
								g_warning("%s: %s", path, e->message);
 | 
				
			||||||
			cairo_surface_set_user_data(surface,
 | 
								g_error_free(e);
 | 
				
			||||||
				&fastiv_io_key_page_previous, result_tail, NULL);
 | 
							}
 | 
				
			||||||
			result_tail = surface;
 | 
					
 | 
				
			||||||
		} else {
 | 
							// TODO(p): Possibly add thumbnail images as well.
 | 
				
			||||||
			result = result_tail = surface;
 | 
							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);
 | 
						g_free(ids);
 | 
				
			||||||
fail_read:
 | 
					fail_read:
 | 
				
			||||||
	heif_context_free(ctx);
 | 
						heif_context_free(ctx);
 | 
				
			||||||
@@ -1454,24 +1495,11 @@ open_libtiff(const gchar *data, gsize len, const gchar *path, GError **error)
 | 
				
			|||||||
	do {
 | 
						do {
 | 
				
			||||||
		// We inform about unsupported directories, but do not fail on them.
 | 
							// We inform about unsupported directories, but do not fail on them.
 | 
				
			||||||
		GError *err = NULL;
 | 
							GError *err = NULL;
 | 
				
			||||||
		cairo_surface_t *surface = load_libtiff_directory(tiff, &err);
 | 
							if (!try_append_page(
 | 
				
			||||||
		if (err) {
 | 
								load_libtiff_directory(tiff, &err), &result, &result_tail)) {
 | 
				
			||||||
			g_warning("%s: %s", path, err->message);
 | 
								g_warning("%s: %s", path, err->message);
 | 
				
			||||||
			g_error_free(err);
 | 
								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));
 | 
						} while (TIFFReadDirectory(tiff));
 | 
				
			||||||
	TIFFClose(tiff);
 | 
						TIFFClose(tiff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1632,7 +1660,7 @@ fastiv_io_open_from_data(const char *data, size_t len, const gchar *path,
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
#endif  // HAVE_XCURSOR --------------------------------------------------------
 | 
					#endif  // HAVE_XCURSOR --------------------------------------------------------
 | 
				
			||||||
#ifdef HAVE_LIBHEIF  //---------------------------------------------------------
 | 
					#ifdef HAVE_LIBHEIF  //---------------------------------------------------------
 | 
				
			||||||
		if ((surface = open_libheif(data, len, error)))
 | 
							if ((surface = open_libheif(data, len, path, error)))
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		if (error) {
 | 
							if (error) {
 | 
				
			||||||
			g_debug("%s", (*error)->message);
 | 
								g_debug("%s", (*error)->message);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user