gimpdrawable-blend.c 8.03 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
Elliot Lee's avatar
Elliot Lee committed
2
3
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * This program is free software: you can redistribute it and/or modify
Elliot Lee's avatar
Elliot Lee committed
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
Elliot Lee's avatar
Elliot Lee committed
7
8
9
10
11
12
13
14
 * (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
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
16
 */
Sven Neumann's avatar
Sven Neumann committed
17

18
19
#include "config.h"

20
#include <cairo.h>
21
#include <gegl.h>
22
#include <gdk-pixbuf/gdk-pixbuf.h>
Manish Singh's avatar
Manish Singh committed
23

24
#include "core-types.h"
Sven Neumann's avatar
Sven Neumann committed
25

26
#include "gegl/gimp-gegl-apply-operation.h"
27
28
#include "gegl/gimp-gegl-utils.h"

29
#include "gimp.h"
30
#include "gimpchannel.h"
31
32
33
34
#include "gimpcontext.h"
#include "gimpdrawable-blend.h"
#include "gimpgradient.h"
#include "gimpimage.h"
35
#include "gimpprogress.h"
Sven Neumann's avatar
Sven Neumann committed
36

37
#include "gimp-intl.h"
38

Elliot Lee's avatar
Elliot Lee committed
39

40
/*  public functions  */
41

Michael Natterer's avatar
Michael Natterer committed
42
void
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
gimp_drawable_blend (GimpDrawable       *drawable,
                     GimpContext        *context,
                     GimpGradient       *gradient,
                     GeglDistanceMetric  metric,
                     GimpLayerMode       paint_mode,
                     GimpGradientType    gradient_type,
                     gdouble             opacity,
                     gdouble             offset,
                     GimpRepeatMode      repeat,
                     gboolean            reverse,
                     gboolean            supersample,
                     gint                max_depth,
                     gdouble             threshold,
                     gboolean            dither,
                     gdouble             startx,
                     gdouble             starty,
                     gdouble             endx,
                     gdouble             endy,
                     GimpProgress       *progress)
62
{
63
64
  GimpImage  *image;
  GeglBuffer *buffer;
65
66
  GeglBuffer *shapeburst = NULL;
  GeglNode   *render;
67
  gint        x, y, width, height;
Elliot Lee's avatar
Elliot Lee committed
68

69
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
70
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
71
  g_return_if_fail (GIMP_IS_CONTEXT (context));
72
  g_return_if_fail (GIMP_IS_GRADIENT (gradient));
73
  g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
74

75
  image = gimp_item_get_image (GIMP_ITEM (drawable));
76

77
  if (! gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height))
78
    return;
79

80
  gimp_set_busy (image->gimp);
Elliot Lee's avatar
Elliot Lee committed
81
82

  /*  Always create an alpha temp buf (for generality) */
83
  buffer = gegl_buffer_new (GEGL_RECTANGLE (x, y, width, height),
84
                            gimp_drawable_get_format_with_alpha (drawable));
Elliot Lee's avatar
Elliot Lee committed
85

86
87
88
89
  if (gradient_type >= GIMP_GRADIENT_SHAPEBURST_ANGULAR &&
      gradient_type <= GIMP_GRADIENT_SHAPEBURST_DIMPLED)
    {
      shapeburst =
90
        gimp_drawable_blend_shapeburst_distmap (drawable, metric,
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
                                                GEGL_RECTANGLE (x, y, width, height),
                                                progress);
    }

  render = gegl_node_new_child (NULL,
                                "operation",             "gimp:blend",
                                "context",               context,
                                "gradient",              gradient,
                                "start-x",               startx,
                                "start-y",               starty,
                                "end-x",                 endx,
                                "end-y",                 endy,
                                "gradient-type",         gradient_type,
                                "gradient-repeat",       repeat,
                                "offset",                offset,
                                "gradient-reverse",      reverse,
                                "supersample",           supersample,
                                "supersample-depth",     max_depth,
                                "supersample-threshold", threshold,
                                "dither",                dither,
                                NULL);

  gimp_gegl_apply_operation (shapeburst, progress, NULL,
                             render,
                             buffer, GEGL_RECTANGLE (x, y, width, height));

  g_object_unref (render);

  if (shapeburst)
    g_object_unref (shapeburst);
Elliot Lee's avatar
Elliot Lee committed
121

122
  gimp_drawable_apply_buffer (drawable, buffer,
123
                              GEGL_RECTANGLE (x, y, width, height),
124
                              TRUE, C_("undo-type", "Blend"),
125
126
127
128
                              opacity, paint_mode,
                              GIMP_LAYER_COLOR_SPACE_AUTO,
                              GIMP_LAYER_COLOR_SPACE_AUTO,
                              GIMP_LAYER_COMPOSITE_AUTO,
129
                              NULL, x, y);
Elliot Lee's avatar
Elliot Lee committed
130

131
  gimp_drawable_update (drawable, x, y, width, height);
Elliot Lee's avatar
Elliot Lee committed
132

133
  g_object_unref (buffer);
134

135
  gimp_unset_busy (image->gimp);
Elliot Lee's avatar
Elliot Lee committed
136
137
}

138
139
GeglBuffer *
gimp_drawable_blend_shapeburst_distmap (GimpDrawable        *drawable,
140
                                        GeglDistanceMetric   metric,
141
142
                                        const GeglRectangle *region,
                                        GimpProgress        *progress)
Elliot Lee's avatar
Elliot Lee committed
143
{
Michael Natterer's avatar
Michael Natterer committed
144
  GimpChannel *mask;
145
  GimpImage   *image;
146
  GeglBuffer  *dist_buffer;
147
  GeglBuffer  *temp_buffer;
148
  GeglNode    *shapeburst;
Elliot Lee's avatar
Elliot Lee committed
149

150
151
152
153
154
155
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);

  image = gimp_item_get_image (GIMP_ITEM (drawable));

Elliot Lee's avatar
Elliot Lee committed
156
  /*  allocate the distance map  */
157
  dist_buffer = gegl_buffer_new (region, babl_format ("Y float"));
Elliot Lee's avatar
Elliot Lee committed
158

159
  /*  allocate the selection mask copy  */
160
  temp_buffer = gegl_buffer_new (region, babl_format ("Y float"));
Elliot Lee's avatar
Elliot Lee committed
161

162
  mask = gimp_image_get_mask (image);
163

164
  /*  If the image mask is not empty, use it as the shape burst source  */
165
  if (! gimp_channel_is_empty (mask))
Elliot Lee's avatar
Elliot Lee committed
166
    {
167
168
      gint x, y, width, height;
      gint off_x, off_y;
Elliot Lee's avatar
Elliot Lee committed
169

170
      gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height);
171
      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
Elliot Lee's avatar
Elliot Lee committed
172
173

      /*  copy the mask to the temp mask  */
174
      gegl_buffer_copy (gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)),
175
                        GEGL_RECTANGLE (x + off_x, y + off_y, width, height),
176
                        GEGL_ABYSS_NONE, temp_buffer, region);
Elliot Lee's avatar
Elliot Lee committed
177
178
179
180
    }
  else
    {
      /*  If the intended drawable has an alpha channel, use that  */
181
      if (gimp_drawable_has_alpha (drawable))
182
        {
183
184
          const Babl *component_format;

185
          component_format = babl_format ("A float");
186

187
          /*  extract the aplha into the temp mask  */
188
          gegl_buffer_set_format (temp_buffer, component_format);
189
          gegl_buffer_copy (gimp_drawable_get_buffer (drawable), region,
190
                            GEGL_ABYSS_NONE,
191
                            temp_buffer, region);
192
          gegl_buffer_set_format (temp_buffer, NULL);
193
        }
Elliot Lee's avatar
Elliot Lee committed
194
      else
195
        {
196
197
          GeglColor *white = gegl_color_new ("white");

198
          /*  Otherwise, just fill the shapeburst to white  */
199
200
          gegl_buffer_set_color (temp_buffer, NULL, white);
          g_object_unref (white);
201
        }
Elliot Lee's avatar
Elliot Lee committed
202
203
    }

204
205
206
  shapeburst = gegl_node_new_child (NULL,
                                    "operation", "gegl:distance-transform",
                                    "normalize", TRUE,
207
                                    "metric",    metric,
208
                                    NULL);
209

210
  if (progress)
211
212
    gimp_gegl_progress_connect (shapeburst, progress,
                                _("Calculating distance map"));
213

214
215
  gimp_gegl_apply_operation (temp_buffer, NULL, NULL,
                             shapeburst,
216
                             dist_buffer, region);
217

218
  g_object_unref (shapeburst);
219

220
  g_object_unref (temp_buffer);
Elliot Lee's avatar
Elliot Lee committed
221

222
  return dist_buffer;
Elliot Lee's avatar
Elliot Lee committed
223
}