1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimppickable.c
5 * Copyright (C) 2004 Michael Natterer <mitch@gimp.org>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 /* This file contains an interface for pixel objects that their color at
22 * a given position can be picked. Also included is a utility for
23 * sampling an average area (which uses the implemented picking
24 * functions).
25 */
26
27 #include "config.h"
28
29 #include <string.h>
30
31 #include <cairo.h>
32 #include <gegl.h>
33 #include <gdk-pixbuf/gdk-pixbuf.h>
34
35 #include "libgimpcolor/gimpcolor.h"
36 #include "libgimpmath/gimpmath.h"
37
38 #include "core-types.h"
39
40 #include "gimpobject.h"
41 #include "gimpimage.h"
42 #include "gimppickable.h"
43
44
45 /* local function prototypes */
46
47 static void gimp_pickable_real_get_pixel_average (GimpPickable *pickable,
48 const GeglRectangle *rect,
49 const Babl *format,
50 gpointer pixel);
51
52
G_DEFINE_INTERFACE(GimpPickable,gimp_pickable,GIMP_TYPE_OBJECT)53 G_DEFINE_INTERFACE (GimpPickable, gimp_pickable, GIMP_TYPE_OBJECT)
54
55
56 /* private functions */
57
58
59 static void
60 gimp_pickable_default_init (GimpPickableInterface *iface)
61 {
62 iface->get_pixel_average = gimp_pickable_real_get_pixel_average;
63
64 g_object_interface_install_property (iface,
65 g_param_spec_object ("buffer",
66 NULL, NULL,
67 GEGL_TYPE_BUFFER,
68 GIMP_PARAM_READABLE));
69 }
70
71 static void
gimp_pickable_real_get_pixel_average(GimpPickable * pickable,const GeglRectangle * rect,const Babl * format,gpointer pixel)72 gimp_pickable_real_get_pixel_average (GimpPickable *pickable,
73 const GeglRectangle *rect,
74 const Babl *format,
75 gpointer pixel)
76 {
77 const Babl *average_format = babl_format ("RaGaBaA double");
78 gdouble average[4] = {};
79 gint n = 0;
80 gint x;
81 gint y;
82 gint c;
83
84 for (y = rect->y; y < rect->y + rect->height; y++)
85 {
86 for (x = rect->x; x < rect->x + rect->width; x++)
87 {
88 gdouble sample[4];
89
90 if (gimp_pickable_get_pixel_at (pickable,
91 x, y, average_format, sample))
92 {
93 for (c = 0; c < 4; c++)
94 average[c] += sample[c];
95
96 n++;
97 }
98 }
99 }
100
101 if (n > 0)
102 {
103 for (c = 0; c < 4; c++)
104 average[c] /= n;
105 }
106
107 babl_process (babl_fish (average_format, format), average, pixel, 1);
108 }
109
110
111 /* public functions */
112
113
114 void
gimp_pickable_flush(GimpPickable * pickable)115 gimp_pickable_flush (GimpPickable *pickable)
116 {
117 GimpPickableInterface *pickable_iface;
118
119 g_return_if_fail (GIMP_IS_PICKABLE (pickable));
120
121 pickable_iface = GIMP_PICKABLE_GET_INTERFACE (pickable);
122
123 if (pickable_iface->flush)
124 pickable_iface->flush (pickable);
125 }
126
127 GimpImage *
gimp_pickable_get_image(GimpPickable * pickable)128 gimp_pickable_get_image (GimpPickable *pickable)
129 {
130 GimpPickableInterface *pickable_iface;
131
132 g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
133
134 pickable_iface = GIMP_PICKABLE_GET_INTERFACE (pickable);
135
136 if (pickable_iface->get_image)
137 return pickable_iface->get_image (pickable);
138
139 return NULL;
140 }
141
142 const Babl *
gimp_pickable_get_format(GimpPickable * pickable)143 gimp_pickable_get_format (GimpPickable *pickable)
144 {
145 GimpPickableInterface *pickable_iface;
146
147 g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
148
149 pickable_iface = GIMP_PICKABLE_GET_INTERFACE (pickable);
150
151 if (pickable_iface->get_format)
152 return pickable_iface->get_format (pickable);
153
154 return NULL;
155 }
156
157 const Babl *
gimp_pickable_get_format_with_alpha(GimpPickable * pickable)158 gimp_pickable_get_format_with_alpha (GimpPickable *pickable)
159 {
160 GimpPickableInterface *pickable_iface;
161
162 g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
163
164 pickable_iface = GIMP_PICKABLE_GET_INTERFACE (pickable);
165
166 if (pickable_iface->get_format_with_alpha)
167 return pickable_iface->get_format_with_alpha (pickable);
168
169 return NULL;
170 }
171
172 GeglBuffer *
gimp_pickable_get_buffer(GimpPickable * pickable)173 gimp_pickable_get_buffer (GimpPickable *pickable)
174 {
175 GimpPickableInterface *pickable_iface;
176
177 g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
178
179 pickable_iface = GIMP_PICKABLE_GET_INTERFACE (pickable);
180
181 if (pickable_iface->get_buffer)
182 return pickable_iface->get_buffer (pickable);
183
184 return NULL;
185 }
186
187 gboolean
gimp_pickable_get_pixel_at(GimpPickable * pickable,gint x,gint y,const Babl * format,gpointer pixel)188 gimp_pickable_get_pixel_at (GimpPickable *pickable,
189 gint x,
190 gint y,
191 const Babl *format,
192 gpointer pixel)
193 {
194 GimpPickableInterface *pickable_iface;
195
196 g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), FALSE);
197 g_return_val_if_fail (pixel != NULL, FALSE);
198
199 if (! format)
200 format = gimp_pickable_get_format (pickable);
201
202 pickable_iface = GIMP_PICKABLE_GET_INTERFACE (pickable);
203
204 if (pickable_iface->get_pixel_at)
205 return pickable_iface->get_pixel_at (pickable, x, y, format, pixel);
206
207 return FALSE;
208 }
209
210 void
gimp_pickable_get_pixel_average(GimpPickable * pickable,const GeglRectangle * rect,const Babl * format,gpointer pixel)211 gimp_pickable_get_pixel_average (GimpPickable *pickable,
212 const GeglRectangle *rect,
213 const Babl *format,
214 gpointer pixel)
215 {
216 GimpPickableInterface *pickable_iface;
217
218 g_return_if_fail (GIMP_IS_PICKABLE (pickable));
219 g_return_if_fail (rect != NULL);
220 g_return_if_fail (pixel != NULL);
221
222 if (! format)
223 format = gimp_pickable_get_format (pickable);
224
225 pickable_iface = GIMP_PICKABLE_GET_INTERFACE (pickable);
226
227 if (pickable_iface->get_pixel_average)
228 pickable_iface->get_pixel_average (pickable, rect, format, pixel);
229 else
230 memset (pixel, 0, babl_format_get_bytes_per_pixel (format));
231 }
232
233 gboolean
gimp_pickable_get_color_at(GimpPickable * pickable,gint x,gint y,GimpRGB * color)234 gimp_pickable_get_color_at (GimpPickable *pickable,
235 gint x,
236 gint y,
237 GimpRGB *color)
238 {
239 gdouble pixel[4];
240
241 g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), FALSE);
242 g_return_val_if_fail (color != NULL, FALSE);
243
244 if (! gimp_pickable_get_pixel_at (pickable, x, y, NULL, pixel))
245 return FALSE;
246
247 gimp_pickable_pixel_to_srgb (pickable, NULL, pixel, color);
248
249 return TRUE;
250 }
251
252 gdouble
gimp_pickable_get_opacity_at(GimpPickable * pickable,gint x,gint y)253 gimp_pickable_get_opacity_at (GimpPickable *pickable,
254 gint x,
255 gint y)
256 {
257 GimpPickableInterface *pickable_iface;
258
259 g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), GIMP_OPACITY_TRANSPARENT);
260
261 pickable_iface = GIMP_PICKABLE_GET_INTERFACE (pickable);
262
263 if (pickable_iface->get_opacity_at)
264 return pickable_iface->get_opacity_at (pickable, x, y);
265
266 return GIMP_OPACITY_TRANSPARENT;
267 }
268
269 void
gimp_pickable_pixel_to_srgb(GimpPickable * pickable,const Babl * format,gpointer pixel,GimpRGB * color)270 gimp_pickable_pixel_to_srgb (GimpPickable *pickable,
271 const Babl *format,
272 gpointer pixel,
273 GimpRGB *color)
274 {
275 GimpPickableInterface *pickable_iface;
276
277 g_return_if_fail (GIMP_IS_PICKABLE (pickable));
278 g_return_if_fail (pixel != NULL);
279 g_return_if_fail (color != NULL);
280
281 if (! format)
282 format = gimp_pickable_get_format (pickable);
283
284 pickable_iface = GIMP_PICKABLE_GET_INTERFACE (pickable);
285
286 if (pickable_iface->pixel_to_srgb)
287 {
288 pickable_iface->pixel_to_srgb (pickable, format, pixel, color);
289 }
290 else
291 {
292 gimp_rgba_set_pixel (color, format, pixel);
293 }
294 }
295
296 void
gimp_pickable_srgb_to_pixel(GimpPickable * pickable,const GimpRGB * color,const Babl * format,gpointer pixel)297 gimp_pickable_srgb_to_pixel (GimpPickable *pickable,
298 const GimpRGB *color,
299 const Babl *format,
300 gpointer pixel)
301 {
302 GimpPickableInterface *pickable_iface;
303
304 g_return_if_fail (GIMP_IS_PICKABLE (pickable));
305 g_return_if_fail (color != NULL);
306 g_return_if_fail (pixel != NULL);
307
308 if (! format)
309 format = gimp_pickable_get_format (pickable);
310
311 pickable_iface = GIMP_PICKABLE_GET_INTERFACE (pickable);
312
313 if (pickable_iface->srgb_to_pixel)
314 {
315 pickable_iface->srgb_to_pixel (pickable, color, format, pixel);
316 }
317 else
318 {
319 gimp_rgba_get_pixel (color, format, pixel);
320 }
321 }
322
323 void
gimp_pickable_srgb_to_image_color(GimpPickable * pickable,const GimpRGB * color,GimpRGB * image_color)324 gimp_pickable_srgb_to_image_color (GimpPickable *pickable,
325 const GimpRGB *color,
326 GimpRGB *image_color)
327 {
328 g_return_if_fail (GIMP_IS_PICKABLE (pickable));
329 g_return_if_fail (color != NULL);
330 g_return_if_fail (image_color != NULL);
331
332 gimp_pickable_srgb_to_pixel (pickable,
333 color,
334 babl_format ("R'G'B'A double"),
335 image_color);
336 }
337
338 gboolean
gimp_pickable_pick_color(GimpPickable * pickable,gint x,gint y,gboolean sample_average,gdouble average_radius,gpointer pixel,GimpRGB * color)339 gimp_pickable_pick_color (GimpPickable *pickable,
340 gint x,
341 gint y,
342 gboolean sample_average,
343 gdouble average_radius,
344 gpointer pixel,
345 GimpRGB *color)
346 {
347 const Babl *format;
348 gdouble sample[4];
349
350 g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), FALSE);
351 g_return_val_if_fail (color != NULL, FALSE);
352
353 format = gimp_pickable_get_format (pickable);
354
355 if (! gimp_pickable_get_pixel_at (pickable, x, y, format, sample))
356 return FALSE;
357
358 if (pixel)
359 memcpy (pixel, sample, babl_format_get_bytes_per_pixel (format));
360
361 if (sample_average)
362 {
363 gint radius = floor (average_radius);
364
365 format = babl_format ("RaGaBaA double");
366
367 gimp_pickable_get_pixel_average (pickable,
368 GEGL_RECTANGLE (x - radius,
369 y - radius,
370 2 * radius + 1,
371 2 * radius + 1),
372 format, sample);
373 }
374
375 gimp_pickable_pixel_to_srgb (pickable, format, sample, color);
376
377 return TRUE;
378 }
379