summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2022-05-09 11:37:48 -0400
committerMatthias Clasen <mclasen@redhat.com>2022-05-11 15:01:09 -0400
commit0806fafbab43b7a08677aa2e4f7ded0dc013e3be (patch)
treedb6f8ac147a83e21a3960e36e670ca4a65b871c2
parentc58606d11607c6c2807fffa47f67fce6263a9b1e (diff)
downloadgtk+-heif-demo.tar.gz
widget-factory: Add an hdr image exampleheif-demo
This uses the heif loader to show an image in the 'color profile' notebook. The current image isn't a very good HDR example, and should be replaced by a more suitable image.
-rwxr-xr-xdemos/widget-factory/hdr-example.heifbin0 -> 5251955 bytes
-rw-r--r--demos/widget-factory/heif-loader.c257
-rw-r--r--demos/widget-factory/heif-loader.h7
-rw-r--r--demos/widget-factory/meson.build6
-rw-r--r--demos/widget-factory/widget-factory.c11
-rw-r--r--demos/widget-factory/widget-factory.gresource.xml1
-rw-r--r--demos/widget-factory/widget-factory.ui19
7 files changed, 297 insertions, 4 deletions
diff --git a/demos/widget-factory/hdr-example.heif b/demos/widget-factory/hdr-example.heif
new file mode 100755
index 0000000000..95152c8259
--- /dev/null
+++ b/demos/widget-factory/hdr-example.heif
Binary files differ
diff --git a/demos/widget-factory/heif-loader.c b/demos/widget-factory/heif-loader.c
new file mode 100644
index 0000000000..f17c3bc177
--- /dev/null
+++ b/demos/widget-factory/heif-loader.c
@@ -0,0 +1,257 @@
+#include "heif-loader.h"
+#include <gtk/gtk.h>
+#include <libheif/heif.h>
+
+static void
+describe_nclx_color_profile (const struct heif_color_profile_nclx *nclx,
+ GString *s)
+{
+ if (nclx->color_primaries == heif_color_primaries_unspecified)
+ return;
+
+ if (nclx->color_primaries == heif_color_primaries_ITU_R_BT_709_5)
+ {
+ if (nclx->transfer_characteristics == heif_transfer_characteristic_IEC_61966_2_1 &&
+ (nclx->matrix_coefficients == heif_matrix_coefficients_ITU_R_BT_470_6_System_B_G ||
+ nclx->matrix_coefficients == heif_matrix_coefficients_ITU_R_BT_601_6))
+ {
+ g_string_append (s, "sRGB");
+ return;
+ }
+
+ if (nclx->transfer_characteristics == heif_transfer_characteristic_linear &&
+ (nclx->matrix_coefficients == heif_matrix_coefficients_ITU_R_BT_470_6_System_B_G ||
+ nclx->matrix_coefficients == heif_matrix_coefficients_ITU_R_BT_601_6))
+ {
+ g_string_append (s, "sRGB linear");
+ return;
+ }
+ }
+
+ if (nclx->color_primaries == heif_color_primaries_ITU_R_BT_2020_2_and_2100_0)
+ {
+ if (nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_2100_0_PQ &&
+ nclx->matrix_coefficients == heif_matrix_coefficients_ITU_R_BT_2020_2_non_constant_luminance)
+ {
+ g_string_append (s, "BT.2020 PQ");
+ return;
+ }
+
+ if (nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_2100_0_HLG &&
+ nclx->matrix_coefficients == heif_matrix_coefficients_ITU_R_BT_2020_2_non_constant_luminance)
+ {
+ g_string_append (s, "BT.2020 HLG");
+ return;
+ }
+ }
+
+ if (nclx->color_primaries == heif_color_primaries_SMPTE_EG_432_1)
+ {
+ if (nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_2100_0_PQ)
+ {
+ g_string_append (s, "P3 PQ");
+ return;
+ }
+ }
+
+ g_string_append_printf (s, "%d/%d/%d",
+ nclx->color_primaries,
+ nclx->matrix_coefficients,
+ nclx->transfer_characteristics);
+}
+
+GdkTexture *
+load_heif_image (const char *resource_path,
+ 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;
+ gsize size;
+ int width, height, bpp, stride, bits;
+ GBytes *bytes;
+ GdkTexture *texture = NULL;
+ GdkColorProfile *profile = NULL;
+ char *profile_type = NULL;
+
+ ctx = heif_context_alloc ();
+
+ bytes = g_resources_lookup_data (resource_path, 0, NULL);
+ data = (uint8_t *) g_bytes_get_data (bytes, &size);
+
+ err = heif_context_read_from_memory (ctx, data, size, NULL);
+
+ g_bytes_unref (bytes);
+
+ 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;
+ }
+
+ switch (heif_image_handle_get_color_profile_type (handle))
+ {
+ case heif_color_profile_type_not_present:
+ break;
+ case heif_color_profile_type_rICC:
+ case heif_color_profile_type_prof:
+ {
+ guchar *icc_data;
+ gsize icc_size;
+
+ profile_type = g_strdup ("icc");
+ icc_size = heif_image_handle_get_raw_color_profile_size (handle);
+ icc_data = g_new0 (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);
+ }
+ break;
+ case heif_color_profile_type_nclx:
+ {
+ struct heif_color_profile_nclx *nclx = NULL;
+
+ err = heif_image_handle_get_nclx_color_profile (handle, &nclx);
+ if (err.code == heif_error_Ok)
+ {
+ GString *s;
+
+ s = g_string_new ("");
+ describe_nclx_color_profile (nclx, s);
+ profile_type = g_string_free (s, FALSE);
+ profile = gdk_color_profile_new_from_cicp (nclx->color_primaries,
+ nclx->transfer_characteristics,
+ 0,
+ TRUE,
+ NULL);
+ heif_nclx_color_profile_free (nclx);
+ }
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ g_string_append_printf (details, "%dā€†Ć—ā€†%d pixels\n%d bits of luma, %d bits of chroma%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" : "");
+
+ if (profile_type)
+ {
+ g_string_append_printf (details, "color profile: %s\n", profile_type);
+ g_free (profile_type);
+ }
+
+ if (profile == NULL)
+ profile = g_object_ref (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);
+ g_object_unref (profile);
+
+out:
+ heif_context_free (ctx);
+ if (handle)
+ heif_image_handle_release (handle);
+ if (image)
+ heif_image_release (image);
+
+ return texture;
+}
diff --git a/demos/widget-factory/heif-loader.h b/demos/widget-factory/heif-loader.h
new file mode 100644
index 0000000000..933254f9b5
--- /dev/null
+++ b/demos/widget-factory/heif-loader.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+GdkTexture *load_heif_image (const char *resource_path,
+ GString *details,
+ GError **error);
diff --git a/demos/widget-factory/meson.build b/demos/widget-factory/meson.build
index 550eb09bd9..fc3b03baad 100644
--- a/demos/widget-factory/meson.build
+++ b/demos/widget-factory/meson.build
@@ -73,10 +73,12 @@ else
)
endif
+libheif_dep = dependency('libheif')
+
executable('gtk4-widget-factory',
- sources: ['widget-factory.c', widgetfactory_resources],
+ sources: ['widget-factory.c', 'heif-loader.c', widgetfactory_resources],
c_args: common_cflags,
- dependencies: [ libgtk_dep, demo_conf_h ],
+ dependencies: [ libgtk_dep, libheif_dep, demo_conf_h ],
include_directories: confinc,
win_subsystem: 'windows',
link_args: extra_demo_ldflags,
diff --git a/demos/widget-factory/widget-factory.c b/demos/widget-factory/widget-factory.c
index 5e0353b80b..ba818e3476 100644
--- a/demos/widget-factory/widget-factory.c
+++ b/demos/widget-factory/widget-factory.c
@@ -27,6 +27,8 @@
#include "demo_conf.h"
+#include "heif-loader.h"
+
static void
change_dark_state (GSimpleAction *action,
GVariant *state,
@@ -2360,6 +2362,15 @@ activate (GApplication *app)
model = (GMenuModel *)gtk_builder_get_object (builder, "new_style_context_menu_model");
set_up_context_popover (widget, model);
+ widget = (GtkWidget *)gtk_builder_get_object (builder, "hdr_picture");
+ widget2 = (GtkWidget *)gtk_builder_get_object (builder, "hdr_label");
+ GString *details = g_string_new ("");
+ GdkTexture *texture = load_heif_image ("/org/gtk/WidgetFactory4/hdr-example.heif", details, NULL);
+ gtk_picture_set_paintable (GTK_PICTURE (widget), GDK_PAINTABLE (texture));
+ gtk_label_set_label (GTK_LABEL (widget2), details->str);
+ g_string_free (details, TRUE);
+ g_object_unref (texture);
+
gtk_window_present (window);
g_object_unref (builder);
diff --git a/demos/widget-factory/widget-factory.gresource.xml b/demos/widget-factory/widget-factory.gresource.xml
index 0db9306704..9062698153 100644
--- a/demos/widget-factory/widget-factory.gresource.xml
+++ b/demos/widget-factory/widget-factory.gresource.xml
@@ -110,6 +110,7 @@
<file>icons/scalable/status/weather-severe-alert-symbolic.svg</file>
<file>icons/scalable/status/weather-showers-symbolic.svg</file>
<file>icons/scalable/status/weather-snow-symbolic.svg</file>
+ <file>hdr-example.heif</file>
</gresource>
<gresource prefix="/org/gtk/WidgetFactory4">
diff --git a/demos/widget-factory/widget-factory.ui b/demos/widget-factory/widget-factory.ui
index 63756441d3..e7bd6dccad 100644
--- a/demos/widget-factory/widget-factory.ui
+++ b/demos/widget-factory/widget-factory.ui
@@ -1586,6 +1586,7 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<object class="GtkImage">
<property name="paintable">resource:///org/gtk/WidgetFactory4/color-profile-check.tiff</property>
<layout>
+
<property name="column">0</property>
<property name="row">3</property>
</layout>
@@ -1615,12 +1616,26 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="position">2</property>
<property name="child">
<object class="GtkBox" id="box11">
- <property name="orientation">1</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkPicture" id="hdr_picture">
+ <property name="can-shrink">1</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="hdr_label">
+ <property name="margin-start">10</property>
+ <property name="margin-end">10</property>
+ <property name="margin-top">10</property>
+ <property name="margin-bottom">10</property>
+ <property name="use-markup">1</property>
+ </object>
+ </child>
</object>
</property>
<property name="tab">
<object class="GtkLabel" id="label10">
- <property name="label" translatable="1">page 3</property>
+ <property name="label" translatable="1">HDR</property>
</object>
</property>
</object>