mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-09-18 21:10:00 +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_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-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
|
||||
save_image (const char *filename,
|
||||
const char *output,
|
||||
GdkMemoryFormat format,
|
||||
GdkColorState *color_state)
|
||||
GdkColorState *color_state,
|
||||
GdkHdrMetadata *metadata)
|
||||
{
|
||||
GdkTexture *orig;
|
||||
GdkColorState *orig_color_state;
|
||||
GdkHdrMetadata *orig_metadata;
|
||||
gsize width, height;
|
||||
GdkTextureDownloader *downloader;
|
||||
GBytes *bytes;
|
||||
gsize stride;
|
||||
@ -44,20 +220,68 @@ save_image (const char *filename,
|
||||
GdkMemoryTextureBuilder *builder;
|
||||
|
||||
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);
|
||||
|
||||
gdk_texture_downloader_set_format (downloader, format);
|
||||
gdk_texture_downloader_set_color_state (downloader, color_state);
|
||||
|
||||
bytes = gdk_texture_downloader_download_bytes (downloader, &stride);
|
||||
gdk_texture_downloader_free (downloader);
|
||||
|
||||
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, format);
|
||||
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_height (builder, gdk_texture_get_height (orig));
|
||||
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);
|
||||
|
||||
texture = gdk_memory_texture_builder_build (builder);
|
||||
|
||||
@ -68,11 +292,44 @@ save_image (const char *filename,
|
||||
|
||||
g_object_unref (texture);
|
||||
g_bytes_unref (bytes);
|
||||
gdk_texture_downloader_free (downloader);
|
||||
g_object_unref (orig);
|
||||
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
|
||||
do_convert (int *argc,
|
||||
const char ***argv)
|
||||
@ -82,9 +339,13 @@ do_convert (int *argc,
|
||||
char *format_name = NULL;
|
||||
char *colorstate_name = NULL;
|
||||
char *cicp_tuple = NULL;
|
||||
char *mdcv_name = NULL;
|
||||
char *lum = NULL;
|
||||
const GOptionEntry entries[] = {
|
||||
{ "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") },
|
||||
{ "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") },
|
||||
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, N_("FILE…") },
|
||||
{ NULL, }
|
||||
@ -92,6 +353,7 @@ do_convert (int *argc,
|
||||
GError *error = NULL;
|
||||
GdkMemoryFormat format = GDK_MEMORY_DEFAULT;
|
||||
GdkColorState *color_state = NULL;
|
||||
GdkHdrMetadata *hdr_metadata = NULL;
|
||||
|
||||
g_set_prgname ("gtk4-image-tool convert");
|
||||
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 (color_state)
|
||||
@ -173,7 +467,7 @@ do_convert (int *argc,
|
||||
if (!color_state)
|
||||
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);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ gtk_tools = [
|
||||
'gtk-image-tool-relabel.c',
|
||||
'gtk-image-tool-show.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-encode-symbolic-svg', ['encodesymbolic.c'], [ libgtk_static_dep ] ],
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user