mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-09-19 13:30:02 +00:00
wip: Hack tone mapping into gtk4-image-tool
This is just for playing around, not intended to be merged.
This commit is contained in:
parent
df450ad353
commit
c023762329
@ -16,3 +16,15 @@ struct _GdkHdrMetadata
|
|||||||
float max_cll;
|
float max_cll;
|
||||||
float max_fall;
|
float max_fall;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline char *
|
||||||
|
gdk_hdr_metadata_to_string (GdkHdrMetadata *hdr)
|
||||||
|
{
|
||||||
|
return g_strdup_printf ("r %f %f, g %f %f, b %f %f, w %f %f, lum %f %f, avg %f %f",
|
||||||
|
hdr->rx, hdr->ry,
|
||||||
|
hdr->gx, hdr->gy,
|
||||||
|
hdr->bx, hdr->by,
|
||||||
|
hdr->wx, hdr->wy,
|
||||||
|
hdr->min_lum, hdr->max_lum,
|
||||||
|
hdr->max_cll, hdr->max_fall);
|
||||||
|
}
|
||||||
|
@ -29,14 +29,190 @@
|
|||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include "gtk-image-tool.h"
|
#include "gtk-image-tool.h"
|
||||||
|
|
||||||
|
// TEMPORARY
|
||||||
|
|
||||||
|
#include "gdk/gdkcolordefs.h"
|
||||||
|
#include "gdk/gdkcolorprivate.h"
|
||||||
|
#include "gdk/gdkhdrmetadataprivate.h"
|
||||||
|
|
||||||
|
#undef gdk_color_state_ref
|
||||||
|
#undef gdk_color_state_unref
|
||||||
|
|
||||||
|
static void
|
||||||
|
multiply (const float m[9],
|
||||||
|
const float v[3],
|
||||||
|
float res[3])
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
res[i] = m[3*i+0]*v[0] + m[3*i+1]*v[1] + m[3*i+2]*v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
static const float rec2020_to_lms[9] = {
|
||||||
|
0.412109, 0.523926, 0.063965,
|
||||||
|
0.166748, 0.720459, 0.112793,
|
||||||
|
0.024170, 0.075439, 0.900391,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const float lms_to_ictcp[9] = {
|
||||||
|
0.500000, 0.500000, 0.000000,
|
||||||
|
1.613770, -3.323486, 1.709717,
|
||||||
|
4.378174, -4.245605, -0.132568,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const float lms_to_rec2020[9] = {
|
||||||
|
3.436607, -2.506452, 0.069845,
|
||||||
|
-0.791330, 1.983600, -0.192271,
|
||||||
|
-0.025950, -0.098914, 1.124864,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const float ictcp_to_lms[9] = {
|
||||||
|
1.000000, 0.008609, 0.111030,
|
||||||
|
1.000000, -0.008609, -0.111030,
|
||||||
|
1.000000, 0.560031, -0.320627,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
rec2100_linear_to_ictcp (float in[4],
|
||||||
|
float out[4])
|
||||||
|
{
|
||||||
|
float lms[3];
|
||||||
|
|
||||||
|
multiply (rec2020_to_lms, in, lms);
|
||||||
|
|
||||||
|
lms[0] = pq_oetf (lms[0]);
|
||||||
|
lms[1] = pq_oetf (lms[1]);
|
||||||
|
lms[2] = pq_oetf (lms[2]);
|
||||||
|
|
||||||
|
multiply (lms_to_ictcp, lms, out);
|
||||||
|
|
||||||
|
out[3] = in[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ictcp_to_rec2100_linear (float in[4],
|
||||||
|
float out[4])
|
||||||
|
{
|
||||||
|
float lms[3];
|
||||||
|
|
||||||
|
multiply (ictcp_to_lms, in, lms);
|
||||||
|
|
||||||
|
lms[0] = pq_eotf (lms[0]);
|
||||||
|
lms[1] = pq_eotf (lms[1]);
|
||||||
|
lms[2] = pq_eotf (lms[2]);
|
||||||
|
|
||||||
|
multiply (lms_to_rec2020, lms, out);
|
||||||
|
|
||||||
|
out[3] = in[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
color_map (GdkColorState *src_color_state,
|
||||||
|
GdkHdrMetadata *src_metadata,
|
||||||
|
GdkColorState *target_color_state,
|
||||||
|
GdkHdrMetadata *target_metadata,
|
||||||
|
float (*values)[4],
|
||||||
|
gsize n_values,
|
||||||
|
int debug)
|
||||||
|
{
|
||||||
|
float ictcp[4];
|
||||||
|
float ref_lum = 203;
|
||||||
|
float src_max_lum;
|
||||||
|
float target_max_lum;
|
||||||
|
float src_lum;
|
||||||
|
float needed_range;
|
||||||
|
float added_range;
|
||||||
|
float new_ref_lum;
|
||||||
|
float rel_highlight;
|
||||||
|
float low;
|
||||||
|
float high;
|
||||||
|
|
||||||
|
src_max_lum = src_metadata->max_lum;
|
||||||
|
target_max_lum = target_metadata->max_lum;
|
||||||
|
|
||||||
|
if (src_max_lum <= target_max_lum * 1.01 &&
|
||||||
|
gdk_color_state_equal (src_color_state, target_color_state))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
needed_range = src_max_lum / ref_lum;
|
||||||
|
added_range = MIN (needed_range, 1.5);
|
||||||
|
new_ref_lum = ref_lum / added_range;
|
||||||
|
|
||||||
|
for (gsize i = 0; i < n_values; i++)
|
||||||
|
{
|
||||||
|
GdkColor tmp;
|
||||||
|
float v[4];
|
||||||
|
|
||||||
|
if (src_max_lum <= target_max_lum * 1.01)
|
||||||
|
{
|
||||||
|
gdk_color_init (&tmp, src_color_state, values[i]);
|
||||||
|
gdk_color_to_float (&tmp, target_color_state, values[i]);
|
||||||
|
gdk_color_finish (&tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gdk_color_init (&tmp, src_color_state, values[i]);
|
||||||
|
gdk_color_to_float (&tmp, gdk_color_state_get_rec2100_linear (), v);
|
||||||
|
gdk_color_finish (&tmp);
|
||||||
|
|
||||||
|
rec2100_linear_to_ictcp (v, ictcp);
|
||||||
|
src_lum = pq_eotf (ictcp[0]) * 10000;
|
||||||
|
low = MIN (src_lum / added_range, new_ref_lum);
|
||||||
|
rel_highlight = CLAMP ((src_lum - new_ref_lum) / (src_max_lum - new_ref_lum), 0, 1);
|
||||||
|
high = pow (rel_highlight, 0.5) * (target_max_lum - new_ref_lum);
|
||||||
|
|
||||||
|
if (debug > -1 && debug == i)
|
||||||
|
{
|
||||||
|
g_print ("needed range: %f\n", needed_range);
|
||||||
|
g_print ("added range: %f\n", added_range);
|
||||||
|
g_print ("new ref lum: %f\n", new_ref_lum);
|
||||||
|
g_print ("rec2100-linear: %f %f %f\n", v[0], v[1], v[2]);
|
||||||
|
g_print ("ictcp: %f %f %f\n", ictcp[0], ictcp[1], ictcp[2]);
|
||||||
|
g_print ("lum: %f\n", src_lum);
|
||||||
|
g_print ("adjusted lum: %f\n", low + high);
|
||||||
|
}
|
||||||
|
|
||||||
|
ictcp[0] = pq_oetf ((low + high) / 10000);
|
||||||
|
ictcp_to_rec2100_linear (ictcp, v);
|
||||||
|
|
||||||
|
gdk_color_init (&tmp, gdk_color_state_get_rec2100_linear (), v);
|
||||||
|
gdk_color_to_float (&tmp, target_color_state, values[i]);
|
||||||
|
|
||||||
|
values[i][0] = CLAMP (values[i][0], 0, 1);
|
||||||
|
values[i][1] = CLAMP (values[i][1], 0, 1);
|
||||||
|
values[i][2] = CLAMP (values[i][2], 0, 1);
|
||||||
|
values[i][3] = CLAMP (values[i][3], 0, 1);
|
||||||
|
|
||||||
|
if (debug > -1 && debug == i)
|
||||||
|
{
|
||||||
|
g_print ("final color: %f %f %f %f\n",
|
||||||
|
values[i][0],
|
||||||
|
values[i][1],
|
||||||
|
values[i][2],
|
||||||
|
values[i][3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
gdk_color_finish (&tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// END TEMPORARY
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
save_image (const char *filename,
|
save_image (const char *filename,
|
||||||
const char *output,
|
const char *output,
|
||||||
GdkMemoryFormat format,
|
GdkMemoryFormat format,
|
||||||
GdkColorState *color_state)
|
GdkColorState *color_state,
|
||||||
|
GdkHdrMetadata *metadata)
|
||||||
{
|
{
|
||||||
GdkTexture *orig;
|
GdkTexture *orig;
|
||||||
|
GdkColorState *orig_color_state;
|
||||||
|
GdkHdrMetadata *orig_metadata;
|
||||||
|
gsize width, height;
|
||||||
GdkTextureDownloader *downloader;
|
GdkTextureDownloader *downloader;
|
||||||
GBytes *bytes;
|
GBytes *bytes;
|
||||||
gsize stride;
|
gsize stride;
|
||||||
@ -44,20 +220,68 @@ save_image (const char *filename,
|
|||||||
GdkMemoryTextureBuilder *builder;
|
GdkMemoryTextureBuilder *builder;
|
||||||
|
|
||||||
orig = load_image_file (filename);
|
orig = load_image_file (filename);
|
||||||
|
width = gdk_texture_get_width (orig);
|
||||||
|
height = gdk_texture_get_height (orig);
|
||||||
|
orig_color_state = gdk_texture_get_color_state (orig);
|
||||||
|
orig_metadata = gdk_texture_get_hdr_metadata (orig);
|
||||||
|
|
||||||
|
if (metadata && orig_metadata)
|
||||||
|
{
|
||||||
|
guchar *data;
|
||||||
|
|
||||||
|
downloader = gdk_texture_downloader_new (orig);
|
||||||
|
|
||||||
|
gdk_texture_downloader_set_format (downloader, GDK_MEMORY_R32G32B32A32_FLOAT);
|
||||||
|
gdk_texture_downloader_set_color_state (downloader, orig_color_state);
|
||||||
|
bytes = gdk_texture_downloader_download_bytes (downloader, &stride);
|
||||||
|
gdk_texture_downloader_free (downloader);
|
||||||
|
|
||||||
|
data = (guchar *) g_bytes_get_data (bytes, NULL);
|
||||||
|
|
||||||
|
for (gsize i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
float (*row)[4];
|
||||||
|
int debug;
|
||||||
|
|
||||||
|
if (i == height / 2)
|
||||||
|
debug = width / 2;
|
||||||
|
else
|
||||||
|
debug = -1;
|
||||||
|
|
||||||
|
row = (gpointer) (data + i * stride);
|
||||||
|
color_map (orig_color_state, orig_metadata, color_state, metadata, row, width, debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder = gdk_memory_texture_builder_new ();
|
||||||
|
gdk_memory_texture_builder_set_bytes (builder, bytes);
|
||||||
|
gdk_memory_texture_builder_set_stride (builder, stride);
|
||||||
|
gdk_memory_texture_builder_set_format (builder, GDK_MEMORY_R32G32B32A32_FLOAT);
|
||||||
|
gdk_memory_texture_builder_set_color_state (builder, color_state);
|
||||||
|
gdk_memory_texture_builder_set_hdr_metadata (builder, metadata);
|
||||||
|
gdk_memory_texture_builder_set_width (builder, width);
|
||||||
|
gdk_memory_texture_builder_set_height (builder, height);
|
||||||
|
|
||||||
|
g_object_unref (orig);
|
||||||
|
orig = gdk_memory_texture_builder_build (builder);
|
||||||
|
g_object_unref (builder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
downloader = gdk_texture_downloader_new (orig);
|
downloader = gdk_texture_downloader_new (orig);
|
||||||
|
|
||||||
gdk_texture_downloader_set_format (downloader, format);
|
gdk_texture_downloader_set_format (downloader, format);
|
||||||
gdk_texture_downloader_set_color_state (downloader, color_state);
|
gdk_texture_downloader_set_color_state (downloader, color_state);
|
||||||
|
|
||||||
bytes = gdk_texture_downloader_download_bytes (downloader, &stride);
|
bytes = gdk_texture_downloader_download_bytes (downloader, &stride);
|
||||||
|
gdk_texture_downloader_free (downloader);
|
||||||
|
|
||||||
builder = gdk_memory_texture_builder_new ();
|
builder = gdk_memory_texture_builder_new ();
|
||||||
gdk_memory_texture_builder_set_bytes (builder, bytes);
|
gdk_memory_texture_builder_set_bytes (builder, bytes);
|
||||||
gdk_memory_texture_builder_set_stride (builder, stride);
|
gdk_memory_texture_builder_set_stride (builder, stride);
|
||||||
gdk_memory_texture_builder_set_format (builder, format);
|
gdk_memory_texture_builder_set_format (builder, format);
|
||||||
gdk_memory_texture_builder_set_color_state (builder, color_state);
|
gdk_memory_texture_builder_set_color_state (builder, color_state);
|
||||||
gdk_memory_texture_builder_set_width (builder, gdk_texture_get_width (orig));
|
gdk_memory_texture_builder_set_hdr_metadata (builder, metadata);
|
||||||
gdk_memory_texture_builder_set_height (builder, gdk_texture_get_height (orig));
|
gdk_memory_texture_builder_set_width (builder, width);
|
||||||
|
gdk_memory_texture_builder_set_height (builder, height);
|
||||||
|
|
||||||
texture = gdk_memory_texture_builder_build (builder);
|
texture = gdk_memory_texture_builder_build (builder);
|
||||||
|
|
||||||
@ -68,11 +292,44 @@ save_image (const char *filename,
|
|||||||
|
|
||||||
g_object_unref (texture);
|
g_object_unref (texture);
|
||||||
g_bytes_unref (bytes);
|
g_bytes_unref (bytes);
|
||||||
gdk_texture_downloader_free (downloader);
|
|
||||||
g_object_unref (orig);
|
g_object_unref (orig);
|
||||||
g_object_unref (builder);
|
g_object_unref (builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
parse_lum (const char *lum,
|
||||||
|
float l[2])
|
||||||
|
{
|
||||||
|
char **s;
|
||||||
|
char *endptr0 = NULL;
|
||||||
|
char *endptr1 = NULL;
|
||||||
|
|
||||||
|
s = g_strsplit (lum, "-", 0);
|
||||||
|
g_print ("lum: '%s' '%s'\n", s[0], s[1]);
|
||||||
|
l[0] = g_ascii_strtod (s[0], &endptr0);
|
||||||
|
l[1] = g_ascii_strtod (s[1], &endptr1);
|
||||||
|
g_strfreev (s);
|
||||||
|
|
||||||
|
return (endptr0 == NULL || endptr0[0] == '\0') &&
|
||||||
|
(endptr1 == NULL || endptr1[0] == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
find_primaries (GdkColorState *color_state,
|
||||||
|
float p[8])
|
||||||
|
{
|
||||||
|
if (gdk_color_state_equal (color_state, gdk_color_state_get_srgb ()))
|
||||||
|
{
|
||||||
|
p[0] = 0.640; p[1] = 0.330;
|
||||||
|
p[2] = 0.300; p[3] = 0.600;
|
||||||
|
p[4] = 0.150; p[5] = 0.060;
|
||||||
|
p[6] = 0.3127; p[7] = 0.3290;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
do_convert (int *argc,
|
do_convert (int *argc,
|
||||||
const char ***argv)
|
const char ***argv)
|
||||||
@ -82,9 +339,13 @@ do_convert (int *argc,
|
|||||||
char *format_name = NULL;
|
char *format_name = NULL;
|
||||||
char *colorstate_name = NULL;
|
char *colorstate_name = NULL;
|
||||||
char *cicp_tuple = NULL;
|
char *cicp_tuple = NULL;
|
||||||
|
char *mdcv_name = NULL;
|
||||||
|
char *lum = NULL;
|
||||||
const GOptionEntry entries[] = {
|
const GOptionEntry entries[] = {
|
||||||
{ "format", 0, 0, G_OPTION_ARG_STRING, &format_name, N_("Format to use"), N_("FORMAT") },
|
{ "format", 0, 0, G_OPTION_ARG_STRING, &format_name, N_("Format to use"), N_("FORMAT") },
|
||||||
{ "color-state", 0, 0, G_OPTION_ARG_STRING, &colorstate_name, N_("Color state to use"), N_("COLORSTATE") },
|
{ "color-state", 0, 0, G_OPTION_ARG_STRING, &colorstate_name, N_("Color state to use"), N_("COLORSTATE") },
|
||||||
|
{ "mdcv", 0, 0, G_OPTION_ARG_STRING, &mdcv_name, N_("MDCV to use"), N_("COLORSTATE") },
|
||||||
|
{ "luminance", 0, 0, G_OPTION_ARG_STRING, &lum, N_("Luminance range"), N_("MIN-MAX") },
|
||||||
{ "cicp", 0, 0, G_OPTION_ARG_STRING, &cicp_tuple, N_("Color state to use, as cicp tuple"), N_("CICP") },
|
{ "cicp", 0, 0, G_OPTION_ARG_STRING, &cicp_tuple, N_("Color state to use, as cicp tuple"), N_("CICP") },
|
||||||
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, N_("FILE…") },
|
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, N_("FILE…") },
|
||||||
{ NULL, }
|
{ NULL, }
|
||||||
@ -92,6 +353,7 @@ do_convert (int *argc,
|
|||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GdkMemoryFormat format = GDK_MEMORY_DEFAULT;
|
GdkMemoryFormat format = GDK_MEMORY_DEFAULT;
|
||||||
GdkColorState *color_state = NULL;
|
GdkColorState *color_state = NULL;
|
||||||
|
GdkHdrMetadata *hdr_metadata = NULL;
|
||||||
|
|
||||||
g_set_prgname ("gtk4-image-tool convert");
|
g_set_prgname ("gtk4-image-tool convert");
|
||||||
context = g_option_context_new (NULL);
|
context = g_option_context_new (NULL);
|
||||||
@ -153,6 +415,38 @@ do_convert (int *argc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mdcv_name)
|
||||||
|
{
|
||||||
|
float primaries[8];
|
||||||
|
float luminances[2];
|
||||||
|
|
||||||
|
if (lum && !parse_lum (lum, luminances))
|
||||||
|
{
|
||||||
|
g_printerr ("Could not parse luminances\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
color_state = find_color_state_by_name (mdcv_name);
|
||||||
|
if (mdcv_name && !color_state)
|
||||||
|
{
|
||||||
|
g_printerr ("MDCV not found\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!find_primaries (color_state, primaries))
|
||||||
|
{
|
||||||
|
g_printerr ("Sorry no primaries\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr_metadata = gdk_hdr_metadata_new (primaries[0], primaries[1],
|
||||||
|
primaries[2], primaries[3],
|
||||||
|
primaries[4], primaries[5],
|
||||||
|
primaries[6], primaries[7],
|
||||||
|
luminances[0], luminances[1],
|
||||||
|
0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (cicp_tuple)
|
if (cicp_tuple)
|
||||||
{
|
{
|
||||||
if (color_state)
|
if (color_state)
|
||||||
@ -173,7 +467,7 @@ do_convert (int *argc,
|
|||||||
if (!color_state)
|
if (!color_state)
|
||||||
color_state = gdk_color_state_get_srgb ();
|
color_state = gdk_color_state_get_srgb ();
|
||||||
|
|
||||||
save_image (filenames[0], filenames[1], format, color_state);
|
save_image (filenames[0], filenames[1], format, color_state, hdr_metadata);
|
||||||
|
|
||||||
g_strfreev (filenames);
|
g_strfreev (filenames);
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ gtk_tools = [
|
|||||||
'gtk-image-tool-relabel.c',
|
'gtk-image-tool-relabel.c',
|
||||||
'gtk-image-tool-show.c',
|
'gtk-image-tool-show.c',
|
||||||
'gtk-image-tool-utils.c',
|
'gtk-image-tool-utils.c',
|
||||||
'../testsuite/reftests/reftest-compare.c'], [libgtk_dep] ],
|
'../testsuite/reftests/reftest-compare.c'], [libgtk_static_dep] ],
|
||||||
['gtk4-update-icon-cache', ['updateiconcache.c', '../gtk/gtkiconcachevalidator.c' ] + extra_update_icon_cache_objs, [ libgtk_dep ] ],
|
['gtk4-update-icon-cache', ['updateiconcache.c', '../gtk/gtkiconcachevalidator.c' ] + extra_update_icon_cache_objs, [ libgtk_dep ] ],
|
||||||
['gtk4-encode-symbolic-svg', ['encodesymbolic.c'], [ libgtk_static_dep ] ],
|
['gtk4-encode-symbolic-svg', ['encodesymbolic.c'], [ libgtk_static_dep ] ],
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user