/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * pika-babl.c * Copyright (C) 2012 Michael Natterer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include #include #include "libpikacolor/pikacolor.h" #include "pika-gegl-types.h" #include "pika-babl.h" #include "pika-intl.h" void pika_babl_init (void) { static const gchar *babl_types[] = { "u8", "u16", "u32", "half", "float", "double" }; gint i; for (i = 0; i < G_N_ELEMENTS (babl_types); i++) { gchar name[16]; g_snprintf (name, sizeof (name), "R %s", babl_types[i]); babl_format_new ("name", name, babl_model ("RGBA"), babl_type (babl_types[i]), babl_component ("R"), NULL); g_snprintf (name, sizeof (name), "R' %s", babl_types[i]); babl_format_new ("name", name, babl_model ("R'G'B'A"), babl_type (babl_types[i]), babl_component ("R'"), NULL); g_snprintf (name, sizeof (name), "R~ %s", babl_types[i]); babl_format_new ("name", name, babl_model ("R~G~B~A"), babl_type (babl_types[i]), babl_component ("R~"), NULL); g_snprintf (name, sizeof (name), "G %s", babl_types[i]); babl_format_new ("name", name, babl_model ("RGBA"), babl_type (babl_types[i]), babl_component ("G"), NULL); g_snprintf (name, sizeof (name), "G' %s", babl_types[i]); babl_format_new ("name", name, babl_model ("R'G'B'A"), babl_type (babl_types[i]), babl_component ("G'"), NULL); g_snprintf (name, sizeof (name), "G~ %s", babl_types[i]); babl_format_new ("name", name, babl_model ("R~G~B~A"), babl_type (babl_types[i]), babl_component ("G~"), NULL); g_snprintf (name, sizeof (name), "B %s", babl_types[i]); babl_format_new ("name", name, babl_model ("RGBA"), babl_type (babl_types[i]), babl_component ("B"), NULL); g_snprintf (name, sizeof (name), "B' %s", babl_types[i]); babl_format_new ("name", name, babl_model ("R'G'B'A"), babl_type (babl_types[i]), babl_component ("B'"), NULL); g_snprintf (name, sizeof (name), "B~ %s", babl_types[i]); babl_format_new ("name", name, babl_model ("R~G~B~A"), babl_type (babl_types[i]), babl_component ("B~"), NULL); g_snprintf (name, sizeof (name), "A %s", babl_types[i]); babl_format_new ("name", name, babl_model ("RGBA"), babl_type (babl_types[i]), babl_component ("A"), NULL); } } void pika_babl_init_fishes (PikaInitStatusFunc status_callback) { /* create a bunch of fishes - to decrease the initial lazy * initialization cost for some interactions */ static const struct { const gchar *from_format; const gchar *to_format; } fishes[] = { { "Y' u8", "RaGaBaA float" }, { "Y u8", "RaGaBaA float" }, { "R'G'B'A u8", "RaGaBaA float" }, { "R'G'B'A float", "R'G'B'A u8" }, { "R'G'B'A float", "R'G'B' u8" }, { "R'G'B'A u8", "RGBA float" }, { "RGBA float", "R'G'B'A u8" }, { "RGBA float", "R'G'B'A u8" }, { "RGBA float", "R'G'B'A float" }, { "Y' u8", "R'G'B' u8" }, { "Y u8", "Y float" }, { "R'G'B' u8", "cairo-RGB24" }, { "R'G'B' u8", "R'G'B'A float" }, { "R'G'B' u8", "R'G'B'A u8" }, { "R'G'B'A u8", "R'G'B'A float" }, { "R'G'B'A u8", "cairo-ARGB32" }, { "R'G'B'A double", "RGBA float" }, { "R'G'B'A float", "RGBA double" }, { "R'G'B' u8", "RGB float" }, { "RGB float", "R'G'B'A float" }, { "R'G'B' u8", "RGBA float" }, { "RaGaBaA float", "R'G'B'A float" }, { "RaGaBaA float", "RGBA float" }, { "RGBA float", "RaGaBaA float" }, { "R'G'B' u8", "RaGaBaA float" }, { "cairo-ARGB32", "R'G'B'A u8" } }; gint i; for (i = 0; i < G_N_ELEMENTS (fishes); i++) { status_callback (NULL, NULL, (gdouble) (i + 1) / (gdouble) G_N_ELEMENTS (fishes) * 0.8); babl_fish (babl_format (fishes[i].from_format), babl_format (fishes[i].to_format)); } } static const struct { const gchar *name; const gchar *description; } babl_descriptions[] = { { "RGB u8", N_("RGB") }, { "R'G'B' u8", N_("RGB") }, { "R~G~B~ u8", N_("RGB") }, { "RGB u16", N_("RGB") }, { "R'G'B' u16", N_("RGB") }, { "R~G~B~ u16", N_("RGB") }, { "RGB u32", N_("RGB") }, { "R'G'B' u32", N_("RGB") }, { "R~G~B~ u32", N_("RGB") }, { "RGB half", N_("RGB") }, { "R'G'B' half", N_("RGB") }, { "R~G~B~ half", N_("RGB") }, { "RGB float", N_("RGB") }, { "R'G'B' float", N_("RGB") }, { "R~G~B~ float", N_("RGB") }, { "RGB double", N_("RGB") }, { "R'G'B' double", N_("RGB") }, { "R~G~B~ double", N_("RGB") }, { "RGBA u8", N_("RGB-alpha") }, { "R'G'B'A u8", N_("RGB-alpha") }, { "R~G~B~A u8", N_("RGB-alpha") }, { "RGBA u16", N_("RGB-alpha") }, { "R'G'B'A u16", N_("RGB-alpha") }, { "R~G~B~A u16", N_("RGB-alpha") }, { "RGBA u32", N_("RGB-alpha") }, { "R'G'B'A u32", N_("RGB-alpha") }, { "R~G~B~A u32", N_("RGB-alpha") }, { "RGBA half", N_("RGB-alpha") }, { "R'G'B'A half", N_("RGB-alpha") }, { "R~G~B~A half", N_("RGB-alpha") }, { "RGBA float", N_("RGB-alpha") }, { "R'G'B'A float", N_("RGB-alpha") }, { "R~G~B~A float", N_("RGB-alpha") }, { "RGBA double", N_("RGB-alpha") }, { "R'G'B'A double", N_("RGB-alpha") }, { "R~G~B~A double", N_("RGB-alpha") }, { "Y u8", N_("Grayscale") }, { "Y' u8", N_("Grayscale") }, { "Y~ u8", N_("Grayscale") }, { "Y u16", N_("Grayscale") }, { "Y' u16", N_("Grayscale") }, { "Y~ u16", N_("Grayscale") }, { "Y u32", N_("Grayscale") }, { "Y' u32", N_("Grayscale") }, { "Y~ u32", N_("Grayscale") }, { "Y half", N_("Grayscale") }, { "Y' half", N_("Grayscale") }, { "Y~ half", N_("Grayscale") }, { "Y float", N_("Grayscale") }, { "Y' float", N_("Grayscale") }, { "Y~ float", N_("Grayscale") }, { "Y double", N_("Grayscale") }, { "Y' double", N_("Grayscale") }, { "Y~ double", N_("Grayscale") }, { "YA u8", N_("Grayscale-alpha") }, { "Y'A u8", N_("Grayscale-alpha") }, { "Y~A u8", N_("Grayscale-alpha") }, { "YA u16", N_("Grayscale-alpha") }, { "Y'A u16", N_("Grayscale-alpha") }, { "Y~A u16", N_("Grayscale-alpha") }, { "YA u32", N_("Grayscale-alpha") }, { "Y'A u32", N_("Grayscale-alpha") }, { "Y~A u32", N_("Grayscale-alpha") }, { "YA half", N_("Grayscale-alpha") }, { "Y'A half", N_("Grayscale-alpha") }, { "Y~A half", N_("Grayscale-alpha") }, { "YA float", N_("Grayscale-alpha") }, { "Y'A float", N_("Grayscale-alpha") }, { "Y~A float", N_("Grayscale-alpha") }, { "YA double", N_("Grayscale-alpha") }, { "Y'A double", N_("Grayscale-alpha") }, { "Y~A double", N_("Grayscale-alpha") }, { "R u8", N_("Red component") }, { "R' u8", N_("Red component") }, { "R~ u8", N_("Red component") }, { "R u16", N_("Red component") }, { "R' u16", N_("Red component") }, { "R~ u16", N_("Red component") }, { "R u32", N_("Red component") }, { "R' u32", N_("Red component") }, { "R~ u32", N_("Red component") }, { "R half", N_("Red component") }, { "R' half", N_("Red component") }, { "R~ half", N_("Red component") }, { "R float", N_("Red component") }, { "R' float", N_("Red component") }, { "R~ float", N_("Red component") }, { "R double", N_("Red component") }, { "R' double", N_("Red component") }, { "R~ double", N_("Red component") }, { "G u8", N_("Green component") }, { "G' u8", N_("Green component") }, { "G~ u8", N_("Green component") }, { "G u16", N_("Green component") }, { "G' u16", N_("Green component") }, { "G~ u16", N_("Green component") }, { "G u32", N_("Green component") }, { "G' u32", N_("Green component") }, { "G~ u32", N_("Green component") }, { "G half", N_("Green component") }, { "G' half", N_("Green component") }, { "G~ half", N_("Green component") }, { "G float", N_("Green component") }, { "G' float", N_("Green component") }, { "G~ float", N_("Green component") }, { "G double", N_("Green component") }, { "G' double", N_("Green component") }, { "G~ double", N_("Green component") }, { "B u8", N_("Blue component") }, { "B' u8", N_("Blue component") }, { "B~ u8", N_("Blue component") }, { "B u16", N_("Blue component") }, { "B' u16", N_("Blue component") }, { "B~ u16", N_("Blue component") }, { "B u32", N_("Blue component") }, { "B' u32", N_("Blue component") }, { "B~ u32", N_("Blue component") }, { "B half", N_("Blue component") }, { "B' half", N_("Blue component") }, { "B~ half", N_("Blue component") }, { "B float", N_("Blue component") }, { "B' float", N_("Blue component") }, { "B~ float", N_("Blue component") }, { "B double", N_("Blue component") }, { "B' double", N_("Blue component") }, { "B~ double", N_("Blue component") }, { "A u8", N_("Alpha component") }, { "A u16", N_("Alpha component") }, { "A u32", N_("Alpha component") }, { "A half", N_("Alpha component") }, { "A float", N_("Alpha component") }, { "A double", N_("Alpha component") } }; static GHashTable *babl_description_hash = NULL; const gchar * pika_babl_format_get_description (const Babl *babl) { const gchar *description; g_return_val_if_fail (babl != NULL, NULL); if (G_UNLIKELY (! babl_description_hash)) { gint i; babl_description_hash = g_hash_table_new (g_str_hash, g_str_equal); for (i = 0; i < G_N_ELEMENTS (babl_descriptions); i++) g_hash_table_insert (babl_description_hash, (gpointer) babl_descriptions[i].name, gettext (babl_descriptions[i].description)); } if (babl_format_is_palette (babl)) { if (babl_format_has_alpha (babl)) return _("Indexed-alpha"); else return _("Indexed"); } description = g_hash_table_lookup (babl_description_hash, babl_format_get_encoding (babl)); if (description) return description; return g_strconcat ("ERROR: unknown Babl format ", babl_format_get_encoding (babl), NULL); } PikaColorProfile * pika_babl_get_builtin_color_profile (PikaImageBaseType base_type, PikaTRCType trc) { static PikaColorProfile *srgb_profile = NULL; static PikaColorProfile *linear_rgb_profile = NULL; static PikaColorProfile *gray_profile = NULL; static PikaColorProfile *linear_gray_profile = NULL; if (base_type == PIKA_GRAY) { if (trc == PIKA_TRC_LINEAR) { if (! linear_gray_profile) { g_set_weak_pointer (&linear_gray_profile, pika_color_profile_new_d65_gray_linear ()); } return linear_gray_profile; } else { if (! gray_profile) { g_set_weak_pointer (&gray_profile, pika_color_profile_new_d65_gray_srgb_trc ()); } return gray_profile; } } else { if (trc == PIKA_TRC_LINEAR) { if (! linear_rgb_profile) { g_set_weak_pointer (&linear_rgb_profile, pika_color_profile_new_rgb_srgb_linear ()); } return linear_rgb_profile; } else { if (! srgb_profile) { g_set_weak_pointer (&srgb_profile, pika_color_profile_new_rgb_srgb ()); } return srgb_profile; } } } PikaColorProfile * pika_babl_format_get_color_profile (const Babl *format) { const Babl *non_linear_format; const gchar *icc; gint icc_len; PikaColorProfile *profile; PikaColorProfile *retval = NULL; g_return_val_if_fail (format != NULL, NULL); if (pika_babl_format_get_trc (format) == PIKA_TRC_NON_LINEAR) { non_linear_format = format; } else { PikaImageBaseType base_type = PIKA_RGB; PikaComponentType component_type; switch (pika_babl_format_get_base_type (format)) { case PIKA_RGB: case PIKA_INDEXED: base_type = PIKA_RGB; break; case PIKA_GRAY: base_type = PIKA_GRAY; break; } component_type = pika_babl_format_get_component_type (format); non_linear_format = pika_babl_format (base_type, pika_babl_precision (component_type, PIKA_TRC_NON_LINEAR), babl_format_has_alpha (format), babl_format_get_space (format)); } icc = babl_space_get_icc (babl_format_get_space (non_linear_format), &icc_len); profile = pika_color_profile_new_from_icc_profile ((const guint8 *) icc, icc_len, NULL); switch (pika_babl_format_get_trc (format)) { case PIKA_TRC_LINEAR: retval = pika_color_profile_new_linear_from_color_profile (profile); break; case PIKA_TRC_NON_LINEAR: retval = g_object_ref (profile); break; case PIKA_TRC_PERCEPTUAL: retval = pika_color_profile_new_srgb_trc_from_color_profile (profile); break; } g_object_unref (profile); return retval; } PikaImageBaseType pika_babl_format_get_base_type (const Babl *format) { const gchar *name; g_return_val_if_fail (format != NULL, -1); name = babl_get_name (babl_format_get_model (format)); if (! strcmp (name, "Y") || ! strcmp (name, "Y'") || ! strcmp (name, "Y~") || ! strcmp (name, "YA") || ! strcmp (name, "Y'A") || ! strcmp (name, "Y~A")) { return PIKA_GRAY; } else if (! strcmp (name, "RGB") || ! strcmp (name, "R'G'B'") || ! strcmp (name, "R~G~B~") || ! strcmp (name, "RGBA") || ! strcmp (name, "R'G'B'A") || ! strcmp (name, "R~G~B~A") || ! strcmp (name, "RaGaBaA") || ! strcmp (name, "R'aG'aB'aA") || ! strcmp (name, "R~aG~aB~aA")) { return PIKA_RGB; } else if (babl_format_is_palette (format)) { return PIKA_INDEXED; } g_return_val_if_reached (-1); } PikaComponentType pika_babl_format_get_component_type (const Babl *format) { const Babl *type; g_return_val_if_fail (format != NULL, -1); type = babl_format_get_type (format, 0); if (type == babl_type ("u8")) return PIKA_COMPONENT_TYPE_U8; else if (type == babl_type ("u16")) return PIKA_COMPONENT_TYPE_U16; else if (type == babl_type ("u32")) return PIKA_COMPONENT_TYPE_U32; else if (type == babl_type ("half")) return PIKA_COMPONENT_TYPE_HALF; else if (type == babl_type ("float")) return PIKA_COMPONENT_TYPE_FLOAT; else if (type == babl_type ("double")) return PIKA_COMPONENT_TYPE_DOUBLE; g_return_val_if_reached (-1); } PikaPrecision pika_babl_format_get_precision (const Babl *format) { const Babl *type; g_return_val_if_fail (format != NULL, -1); type = babl_format_get_type (format, 0); switch (pika_babl_format_get_trc (format)) { case PIKA_TRC_LINEAR: if (type == babl_type ("u8")) return PIKA_PRECISION_U8_LINEAR; else if (type == babl_type ("u16")) return PIKA_PRECISION_U16_LINEAR; else if (type == babl_type ("u32")) return PIKA_PRECISION_U32_LINEAR; else if (type == babl_type ("half")) return PIKA_PRECISION_HALF_LINEAR; else if (type == babl_type ("float")) return PIKA_PRECISION_FLOAT_LINEAR; else if (type == babl_type ("double")) return PIKA_PRECISION_DOUBLE_LINEAR; break; case PIKA_TRC_NON_LINEAR: if (type == babl_type ("u8")) return PIKA_PRECISION_U8_NON_LINEAR; else if (type == babl_type ("u16")) return PIKA_PRECISION_U16_NON_LINEAR; else if (type == babl_type ("u32")) return PIKA_PRECISION_U32_NON_LINEAR; else if (type == babl_type ("half")) return PIKA_PRECISION_HALF_NON_LINEAR; else if (type == babl_type ("float")) return PIKA_PRECISION_FLOAT_NON_LINEAR; else if (type == babl_type ("double")) return PIKA_PRECISION_DOUBLE_NON_LINEAR; break; case PIKA_TRC_PERCEPTUAL: if (type == babl_type ("u8")) return PIKA_PRECISION_U8_PERCEPTUAL; else if (type == babl_type ("u16")) return PIKA_PRECISION_U16_PERCEPTUAL; else if (type == babl_type ("u32")) return PIKA_PRECISION_U32_PERCEPTUAL; else if (type == babl_type ("half")) return PIKA_PRECISION_HALF_PERCEPTUAL; else if (type == babl_type ("float")) return PIKA_PRECISION_FLOAT_PERCEPTUAL; else if (type == babl_type ("double")) return PIKA_PRECISION_DOUBLE_PERCEPTUAL; break; } g_return_val_if_reached (-1); } PikaTRCType pika_babl_format_get_trc (const Babl *format) { const gchar *name; g_return_val_if_fail (format != NULL, FALSE); name = babl_get_name (babl_format_get_model (format)); if (! strcmp (name, "Y") || ! strcmp (name, "YA") || ! strcmp (name, "RGB") || ! strcmp (name, "RGBA") || ! strcmp (name, "RaGaBaA")) { return PIKA_TRC_LINEAR; } else if (! strcmp (name, "Y'") || ! strcmp (name, "Y'A") || ! strcmp (name, "R'G'B'") || ! strcmp (name, "R'G'B'A") || ! strcmp (name, "R'aG'aB'aA")) { return PIKA_TRC_NON_LINEAR; } else if (! strcmp (name, "Y~") || ! strcmp (name, "Y~A") || ! strcmp (name, "R~G~B~") || ! strcmp (name, "R~G~B~A") || ! strcmp (name, "R~aG~aB~aA")) { return PIKA_TRC_PERCEPTUAL; } else if (babl_format_is_palette (format)) { return PIKA_TRC_NON_LINEAR; } g_return_val_if_reached (PIKA_TRC_LINEAR); } PikaComponentType pika_babl_component_type (PikaPrecision precision) { switch (precision) { case PIKA_PRECISION_U8_LINEAR: case PIKA_PRECISION_U8_NON_LINEAR: case PIKA_PRECISION_U8_PERCEPTUAL: return PIKA_COMPONENT_TYPE_U8; case PIKA_PRECISION_U16_LINEAR: case PIKA_PRECISION_U16_NON_LINEAR: case PIKA_PRECISION_U16_PERCEPTUAL: return PIKA_COMPONENT_TYPE_U16; case PIKA_PRECISION_U32_LINEAR: case PIKA_PRECISION_U32_NON_LINEAR: case PIKA_PRECISION_U32_PERCEPTUAL: return PIKA_COMPONENT_TYPE_U32; case PIKA_PRECISION_HALF_LINEAR: case PIKA_PRECISION_HALF_NON_LINEAR: case PIKA_PRECISION_HALF_PERCEPTUAL: return PIKA_COMPONENT_TYPE_HALF; case PIKA_PRECISION_FLOAT_LINEAR: case PIKA_PRECISION_FLOAT_NON_LINEAR: case PIKA_PRECISION_FLOAT_PERCEPTUAL: return PIKA_COMPONENT_TYPE_FLOAT; case PIKA_PRECISION_DOUBLE_LINEAR: case PIKA_PRECISION_DOUBLE_NON_LINEAR: case PIKA_PRECISION_DOUBLE_PERCEPTUAL: return PIKA_COMPONENT_TYPE_DOUBLE; } g_return_val_if_reached (-1); } PikaTRCType pika_babl_trc (PikaPrecision precision) { switch (precision) { case PIKA_PRECISION_U8_LINEAR: case PIKA_PRECISION_U16_LINEAR: case PIKA_PRECISION_U32_LINEAR: case PIKA_PRECISION_HALF_LINEAR: case PIKA_PRECISION_FLOAT_LINEAR: case PIKA_PRECISION_DOUBLE_LINEAR: return PIKA_TRC_LINEAR; case PIKA_PRECISION_U8_NON_LINEAR: case PIKA_PRECISION_U16_NON_LINEAR: case PIKA_PRECISION_U32_NON_LINEAR: case PIKA_PRECISION_HALF_NON_LINEAR: case PIKA_PRECISION_FLOAT_NON_LINEAR: case PIKA_PRECISION_DOUBLE_NON_LINEAR: return PIKA_TRC_NON_LINEAR; case PIKA_PRECISION_U8_PERCEPTUAL: case PIKA_PRECISION_U16_PERCEPTUAL: case PIKA_PRECISION_U32_PERCEPTUAL: case PIKA_PRECISION_HALF_PERCEPTUAL: case PIKA_PRECISION_FLOAT_PERCEPTUAL: case PIKA_PRECISION_DOUBLE_PERCEPTUAL: return PIKA_TRC_PERCEPTUAL; } g_return_val_if_reached (PIKA_TRC_LINEAR); } PikaPrecision pika_babl_precision (PikaComponentType component, PikaTRCType trc) { switch (component) { case PIKA_COMPONENT_TYPE_U8: switch (trc) { case PIKA_TRC_LINEAR: return PIKA_PRECISION_U8_LINEAR; case PIKA_TRC_NON_LINEAR: return PIKA_PRECISION_U8_NON_LINEAR; case PIKA_TRC_PERCEPTUAL: return PIKA_PRECISION_U8_PERCEPTUAL; default: break; } case PIKA_COMPONENT_TYPE_U16: switch (trc) { case PIKA_TRC_LINEAR: return PIKA_PRECISION_U16_LINEAR; case PIKA_TRC_NON_LINEAR: return PIKA_PRECISION_U16_NON_LINEAR; case PIKA_TRC_PERCEPTUAL: return PIKA_PRECISION_U16_PERCEPTUAL; default: break; } case PIKA_COMPONENT_TYPE_U32: switch (trc) { case PIKA_TRC_LINEAR: return PIKA_PRECISION_U32_LINEAR; case PIKA_TRC_NON_LINEAR: return PIKA_PRECISION_U32_NON_LINEAR; case PIKA_TRC_PERCEPTUAL: return PIKA_PRECISION_U32_PERCEPTUAL; default: break; } case PIKA_COMPONENT_TYPE_HALF: switch (trc) { case PIKA_TRC_LINEAR: return PIKA_PRECISION_HALF_LINEAR; case PIKA_TRC_NON_LINEAR: return PIKA_PRECISION_HALF_NON_LINEAR; case PIKA_TRC_PERCEPTUAL: return PIKA_PRECISION_HALF_PERCEPTUAL; default: break; } case PIKA_COMPONENT_TYPE_FLOAT: switch (trc) { case PIKA_TRC_LINEAR: return PIKA_PRECISION_FLOAT_LINEAR; case PIKA_TRC_NON_LINEAR: return PIKA_PRECISION_FLOAT_NON_LINEAR; case PIKA_TRC_PERCEPTUAL: return PIKA_PRECISION_FLOAT_PERCEPTUAL; default: break; } case PIKA_COMPONENT_TYPE_DOUBLE: switch (trc) { case PIKA_TRC_LINEAR: return PIKA_PRECISION_DOUBLE_LINEAR; case PIKA_TRC_NON_LINEAR: return PIKA_PRECISION_DOUBLE_NON_LINEAR; case PIKA_TRC_PERCEPTUAL: return PIKA_PRECISION_DOUBLE_PERCEPTUAL; default: break; } default: break; } g_return_val_if_reached (-1); } gboolean pika_babl_is_valid (PikaImageBaseType base_type, PikaPrecision precision) { switch (base_type) { case PIKA_RGB: case PIKA_GRAY: return TRUE; case PIKA_INDEXED: switch (precision) { case PIKA_PRECISION_U8_NON_LINEAR: return TRUE; default: return FALSE; } } g_return_val_if_reached (FALSE); } PikaComponentType pika_babl_is_bounded (PikaPrecision precision) { switch (pika_babl_component_type (precision)) { case PIKA_COMPONENT_TYPE_U8: case PIKA_COMPONENT_TYPE_U16: case PIKA_COMPONENT_TYPE_U32: return TRUE; case PIKA_COMPONENT_TYPE_HALF: case PIKA_COMPONENT_TYPE_FLOAT: case PIKA_COMPONENT_TYPE_DOUBLE: return FALSE; } g_return_val_if_reached (FALSE); } const Babl * pika_babl_format (PikaImageBaseType base_type, PikaPrecision precision, gboolean with_alpha, const Babl *space) { switch (base_type) { case PIKA_RGB: switch (precision) { case PIKA_PRECISION_U8_LINEAR: if (with_alpha) return babl_format_with_space ("RGBA u8", space); else return babl_format_with_space ("RGB u8", space); case PIKA_PRECISION_U8_NON_LINEAR: if (with_alpha) return babl_format_with_space ("R'G'B'A u8", space); else return babl_format_with_space ("R'G'B' u8", space); case PIKA_PRECISION_U8_PERCEPTUAL: if (with_alpha) return babl_format_with_space ("R~G~B~A u8", space); else return babl_format_with_space ("R~G~B~ u8", space); case PIKA_PRECISION_U16_LINEAR: if (with_alpha) return babl_format_with_space ("RGBA u16", space); else return babl_format_with_space ("RGB u16", space); case PIKA_PRECISION_U16_NON_LINEAR: if (with_alpha) return babl_format_with_space ("R'G'B'A u16", space); else return babl_format_with_space ("R'G'B' u16", space); case PIKA_PRECISION_U16_PERCEPTUAL: if (with_alpha) return babl_format_with_space ("R~G~B~A u16", space); else return babl_format_with_space ("R~G~B~ u16", space); case PIKA_PRECISION_U32_LINEAR: if (with_alpha) return babl_format_with_space ("RGBA u32", space); else return babl_format_with_space ("RGB u32", space); case PIKA_PRECISION_U32_NON_LINEAR: if (with_alpha) return babl_format_with_space ("R'G'B'A u32", space); else return babl_format_with_space ("R'G'B' u32", space); case PIKA_PRECISION_U32_PERCEPTUAL: if (with_alpha) return babl_format_with_space ("R~G~B~A u32", space); else return babl_format_with_space ("R~G~B~ u32", space); case PIKA_PRECISION_HALF_LINEAR: if (with_alpha) return babl_format_with_space ("RGBA half", space); else return babl_format_with_space ("RGB half", space); case PIKA_PRECISION_HALF_NON_LINEAR: if (with_alpha) return babl_format_with_space ("R'G'B'A half", space); else return babl_format_with_space ("R'G'B' half", space); case PIKA_PRECISION_HALF_PERCEPTUAL: if (with_alpha) return babl_format_with_space ("R~G~B~A half", space); else return babl_format_with_space ("R~G~B~ half", space); case PIKA_PRECISION_FLOAT_LINEAR: if (with_alpha) return babl_format_with_space ("RGBA float", space); else return babl_format_with_space ("RGB float", space); case PIKA_PRECISION_FLOAT_NON_LINEAR: if (with_alpha) return babl_format_with_space ("R'G'B'A float", space); else return babl_format_with_space ("R'G'B' float", space); case PIKA_PRECISION_FLOAT_PERCEPTUAL: if (with_alpha) return babl_format_with_space ("R~G~B~A float", space); else return babl_format_with_space ("R~G~B~ float", space); case PIKA_PRECISION_DOUBLE_LINEAR: if (with_alpha) return babl_format_with_space ("RGBA double", space); else return babl_format_with_space ("RGB double", space); case PIKA_PRECISION_DOUBLE_NON_LINEAR: if (with_alpha) return babl_format_with_space ("R'G'B'A double", space); else return babl_format_with_space ("R'G'B' double", space); case PIKA_PRECISION_DOUBLE_PERCEPTUAL: if (with_alpha) return babl_format_with_space ("R~G~B~A double", space); else return babl_format_with_space ("R~G~B~ double", space); default: break; } break; case PIKA_GRAY: switch (precision) { case PIKA_PRECISION_U8_LINEAR: if (with_alpha) return babl_format_with_space ("YA u8", space); else return babl_format_with_space ("Y u8", space); case PIKA_PRECISION_U8_NON_LINEAR: if (with_alpha) return babl_format_with_space ("Y'A u8", space); else return babl_format_with_space ("Y' u8", space); case PIKA_PRECISION_U8_PERCEPTUAL: if (with_alpha) return babl_format_with_space ("Y~A u8", space); else return babl_format_with_space ("Y~ u8", space); case PIKA_PRECISION_U16_LINEAR: if (with_alpha) return babl_format_with_space ("YA u16", space); else return babl_format_with_space ("Y u16", space); case PIKA_PRECISION_U16_NON_LINEAR: if (with_alpha) return babl_format_with_space ("Y'A u16", space); else return babl_format_with_space ("Y' u16", space); case PIKA_PRECISION_U16_PERCEPTUAL: if (with_alpha) return babl_format_with_space ("Y~A u16", space); else return babl_format_with_space ("Y~ u16", space); case PIKA_PRECISION_U32_LINEAR: if (with_alpha) return babl_format_with_space ("YA u32", space); else return babl_format_with_space ("Y u32", space); case PIKA_PRECISION_U32_NON_LINEAR: if (with_alpha) return babl_format_with_space ("Y'A u32", space); else return babl_format_with_space ("Y' u32", space); case PIKA_PRECISION_U32_PERCEPTUAL: if (with_alpha) return babl_format_with_space ("Y~A u32", space); else return babl_format_with_space ("Y~ u32", space); case PIKA_PRECISION_HALF_LINEAR: if (with_alpha) return babl_format_with_space ("YA half", space); else return babl_format_with_space ("Y half", space); case PIKA_PRECISION_HALF_NON_LINEAR: if (with_alpha) return babl_format_with_space ("Y'A half", space); else return babl_format_with_space ("Y' half", space); case PIKA_PRECISION_HALF_PERCEPTUAL: if (with_alpha) return babl_format_with_space ("Y~A half", space); else return babl_format_with_space ("Y~ half", space); case PIKA_PRECISION_FLOAT_LINEAR: if (with_alpha) return babl_format_with_space ("YA float", space); else return babl_format_with_space ("Y float", space); case PIKA_PRECISION_FLOAT_NON_LINEAR: if (with_alpha) return babl_format_with_space ("Y'A float", space); else return babl_format_with_space ("Y' float", space); case PIKA_PRECISION_FLOAT_PERCEPTUAL: if (with_alpha) return babl_format_with_space ("Y~A float", space); else return babl_format_with_space ("Y~ float", space); case PIKA_PRECISION_DOUBLE_LINEAR: if (with_alpha) return babl_format_with_space ("YA double", space); else return babl_format_with_space ("Y double", space); case PIKA_PRECISION_DOUBLE_NON_LINEAR: if (with_alpha) return babl_format_with_space ("Y'A double", space); else return babl_format_with_space ("Y' double", space); case PIKA_PRECISION_DOUBLE_PERCEPTUAL: if (with_alpha) return babl_format_with_space ("Y~A double", space); else return babl_format_with_space ("Y~ double", space); default: break; } break; case PIKA_INDEXED: /* need to use the image's api for this */ break; } g_return_val_if_reached (NULL); } const Babl * pika_babl_mask_format (PikaPrecision precision) { switch (pika_babl_component_type (precision)) { case PIKA_COMPONENT_TYPE_U8: return babl_format ("Y u8"); case PIKA_COMPONENT_TYPE_U16: return babl_format ("Y u16"); case PIKA_COMPONENT_TYPE_U32: return babl_format ("Y u32"); case PIKA_COMPONENT_TYPE_HALF: return babl_format ("Y half"); case PIKA_COMPONENT_TYPE_FLOAT: return babl_format ("Y float"); case PIKA_COMPONENT_TYPE_DOUBLE: return babl_format ("Y double"); } g_return_val_if_reached (NULL); } const Babl * pika_babl_component_format (PikaImageBaseType base_type, PikaPrecision precision, gint index) { switch (base_type) { case PIKA_RGB: switch (precision) { case PIKA_PRECISION_U8_LINEAR: switch (index) { case 0: return babl_format ("R u8"); case 1: return babl_format ("G u8"); case 2: return babl_format ("B u8"); case 3: return babl_format ("A u8"); default: break; } break; case PIKA_PRECISION_U8_NON_LINEAR: switch (index) { case 0: return babl_format ("R' u8"); case 1: return babl_format ("G' u8"); case 2: return babl_format ("B' u8"); case 3: return babl_format ("A u8"); default: break; } break; case PIKA_PRECISION_U8_PERCEPTUAL: switch (index) { case 0: return babl_format ("R~ u8"); case 1: return babl_format ("G~ u8"); case 2: return babl_format ("B~ u8"); case 3: return babl_format ("A u8"); default: break; } break; case PIKA_PRECISION_U16_LINEAR: switch (index) { case 0: return babl_format ("R u16"); case 1: return babl_format ("G u16"); case 2: return babl_format ("B u16"); case 3: return babl_format ("A u16"); default: break; } break; case PIKA_PRECISION_U16_NON_LINEAR: switch (index) { case 0: return babl_format ("R' u16"); case 1: return babl_format ("G' u16"); case 2: return babl_format ("B' u16"); case 3: return babl_format ("A u16"); default: break; } break; case PIKA_PRECISION_U16_PERCEPTUAL: switch (index) { case 0: return babl_format ("R~ u16"); case 1: return babl_format ("G~ u16"); case 2: return babl_format ("B~ u16"); case 3: return babl_format ("A u16"); default: break; } break; case PIKA_PRECISION_U32_LINEAR: switch (index) { case 0: return babl_format ("R u32"); case 1: return babl_format ("G u32"); case 2: return babl_format ("B u32"); case 3: return babl_format ("A u32"); default: break; } break; case PIKA_PRECISION_U32_NON_LINEAR: switch (index) { case 0: return babl_format ("R' u32"); case 1: return babl_format ("G' u32"); case 2: return babl_format ("B' u32"); case 3: return babl_format ("A u32"); default: break; } break; case PIKA_PRECISION_U32_PERCEPTUAL: switch (index) { case 0: return babl_format ("R~ u32"); case 1: return babl_format ("G~ u32"); case 2: return babl_format ("B~ u32"); case 3: return babl_format ("A u32"); default: break; } break; case PIKA_PRECISION_HALF_LINEAR: switch (index) { case 0: return babl_format ("R half"); case 1: return babl_format ("G half"); case 2: return babl_format ("B half"); case 3: return babl_format ("A half"); default: break; } break; case PIKA_PRECISION_HALF_NON_LINEAR: switch (index) { case 0: return babl_format ("R' half"); case 1: return babl_format ("G' half"); case 2: return babl_format ("B' half"); case 3: return babl_format ("A half"); default: break; } break; case PIKA_PRECISION_HALF_PERCEPTUAL: switch (index) { case 0: return babl_format ("R~ half"); case 1: return babl_format ("G~ half"); case 2: return babl_format ("B~ half"); case 3: return babl_format ("A half"); default: break; } break; case PIKA_PRECISION_FLOAT_LINEAR: switch (index) { case 0: return babl_format ("R float"); case 1: return babl_format ("G float"); case 2: return babl_format ("B float"); case 3: return babl_format ("A float"); default: break; } break; case PIKA_PRECISION_FLOAT_NON_LINEAR: switch (index) { case 0: return babl_format ("R' float"); case 1: return babl_format ("G' float"); case 2: return babl_format ("B' float"); case 3: return babl_format ("A float"); default: break; } break; case PIKA_PRECISION_FLOAT_PERCEPTUAL: switch (index) { case 0: return babl_format ("R~ float"); case 1: return babl_format ("G~ float"); case 2: return babl_format ("B~ float"); case 3: return babl_format ("A float"); default: break; } break; case PIKA_PRECISION_DOUBLE_LINEAR: switch (index) { case 0: return babl_format ("R double"); case 1: return babl_format ("G double"); case 2: return babl_format ("B double"); case 3: return babl_format ("A double"); default: break; } break; case PIKA_PRECISION_DOUBLE_NON_LINEAR: switch (index) { case 0: return babl_format ("R' double"); case 1: return babl_format ("G' double"); case 2: return babl_format ("B' double"); case 3: return babl_format ("A double"); default: break; } break; case PIKA_PRECISION_DOUBLE_PERCEPTUAL: switch (index) { case 0: return babl_format ("R~ double"); case 1: return babl_format ("G~ double"); case 2: return babl_format ("B~ double"); case 3: return babl_format ("A double"); default: break; } break; default: break; } break; case PIKA_GRAY: switch (precision) { case PIKA_PRECISION_U8_LINEAR: switch (index) { case 0: return babl_format ("Y u8"); case 1: return babl_format ("A u8"); default: break; } break; case PIKA_PRECISION_U8_NON_LINEAR: switch (index) { case 0: return babl_format ("Y' u8"); case 1: return babl_format ("A u8"); default: break; } break; case PIKA_PRECISION_U8_PERCEPTUAL: switch (index) { case 0: return babl_format ("Y~ u8"); case 1: return babl_format ("A u8"); default: break; } break; case PIKA_PRECISION_U16_LINEAR: switch (index) { case 0: return babl_format ("Y u16"); case 1: return babl_format ("A u16"); default: break; } break; case PIKA_PRECISION_U16_NON_LINEAR: switch (index) { case 0: return babl_format ("Y' u16"); case 1: return babl_format ("A u16"); default: break; } break; case PIKA_PRECISION_U16_PERCEPTUAL: switch (index) { case 0: return babl_format ("Y~ u16"); case 1: return babl_format ("A u16"); default: break; } break; case PIKA_PRECISION_U32_LINEAR: switch (index) { case 0: return babl_format ("Y u32"); case 1: return babl_format ("A u32"); default: break; } break; case PIKA_PRECISION_U32_NON_LINEAR: switch (index) { case 0: return babl_format ("Y' u32"); case 1: return babl_format ("A u32"); default: break; } break; case PIKA_PRECISION_U32_PERCEPTUAL: switch (index) { case 0: return babl_format ("Y~ u32"); case 1: return babl_format ("A u32"); default: break; } break; case PIKA_PRECISION_HALF_LINEAR: switch (index) { case 0: return babl_format ("Y half"); case 1: return babl_format ("A half"); default: break; } break; case PIKA_PRECISION_HALF_NON_LINEAR: switch (index) { case 0: return babl_format ("Y' half"); case 1: return babl_format ("A half"); default: break; } break; case PIKA_PRECISION_HALF_PERCEPTUAL: switch (index) { case 0: return babl_format ("Y~ half"); case 1: return babl_format ("A half"); default: break; } break; case PIKA_PRECISION_FLOAT_LINEAR: switch (index) { case 0: return babl_format ("Y float"); case 1: return babl_format ("A float"); default: break; } break; case PIKA_PRECISION_FLOAT_NON_LINEAR: switch (index) { case 0: return babl_format ("Y' float"); case 1: return babl_format ("A float"); default: break; } break; case PIKA_PRECISION_FLOAT_PERCEPTUAL: switch (index) { case 0: return babl_format ("Y~ float"); case 1: return babl_format ("A float"); default: break; } break; case PIKA_PRECISION_DOUBLE_LINEAR: switch (index) { case 0: return babl_format ("Y double"); case 1: return babl_format ("A double"); default: break; } break; case PIKA_PRECISION_DOUBLE_NON_LINEAR: switch (index) { case 0: return babl_format ("Y' double"); case 1: return babl_format ("A double"); default: break; } break; case PIKA_PRECISION_DOUBLE_PERCEPTUAL: switch (index) { case 0: return babl_format ("Y~ double"); case 1: return babl_format ("A double"); default: break; } break; default: break; } break; case PIKA_INDEXED: /* need to use the image's api for this */ break; } g_return_val_if_reached (NULL); } const Babl * pika_babl_format_change_component_type (const Babl *format, PikaComponentType component) { g_return_val_if_fail (format != NULL, NULL); return pika_babl_format (pika_babl_format_get_base_type (format), pika_babl_precision ( component, pika_babl_format_get_trc (format)), babl_format_has_alpha (format), babl_format_get_space (format)); } const Babl * pika_babl_format_change_trc (const Babl *format, PikaTRCType trc) { g_return_val_if_fail (format != NULL, NULL); return pika_babl_format (pika_babl_format_get_base_type (format), pika_babl_precision ( pika_babl_format_get_component_type (format), trc), babl_format_has_alpha (format), babl_format_get_space (format)); } gchar ** pika_babl_print_pixel (const Babl *format, gpointer pixel) { PikaPrecision precision; gint n_components; guchar tmp_pixel[32]; gchar **strings; g_return_val_if_fail (format != NULL, NULL); g_return_val_if_fail (pixel != NULL, NULL); precision = pika_babl_format_get_precision (format); if (babl_format_is_palette (format)) { const Babl *f = pika_babl_format (PIKA_RGB, precision, babl_format_has_alpha (format), babl_format_get_space (format)); babl_process (babl_fish (format, f), pixel, tmp_pixel, 1); format = f; pixel = tmp_pixel; } n_components = babl_format_get_n_components (format); strings = g_new0 (gchar *, n_components + 1); switch (pika_babl_format_get_component_type (format)) { case PIKA_COMPONENT_TYPE_U8: { guchar *color = pixel; gint i; for (i = 0; i < n_components; i++) strings[i] = g_strdup_printf ("%d", color[i]); } break; case PIKA_COMPONENT_TYPE_U16: { guint16 *color = pixel; gint i; for (i = 0; i < n_components; i++) strings[i] = g_strdup_printf ("%u", color[i]); } break; case PIKA_COMPONENT_TYPE_U32: { guint32 *color = pixel; gint i; for (i = 0; i < n_components; i++) strings[i] = g_strdup_printf ("%u", color[i]); } break; case PIKA_COMPONENT_TYPE_HALF: { PikaPrecision p; const Babl *f; p = pika_babl_precision (PIKA_COMPONENT_TYPE_FLOAT, pika_babl_format_get_trc (format)); f = pika_babl_format (pika_babl_format_get_base_type (format), p, babl_format_has_alpha (format), babl_format_get_space (format)); babl_process (babl_fish (format, f), pixel, tmp_pixel, 1); pixel = tmp_pixel; } /* fall through */ case PIKA_COMPONENT_TYPE_FLOAT: { gfloat *color = pixel; gint i; for (i = 0; i < n_components; i++) strings[i] = g_strdup_printf ("%0.6f", color[i]); } break; case PIKA_COMPONENT_TYPE_DOUBLE: { gdouble *color = pixel; gint i; for (i = 0; i < n_components; i++) strings[i] = g_strdup_printf ("%0.6f", color[i]); } break; } return strings; }