1 /* This file is an image processing operation for GEGL 2 * 3 * GEGL is free software; you can redistribute it and/or 4 * modify it under the terms of the GNU Lesser General Public 5 * License as published by the Free Software Foundation; either 6 * version 3 of the License, or (at your option) any later version. 7 * 8 * GEGL is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * Lesser General Public License for more details. 12 * 13 * You should have received a copy of the GNU Lesser General Public 14 * License along with GEGL; if not, see <https://www.gnu.org/licenses/>. 15 * 16 * Copyright 2015 Thomas Manni <thomas.manni@free.fr> 17 */ 18 19 #include "config.h" 20 #include <glib/gi18n-lib.h> 21 22 #ifdef GEGL_PROPERTIES 23 24 enum_start (gegl_component_extract) 25 enum_value (GEGL_COMPONENT_EXTRACT_RGB_RED, "rgb-r", N_("RGB Red")) 26 enum_value (GEGL_COMPONENT_EXTRACT_RGB_GREEN, "rgb-g", N_("RGB Green")) 27 enum_value (GEGL_COMPONENT_EXTRACT_RGB_BLUE, "rgb-b", N_("RGB Blue")) 28 enum_value (GEGL_COMPONENT_EXTRACT_HUE, "hue", N_("Hue")) 29 enum_value (GEGL_COMPONENT_EXTRACT_HSV_SATURATION, "hsv-s", N_("HSV Saturation")) 30 enum_value (GEGL_COMPONENT_EXTRACT_HSV_VALUE, "hsv-v", N_("HSV Value")) 31 enum_value (GEGL_COMPONENT_EXTRACT_HSL_SATURATION, "hsl-s", N_("HSL Saturation")) 32 enum_value (GEGL_COMPONENT_EXTRACT_HSL_LIGHTNESS, "hsl-l", N_("HSL Lightness")) 33 enum_value (GEGL_COMPONENT_EXTRACT_CMYK_CYAN, "cmyk-c", N_("CMYK Cyan")) 34 enum_value (GEGL_COMPONENT_EXTRACT_CMYK_MAGENTA, "cmyk-m", N_("CMYK Magenta")) 35 enum_value (GEGL_COMPONENT_EXTRACT_CMYK_YELLOW, "cmyk-y", N_("CMYK Yellow")) 36 enum_value (GEGL_COMPONENT_EXTRACT_CMYK_KEY, "cmyk-k", N_("CMYK Key")) 37 enum_value (GEGL_COMPONENT_EXTRACT_YCBCR_Y, "ycbcr-y", N_("Y'CbCr Y'")) 38 enum_value (GEGL_COMPONENT_EXTRACT_YCBCR_CB, "ycbcr-cb", N_("Y'CbCr Cb")) 39 enum_value (GEGL_COMPONENT_EXTRACT_YCBCR_CR, "ycbcr-cr", N_("Y'CbCr Cr")) 40 enum_value (GEGL_COMPONENT_EXTRACT_LAB_L, "lab-l", N_("LAB L")) 41 enum_value (GEGL_COMPONENT_EXTRACT_LAB_A, "lab-a", N_("LAB A")) 42 enum_value (GEGL_COMPONENT_EXTRACT_LAB_B, "lab-b", N_("LAB B")) 43 enum_value (GEGL_COMPONENT_EXTRACT_LCH_C, "lch-c", N_("LCH C(ab)")) 44 enum_value (GEGL_COMPONENT_EXTRACT_LCH_H, "lch-h", N_("LCH H(ab)")) 45 enum_value (GEGL_COMPONENT_EXTRACT_ALPHA, "alpha", N_("Alpha")) 46 enum_end (GeglComponentExtract) 47 48 property_enum (component, _("Component"), 49 GeglComponentExtract, gegl_component_extract, 50 GEGL_COMPONENT_EXTRACT_RGB_RED) 51 description (_("Component to extract")) 52 53 property_boolean (invert, _("Invert component"), FALSE) 54 description (_("Invert the extracted component")) 55 56 property_boolean (linear, _("Linear output"), FALSE) 57 description (_("Use linear output instead of gamma corrected")) 58 59 #else 60 61 #define GEGL_OP_POINT_FILTER 62 #define GEGL_OP_NAME component_extract 63 #define GEGL_OP_C_SOURCE component-extract.c 64 65 #include "gegl-op.h" 66 67 static void 68 prepare (GeglOperation *operation) 69 { 70 const Babl *space = gegl_operation_get_source_space (operation, "input"); 71 GeglProperties *o = GEGL_PROPERTIES (operation); 72 const Babl *input_format = NULL; 73 const Babl *output_format = (o->linear ? 74 babl_format_with_space ("Y float", space) : 75 babl_format_with_space ("Y' float", space)); 76 77 switch (o->component) 78 { 79 case GEGL_COMPONENT_EXTRACT_ALPHA: 80 input_format = babl_format_with_space ("YA float", space); 81 break; 82 83 case GEGL_COMPONENT_EXTRACT_RGB_RED: 84 case GEGL_COMPONENT_EXTRACT_RGB_GREEN: 85 case GEGL_COMPONENT_EXTRACT_RGB_BLUE: 86 input_format = babl_format_with_space ("R'G'B' float", space); 87 break; 88 89 case GEGL_COMPONENT_EXTRACT_HUE: 90 case GEGL_COMPONENT_EXTRACT_HSV_SATURATION: 91 case GEGL_COMPONENT_EXTRACT_HSV_VALUE: 92 input_format = babl_format_with_space ("HSV float", space); 93 break; 94 95 case GEGL_COMPONENT_EXTRACT_HSL_LIGHTNESS: 96 case GEGL_COMPONENT_EXTRACT_HSL_SATURATION: 97 input_format = babl_format_with_space ("HSL float", space); 98 break; 99 100 case GEGL_COMPONENT_EXTRACT_CMYK_CYAN: 101 case GEGL_COMPONENT_EXTRACT_CMYK_MAGENTA: 102 case GEGL_COMPONENT_EXTRACT_CMYK_YELLOW: 103 case GEGL_COMPONENT_EXTRACT_CMYK_KEY: 104 input_format = babl_format_with_space ("CMYK float", space); 105 break; 106 107 case GEGL_COMPONENT_EXTRACT_YCBCR_Y: 108 case GEGL_COMPONENT_EXTRACT_YCBCR_CB: 109 case GEGL_COMPONENT_EXTRACT_YCBCR_CR: 110 input_format = babl_format_with_space ("Y'CbCr float", space); 111 break; 112 113 case GEGL_COMPONENT_EXTRACT_LAB_L: 114 case GEGL_COMPONENT_EXTRACT_LAB_A: 115 case GEGL_COMPONENT_EXTRACT_LAB_B: 116 input_format = babl_format_with_space ("CIE Lab float", space); 117 break; 118 119 case GEGL_COMPONENT_EXTRACT_LCH_C: 120 case GEGL_COMPONENT_EXTRACT_LCH_H: 121 input_format = babl_format_with_space ("CIE LCH(ab) float", space); 122 break; 123 } 124 125 gegl_operation_set_format (operation, "input", input_format); 126 gegl_operation_set_format (operation, "output", output_format); 127 } 128 129 static gboolean 130 process (GeglOperation *operation, 131 void *in_buf, 132 void *out_buf, 133 glong samples, 134 const GeglRectangle *roi, 135 gint level) 136 { 137 GeglProperties *o = GEGL_PROPERTIES (operation); 138 const Babl *format = gegl_operation_get_format (operation, "input"); 139 gfloat *in = in_buf; 140 gfloat *out = out_buf; 141 gint component_index = 0; 142 gint n_components; 143 gdouble min = 0.0; 144 gdouble max = 1.0; 145 146 n_components = babl_format_get_n_components (format); 147 148 switch (o->component) 149 { 150 case GEGL_COMPONENT_EXTRACT_RGB_RED: 151 case GEGL_COMPONENT_EXTRACT_HUE: 152 case GEGL_COMPONENT_EXTRACT_CMYK_CYAN: 153 case GEGL_COMPONENT_EXTRACT_YCBCR_Y: 154 case GEGL_COMPONENT_EXTRACT_LAB_L: 155 component_index = 0; 156 157 if (o->component == GEGL_COMPONENT_EXTRACT_LAB_L) 158 { 159 max = 100.0; 160 } 161 break; 162 163 case GEGL_COMPONENT_EXTRACT_RGB_GREEN: 164 case GEGL_COMPONENT_EXTRACT_HSV_SATURATION: 165 case GEGL_COMPONENT_EXTRACT_HSL_SATURATION: 166 case GEGL_COMPONENT_EXTRACT_CMYK_MAGENTA: 167 case GEGL_COMPONENT_EXTRACT_YCBCR_CB: 168 case GEGL_COMPONENT_EXTRACT_LAB_A: 169 case GEGL_COMPONENT_EXTRACT_LCH_C: 170 case GEGL_COMPONENT_EXTRACT_ALPHA: 171 component_index = 1; 172 173 if (o->component == GEGL_COMPONENT_EXTRACT_YCBCR_CB) 174 { 175 min = -0.5; 176 max = 0.5; 177 } 178 else if (o->component == GEGL_COMPONENT_EXTRACT_LAB_A) 179 { 180 min = -127.5; 181 max = 127.5; 182 } 183 else if (o->component == GEGL_COMPONENT_EXTRACT_LCH_C) 184 { 185 max = 200.0; 186 } 187 break; 188 189 case GEGL_COMPONENT_EXTRACT_RGB_BLUE: 190 case GEGL_COMPONENT_EXTRACT_HSV_VALUE: 191 case GEGL_COMPONENT_EXTRACT_HSL_LIGHTNESS: 192 case GEGL_COMPONENT_EXTRACT_CMYK_YELLOW: 193 case GEGL_COMPONENT_EXTRACT_YCBCR_CR: 194 case GEGL_COMPONENT_EXTRACT_LAB_B: 195 case GEGL_COMPONENT_EXTRACT_LCH_H: 196 component_index = 2; 197 198 if (o->component == GEGL_COMPONENT_EXTRACT_YCBCR_CR) 199 { 200 min = -0.5; 201 max = 0.5; 202 } 203 else if (o->component == GEGL_COMPONENT_EXTRACT_LAB_B) 204 { 205 min = -127.5; 206 max = 127.5; 207 } 208 else if (o->component == GEGL_COMPONENT_EXTRACT_LCH_H) 209 { 210 min = 0.0; 211 max = 360.0; 212 } 213 break; 214 215 case GEGL_COMPONENT_EXTRACT_CMYK_KEY: 216 component_index = 3; 217 break; 218 } 219 220 while (samples--) 221 { 222 gdouble value = in[component_index]; 223 224 if (min != 0.0 || max != 1.0) 225 { 226 gdouble scale = 1.0 / (max - min); 227 gdouble offset = -min; 228 229 value = CLAMP ((value + offset) * scale, 0.0, 1.0); 230 } 231 232 if (o->invert) 233 out[0] = 1.0 - value; 234 else 235 out[0] = value; 236 237 in += n_components; 238 out += 1; 239 } 240 241 242 return TRUE; 243 } 244 245 static void 246 gegl_op_class_init (GeglOpClass *klass) 247 { 248 GeglOperationClass *operation_class; 249 GeglOperationPointFilterClass *point_filter_class; 250 251 operation_class = GEGL_OPERATION_CLASS (klass); 252 point_filter_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); 253 254 operation_class->prepare = prepare; 255 operation_class->opencl_support = FALSE; 256 point_filter_class->process = process; 257 258 gegl_operation_class_set_keys (operation_class, 259 "name", "gegl:component-extract", 260 "title", _("Extract Component"), 261 "reference-hash", "9e9128c635e84fd177d733ba300d6ef5", 262 "reference-hashB", "1ad6d3caf43fd510eddb8b890103b5c9", 263 "categories", "color", 264 "description", _("Extract a color model component"), 265 NULL); 266 } 267 268 #endif 269