1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <cairo.h>
21 #include <gdk-pixbuf/gdk-pixbuf.h>
22 #include <gegl.h>
23 
24 #include "libgimpbase/gimpbase.h"
25 #include "libgimpcolor/gimpcolor.h"
26 
27 #include "core/core-types.h"
28 
29 #include "core/gimp.h"
30 #include "core/gimpbrush.h"
31 #include "core/gimpbrush-load.h"
32 #include "core/gimpbrush-private.h"
33 #include "core/gimpdrawable.h"
34 #include "core/gimpimage.h"
35 #include "core/gimplayer-new.h"
36 #include "core/gimpimage-resize.h"
37 #include "core/gimpparamspecs.h"
38 #include "core/gimptempbuf.h"
39 
40 #include "pdb/gimpprocedure.h"
41 
42 #include "file-data-gbr.h"
43 
44 #include "gimp-intl.h"
45 
46 
47 /*  local function prototypes  */
48 
49 static GimpImage * file_gbr_brush_to_image (Gimp         *gimp,
50                                             GimpBrush    *brush);
51 static GimpBrush * file_gbr_image_to_brush (GimpImage    *image,
52                                             GimpDrawable *drawable,
53                                             const gchar  *name,
54                                             gdouble       spacing);
55 
56 
57 /*  public functions  */
58 
59 GimpValueArray *
file_gbr_load_invoker(GimpProcedure * procedure,Gimp * gimp,GimpContext * context,GimpProgress * progress,const GimpValueArray * args,GError ** error)60 file_gbr_load_invoker (GimpProcedure         *procedure,
61                        Gimp                  *gimp,
62                        GimpContext           *context,
63                        GimpProgress          *progress,
64                        const GimpValueArray  *args,
65                        GError               **error)
66 {
67   GimpValueArray *return_vals;
68   GimpImage      *image = NULL;
69   const gchar    *uri;
70   GFile          *file;
71   GInputStream   *input;
72   GError         *my_error = NULL;
73 
74   gimp_set_busy (gimp);
75 
76   uri  = g_value_get_string (gimp_value_array_index (args, 1));
77   file = g_file_new_for_uri (uri);
78 
79   input = G_INPUT_STREAM (g_file_read (file, NULL, &my_error));
80 
81   if (input)
82     {
83       GimpBrush *brush = gimp_brush_load_brush (context, file, input, error);
84 
85       if (brush)
86         {
87           image = file_gbr_brush_to_image (gimp, brush);
88           g_object_unref (brush);
89         }
90 
91       g_object_unref (input);
92     }
93   else
94     {
95       g_propagate_prefixed_error (error, my_error,
96                                   _("Could not open '%s' for reading: "),
97                                   gimp_file_get_utf8_name (file));
98     }
99 
100   g_object_unref (file);
101 
102   return_vals = gimp_procedure_get_return_values (procedure, image != NULL,
103                                                   error ? *error : NULL);
104 
105   if (image)
106     gimp_value_set_image (gimp_value_array_index (return_vals, 1), image);
107 
108   gimp_unset_busy (gimp);
109 
110   return return_vals;
111 }
112 
113 GimpValueArray *
file_gbr_save_invoker(GimpProcedure * procedure,Gimp * gimp,GimpContext * context,GimpProgress * progress,const GimpValueArray * args,GError ** error)114 file_gbr_save_invoker (GimpProcedure         *procedure,
115                        Gimp                  *gimp,
116                        GimpContext           *context,
117                        GimpProgress          *progress,
118                        const GimpValueArray  *args,
119                        GError               **error)
120 {
121   GimpValueArray *return_vals;
122   GimpImage      *image;
123   GimpDrawable   *drawable;
124   GimpBrush      *brush;
125   const gchar    *uri;
126   const gchar    *name;
127   GFile          *file;
128   gint            spacing;
129   gboolean        success;
130 
131   gimp_set_busy (gimp);
132 
133   image    = gimp_value_get_image (gimp_value_array_index (args, 1), gimp);
134   drawable = gimp_value_get_drawable (gimp_value_array_index (args, 2), gimp);
135   uri      = g_value_get_string (gimp_value_array_index (args, 3));
136   spacing  = g_value_get_int (gimp_value_array_index (args, 5));
137   name     = g_value_get_string (gimp_value_array_index (args, 6));
138 
139   file = g_file_new_for_uri (uri);
140 
141   brush = file_gbr_image_to_brush (image, drawable, name, spacing);
142 
143   gimp_data_set_file (GIMP_DATA (brush), file, TRUE, TRUE);
144 
145   success = gimp_data_save (GIMP_DATA (brush), error);
146 
147   g_object_unref (brush);
148   g_object_unref (file);
149 
150   return_vals = gimp_procedure_get_return_values (procedure, success,
151                                                   error ? *error : NULL);
152 
153   gimp_unset_busy (gimp);
154 
155   return return_vals;
156 }
157 
158 GimpLayer *
file_gbr_brush_to_layer(GimpImage * image,GimpBrush * brush)159 file_gbr_brush_to_layer (GimpImage *image,
160                          GimpBrush *brush)
161 {
162   GimpLayer    *layer;
163   const Babl   *format;
164   gboolean      alpha;
165   gint          width;
166   gint          height;
167   gint          image_width;
168   gint          image_height;
169   GimpTempBuf  *mask;
170   GimpTempBuf  *pixmap;
171   GeglBuffer   *buffer;
172 
173   g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
174   g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
175 
176   mask   = gimp_brush_get_mask   (brush);
177   pixmap = gimp_brush_get_pixmap (brush);
178 
179   if (pixmap)
180     alpha = TRUE;
181   else
182     alpha = FALSE;
183 
184   width  = gimp_temp_buf_get_width  (mask);
185   height = gimp_temp_buf_get_height (mask);
186 
187   image_width  = gimp_image_get_width  (image);
188   image_height = gimp_image_get_height (image);
189 
190   if (width > image_width || height > image_height)
191     {
192       gint new_width  = MAX (image_width,  width);
193       gint new_height = MAX (image_height, height);
194 
195       gimp_image_resize (image, gimp_get_user_context (image->gimp),
196                          new_width, new_height,
197                          (new_width  - image_width) / 2,
198                          (new_height - image_height) / 2,
199                          NULL);
200 
201       image_width  = new_width;
202       image_height = new_height;
203     }
204 
205   format = gimp_image_get_layer_format (image, alpha);
206 
207   layer = gimp_layer_new (image, width, height, format,
208                           gimp_object_get_name (brush),
209                           1.0, GIMP_LAYER_MODE_NORMAL);
210 
211   gimp_item_set_offset (GIMP_ITEM (layer),
212                         (image_width  - width)  / 2,
213                         (image_height - height) / 2);
214 
215   buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
216 
217   if (pixmap)
218     {
219       guchar *pixmap_data;
220       guchar *mask_data;
221       guchar *p;
222       guchar *m;
223       gint    i;
224 
225       gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
226                        babl_format ("R'G'B' u8"),
227                        gimp_temp_buf_get_data (pixmap), GEGL_AUTO_ROWSTRIDE);
228 
229       pixmap_data = gegl_buffer_linear_open (buffer, NULL, NULL, NULL);
230       mask_data   = gimp_temp_buf_get_data (mask);
231 
232       for (i = 0, p = pixmap_data, m = mask_data;
233            i < width * height;
234            i++, p += 4, m += 1)
235         {
236           p[3] = *m;
237         }
238 
239       gegl_buffer_linear_close (buffer, pixmap_data);
240     }
241   else
242     {
243       guchar *mask_data = gimp_temp_buf_get_data (mask);
244       gint    i;
245 
246       for (i = 0; i < width * height; i++)
247         mask_data[i] = 255 - mask_data[i];
248 
249       gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
250                        babl_format ("Y' u8"),
251                        mask_data, GEGL_AUTO_ROWSTRIDE);
252     }
253 
254   return layer;
255 }
256 
257 GimpBrush *
file_gbr_drawable_to_brush(GimpDrawable * drawable,const GeglRectangle * rect,const gchar * name,gdouble spacing)258 file_gbr_drawable_to_brush (GimpDrawable        *drawable,
259                             const GeglRectangle *rect,
260                             const gchar         *name,
261                             gdouble              spacing)
262 {
263   GimpBrush   *brush;
264   GeglBuffer  *buffer;
265   GimpTempBuf *mask;
266   GimpTempBuf *pixmap = NULL;
267   gint         width;
268   gint         height;
269 
270   g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
271   g_return_val_if_fail (rect != NULL, NULL);
272 
273   buffer = gimp_drawable_get_buffer (drawable);
274   width  = rect->width;
275   height = rect->height;
276 
277   brush = g_object_new (GIMP_TYPE_BRUSH,
278                         "name",      name,
279                         "mime-type", "image/x-gimp-gbr",
280                         "spacing",   spacing,
281                         NULL);
282 
283   mask = gimp_temp_buf_new (width, height, babl_format ("Y u8"));
284 
285   if (gimp_drawable_is_gray (drawable))
286     {
287       guchar *m = gimp_temp_buf_get_data (mask);
288       gint    i;
289 
290       if (gimp_drawable_has_alpha (drawable))
291         {
292           GeglBufferIterator *iter;
293           GimpRGB             white;
294 
295           gimp_rgba_set_uchar (&white, 255, 255, 255, 255);
296 
297           iter = gegl_buffer_iterator_new (buffer, rect, 0,
298                                            babl_format ("Y'A u8"),
299                                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE,
300                                            1);
301 
302           while (gegl_buffer_iterator_next (iter))
303             {
304               guint8 *data = (guint8 *) iter->items[0].data;
305               gint    j;
306 
307               for (j = 0; j < iter->length; j++)
308                 {
309                   GimpRGB gray;
310                   gint    x, y;
311                   gint    dest;
312 
313                   gimp_rgba_set_uchar (&gray,
314                                        data[0], data[0], data[0],
315                                        data[1]);
316 
317                   gimp_rgb_composite (&gray, &white,
318                                       GIMP_RGB_COMPOSITE_BEHIND);
319 
320                   x = iter->items[0].roi.x + j % iter->items[0].roi.width;
321                   y = iter->items[0].roi.y + j / iter->items[0].roi.width;
322 
323                   dest = y * width + x;
324 
325                   gimp_rgba_get_uchar (&gray, &m[dest], NULL, NULL, NULL);
326 
327                   data += 2;
328                 }
329             }
330         }
331       else
332         {
333           gegl_buffer_get (buffer, rect, 1.0,
334                            babl_format ("Y' u8"), m,
335                            GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
336         }
337 
338       /*  invert  */
339       for (i = 0; i < width * height; i++)
340         m[i] = 255 - m[i];
341     }
342   else
343     {
344       pixmap = gimp_temp_buf_new (width, height, babl_format ("R'G'B' u8"));
345 
346       gegl_buffer_get (buffer, rect, 1.0,
347                        babl_format ("R'G'B' u8"),
348                        gimp_temp_buf_get_data (pixmap),
349                        GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
350 
351       gegl_buffer_get (buffer, rect, 1.0,
352                        babl_format ("A u8"),
353                        gimp_temp_buf_get_data (mask),
354                        GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
355     }
356 
357 
358   brush->priv->mask   = mask;
359   brush->priv->pixmap = pixmap;
360 
361   return brush;
362 }
363 
364 
365 /*  private functions  */
366 
367 static GimpImage *
file_gbr_brush_to_image(Gimp * gimp,GimpBrush * brush)368 file_gbr_brush_to_image (Gimp      *gimp,
369                          GimpBrush *brush)
370 {
371   GimpImage         *image;
372   GimpLayer         *layer;
373   const gchar       *name;
374   GimpImageBaseType  base_type;
375   gint               width;
376   gint               height;
377   GimpTempBuf       *mask   = gimp_brush_get_mask   (brush);
378   GimpTempBuf       *pixmap = gimp_brush_get_pixmap (brush);
379   GimpParasite      *parasite;
380 
381   if (pixmap)
382     base_type = GIMP_RGB;
383   else
384     base_type = GIMP_GRAY;
385 
386   name   = gimp_object_get_name (brush);
387   width  = gimp_temp_buf_get_width  (mask);
388   height = gimp_temp_buf_get_height (mask);
389 
390   image = gimp_image_new (gimp, width, height, base_type,
391                           GIMP_PRECISION_U8_GAMMA);
392 
393   parasite = gimp_parasite_new ("gimp-brush-name",
394                                 GIMP_PARASITE_PERSISTENT,
395                                 strlen (name) + 1, name);
396   gimp_image_parasite_attach (image, parasite, FALSE);
397   gimp_parasite_free (parasite);
398 
399   layer = file_gbr_brush_to_layer (image, brush);
400   gimp_image_add_layer (image, layer, NULL, 0, FALSE);
401 
402   return image;
403 }
404 
405 static GimpBrush *
file_gbr_image_to_brush(GimpImage * image,GimpDrawable * drawable,const gchar * name,gdouble spacing)406 file_gbr_image_to_brush (GimpImage    *image,
407                          GimpDrawable *drawable,
408                          const gchar  *name,
409                          gdouble       spacing)
410 {
411   gint width  = gimp_item_get_width  (GIMP_ITEM (drawable));
412   gint height = gimp_item_get_height (GIMP_ITEM (drawable));
413 
414   return file_gbr_drawable_to_brush (drawable,
415                                      GEGL_RECTANGLE (0, 0, width, height),
416                                      name, spacing);
417 }
418