[gtk/heif-demo: 4/5] Add a quick-and-dirty heif loading test
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/heif-demo: 4/5] Add a quick-and-dirty heif loading test
- Date: Mon, 9 May 2022 15:39:09 +0000 (UTC)
commit 4115865e752872f38cd1ccdfba2de7a99952074b
Author: Matthias Clasen <mclasen redhat com>
Date: Sun May 8 00:23:35 2022 -0400
Add a quick-and-dirty heif loading test
This uses libheif to load an image and produce
a texture. If the image has more than 8 bits of
chroma or luma, the texture will be 16bit.
tests/meson.build | 9 +++
tests/testheif.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 196 insertions(+)
---
diff --git a/tests/meson.build b/tests/meson.build
index d837b5af6d..8f1ff34381 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -148,3 +148,12 @@ if libsysprof_dep.found()
dependencies: [libsysprof_dep, platform_gio_dep, libm],
)
endif
+
+libheif_dep = dependency('libheif')
+
+if libheif_dep.found()
+ executable('testheif',
+ sources: 'testheif.c',
+ dependencies: [libgtk_dep, libheif_dep],
+ )
+endif
diff --git a/tests/testheif.c b/tests/testheif.c
new file mode 100644
index 0000000000..14b6a395d7
--- /dev/null
+++ b/tests/testheif.c
@@ -0,0 +1,187 @@
+#include <gtk/gtk.h>
+#include <libheif/heif.h>
+
+static GdkTexture *
+load_heif_image (const char *filename,
+ GString *details,
+ GError **error)
+{
+ struct heif_context *ctx;
+ struct heif_error err;
+ struct heif_image_handle *handle = NULL;
+ struct heif_image *image = NULL;
+ enum heif_chroma chroma;
+ GdkMemoryFormat format;
+ const char *format_name;
+ uint8_t *data = NULL;
+ int width, height, bpp, stride, bits;
+ GBytes *bytes;
+ GdkTexture *texture = NULL;
+ GdkColorProfile *profile = NULL;
+ gsize icc_size;
+ guchar *icc_data;
+
+ ctx = heif_context_alloc ();
+
+ err = heif_context_read_from_file (ctx, filename, NULL);
+
+ if (err.code != heif_error_Ok)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, err.message);
+ goto out;
+ }
+
+ err = heif_context_get_primary_image_handle (ctx, &handle);
+ if (err.code != heif_error_Ok)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, err.message);
+ goto out;
+ }
+
+ icc_size = heif_image_handle_get_raw_color_profile_size (handle);
+ icc_data = g_new (guchar, icc_size);
+ err = heif_image_handle_get_raw_color_profile (handle, icc_data);
+ if (err.code == heif_error_Ok)
+ {
+ bytes = g_bytes_new (icc_data, icc_size);
+ profile = gdk_color_profile_new_from_icc_bytes (bytes, NULL);
+ g_bytes_unref (bytes);
+ }
+ g_free (icc_data);
+
+ g_string_append_printf (details, "%dāĆā%d pixels\n%d bits of luma, %d bits of chroma%s%s\n",
+ heif_image_handle_get_width (handle),
+ heif_image_handle_get_height (handle),
+ heif_image_handle_get_luma_bits_per_pixel (handle),
+ heif_image_handle_get_chroma_bits_per_pixel (handle),
+ heif_image_handle_has_alpha_channel (handle) ? ", with alpha" : "",
+ profile ? ", has ICC profile" : "");
+
+ if (profile == NULL)
+ profile = gdk_color_profile_get_srgb ();
+
+ if (heif_image_handle_has_alpha_channel (handle))
+ {
+ if (heif_image_handle_get_luma_bits_per_pixel (handle) > 8 ||
+ heif_image_handle_get_chroma_bits_per_pixel (handle) > 8)
+ {
+ chroma = heif_chroma_interleaved_RRGGBBAA_BE;
+ format = GDK_MEMORY_R16G16B16A16;
+ format_name = "R<sub>16</sub>G<sub>16</sub>B<sub>16</sub>A<sub>16</sub>";
+ }
+ else
+ {
+ chroma = heif_chroma_interleaved_RGBA;
+ format = GDK_MEMORY_R8G8B8A8;
+ format_name = "R<sub>8</sub>G<sub>8</sub>B<sub>8</sub>A<sub>8</sub>";
+ }
+ }
+ else
+ {
+ if (heif_image_handle_get_luma_bits_per_pixel (handle) > 8 ||
+ heif_image_handle_get_chroma_bits_per_pixel (handle) > 8)
+ {
+ chroma = heif_chroma_interleaved_RRGGBB_BE;
+ format = GDK_MEMORY_R16G16B16;
+ format_name = "R<sub>16</sub>G<sub>16</sub>B<sub>16</sub>";
+ }
+ else
+ {
+ chroma = heif_chroma_interleaved_RGB;
+ format = GDK_MEMORY_R8G8B8;
+ format_name = "R<sub>8</sub>G<sub>8</sub>B<sub>8</sub>";
+ }
+ }
+
+ err = heif_decode_image (handle, &image, heif_colorspace_RGB, chroma, NULL);
+ if (err.code != heif_error_Ok)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, err.message);
+ goto out;
+ }
+
+ width = heif_image_get_width (image, heif_channel_interleaved);
+ height = heif_image_get_height (image, heif_channel_interleaved);
+ bpp = heif_image_get_bits_per_pixel (image, heif_channel_interleaved);
+ data = (uint8_t*)heif_image_get_plane_readonly (image, heif_channel_interleaved, &stride);
+ bits = heif_image_get_bits_per_pixel_range (image, heif_channel_interleaved);
+
+ g_string_append_printf (details, "texture format %s", format_name);
+
+ if (format == GDK_MEMORY_R16G16B16A16 || format == GDK_MEMORY_R16G16B16)
+ {
+ /* Shift image data to full 16bit range */
+ int shift = 16 - bits;
+ if (shift > 0)
+ {
+ for (int y = 0; y < height; ++y)
+ {
+ uint8_t *row = data + y * stride;
+
+ for (int x = 0; x < stride; x += 2)
+ {
+ uint8_t* p = &row[x];
+ int v = (p[0] << 8) | p[1];
+ v = (v << shift) | (v >> (16 - shift));
+ p[1] = (uint8_t) (v >> 8);
+ p[0] = (uint8_t) (v & 0xFF);
+ }
+ }
+ }
+ }
+
+ bytes = g_bytes_new_with_free_func (data, height * stride * bpp, (GDestroyNotify)heif_image_release,
image);
+
+ image = NULL;
+
+ texture = gdk_memory_texture_new_with_color_profile (width, height,
+ format, profile,
+ bytes, stride);
+ g_bytes_unref (bytes);
+
+out:
+ heif_context_free (ctx);
+ if (handle)
+ heif_image_handle_release (handle);
+ if (image)
+ heif_image_release (image);
+
+ return texture;
+}
+
+int main (int argc, char *argv[])
+{
+ GdkTexture *texture;
+ GError *error = NULL;
+ GtkWidget *window, *picture, *box, *label;
+ GString *details;
+
+ gtk_init ();
+
+ details = g_string_new ("");
+
+ texture = load_heif_image (argv[1], details, &error);
+ if (!texture)
+ g_error ("%s", error->message);
+
+ window = gtk_window_new ();
+
+ gtk_window_set_title (GTK_WINDOW (window), argv[1]);
+ gtk_window_set_default_size (GTK_WINDOW (window), 1024, 768);
+
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
+ picture = gtk_picture_new_for_paintable (GDK_PAINTABLE (texture));
+ gtk_box_append (GTK_BOX (box), picture);
+ label = gtk_label_new (details->str);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_widget_set_margin_bottom (label, 10);
+ gtk_box_append (GTK_BOX (box), label);
+ gtk_window_set_child (GTK_WINDOW (window), box);
+
+ g_string_free (details, TRUE);
+
+ gtk_window_present (GTK_WINDOW (window));
+
+ while (1)
+ g_main_context_iteration (NULL, TRUE);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]