Пример #1
0
static gboolean
gimp_operation_tile_source_process (GeglOperation       *operation,
                                    GeglBuffer          *output,
                                    const GeglRectangle *result)
{
  GimpOperationTileSource *self = GIMP_OPERATION_TILE_SOURCE (operation);
  const Babl              *format;
  PixelRegion              srcPR;
  gpointer                 pr;

  if (! self->tile_manager)
    return FALSE;

  format = gegl_operation_get_format (operation, "output");

  pixel_region_init (&srcPR, self->tile_manager,
                     result->x,     result->y,
                     result->width, result->height,
                     FALSE);

  for (pr = pixel_regions_register (1, &srcPR);
       pr;
       pr = pixel_regions_process (pr))
    {
      GeglRectangle rect = { srcPR.x, srcPR.y, srcPR.w, srcPR.h };

      gegl_buffer_set (output, &rect, 1, format, srcPR.data, srcPR.rowstride);
    }

  return TRUE;
}
Пример #2
0
static void
render_blob (GimpBlob    *blob,
             PixelRegion *dest)
{
  gpointer  pr;

  for (pr = pixel_regions_register (1, dest);
       pr != NULL;
       pr = pixel_regions_process (pr))
    {
      guchar *d = dest->data;
      gint    h = dest->h;
      gint    y;

      for (y = 0; y < h; y++, d += dest->rowstride)
        {
          render_blob_line (blob, d, dest->x, dest->y + y, dest->w);
        }
    }
}
Пример #3
0
static void
gimp_clone_motion (GimpSourceCore   *source_core,
                   GimpDrawable     *drawable,
                   GimpPaintOptions *paint_options,
                   const GimpCoords *coords,
                   gdouble           opacity,
                   GimpPickable     *src_pickable,
                   PixelRegion      *srcPR,
                   gint              src_offset_x,
                   gint              src_offset_y,
                   TempBuf          *paint_area,
                   gint              paint_area_offset_x,
                   gint              paint_area_offset_y,
                   gint              paint_area_width,
                   gint              paint_area_height)
{
  GimpPaintCore      *paint_core     = GIMP_PAINT_CORE (source_core);
  GimpCloneOptions   *options        = GIMP_CLONE_OPTIONS (paint_options);
  GimpSourceOptions  *source_options = GIMP_SOURCE_OPTIONS (paint_options);
  GimpContext        *context        = GIMP_CONTEXT (paint_options);
  GimpImage          *image          = gimp_item_get_image (GIMP_ITEM (drawable));
  GimpImage          *src_image      = NULL;
  GimpDynamicsOutput *force_output;
  GimpImageType       src_type       = 0;
  GimpImageType       dest_type;
  gpointer            pr = NULL;
  gint                y;
  PixelRegion         destPR;
  GimpPattern        *pattern = NULL;
  gdouble             fade_point;
  gdouble             force;

  switch (options->clone_type)
    {
    case GIMP_IMAGE_CLONE:
      src_image = gimp_pickable_get_image (src_pickable);

      src_type = gimp_pickable_get_image_type (src_pickable);

      if (gimp_pickable_get_bytes (src_pickable) < srcPR->bytes)
        src_type = GIMP_IMAGE_TYPE_WITH_ALPHA (src_type);

      pixel_region_init_temp_buf (&destPR, paint_area,
                                  paint_area_offset_x, paint_area_offset_y,
                                  paint_area_width, paint_area_height);

      pr = pixel_regions_register (2, srcPR, &destPR);
      break;

    case GIMP_PATTERN_CLONE:
      pattern = gimp_context_get_pattern (context);

      pixel_region_init_temp_buf (&destPR, paint_area,
                                  0, 0,
                                  paint_area->width, paint_area->height);

      pr = pixel_regions_register (1, &destPR);
      break;
    }

  dest_type = gimp_drawable_type (drawable);

  for (; pr != NULL; pr = pixel_regions_process (pr))
    {
      guchar *s = srcPR->data;
      guchar *d = destPR.data;

      for (y = 0; y < destPR.h; y++)
        {
          switch (options->clone_type)
            {
            case GIMP_IMAGE_CLONE:
              gimp_clone_line_image (image, dest_type,
                                     src_image, src_type,
                                     s, d,
                                     srcPR->bytes, destPR.bytes, destPR.w);
              s += srcPR->rowstride;
              break;

            case GIMP_PATTERN_CLONE:
              gimp_clone_line_pattern (image, dest_type,
                                       pattern, d,
                                       paint_area->x     + src_offset_x,
                                       paint_area->y + y + src_offset_y,
                                       destPR.bytes, destPR.w);
              break;
            }

          d += destPR.rowstride;
        }
    }

  force_output = gimp_dynamics_get_output (GIMP_BRUSH_CORE (paint_core)->dynamics,
                                           GIMP_DYNAMICS_OUTPUT_FORCE);

  fade_point = gimp_paint_options_get_fade (paint_options, image,
                                            paint_core->pixel_dist);

  force = gimp_dynamics_output_get_linear_value (force_output,
                                                 coords,
                                                 paint_options,
                                                 fade_point);

  gimp_brush_core_paste_canvas (GIMP_BRUSH_CORE (paint_core), drawable,
                                coords,
                                MIN (opacity, GIMP_OPACITY_OPAQUE),
                                gimp_context_get_opacity (context),
                                gimp_context_get_paint_mode (context),
                                gimp_paint_options_get_brush_mode (paint_options),
                                force,

                                /* In fixed mode, paint incremental so the
                                 * individual brushes are properly applied
                                 * on top of each other.
                                 * Otherwise the stuff we paint is seamless
                                 * and we don't need intermediate masking.
                                 */
                                source_options->align_mode ==
                                GIMP_SOURCE_ALIGN_FIXED ?
                                GIMP_PAINT_INCREMENTAL : GIMP_PAINT_CONSTANT);
}
Пример #4
0
static void
gimp_text_layer_render_layout (GimpTextLayer  *layer,
                               GimpTextLayout *layout)
{
  GimpDrawable    *drawable = GIMP_DRAWABLE (layer);
  GimpItem        *item     = GIMP_ITEM (layer);
  GimpImage       *image    = gimp_item_get_image (item);
  cairo_t         *cr;
  cairo_surface_t *surface;
  PixelRegion      layerPR;
  const guchar    *data;
  GimpImageType    layer_type;
  gint             layer_alpha_byte;
  gint             rowstride;
  gint             width;
  gint             height;
  gpointer         pr;

  g_return_if_fail (gimp_drawable_has_alpha (drawable));

  width  = gimp_item_get_width  (item);
  height = gimp_item_get_height (item);

  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);

  cr = cairo_create (surface);
  gimp_text_layout_render (layout, cr, layer->text->base_dir, FALSE);
  cairo_destroy (cr);

  pixel_region_init (&layerPR, gimp_drawable_get_tiles (drawable),
                     0, 0, width, height, TRUE);

  layer_type = gimp_drawable_type (drawable);
  layer_alpha_byte = layerPR.bytes - 1;

  cairo_surface_flush (surface);
  data      = cairo_image_surface_get_data (surface);
  rowstride = cairo_image_surface_get_stride (surface);

  for (pr = pixel_regions_register (1, &layerPR);
       pr != NULL;
       pr = pixel_regions_process (pr))
    {
      const guchar *src  = data + layerPR.y * rowstride + layerPR.x * 4;
      guchar       *dest = layerPR.data;
      gint          rows = layerPR.h;

      while (rows--)
        {
          const guchar *s = src;
          guchar       *d = dest;
          gint          w = layerPR.w;

          while (w--)
            {
              guchar color[4];

              GIMP_CAIRO_ARGB32_GET_PIXEL (s,
                                           color[0],
                                           color[1],
                                           color[2],
                                           color[3]);

              gimp_image_transform_color (image,
                                          layer_type, d, GIMP_RGB, color);
              d[layer_alpha_byte] = color[3];

              s += 4;
              d += layerPR.bytes;
            }

          src  += rowstride;
          dest += layerPR.rowstride;
        }
    }

  cairo_surface_destroy (surface);

  gimp_drawable_update (drawable, 0, 0, width, height);
}
Пример #5
0
/**
 * gimp_channel_combine_ellipse_rect:
 * @mask:      the channel with which to combine the elliptic rect
 * @op:        whether to replace, add to, or subtract from the current
 *             contents
 * @x:         x coordinate of upper left corner of bounding rect
 * @y:         y coordinate of upper left corner of bounding rect
 * @w:         width of bounding rect
 * @h:         height of bounding rect
 * @a:         elliptic a-constant applied to corners
 * @b:         elliptic b-constant applied to corners
 * @antialias: if %TRUE, antialias the elliptic corners
 *
 * Used for rounded cornered rectangles and ellipses.  If @op is
 * %GIMP_CHANNEL_OP_REPLACE or %GIMP_CHANNEL_OP_ADD, sets pixels
 * within the ellipse to 255.  If @op is %GIMP_CHANNEL_OP_SUBTRACT,
 * sets pixels within to zero.  If @antialias is %TRUE, pixels that
 * impinge on the edge of the ellipse are set to intermediate values,
 * depending on how much they overlap.
 **/
void
gimp_channel_combine_ellipse_rect (GimpChannel    *mask,
                                   GimpChannelOps  op,
                                   gint            x,
                                   gint            y,
                                   gint            w,
                                   gint            h,
                                   gdouble         a,
                                   gdouble         b,
                                   gboolean        antialias)
{
  PixelRegion  maskPR;
  gdouble      a_sqr;
  gdouble      b_sqr;
  gdouble      ellipse_center_x;
  gint         x0, y0;
  gint         width, height;
  gpointer     pr;

  g_return_if_fail (GIMP_IS_CHANNEL (mask));
  g_return_if_fail (a >= 0.0 && b >= 0.0);
  g_return_if_fail (op != GIMP_CHANNEL_OP_INTERSECT);

  /* Make sure the elliptic corners fit into the rect */
  a = MIN (a, w / 2.0);
  b = MIN (b, h / 2.0);

  a_sqr = SQR (a);
  b_sqr = SQR (b);

  if (! gimp_rectangle_intersect (x, y, w, h,
                                  0, 0,
                                  gimp_item_get_width  (GIMP_ITEM (mask)),
                                  gimp_item_get_height (GIMP_ITEM (mask)),
                                  &x0, &y0, &width, &height))
    return;

  ellipse_center_x = x + a;

  pixel_region_init (&maskPR, gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)),
                     x0, y0, width, height, TRUE);

  for (pr = pixel_regions_register (1, &maskPR);
       pr != NULL;
       pr = pixel_regions_process (pr))
    {
      guchar *data = maskPR.data;
      gint    py;

      for (py = maskPR.y;
           py < maskPR.y + maskPR.h;
           py++, data += maskPR.rowstride)
        {
          const gint px = maskPR.x;
          gdouble    ellipse_center_y;

          if (py >= y + b && py < y + h - b)
            {
              /*  we are on a row without rounded corners  */
              gimp_channel_combine_span (data, op, 0, maskPR.w, 255);
              continue;
            }

          /* Match the ellipse center y with our current y */
          if (py < y + b)
            {
              ellipse_center_y = y + b;
            }
          else
            {
              ellipse_center_y = y + h - b;
            }

          /* For a non-antialiased ellipse, use the normal equation
           * for an ellipse with an arbitrary center
           * (ellipse_center_x, ellipse_center_y).
           */
          if (! antialias)
            {
              gdouble     half_ellipse_width_at_y;
              gint        x_start;
              gint        x_end;

              half_ellipse_width_at_y =
                sqrt (a_sqr -
                      a_sqr * SQR (py + 0.5f - ellipse_center_y) / b_sqr);

              x_start = ROUND (ellipse_center_x - half_ellipse_width_at_y);
              x_end   = ROUND (ellipse_center_x + w - 2 * a +
                               half_ellipse_width_at_y);

              gimp_channel_combine_span (data, op,
                                         MAX (x_start - px, 0),
                                         MIN (x_end   - px, maskPR.w), 255);
            }
          else  /* use antialiasing */
            {
              /* algorithm changed 7-18-04, because the previous one
               * did not work well for eccentric ellipses.  The new
               * algorithm measures the distance to the ellipse in the
               * X and Y directions, and uses trigonometry to
               * approximate the distance to the ellipse as the
               * distance to the hypotenuse of a right triangle whose
               * legs are the X and Y distances.  (WES)
               */
              const gfloat yi       = ABS (py + 0.5 - ellipse_center_y);
              gint         last_val = -1;
              gint         x_start  = px;
              gint         cur_x;

              for (cur_x = px; cur_x < (px + maskPR.w); cur_x++)
                {
                  gfloat  xj;
                  gfloat  xdist;
                  gfloat  ydist;
                  gfloat  r;
                  gfloat  dist;
                  gint    val;

                  if (cur_x < x + w / 2)
                    {
                      ellipse_center_x = x + a;
                    }
                  else
                    {
                      ellipse_center_x = x + w - a;
                    }

                  xj = ABS (cur_x + 0.5 - ellipse_center_x);

                  if (yi < b)
                    xdist = xj - a * sqrt (1 - SQR (yi) / b_sqr);
                  else
                    xdist = 1000.0;  /* anything large will work */

                  if (xj < a)
                    ydist = yi - b * sqrt (1 - SQR (xj) / a_sqr);
                  else
                    ydist = 1000.0;  /* anything large will work */

                  r = hypot (xdist, ydist);

                  if (r < 0.001)
                    dist = 0.;
                  else
                    dist = xdist * ydist / r; /* trig formula for distance to
                                               * hypotenuse
                                               */

                  if (xdist < 0.0)
                    dist *= -1;

                  if (dist < -0.5)
                    val = 255;
                  else if (dist < 0.5)
                    val = (gint) (255 * (1 - (dist + 0.5)));
                  else
                    val = 0;

                  if (last_val != val)
                    {
                      if (last_val != -1)
                        gimp_channel_combine_span (data, op,
                                                   MAX (x_start - px, 0),
                                                   MIN (cur_x   - px, maskPR.w),
                                                   last_val);

                      x_start = cur_x;
                      last_val = val;
                    }

                  /*  skip ahead if we are on the straight segment
                   *  between rounded corners
                   */
                  if (cur_x >= x + a && cur_x < x + w - a)
                    {
                      gimp_channel_combine_span (data, op,
                                                 MAX (x_start - px, 0),
                                                 MIN (cur_x   - px, maskPR.w),
                                                 last_val);

                      x_start = cur_x;
                      cur_x = x + w - a;
                      last_val = val = 255;
                    }

                  /* Time to change center? */
                  if (cur_x >= x + w / 2)
                    {
                      ellipse_center_x = x + w - a;
                    }
                }

              gimp_channel_combine_span (data, op,
                                         MAX (x_start - px, 0),
                                         MIN (cur_x   - px, maskPR.w),
                                         last_val);
            }
        }
    }

  /*  use the intersected values for the boundary calculation  */
  x = x0;
  y = y0;
  w = width;
  h = height;

  /*  determine new boundary  */
  if (mask->bounds_known && (op == GIMP_CHANNEL_OP_ADD) && ! mask->empty)
    {
      if (x < mask->x1)
        mask->x1 = x;
      if (y < mask->y1)
        mask->y1 = y;
      if ((x + w) > mask->x2)
        mask->x2 = (x + w);
      if ((y + h) > mask->y2)
        mask->y2 = (y + h);
    }
  else if (op == GIMP_CHANNEL_OP_REPLACE || mask->empty)
    {
      mask->empty = FALSE;
      mask->x1    = x;
      mask->y1    = y;
      mask->x2    = x + w;
      mask->y2    = y + h;
    }
  else
    {
      mask->bounds_known = FALSE;
    }

  gimp_drawable_update (GIMP_DRAWABLE (mask), x, y, w, h);
}
Пример #6
0
TempBuf *
gimp_paint_core_get_orig_proj (GimpPaintCore *core,
                               GimpPickable  *pickable,
                               gint           x,
                               gint           y,
                               gint           width,
                               gint           height)
{
  TileManager  *src_tiles;
  PixelRegion   srcPR;
  PixelRegion   destPR;
  Tile         *saved_tile;
  gboolean      release_tile;
  gint          h;
  gint          pixelwidth;
  gint          pickable_width;
  gint          pickable_height;
  const guchar *s;
  guchar       *d;
  gpointer      pr;

  g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), NULL);
  g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
  g_return_val_if_fail (core->saved_proj_tiles != NULL, NULL);

  core->orig_proj_buf = temp_buf_resize (core->orig_proj_buf,
                                         gimp_pickable_get_bytes (pickable),
                                         x, y, width, height);

  src_tiles = gimp_pickable_get_tiles (pickable);

  pickable_width  = tile_manager_width  (src_tiles);
  pickable_height = tile_manager_height (src_tiles);

  gimp_rectangle_intersect (x, y,
                            width, height,
                            0, 0,
                            pickable_width, pickable_height,
                            &x, &y,
                            &width, &height);

  /*  configure the pixel regions  */
  pixel_region_init (&srcPR, src_tiles,
                     x, y, width, height,
                     FALSE);

  pixel_region_init_temp_buf (&destPR, core->orig_proj_buf,
                              x - core->orig_proj_buf->x,
                              y - core->orig_proj_buf->y,
                              width, height);

  for (pr = pixel_regions_register (2, &srcPR, &destPR);
       pr != NULL;
       pr = pixel_regions_process (pr))
    {
      /*  If the saved tile corresponding to this location is valid, use it  */
      saved_tile = tile_manager_get_tile (core->saved_proj_tiles,
                                          srcPR.x, srcPR.y,
                                          FALSE, FALSE);

      if (tile_is_valid (saved_tile))
        {
          release_tile = TRUE;

          saved_tile = tile_manager_get_tile (core->saved_proj_tiles,
                                              srcPR.x, srcPR.y,
                                              TRUE, FALSE);
          s = tile_data_pointer (saved_tile, srcPR.x, srcPR.y);
        }
      else
        {
          release_tile = FALSE;

          s = srcPR.data;
        }

      d = destPR.data;

      pixelwidth = srcPR.w * srcPR.bytes;

      h = srcPR.h;
      while (h --)
        {
          memcpy (d, s, pixelwidth);

          s += srcPR.rowstride;
          d += destPR.rowstride;
        }

      if (release_tile)
        tile_release (saved_tile, FALSE);
    }

  return core->orig_proj_buf;
}