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