Example #1
0
static void
median (GeglBuffer *src,
        GeglBuffer *dst,
        gint        radius,
        gdouble     rank)
{
  RankList list = {0};

  gint x,y;
  gint offset;
  gfloat *src_buf;
  gfloat *dst_buf;


  src_buf = g_new0 (gfloat, gegl_buffer_get_pixel_count (src) * 4);
  dst_buf = g_new0 (gfloat, gegl_buffer_get_pixel_count (dst) * 4);

  gegl_buffer_get (src, NULL, 1.0, babl_format ("RGBA float"), src_buf,
                   GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

  offset = 0;
  for (y=0; y<gegl_buffer_get_height (dst); y++)
    for (x=0; x<gegl_buffer_get_width (dst); x++)
      {
        gint u,v;
        gfloat *median_pix;

        list_clear (&list);

        for (v=y-radius;v<=y+radius;v++)
          for (u=x-radius;u<=x+radius;u++)
            {
              gint ru, rv;

              ru = (x-u)*(x-u);
              rv = (y-v)*(y-v);

              if (u >= 0 && u < gegl_buffer_get_width (dst) &&
                  v >= 0 && v < gegl_buffer_get_height (dst) &&
                  (ru+rv) < radius* radius
                  )
                {
                  gfloat *src_pix = src_buf + (u+(v * gegl_buffer_get_width (src))) * 4;
                  gfloat luma = (src_pix[0] * 0.212671 +
                                 src_pix[1] * 0.715160 +
                                 src_pix[2] * 0.072169);
                  list_add (&list, luma, src_pix);
                }
            }

        median_pix = list_percentile (&list, rank);
        for (u=0; u<4;u++)
          dst_buf[offset*4+u] = median_pix[u];
        offset++;
      }
  gegl_buffer_set (dst, NULL, 0, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE);
  g_free (src_buf);
  g_free (dst_buf);
}
Example #2
0
TileManager *
gimp_buffer_to_tiles (GeglBuffer *buffer)
{
  const Babl    *format     = gegl_buffer_get_format (buffer);
  TileManager   *new_tiles  = NULL;
  GeglNode      *source     = NULL;
  GeglNode      *sink       = NULL;

  g_return_val_if_fail (buffer != NULL, NULL);

  /* Setup and process the graph */
  new_tiles = tile_manager_new (gegl_buffer_get_width (buffer),
                                gegl_buffer_get_height (buffer),
                                gimp_babl_format_to_legacy_bpp (format));
  source = gegl_node_new_child (NULL,
                                "operation", "gegl:buffer-source",
                                "buffer",    buffer,
                                NULL);
  sink = gegl_node_new_child (NULL,
                              "operation",    "gimp:tilemanager-sink",
                              "tile-manager", new_tiles,
                              NULL);
  gegl_node_link_many (source, sink, NULL);
  gegl_node_process (sink);

  /* Clenaup */
  g_object_unref (sink);
  g_object_unref (source);

  return new_tiles;
}
Example #3
0
void
gimp_create_image_from_buffer (Gimp       *gimp,
                               GeglBuffer *buffer)
{
  GimpImage  *image;
  GimpLayer  *layer;
  const Babl *format;

  g_return_if_fail (GIMP_IS_GIMP (gimp));
  g_return_if_fail (GEGL_IS_BUFFER (buffer));

  format = gegl_buffer_get_format (buffer);

  image = gimp_create_image (gimp,
                             gegl_buffer_get_width  (buffer),
                             gegl_buffer_get_height (buffer),
                             gimp_babl_format_get_base_type (format),
                             gimp_babl_format_get_precision (format),
                             FALSE);

  layer = gimp_layer_new_from_buffer (buffer, image, format,
                                      "Debug Image",
                                      GIMP_OPACITY_OPAQUE,
                                      GIMP_NORMAL_MODE);
  gimp_image_add_layer (image, layer, NULL, -1, FALSE);

  gimp_create_display (gimp, image, GIMP_UNIT_PIXEL, 1.0);
}
void
gimp_channel_combine_buffer (GimpChannel    *mask,
                             GeglBuffer     *add_on_buffer,
                             GimpChannelOps  op,
                             gint            off_x,
                             gint            off_y)
{
  GeglBuffer *buffer;
  gint        x, y, w, h;

  g_return_if_fail (GIMP_IS_CHANNEL (mask));
  g_return_if_fail (GEGL_IS_BUFFER (add_on_buffer));

  buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));

  if (! gimp_gegl_mask_combine_buffer (buffer, add_on_buffer,
                                       op, off_x, off_y))
    return;

  gimp_rectangle_intersect (off_x, off_y,
                            gegl_buffer_get_width  (add_on_buffer),
                            gegl_buffer_get_height (add_on_buffer),
                            0, 0,
                            gimp_item_get_width  (GIMP_ITEM (mask)),
                            gimp_item_get_height (GIMP_ITEM (mask)),
                            &x, &y, &w, &h);

  mask->bounds_known = FALSE;

  gimp_drawable_update (GIMP_DRAWABLE (mask), x, y, w, h);
}
Example #5
0
gint
gimp_buffer_get_height (const GimpBuffer *buffer)
{
  g_return_val_if_fail (GIMP_IS_BUFFER (buffer), 0);

  return gegl_buffer_get_height (buffer->buffer);
}
Example #6
0
void
gimp_channel_combine_buffer (GimpChannel    *mask,
                             GeglBuffer     *add_on_buffer,
                             GimpChannelOps  op,
                             gint            off_x,
                             gint            off_y)
{
  GimpChannelCombineData data;

  g_return_if_fail (GIMP_IS_CHANNEL (mask));
  g_return_if_fail (GEGL_IS_BUFFER (add_on_buffer));

  if (gimp_channel_combine_start (mask, op,
                                  GEGL_RECTANGLE (
                                    off_x,
                                    off_y,
                                    gegl_buffer_get_width  (add_on_buffer),
                                    gegl_buffer_get_height (add_on_buffer)),
                                  FALSE, FALSE, &data))
    {
      GeglBuffer *buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));

      gimp_gegl_mask_combine_buffer (buffer, add_on_buffer, op,
                                     off_x, off_y);
    }

  gimp_channel_combine_end (mask, &data);
}
Example #7
0
/**
 * gimp_layer_new_from_gegl_buffer:
 * @buffer:     The buffer to make the new layer from.
 * @dest_image: The image the new layer will be added to.
 * @format:     The #Babl format of the new layer.
 * @name:       The new layer's name.
 * @opacity:    The new layer's opacity.
 * @mode:       The new layer's mode.
 *
 * Copies %buffer to a layer taking into consideration the
 * possibility of transforming the contents to meet the requirements
 * of the target image type
 *
 * Return value: The new layer.
 **/
GimpLayer *
gimp_layer_new_from_gegl_buffer (GeglBuffer           *buffer,
                                 GimpImage            *dest_image,
                                 const Babl           *format,
                                 const gchar          *name,
                                 gdouble               opacity,
                                 GimpLayerModeEffects  mode,
                                 GimpColorProfile     *buffer_profile)
{
  GimpLayer *layer;

  g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
  g_return_val_if_fail (GIMP_IS_IMAGE (dest_image), NULL);
  g_return_val_if_fail (format != NULL, NULL);
  g_return_val_if_fail (buffer_profile == NULL ||
                        GIMP_IS_COLOR_PROFILE (buffer_profile), NULL);

  /*  do *not* use the buffer's format because this function gets
   *  buffers of any format passed, and converts them
   */
  layer = gimp_layer_new (dest_image,
                          gegl_buffer_get_width  (buffer),
                          gegl_buffer_get_height (buffer),
                          format,
                          name, opacity, mode);

  gimp_layer_new_convert_buffer (layer, buffer, buffer_profile, NULL);

  return layer;
}
static GimpBezierDesc *
gimp_brush_transform_boundary_exact (GimpBrush *brush,
                                     gdouble    scale,
                                     gdouble    aspect_ratio,
                                     gdouble    angle,
                                     gdouble    hardness)
{
  const GimpTempBuf *mask;

  mask = gimp_brush_transform_mask (brush, NULL,
                                    scale, aspect_ratio, angle, hardness);

  if (mask)
    {
      GeglBuffer    *buffer;
      GimpBoundSeg  *bound_segs;
      gint           n_bound_segs;

      buffer = gimp_temp_buf_create_buffer ((GimpTempBuf *) mask);

      bound_segs = gimp_boundary_find (buffer, NULL,
                                       babl_format ("Y float"),
                                       GIMP_BOUNDARY_WITHIN_BOUNDS,
                                       0, 0,
                                       gegl_buffer_get_width  (buffer),
                                       gegl_buffer_get_height (buffer),
                                       0.0,
                                       &n_bound_segs);

      g_object_unref (buffer);

      if (bound_segs)
        {
          GimpBoundSeg *stroke_segs;
          gint          n_stroke_groups;

          stroke_segs = gimp_boundary_sort (bound_segs, n_bound_segs,
                                            &n_stroke_groups);

          g_free (bound_segs);

          if (stroke_segs)
            {
              GimpBezierDesc *path;

              path = gimp_bezier_desc_new_from_bound_segs (stroke_segs,
                                                           n_bound_segs,
                                                           n_stroke_groups);

              g_free (stroke_segs);

              return path;
            }
        }
    }

  return NULL;
}
Example #9
0
static gboolean
debug_show_image_graph (GimpImage *source_image)
{
  Gimp            *gimp        = source_image->gimp;
  GimpProjectable *projectable = GIMP_PROJECTABLE (source_image);
  GeglNode        *image_graph = gimp_projectable_get_graph (projectable);
  GeglNode        *output_node = gegl_node_get_output_proxy (image_graph, "output");
  GimpImage       *new_image   = NULL;
  GimpLayer       *layer       = NULL;
  GeglNode        *introspect  = NULL;
  GeglNode        *sink        = NULL;
  GeglBuffer      *buffer      = NULL;
  gchar           *new_name    = NULL;

  /* Setup and process the introspection graph */
  introspect = gegl_node_new_child (NULL,
                                    "operation", "gegl:introspect",
                                    "node",      output_node,
                                    NULL);
  sink = gegl_node_new_child (NULL,
                              "operation", "gegl:buffer-sink",
                              "buffer",    &buffer,
                              NULL);
  gegl_node_link_many (introspect, sink, NULL);
  gegl_node_process (sink);

  /* Create a new image of the result */
  new_name = g_strdup_printf ("%s GEGL graph",
                              gimp_image_get_display_name (source_image));
  new_image = gimp_create_image (gimp,
                                 gegl_buffer_get_width (buffer),
                                 gegl_buffer_get_height (buffer),
                                 GIMP_RGB,
                                 GIMP_PRECISION_U8,
                                 FALSE);
  gimp_image_set_uri (new_image, new_name);
  layer = gimp_layer_new_from_buffer (buffer,
                                      new_image,
                                      gimp_image_get_layer_format (new_image,
                                                                   TRUE),
                                      new_name,
                                      1.0,
                                      GIMP_NORMAL_MODE);
  gimp_image_add_layer (new_image, layer, NULL, 0, FALSE);
  gimp_create_display (gimp, new_image, GIMP_UNIT_PIXEL, 1.0);

  /* Cleanup */
  g_object_unref (new_image);
  g_free (new_name);
  g_object_unref (buffer);
  g_object_unref (sink);
  g_object_unref (introspect);
  g_object_unref (source_image);

  return FALSE;
}
Example #10
0
static void
gimp_smudge_accumulator_coords (GimpPaintCore    *paint_core,
                                const GimpCoords *coords,
                                gint             *x,
                                gint             *y)
{
  GimpSmudge *smudge = GIMP_SMUDGE (paint_core);

  *x = (gint) coords->x - gegl_buffer_get_width  (smudge->accum_buffer) / 2;
  *y = (gint) coords->y - gegl_buffer_get_height (smudge->accum_buffer) / 2;
}
Example #11
0
void
gimp_applicator_apply (GimpApplicator       *applicator,
                       GeglBuffer           *src_buffer,
                       GeglBuffer           *apply_buffer,
                       gint                  apply_buffer_x,
                       gint                  apply_buffer_y,
                       gdouble               opacity,
                       GimpLayerModeEffects  paint_mode)
{
    gint width  = gegl_buffer_get_width  (apply_buffer);
    gint height = gegl_buffer_get_height (apply_buffer);

    if (applicator->src_buffer != src_buffer)
    {
        applicator->src_buffer = src_buffer;

        gegl_node_set (applicator->src_node,
                       "buffer", src_buffer,
                       NULL);
    }

    if (applicator->apply_buffer != apply_buffer)
    {
        applicator->apply_buffer = apply_buffer;

        gegl_node_set (applicator->apply_src_node,
                       "buffer", apply_buffer,
                       NULL);
    }


    gegl_node_set (applicator->apply_offset_node,
                   "x", (gdouble) apply_buffer_x,
                   "y", (gdouble) apply_buffer_y,
                   NULL);

    if ((applicator->opacity    != opacity) ||
            (applicator->paint_mode != paint_mode))
    {
        applicator->opacity    = opacity;
        applicator->paint_mode = paint_mode;

        gimp_gegl_mode_node_set (applicator->mode_node,
                                 paint_mode, opacity, FALSE);
    }

    gegl_processor_set_rectangle (applicator->processor,
                                  GEGL_RECTANGLE (apply_buffer_x,
                                          apply_buffer_y,
                                          width, height));

    while (gegl_processor_work (applicator->processor, NULL));
}
Example #12
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *aux,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglBuffer            *temp_in;
  GeglBuffer            *temp_aux;

  /* FIXME: just pass the originals buffers if the result rectangle does not
   * include both input buffers
   */

  temp_in = gegl_buffer_create_sub_buffer (input, result);
  temp_aux = gegl_buffer_create_sub_buffer (aux, result);

    {
      gfloat *buf  = g_new0 (gfloat, result->width * result->height * 4);
      gfloat *bufB = g_new0 (gfloat, result->width * result->height * 4);

      gegl_buffer_get (temp_in,  NULL, 1.0, babl_format ("RGBA float"), buf,
                       GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
      gegl_buffer_get (temp_aux, NULL, 1.0, babl_format ("RGBA float"), bufB,
                       GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
        {
          gint offset=0;
          gint x,y;
          for (y=0;y<gegl_buffer_get_height (output);y++)
            for (x=0;x<gegl_buffer_get_width (output);x++)
              {
                if (x + result->x >= gegl_buffer_get_width (input))
                  {
                    buf[offset+0]=bufB[offset+0];
                    buf[offset+1]=bufB[offset+1];
                    buf[offset+2]=bufB[offset+2];
                    buf[offset+3]=bufB[offset+3];
                  }
                offset+=4;
              }
        }
      gegl_buffer_set (output, NULL, 0, babl_format ("RGBA float"), buf,
                       GEGL_AUTO_ROWSTRIDE);

      g_free (buf);
      g_free (bufB);
    }
  g_object_unref (temp_in);
  g_object_unref (temp_aux);

  return  TRUE;
}
Example #13
0
static GeglRectangle
get_bounding_box (GeglOperation *operation)
{
  GeglProperties   *o = GEGL_PROPERTIES (operation);
  GeglRectangle result = {0,0,0,0};

  load_buffer (o);

  result.width  = gegl_buffer_get_width (GEGL_BUFFER (o->user_data));
  result.height = gegl_buffer_get_height (GEGL_BUFFER (o->user_data));
  return result;
}
Example #14
0
gint64
gimp_gegl_buffer_get_memsize (GeglBuffer *buffer)
{
  if (buffer)
    {
      const Babl *format = gegl_buffer_get_format (buffer);

      return (babl_format_get_bytes_per_pixel (format) *
              gegl_buffer_get_width (buffer) *
              gegl_buffer_get_height (buffer) +
              gimp_g_object_get_memsize (G_OBJECT (buffer)));
    }

  return 0;
}
Example #15
0
gint64
gimp_gegl_pyramid_get_memsize (GeglBuffer *buffer)
{
  if (buffer)
    {
      const Babl *format = gegl_buffer_get_format (buffer);

      /* The pyramid levels constitute a geometric sum with a ratio of 1/4. */
      return ((gint64) babl_format_get_bytes_per_pixel (format) *
              (gint64) gegl_buffer_get_width (buffer) *
              (gint64) gegl_buffer_get_height (buffer) * 1.33 +
              gimp_g_object_get_memsize (G_OBJECT (buffer)));
    }

  return 0;
}
Example #16
0
static GeglRectangle
get_bounding_box (GeglOperation *operation)
{
  GeglRectangle result = {0,0,0,0};
  GeglChantO   *o = GEGL_CHANT_PROPERTIES (operation);

  load_buffer (o);

  if (o->chant_data)
    {
      result.width  = gegl_buffer_get_width  (GEGL_BUFFER (o->chant_data));
      result.height = gegl_buffer_get_height (GEGL_BUFFER (o->chant_data));
    }

  return result;
}
Example #17
0
static gdouble
gradient_calc_shapeburst_dimpled_factor (GeglBuffer *dist_buffer,
                                         gdouble     x,
                                         gdouble     y)
{
  gint   ix = CLAMP (x, 0.0, gegl_buffer_get_width  (dist_buffer) - 0.7);
  gint   iy = CLAMP (y, 0.0, gegl_buffer_get_height (dist_buffer) - 0.7);
  gfloat value;

  gegl_buffer_get (dist_buffer, GEGL_RECTANGLE (ix, iy, 1, 1), 1.0,
                   NULL, &value,
                   GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

  value = cos (0.5 * G_PI * value);

  return value;
}
Example #18
0
gboolean
gimp_edit_fade (GimpImage   *image,
                GimpContext *context)
{
  GimpDrawableUndo *undo;

  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), FALSE);

  undo = GIMP_DRAWABLE_UNDO (gimp_image_undo_get_fadeable (image));

  if (undo && undo->applied_buffer)
    {
      GimpDrawable *drawable;
      GeglBuffer   *buffer;

      drawable = GIMP_DRAWABLE (GIMP_ITEM_UNDO (undo)->item);

      g_object_ref (undo);
      buffer = g_object_ref (undo->applied_buffer);

      gimp_image_undo (image);

      gimp_drawable_apply_buffer (drawable, buffer,
                                  GEGL_RECTANGLE (0, 0,
                                                  gegl_buffer_get_width (undo->buffer),
                                                  gegl_buffer_get_height (undo->buffer)),
                                  TRUE,
                                  gimp_object_get_name (undo),
                                  gimp_context_get_opacity (context),
                                  gimp_context_get_paint_mode (context),
                                  GIMP_LAYER_COLOR_SPACE_AUTO,
                                  GIMP_LAYER_COLOR_SPACE_AUTO,
                                  GIMP_LAYER_COMPOSITE_AUTO,
                                  NULL, undo->x, undo->y);

      g_object_unref (buffer);
      g_object_unref (undo);

      return TRUE;
    }

  return FALSE;
}
Example #19
0
static gboolean
gimp_projection_get_pixel_at (GimpPickable *pickable,
                              gint          x,
                              gint          y,
                              const Babl   *format,
                              gpointer      pixel)
{
  GeglBuffer *buffer = gimp_projection_get_buffer (pickable);

  if (x <  0                               ||
      y <  0                               ||
      x >= gegl_buffer_get_width  (buffer) ||
      y >= gegl_buffer_get_height (buffer))
    return FALSE;

  gegl_buffer_sample (buffer, x, y, NULL, pixel, format,
                      GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

  return TRUE;
}
Example #20
0
/**
 * gimp_seamless_clone_tool_start:
 * @sc: The GimpSeamlessCloneTool to initialize for usage on the given
 *      display
 * @display: The display to initialize the tool for
 *
 * A utility function to initialize a tool for working on a given
 * display. At the beginning of each function, we can check if the event's
 * display is the same as the tool's one, and if not call this. This is
 * not required by the gimptool interface or anything like that, but
 * this is a convenient way to do all the initialization work in one
 * place, and this is how the base class (GimpDrawTool) does that
 */
static void
gimp_seamless_clone_tool_start (GimpSeamlessCloneTool *sc,
                                GimpDisplay           *display)
{
  GimpTool     *tool     = GIMP_TOOL (sc);
  GimpImage    *image    = gimp_display_get_image (display);
  GimpDrawable *drawable = gimp_image_get_active_drawable (image);

  /* First handle the paste - we need to make sure we have one in order
   * to do anything else.
   */
  if (sc->paste == NULL)
    {
      GimpBuffer *buffer = gimp_clipboard_get_buffer (tool->tool_info->gimp);

      if (! buffer)
        {
          gimp_tool_push_status (tool, display,
                                 "%s",
                                 _("There is no image data in the clipboard to paste."));
          return;
        }

      sc->paste = gegl_buffer_dup (gimp_buffer_get_buffer (buffer));
      g_object_unref (buffer);

      sc->width  = gegl_buffer_get_width  (sc->paste);
      sc->height = gegl_buffer_get_height (sc->paste);
    }

  /* Free resources which are relevant only for the previous display */
  gimp_seamless_clone_tool_stop (sc, TRUE);

  tool->display = display;

  gimp_seamless_clone_tool_create_filter (sc, drawable);

  gimp_draw_tool_start (GIMP_DRAW_TOOL (sc), display);

  sc->tool_state = SC_STATE_RENDER_WAIT;
}
Example #21
0
GimpLayerMask *
gimp_layer_mask_new_from_buffer (GeglBuffer    *buffer,
                                 GimpImage     *image,
                                 const gchar   *name,
                                 const GimpRGB *color)
{
  GimpLayerMask  *layer_mask;
  GeglBuffer *dest;

  g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);

  layer_mask = gimp_layer_mask_new (image,
                                    gegl_buffer_get_width  (buffer),
                                    gegl_buffer_get_height (buffer),
                                    name, color);

  dest = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer_mask));
  gegl_buffer_copy (buffer, NULL, dest, NULL);

  return layer_mask;
}
static void
gimp_n_point_deformation_tool_apply_deformation (GimpNPointDeformationTool *npd_tool)
{
  GimpTool                     *tool = GIMP_TOOL (npd_tool);
  GimpNPointDeformationOptions *npd_options;
  GeglBuffer                   *buffer;
  GimpImage                    *image;
  gint                          width, height, prev;

  npd_options = GIMP_N_POINT_DEFORMATION_TOOL_GET_OPTIONS (npd_tool);

  image  = gimp_display_get_image (tool->display);
  buffer = gimp_drawable_get_buffer (tool->drawable);

  width  = gegl_buffer_get_width  (buffer);
  height = gegl_buffer_get_height (buffer);

  prev = npd_options->rigidity;
  npd_options->rigidity = 0;
  gimp_n_point_deformation_tool_set_options (npd_tool, npd_options);
  npd_options->rigidity = prev;

  gimp_drawable_push_undo (tool->drawable, _("N-Point Deformation"), NULL,
                           0, 0, width, height);


  gimp_gegl_apply_operation (NULL, NULL, _("N-Point Deformation"),
                             npd_tool->npd_node,
                             gimp_drawable_get_buffer (tool->drawable),
                             NULL);

  gimp_drawable_update (tool->drawable,
                        0, 0, width, height);

  gimp_projection_flush (gimp_image_get_projection (image));
}
Example #23
0
static void
kuwahara (GeglBuffer *src,
          GeglBuffer *dst,
          gint        radius)
{
  gint u,v;
  gint offset;
  gfloat *src_buf;
  gfloat *dst_buf;

  src_buf = g_new0 (gfloat, gegl_buffer_get_pixel_count (src) * 4);
  dst_buf = g_new0 (gfloat, gegl_buffer_get_pixel_count (dst) * 4);

  gegl_buffer_get (src, NULL, 1.0, babl_format ("RGBA float"), src_buf,
                   GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

  offset = 0;
  for (v=0; v<gegl_buffer_get_height (dst); v++)
    for (u=0; u<gegl_buffer_get_width (dst); u++)
      {
        gint component;

        for (component=0; component<3; component++)
          {
            gfloat value=0.0;
            gfloat best=1000000.0;

            gfloat mean = 0.0;
            gfloat variance = 0.0;

            compute_rectangle (src_buf,
                               gegl_buffer_get_width (src),
                               gegl_buffer_get_height (src),
                               u - radius - 1,
                               v - radius - 1,
                               1 + radius,
                               1 + radius,
                               component,
                               NULL, /* min */
                               NULL, /* max */
                               &mean,
                               &variance);
            if (variance<best)
              {
                best = variance;
                value = mean;
              }

            compute_rectangle (src_buf,
                               gegl_buffer_get_width (src),
                               gegl_buffer_get_height (src),
                               u,
                               v - radius - 1,
                               1 + radius,
                               1 + radius,
                               component,
                               NULL, /* min */
                               NULL, /* max */
                               &mean,
                               &variance);
            if (variance<best)
              {
                best = variance;
                value = mean;
              }

            compute_rectangle (src_buf,
                               gegl_buffer_get_width (src),
                               gegl_buffer_get_height (src),
                               u - radius - 1,
                               v,
                               1 + radius,
                               1 + radius,
                               component,
                               NULL, /* min */
                               NULL, /* max */
                               &mean,
                               &variance);
            if (variance<best)
              {
                best = variance;
                value = mean;
              }

            compute_rectangle (src_buf,
                               gegl_buffer_get_width (src),
                               gegl_buffer_get_height (src),
                               u,
                               v,
                               1 + radius,
                               1 + radius,
                               component,
                               NULL, /* min */
                               NULL, /* max */
                               &mean,
                               &variance);

            if (variance<best)
              {
                best = variance;
                value = mean;
              }
            dst_buf [offset++] = value;
          }
          dst_buf [offset] = src_buf[offset];
          offset++;
      }

  gegl_buffer_set (dst, NULL, 0, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE);
  g_free (src_buf);
  g_free (dst_buf);
}
static void
gimp_image_convert_profile_rgb (GimpImage                *image,
                                GimpColorProfile         *src_profile,
                                GimpColorProfile         *dest_profile,
                                GimpColorRenderingIntent  intent,
                                gboolean                  bpc,
                                GimpProgress             *progress)
{
  GList *layers;
  GList *list;
  gint   n_drawables;
  gint   nth_drawable;

  layers = gimp_image_get_layer_list (image);

  n_drawables = g_list_length (layers);

  for (list = layers, nth_drawable = 0;
       list;
       list = g_list_next (list), nth_drawable++)
    {
      GimpDrawable    *drawable = list->data;
      cmsHPROFILE      src_lcms;
      cmsHPROFILE      dest_lcms;
      const Babl      *iter_format;
      cmsUInt32Number  lcms_format;
      cmsUInt32Number  flags;
      cmsHTRANSFORM    transform;

      if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
        continue;

      src_lcms  = gimp_color_profile_get_lcms_profile (src_profile);
      dest_lcms = gimp_color_profile_get_lcms_profile (dest_profile);

      iter_format =
        gimp_color_profile_get_format (gimp_drawable_get_format (drawable),
                                       &lcms_format);

      flags = cmsFLAGS_NOOPTIMIZE;

      if (bpc)
        flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;

      transform = cmsCreateTransform (src_lcms,  lcms_format,
                                      dest_lcms, lcms_format,
                                      intent, flags);

      if (transform)
        {
          GeglBuffer         *buffer;
          GeglBufferIterator *iter;

          buffer = gimp_drawable_get_buffer (drawable);

          gimp_drawable_push_undo (drawable, NULL, NULL,
                                   0, 0,
                                   gegl_buffer_get_width  (buffer),
                                   gegl_buffer_get_height (buffer));

          iter = gegl_buffer_iterator_new (buffer, NULL, 0,
                                           iter_format,
                                           GEGL_ACCESS_READWRITE,
                                           GEGL_ABYSS_NONE);

          while (gegl_buffer_iterator_next (iter))
            {
              cmsDoTransform (transform,
                              iter->data[0], iter->data[0], iter->length);
            }

          gimp_drawable_update (drawable, 0, 0,
                                gegl_buffer_get_width  (buffer),
                                gegl_buffer_get_height (buffer));

          cmsDeleteTransform (transform);
        }

      if (progress)
        gimp_progress_set_value (progress,
                                 (gdouble) nth_drawable / (gdouble) n_drawables);
    }

  g_list_free (layers);
}
Example #25
0
static void
snn_percentile (GeglBuffer *src,
                GeglBuffer *dst,
                gdouble     radius,
                gdouble     percentile,
                gint        pairs)
{
    gint    x, y;
    gint    offset;
    gfloat *src_buf;
    gfloat *dst_buf;
    RankList list = {0};

    src_buf = g_new0 (gfloat, gegl_buffer_get_pixel_count (src) * 4);
    dst_buf = g_new0 (gfloat, gegl_buffer_get_pixel_count (dst) * 4);

    gegl_buffer_get (src, 1.0, NULL, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE);

    offset = 0;
    percentile/= 100.0;

    for (y=0; y<gegl_buffer_get_height (dst); y++)
        for (x=0; x<gegl_buffer_get_width (dst); x++)
        {
            gint u,v;
            gfloat *center_pix = src_buf + offset * 4;

            list_clear (&list);

            /* iterate through the upper left quater of pixels */
            for (v=-radius; v<=0; v++)
                for (u=-radius; u<= (pairs==1?radius:0); u++)
                {
                    gfloat *selected_pix = center_pix;
                    gfloat  best_diff = 1000.0;
                    gint    i;

                    /* skip computations for the center pixel */
                    if (u != 0 &&
                            v != 0)
                    {
                        /* compute the coordinates of the symmetric pairs for
                         * this locaiton in the quadrant
                         */
                        gint xs[4] = {x+u, x-u, x-u, x+u};
                        gint ys[4] = {y+v, y-v, y+v, y-v};

                        /* check which member of the symmetric quadruple to use */
                        for (i=0; i<pairs*2; i++)
                        {
                            if (xs[i] >= 0 && xs[i] < gegl_buffer_get_width (src) &&
                                    ys[i] >= 0 && ys[i] < gegl_buffer_get_height (src))
                            {
                                gfloat *tpix = src_buf + (xs[i]+ys[i]*gegl_buffer_get_width (src))*4;
                                gfloat diff = colordiff (tpix, center_pix);
                                if (diff < best_diff)
                                {
                                    best_diff = diff;
                                    selected_pix = tpix;
                                }
                            }
                        }
                    }

                    list_add (&list, rgb2luminance(selected_pix), selected_pix);

                    if (u==0 && v==0)
                        break; /* to avoid doubly processing when using only 1 pair */
                }
            {
                gfloat *result = list_percentile (&list, percentile);
                for (u=0; u<4; u++)
                    dst_buf[offset*4+u] = result[u];
            }
            offset++;
        }
    gegl_buffer_set (dst, NULL, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE);
    g_free (src_buf);
    g_free (dst_buf);
}
Example #26
0
static GeglBuffer *
gimp_source_core_real_get_source (GimpSourceCore   *source_core,
                                  GimpDrawable     *drawable,
                                  GimpPaintOptions *paint_options,
                                  GimpPickable     *src_pickable,
                                  gint              src_offset_x,
                                  gint              src_offset_y,
                                  GeglBuffer       *paint_buffer,
                                  gint              paint_buffer_x,
                                  gint              paint_buffer_y,
                                  gint             *paint_area_offset_x,
                                  gint             *paint_area_offset_y,
                                  gint             *paint_area_width,
                                  gint             *paint_area_height,
                                  GeglRectangle    *src_rect)
{
  GimpSourceOptions *options    = GIMP_SOURCE_OPTIONS (paint_options);
  GimpImage         *image      = gimp_item_get_image (GIMP_ITEM (drawable));
  GimpImage         *src_image  = gimp_pickable_get_image (src_pickable);
  GeglBuffer        *src_buffer = gimp_pickable_get_buffer (src_pickable);
  GeglBuffer        *dest_buffer;
  gint               x, y;
  gint               width, height;

  if (! gimp_rectangle_intersect (paint_buffer_x + src_offset_x,
                                  paint_buffer_y + src_offset_y,
                                  gegl_buffer_get_width  (paint_buffer),
                                  gegl_buffer_get_height (paint_buffer),
                                  0, 0,
                                  gegl_buffer_get_width  (src_buffer),
                                  gegl_buffer_get_height (src_buffer),
                                  &x, &y,
                                  &width, &height))
    {
      return FALSE;
    }

  /*  If the source image is different from the destination,
   *  then we should copy straight from the source image
   *  to the canvas.
   *  Otherwise, we need a call to get_orig_image to make sure
   *  we get a copy of the unblemished (offset) image
   */
  if ((  options->sample_merged && (src_image                 != image)) ||
      (! options->sample_merged && (source_core->src_drawable != drawable)))
    {
      dest_buffer = src_buffer;
    }
  else
    {
      /*  get the original image  */
      if (options->sample_merged)
        dest_buffer = gimp_paint_core_get_orig_proj (GIMP_PAINT_CORE (source_core));
      else
        dest_buffer = gimp_paint_core_get_orig_image (GIMP_PAINT_CORE (source_core));
    }

  *paint_area_offset_x = x - (paint_buffer_x + src_offset_x);
  *paint_area_offset_y = y - (paint_buffer_y + src_offset_y);
  *paint_area_width    = width;
  *paint_area_height   = height;

  *src_rect = *GEGL_RECTANGLE (x, y, width, height);

  return g_object_ref (dest_buffer);
}
Example #27
0
/**
 * gimp_color_transform_process_buffer:
 * @transform:
 * @src_format:
 * @src_rect:
 * @dest_format:
 * @dest_rect:
 *
 * This function transforms buffer into another buffer.
 *
 * Since: 2.10
 **/
void
gimp_color_transform_process_buffer (GimpColorTransform  *transform,
                                     GeglBuffer          *src_buffer,
                                     const GeglRectangle *src_rect,
                                     GeglBuffer          *dest_buffer,
                                     const GeglRectangle *dest_rect)
{
  GimpColorTransformPrivate *priv;
  GeglBufferIterator        *iter;
  gint                       total_pixels;
  gint                       done_pixels = 0;

  g_return_if_fail (GIMP_IS_COLOR_TRANSFORM (transform));
  g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
  g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));

  priv = transform->priv;

  if (src_rect)
    {
      total_pixels = src_rect->width * src_rect->height;
    }
  else
    {
      total_pixels = (gegl_buffer_get_width  (src_buffer) *
                      gegl_buffer_get_height (src_buffer));
    }

  if (src_buffer != dest_buffer)
    {
      const Babl *fish = NULL;

      if (babl_format_has_alpha (priv->dest_format))
        fish = babl_fish (priv->src_format,
                          priv->dest_format);

      iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0,
                                       priv->src_format,
                                       GEGL_ACCESS_READ,
                                       GEGL_ABYSS_NONE);

      gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0,
                                priv->dest_format,
                                GEGL_ACCESS_WRITE,
                                GEGL_ABYSS_NONE);

      while (gegl_buffer_iterator_next (iter))
        {
          /* make sure the alpha channel is copied too, lcms doesn't copy it */
          if (fish)
            babl_process (fish, iter->data[0], iter->data[1], iter->length);

          cmsDoTransform (priv->transform,
                          iter->data[0], iter->data[1], iter->length);

          done_pixels += iter->roi[0].width * iter->roi[0].height;

          g_signal_emit (transform, gimp_color_transform_signals[PROGRESS], 0,
                         (gdouble) done_pixels /
                         (gdouble) total_pixels);
        }
    }
  else
    {
      iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0,
                                       priv->src_format,
                                       GEGL_ACCESS_READWRITE,
                                       GEGL_ABYSS_NONE);

      while (gegl_buffer_iterator_next (iter))
        {
          cmsDoTransform (priv->transform,
                          iter->data[0], iter->data[0], iter->length);

          done_pixels += iter->roi[0].width * iter->roi[0].height;

          g_signal_emit (transform, gimp_color_transform_signals[PROGRESS], 0,
                         (gdouble) done_pixels /
                         (gdouble) total_pixels);
        }
    }

  g_signal_emit (transform, gimp_color_transform_signals[PROGRESS], 0,
                 1.0);
}
Example #28
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglProperties *o        = GEGL_PROPERTIES (operation);
  const Babl *src_format   = gegl_operation_get_source_format (operation, "input");
  const Babl *dst_format   = gegl_operation_get_format (operation, "output");
  gint        src_components = babl_format_get_n_components (src_format);
  gint        dst_components = babl_format_get_n_components (dst_format);

  gint     width, height;
  gint     row_size;
  gint     y;
  gdouble *top_row  = NULL;
  gdouble *dst_row  = NULL;
  gdouble *src_row  = NULL;
  gdouble *p_top    = NULL;
  gdouble *p_dst    = NULL;

  width = gegl_buffer_get_width (input);
  height = gegl_buffer_get_height (input);
  row_size = width + 1;

  top_row = g_new0 (gdouble, row_size * dst_components);
  dst_row = g_new0 (gdouble, row_size * dst_components);
  src_row = g_new  (gdouble, row_size * src_components);

  p_top = top_row;
  p_dst = dst_row;

  for (y = 0; y < height; y++)
    {
      GeglRectangle row_rect = {-1, y, width + 1, 1};

      gegl_buffer_get (input, &row_rect, 1.0, src_format, src_row,
                       GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

      compute_row_integral (src_row + src_components,
                            p_top + dst_components,
                            p_dst + dst_components,
                            width,
                            src_components,
                            o->squared);

      gegl_buffer_set (output, &row_rect, 0, dst_format, p_dst,
                       GEGL_AUTO_ROWSTRIDE);

      p_top = p_dst;

      if (p_dst == top_row)
        p_dst = dst_row;
      else
        p_dst = top_row;
    }

  g_free (top_row);
  g_free (dst_row);
  g_free (src_row);

  return TRUE;
}
Example #29
0
/* This works similarly to gimp_paint_core_paste. However, instead of
 * combining the canvas to the paint core drawable using one of the
 * combination modes, it uses a "replace" mode (i.e. transparent
 * pixels in the canvas erase the paint core drawable).

 * When not drawing on alpha-enabled images, it just paints using
 * NORMAL mode.
 */
void
gimp_paint_core_replace (GimpPaintCore            *core,
                         const GimpTempBuf        *paint_mask,
                         gint                      paint_mask_offset_x,
                         gint                      paint_mask_offset_y,
                         GimpDrawable             *drawable,
                         gdouble                   paint_opacity,
                         gdouble                   image_opacity,
                         GimpPaintApplicationMode  mode)
{
  GeglRectangle  mask_rect;
  GeglBuffer    *paint_mask_buffer;
  gint           width, height;

  if (! gimp_drawable_has_alpha (drawable))
    {
      gimp_paint_core_paste (core, paint_mask,
                             paint_mask_offset_x,
                             paint_mask_offset_y,
                             drawable,
                             paint_opacity,
                             image_opacity, GIMP_NORMAL_MODE,
                             mode);
      return;
    }

  width  = gegl_buffer_get_width  (core->paint_buffer);
  height = gegl_buffer_get_height (core->paint_buffer);

  if (mode == GIMP_PAINT_CONSTANT &&

      /* Some tools (ink) paint the mask to paint_core->canvas_buffer
       * directly. Don't need to copy it in this case.
       */
      paint_mask != NULL)
    {
      if (core->applicator)
        {
          paint_mask_buffer =
            gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);

          /* combine the paint mask and the canvas buffer */
          gimp_gegl_combine_mask_weird (paint_mask_buffer,
                                        GEGL_RECTANGLE (paint_mask_offset_x,
                                                        paint_mask_offset_y,
                                                        width, height),
                                        core->canvas_buffer,
                                        GEGL_RECTANGLE (core->paint_buffer_x,
                                                        core->paint_buffer_y,
                                                        width, height),
                                        paint_opacity,
                                        GIMP_IS_AIRBRUSH (core));

          g_object_unref (paint_mask_buffer);
        }
      else
        {
          /* Mix paint mask and canvas_buffer */
          combine_paint_mask_to_canvas_mask (paint_mask,
                                             paint_mask_offset_x,
                                             paint_mask_offset_y,
                                             core->canvas_buffer,
                                             core->paint_buffer_x,
                                             core->paint_buffer_y,
                                             paint_opacity,
                                             GIMP_IS_AIRBRUSH (core));
        }

      /* initialize the maskPR from the canvas buffer */
      paint_mask_buffer = g_object_ref (core->canvas_buffer);

      mask_rect = *GEGL_RECTANGLE (core->paint_buffer_x,
                                   core->paint_buffer_y,
                                   width, height);
    }
  else
    {
      paint_mask_buffer =
        gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);

      mask_rect = *GEGL_RECTANGLE (paint_mask_offset_x,
                                   paint_mask_offset_y,
                                   width, height);
    }

  /*  apply the paint area to the image  */
  gimp_drawable_replace_buffer (drawable, core->paint_buffer,
                                GEGL_RECTANGLE (0, 0, width, height),
                                FALSE, NULL,
                                image_opacity,
                                paint_mask_buffer, &mask_rect,
                                core->paint_buffer_x,
                                core->paint_buffer_y);

  g_object_unref (paint_mask_buffer);

  /*  Update the undo extents  */
  core->x1 = MIN (core->x1, core->paint_buffer_x);
  core->y1 = MIN (core->y1, core->paint_buffer_y);
  core->x2 = MAX (core->x2, core->paint_buffer_x + width);
  core->y2 = MAX (core->y2, core->paint_buffer_y + height);

  /*  Update the drawable  */
  gimp_drawable_update (drawable,
                        core->paint_buffer_x,
                        core->paint_buffer_y,
                        width, height);
}
Example #30
0
void
gimp_paint_core_paste (GimpPaintCore            *core,
                       const GimpTempBuf        *paint_mask,
                       gint                      paint_mask_offset_x,
                       gint                      paint_mask_offset_y,
                       GimpDrawable             *drawable,
                       gdouble                   paint_opacity,
                       gdouble                   image_opacity,
                       GimpLayerModeEffects      paint_mode,
                       GimpPaintApplicationMode  mode)
{
  gint width  = gegl_buffer_get_width  (core->paint_buffer);
  gint height = gegl_buffer_get_height (core->paint_buffer);

  if (core->applicator)
    {
      /*  If the mode is CONSTANT:
       *   combine the canvas buf, the paint mask to the canvas buffer
       */
      if (mode == GIMP_PAINT_CONSTANT)
        {
          /* Some tools (ink) paint the mask to paint_core->canvas_buffer
           * directly. Don't need to copy it in this case.
           */
          if (paint_mask != NULL)
            {
              GeglBuffer *paint_mask_buffer =
                gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);

              gimp_gegl_combine_mask_weird (paint_mask_buffer,
                                            GEGL_RECTANGLE (paint_mask_offset_x,
                                                            paint_mask_offset_y,
                                                            width, height),
                                            core->canvas_buffer,
                                            GEGL_RECTANGLE (core->paint_buffer_x,
                                                            core->paint_buffer_y,
                                                            width, height),
                                            paint_opacity,
                                            GIMP_IS_AIRBRUSH (core));

              g_object_unref (paint_mask_buffer);
            }

          gimp_gegl_apply_mask (core->canvas_buffer,
                                GEGL_RECTANGLE (core->paint_buffer_x,
                                                core->paint_buffer_y,
                                                width, height),
                                core->paint_buffer,
                                GEGL_RECTANGLE (0, 0, width, height),
                                1.0);

          gimp_applicator_set_src_buffer (core->applicator,
                                          core->undo_buffer);
        }
      /*  Otherwise:
       *   combine the canvas buf and the paint mask to the canvas buf
       */
      else
        {
          GeglBuffer *paint_mask_buffer =
            gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);

          gimp_gegl_apply_mask (paint_mask_buffer,
                                GEGL_RECTANGLE (paint_mask_offset_x,
                                                paint_mask_offset_y,
                                                width, height),
                                core->paint_buffer,
                                GEGL_RECTANGLE (0, 0, width, height),
                                paint_opacity);

          g_object_unref (paint_mask_buffer);

          gimp_applicator_set_src_buffer (core->applicator,
                                          gimp_drawable_get_buffer (drawable));
        }

      gimp_applicator_set_apply_buffer (core->applicator,
                                        core->paint_buffer);
      gimp_applicator_set_apply_offset (core->applicator,
                                        core->paint_buffer_x,
                                        core->paint_buffer_y);

      gimp_applicator_set_mode (core->applicator,
                                image_opacity, paint_mode);

      /*  apply the paint area to the image  */
      gimp_applicator_blit (core->applicator,
                            GEGL_RECTANGLE (core->paint_buffer_x,
                                            core->paint_buffer_y,
                                            width, height));
    }
  else
    {
      GimpTempBuf *paint_buf = gimp_gegl_buffer_get_temp_buf (core->paint_buffer);
      GeglBuffer  *dest_buffer;
      GeglBuffer  *src_buffer;

      if (! paint_buf)
        return;

      if (core->comp_buffer)
        dest_buffer = core->comp_buffer;
      else
        dest_buffer = gimp_drawable_get_buffer (drawable);

      if (mode == GIMP_PAINT_CONSTANT)
        {
          /* This step is skipped by the ink tool, which writes
           * directly to canvas_buffer
           */
          if (paint_mask != NULL)
            {
              /* Mix paint mask and canvas_buffer */
              combine_paint_mask_to_canvas_mask (paint_mask,
                                                 paint_mask_offset_x,
                                                 paint_mask_offset_y,
                                                 core->canvas_buffer,
                                                 core->paint_buffer_x,
                                                 core->paint_buffer_y,
                                                 paint_opacity,
                                                 GIMP_IS_AIRBRUSH (core));
            }

          /* Write canvas_buffer to paint_buf */
          canvas_buffer_to_paint_buf_alpha (paint_buf,
                                            core->canvas_buffer,
                                            core->paint_buffer_x,
                                            core->paint_buffer_y);

          /* undo buf -> paint_buf -> dest_buffer */
          src_buffer = core->undo_buffer;
        }
      else
        {
          g_return_if_fail (paint_mask);

          /* Write paint_mask to paint_buf, does not modify canvas_buffer */
          paint_mask_to_paint_buffer (paint_mask,
                                      paint_mask_offset_x,
                                      paint_mask_offset_y,
                                      paint_buf,
                                      paint_opacity);

          /* dest_buffer -> paint_buf -> dest_buffer */
          src_buffer = dest_buffer;
        }

      do_layer_blend (src_buffer,
                      dest_buffer,
                      paint_buf,
                      core->mask_buffer,
                      image_opacity,
                      core->paint_buffer_x,
                      core->paint_buffer_y,
                      core->mask_x_offset,
                      core->mask_y_offset,
                      core->linear_mode,
                      paint_mode);

      if (core->comp_buffer)
        {
          mask_components_onto (src_buffer,
                                core->comp_buffer,
                                gimp_drawable_get_buffer (drawable),
                                GEGL_RECTANGLE(core->paint_buffer_x,
                                               core->paint_buffer_y,
                                               width,
                                               height),
                                gimp_drawable_get_active_mask (drawable),
                                core->linear_mode);
        }
    }

  /*  Update the undo extents  */
  core->x1 = MIN (core->x1, core->paint_buffer_x);
  core->y1 = MIN (core->y1, core->paint_buffer_y);
  core->x2 = MAX (core->x2, core->paint_buffer_x + width);
  core->y2 = MAX (core->y2, core->paint_buffer_y + height);

  /*  Update the drawable  */
  gimp_drawable_update (drawable,
                        core->paint_buffer_x,
                        core->paint_buffer_y,
                        width, height);
}