static gpointer iterator_buf_pool_get (gint size)
{
  gint i;
  g_static_mutex_lock (&pool_mutex);

  if (G_UNLIKELY (!buf_pool))
    {
      buf_pool = g_array_new (TRUE, TRUE, sizeof (BufInfo));
    }
  for (i=0; i<buf_pool->len; i++)
    {
      BufInfo *info = &g_array_index (buf_pool, BufInfo, i);
      if (info->size >= size && info->used == 0)
        {
          info->used ++;
          g_static_mutex_unlock (&pool_mutex);
          return info->buf;
        }
    }
  {
    BufInfo info = {0, 1, NULL};
    info.size = size;
    info.buf = gegl_malloc (size);
    g_array_append_val (buf_pool, info);
    g_static_mutex_unlock (&pool_mutex);
    return info.buf;
  }
}
Пример #2
0
static gpointer
gegl_memdup (gpointer src, gsize size)
{
  gpointer ret;
  ret = gegl_malloc (size);
  memcpy (ret, src, size);
  return ret;
}
Пример #3
0
GeglTile *
gegl_tile_new (gint size)
{
  GeglTile *tile = gegl_tile_new_bare ();

  tile->data = gegl_malloc (size);
  tile->size = size;

  return tile;
}
Пример #4
0
int main(int argc, char **argv)
{
  GeglTile *tile;
  GeglBuffer *buf_a, *buf_b, *buf_small_lin, *buf_big_lin;
  gpointer shared_data = NULL;
  gboolean result = TRUE;
  gpointer scratch_data;
  GeglRectangle buffer_rect = *GEGL_RECTANGLE(0, 0, 128, 128);

  gegl_init (&argc, &argv);

  buf_a = gegl_buffer_new (&buffer_rect, babl_format("RGBA u8"));
  buf_b = gegl_buffer_new (&buffer_rect, babl_format("RGBA u8"));
  buf_small_lin = gegl_buffer_linear_new (&buffer_rect, babl_format("RGBA float"));
  buf_big_lin = gegl_buffer_linear_new (GEGL_RECTANGLE(0, 0, 1024, 1024), babl_format("RGBA float"));

  tile = gegl_tile_source_get_tile (GEGL_TILE_SOURCE (buf_a), 0, 0, 0);
  shared_data = gegl_tile_get_data(tile);
  gegl_tile_unref (tile);

  if (!assert_is_empty (buf_a, 0, 0, shared_data))
    result = FALSE;
  if (!assert_is_empty (buf_b, 0, 1, shared_data))
    result = FALSE;

  if (!assert_is_empty (buf_a, 0, 0, shared_data))
    result = FALSE;
  if (!assert_is_empty (buf_b, 0, 1, shared_data))
    result = FALSE;

  if (!assert_is_empty (buf_small_lin, 0, 0, shared_data))
    result = FALSE;

  if (!assert_is_unshared (buf_big_lin, 0, 0, shared_data))
    result = FALSE;

  scratch_data = gegl_malloc(4 * buffer_rect.width * buffer_rect.height);
  gegl_buffer_get (buf_a, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE);
  gegl_buffer_get (buf_b, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE);
  gegl_buffer_get (buf_small_lin, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE);
  gegl_buffer_get (buf_big_lin, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE);
  gegl_free (scratch_data);

  g_object_unref(buf_a);
  g_object_unref(buf_b);
  g_object_unref(buf_small_lin);
  g_object_unref(buf_big_lin);

  gegl_exit();

  if (result)
    return SUCCESS;
  return FAILURE;
}
Пример #5
0
static void
wav_hor_blur (GeglBuffer          *src,
              GeglBuffer          *dst,
              const GeglRectangle *dst_rect,
              gint                 radius,
              const Babl          *format)
{
  gint x, y;

  GeglRectangle write_rect = {dst_rect->x, dst_rect->y, dst_rect->width, 1};

  GeglRectangle read_rect = {dst_rect->x - radius, dst_rect->y,
                             dst_rect->width + 2 * radius, 1};

  gfloat *src_buf = gegl_malloc (read_rect.width * sizeof (gfloat) * 3);
  gfloat *dst_buf = gegl_malloc (write_rect.width * sizeof (gfloat) * 3);

  for (y = 0; y < dst_rect->height; y++)
    {
      gint offset     = 0;
      read_rect.y     = dst_rect->y + y;
      write_rect.y    = dst_rect->y + y;

      gegl_buffer_get (src, &read_rect, 1.0, format, src_buf,
                       GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);

      for (x = 0; x < dst_rect->width; x++)
        {
          wav_get_mean_pixel_1D (src_buf + offset,
                                 dst_buf + offset,
                                 radius);
          offset += 3;
        }

      gegl_buffer_set (dst, &write_rect, 0, format, dst_buf,
                       GEGL_AUTO_ROWSTRIDE);
    }

  gegl_free (src_buf);
  gegl_free (dst_buf);
}
Пример #6
0
static void
fir_ver_blur (GeglBuffer          *src,
              const GeglRectangle *rect,
              GeglBuffer          *dst,
              gfloat              *cmatrix,
              gint                 clen,
              GeglAbyssPolicy      policy,
              const Babl          *format)
{
  GeglRectangle  cur_col = *rect;
  GeglRectangle  in_col;
  const gint     nc = babl_format_get_n_components (format);
  gfloat        *col;
  gfloat        *out;
  gint           v;

  cur_col.width = 1;

  in_col         = cur_col;
  in_col.height += clen - 1;
  in_col.y      -= clen / 2;

  col = gegl_malloc (sizeof (gfloat) * in_col.height  * nc);
  out = gegl_malloc (sizeof (gfloat) * cur_col.height * nc);

  for (v = 0; v < rect->width; v++)
    {
      cur_col.x = in_col.x = rect->x + v;

      gegl_buffer_get (src, &in_col, 1.0, format, col, GEGL_AUTO_ROWSTRIDE, policy);

      fir_blur_1D (col, out, cmatrix, clen, rect->height, nc);

      gegl_buffer_set (dst, &cur_col, 0, format, out, GEGL_AUTO_ROWSTRIDE);
    }

  gegl_free (out);
  gegl_free (col);
}
Пример #7
0
static void
fir_hor_blur (GeglBuffer          *src,
              const GeglRectangle *rect,
              GeglBuffer          *dst,
              gfloat              *cmatrix,
              gint                 clen,
              GeglAbyssPolicy      policy,
              const Babl          *format)
{
  GeglRectangle  cur_row = *rect;
  GeglRectangle  in_row;
  const gint     nc = babl_format_get_n_components (format);
  gfloat        *row;
  gfloat        *out;
  gint           v;

  cur_row.height = 1;

  in_row         = cur_row;
  in_row.width  += clen - 1;
  in_row.x      -= clen / 2;

  row = gegl_malloc (sizeof (gfloat) * in_row.width  * nc);
  out = gegl_malloc (sizeof (gfloat) * cur_row.width * nc);

  for (v = 0; v < rect->height; v++)
    {
      cur_row.y = in_row.y = rect->y + v;

      gegl_buffer_get (src, &in_row, 1.0, format, row, GEGL_AUTO_ROWSTRIDE, policy);

      fir_blur_1D (row, out, cmatrix, clen, rect->width, nc);

      gegl_buffer_set (dst, &cur_row, 0, format, out, GEGL_AUTO_ROWSTRIDE);
    }

  gegl_free (out);
  gegl_free (row);
}
Пример #8
0
static void
gegl_random_init (void)
{
  if (random_data_inited)
    return;
  else
    {
      GRand *gr = g_rand_new_with_seed (42);
      gint   i;

      /* Ensure alignment, needed with the use of CL_MEM_USE_HOST_PTR */
      gegl_random_data = gegl_malloc (RANDOM_DATA_SIZE * sizeof (guint32));

      for (i = 0; i < RANDOM_DATA_SIZE; i++)
        gegl_random_data[i] = g_rand_int (gr);

      g_rand_free (gr);
      random_data_inited = TRUE;
    }
}
Пример #9
0
static void
get_indirect (GeglBufferIterator *iter,
              int        index)
{
  GeglBufferIteratorPriv *priv = iter->priv;
  SubIterState           *sub  = &priv->sub_iter[index];

  sub->real_data = gegl_malloc (sub->format_bpp * sub->real_roi.width * sub->real_roi.height);

  if (sub->access_mode & GEGL_ACCESS_READ)
    {
      gegl_buffer_get_unlocked (sub->buffer, sub->level?1.0/(1<<sub->level):1.0, &sub->real_roi, sub->format, sub->real_data,
                                GEGL_AUTO_ROWSTRIDE, sub->abyss_policy);
    }

  sub->row_stride = sub->real_roi.width * sub->format_bpp;

  iter->data[index] = sub->real_data;
  sub->current_tile_mode = GeglIteratorTileMode_GetBuffer;
}
Пример #10
0
static gint
fir_gen_convolve_matrix (gfloat   sigma,
                         gfloat **cmatrix)
{
  gint    clen;
  gfloat *cmatrix_p;

  clen = fir_calc_convolve_matrix_length (sigma);

  *cmatrix  = gegl_malloc (sizeof (gfloat) * clen);
  cmatrix_p = *cmatrix;

  if (clen == 1)
    {
      cmatrix_p [0] = 1;
    }
  else
    {
      gint    i;
      gdouble sum = 0;
      gint    half_clen = clen / 2;

      for (i = 0; i < clen; i++)
        {
          cmatrix_p [i] = gaussian_func_1d (i - half_clen, sigma);
          sum += cmatrix_p [i];
        }

      for (i = 0; i < clen; i++)
        {
          cmatrix_p [i] /= sum;
        }
    }

  return clen;
}
Пример #11
0
static gboolean
test_scale (const gdouble scale, const gint x, const gint y, const Babl *format)
{
  GeglNode *checkerboard;
  GeglBuffer *tmp_buffer;
  gboolean result = FALSE;

  const gint bpp = babl_format_get_bytes_per_pixel (format);
  const gint scaled_width  = 32;
  const gint scaled_height = 32;
  gint pad = 32;

  guchar *output_buffer_scaled = gegl_malloc (scaled_width * scaled_height * bpp);
  guchar *output_node_scaled   = gegl_malloc (scaled_width * scaled_height * bpp);

  if (2 / scale > pad)
    pad = 2 / scale + 2;

  tmp_buffer = gegl_buffer_new (GEGL_RECTANGLE ((x / scale) - pad,
                                                (y / scale) - pad,
                                                (scaled_width / scale) + (2 * pad),
                                                (scaled_height / scale) + (2 * pad)),
                                babl_format ("RGBA float"));

  checkerboard = gegl_node_new_child(NULL,
                                     "operation", "gegl:checkerboard",
                                     "x", 16,
                                     "y", 16,
                                     NULL);

  gegl_node_blit_buffer (checkerboard,
                         tmp_buffer,
                         NULL,
                         0,
                         GEGL_ABYSS_NONE);

  gegl_buffer_get (tmp_buffer,
                   GEGL_RECTANGLE (x, y, scaled_width, scaled_height),
                   scale,
                   format,
                   output_buffer_scaled,
                   GEGL_AUTO_ROWSTRIDE,
                   GEGL_ABYSS_NONE);

  g_object_unref (checkerboard);
  g_object_unref (tmp_buffer);

  /* Re-create the node so we don't hit its cache */
  checkerboard = gegl_node_new_child(NULL,
                                     "operation", "gegl:checkerboard",
                                     "x", 16,
                                     "y", 16,
                                     NULL);

  gegl_node_blit (checkerboard,
                  scale,
                  GEGL_RECTANGLE (x, y, scaled_width, scaled_height),
                  format,
                  output_node_scaled,
                  GEGL_AUTO_ROWSTRIDE,
                  0);

  g_object_unref (checkerboard);

  if (0 == memcmp (output_buffer_scaled, output_node_scaled, scaled_width * scaled_height * bpp))
    {
      printf (".");
      fflush(stdout);
      result = TRUE;
    }
  else
    {
      printf ("\n scale=%.4f at %d, %d in \"%s\" ... FAIL\n", scale, x, y, babl_get_name (format));
      result = FALSE;
    }

  gegl_free (output_buffer_scaled);
  gegl_free (output_node_scaled);

  return result;
}
Пример #12
0
/**
 * Process the gegl filter
 * @param operation the given Gegl operation
 * @param input the input buffer.
 * @param output the output buffer.
 * @param result the region of interest.
 * @param level the level of detail
 * @return True, if the filter was successfull applied.
 */
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglProperties         *o = GEGL_PROPERTIES (operation);
  const Babl  *input_format = gegl_buffer_get_format (input);
  const int bytes_per_pixel = babl_format_get_bytes_per_pixel (input_format);

  /**
   * src_buf, dst_buf:
   * Input- and output-buffers, containing the whole selection,
   * the filter should be applied on.
   *
   * src_pixel, dst_pixel:
   * pointers to the current source- and destination-pixel.
   * Using these pointers, the reading and writing can be delayed till the
   * end of the loop. Hence src_pixel can also point to background_color if
   * necessary.
   */
  guint8    *src_buf, *dst_buf, *src_pixel, *dst_pixel, background_color[bytes_per_pixel];

  /**
   * (x, y): Position of the pixel we compute at the moment.
   * (width, height): Dimensions of the lens
   * pixel_offset: For calculating the pixels position in src_buf / dst_buf.
   */
  gint         x, y,
               width, height,
               pixel_offset, projected_pixel_offset;

  /**
   * Further parameters that are needed to calculate the position of a projected
   * further pixel at (x, y).
   */
  gfloat       a, b, c,
               asqr, bsqr, csqr,
               dx, dy, dysqr,
               projected_x, projected_y,
               refraction_index;

  gboolean     keep_surroundings;

  width = result->width;
  height = result->height;

  refraction_index = o->refraction_index;
  keep_surroundings = o->keep_surroundings;
  gegl_color_get_pixel (o->background_color, input_format, background_color);

  a = 0.5 * width;
  b = 0.5 * height;
  c = MIN (a, b);
  asqr = a * a;
  bsqr = b * b;
  csqr = c * c;

  /**
   * Todo: We might want to change the buffers sizes, as the memory consumption
   * could be rather large.However, due to the lens, it might happen, that one pixel from the
   * images center gets stretched to the whole image, so we will still need
   * at least a src_buf of size (width/2) * (height/2) * 4 to be able to
   * process one quarter of the image.
   */
  src_buf = gegl_malloc (width * height * bytes_per_pixel);
  dst_buf = gegl_malloc (width * height * bytes_per_pixel);

  gegl_buffer_get (input, result, 1.0, input_format, src_buf,
                   GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

  for (y = 0; y < height; y++)
    {
      /* dy is the current pixels distance (in y-direction) of the lenses center */
      dy = -((gfloat)y - b + 0.5);

      /**
       * To determine, whether the pixel is within the elliptical region affected
       * by the lens, we furthermore need the squared distance. So we calculate it
       * once for each row.
       */
      dysqr = dy * dy;
      for (x = 0; x < width; x++)
        {
          /* Again we need to calculate the pixels distance from the lens dx. */
          dx = (gfloat)x - a + 0.5;

          /* Given x and y we can now determine the pixels offset in our buffer. */
          pixel_offset = (x + y * width) * bytes_per_pixel;

          /* As described above, we only read and write image data once. */
          dst_pixel = &dst_buf[pixel_offset];

          if (dysqr < (bsqr - (bsqr * dx * dx) / asqr))
            {
              /**
               * If (x, y) is inside the affected region, we can find its projected
               * position, calculate the projected_pixel_offset and set the src_pixel
               * to where we want to copy the pixel-data from.
               */
              find_projected_pos (asqr, bsqr, csqr, dx, dy, refraction_index,
                                  &projected_x, &projected_y);

              projected_pixel_offset = ( (gint)(-projected_y + b) * width +
                                         (gint)( projected_x + a) ) * bytes_per_pixel;

              src_pixel = &src_buf[projected_pixel_offset];
            }
          else
            {
              /**
               * Otherwise (that is for pixels outside the lens), we could either leave
               * the image data unchanged, or set it to a specified 'background_color',
               * depending on the user input.
               */
              if (keep_surroundings)
                src_pixel = &src_buf[pixel_offset];
              else
                src_pixel = background_color;
            }

          /**
           * At the end, we can copy the src_pixel (which was determined above), to
           * dst_pixel.
           */
          memcpy (dst_pixel, src_pixel, bytes_per_pixel);
        }
  }

  gegl_buffer_set (output, result, 0, gegl_buffer_get_format (output), dst_buf,
                   GEGL_AUTO_ROWSTRIDE);

  gegl_free (dst_buf);
  gegl_free (src_buf);

  return TRUE;
}
Пример #13
0
void *
alloc_for_format(const Babl *format, int pixels) {
    const size_t bytes = babl_format_get_bytes_per_pixel(format)*pixels;
    return gegl_malloc(bytes);
}
Пример #14
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglChantO *o                    = GEGL_CHANT_PROPERTIES (operation);
  GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);

  gfloat *src_buf;
  gfloat *dst_buf;

  gint n_pixels = result->width * result->height;
  GeglRectangle src_rect;

  gfloat *current_pix;
  gfloat *target_pix;
  gfloat *dst_pix;

  gint x, y;
  gint total_src_pixels;
  gint total_dst_pixels;

  gint bleed_max;
  gint bleed_index;
  gfloat blend_coefficient;

  GHashTable *bleed_table;

  static GMutex mutex = { 0, };

  g_mutex_lock (&mutex);
  if (!o->chant_data)
    {
      o->chant_data = g_hash_table_new_full (tuple_hash, tuple_equal, g_free, g_free);
      calculate_bleed (operation, input);
    }
  g_mutex_unlock (&mutex);

  bleed_table = (GHashTable*) o->chant_data;

  src_rect.x      = result->x - op_area->left;
  src_rect.width  = result->width + op_area->left + op_area->right;
  src_rect.y      = result->y - op_area->top;
  src_rect.height = result->height + op_area->top + op_area->bottom;

  total_src_pixels = src_rect.width * src_rect.height;
  total_dst_pixels = result->width * result->height;

  src_buf = gegl_malloc (4 * total_src_pixels * sizeof (gfloat));
  dst_buf = gegl_malloc (4 * total_dst_pixels * sizeof (gfloat));

  gegl_buffer_get (input,
                   &src_rect,
                   1.0,
                   babl_format ("RGBA float"),
                   src_buf,
                   GEGL_AUTO_ROWSTRIDE,
                   GEGL_ABYSS_NONE);

  current_pix = src_buf + 4*(o->strength + src_rect.width * o->strength);
  dst_pix = dst_buf;
  x = 0;
  y = 0;
  n_pixels = result->width * result->height;
  bleed_max = 0;
  bleed_index = 0;
  while (n_pixels--)
    {
      gint i;
      pair key = {x + result->x, y + result->y};
      gint *bleed = g_hash_table_lookup (bleed_table, &key);

      if (x == 0) {
        for (i = 0; i < o->strength; i++)
          {
            pair key = {result->x - i, y + result->y};
            gint *bleed = g_hash_table_lookup (bleed_table, &key);
            if (bleed) {
              bleed_max = *bleed;
              bleed_index = *bleed - i;
              break;
            }
          }
      }

      for (i = 0; i < 4; i++)
        dst_pix[i] = current_pix[i];

      if (bleed)
        {
          gfloat blend_color[4];
          gfloat blend_amount[4];
          gfloat *blend_pix;

          bleed_max = *bleed;
          bleed_index = *bleed;
          target_pix = current_pix;
          blend_pix = current_pix - 12;
          for (i = 0; i < 4; i++)
            {
              blend_amount[i] = target_pix[i] - blend_pix[i];
              blend_color[i] = blend_pix[i] + blend_amount[i];
              dst_pix[i] = (2.0 * blend_color[i] + dst_pix[i])/3.0;
            }
        }
      else if (bleed_index > 0)
        {
          gfloat blend_color[4];
          gfloat blend_amount[4];
          gfloat *blend_pix;
          bleed_index--;
          blend_coefficient = 1.0 - ((gfloat) bleed_index)/(gfloat) bleed_max;
          blend_pix = current_pix - 4 * (bleed_max - bleed_index) - 12;
          target_pix = current_pix;
          for (i = 0; i < 4; i++)
            {
              blend_amount[i] = target_pix[i] - blend_pix[i];
              blend_color[i] = blend_pix[i] + blend_amount[i] * blend_coefficient;
              dst_pix[i] = (2.0 * blend_color[i] + dst_pix[i])/3.0;
            }
        }

      x++;
      current_pix += 4;
      dst_pix += 4;
      if (x >= result->width)
        {
          bleed_max = 0;
          bleed_index = 0;
          x = 0;
          y++;
          current_pix += 8 * o->strength;
        }
    }
  gegl_buffer_set (output,
                   result,
                   1,
                   babl_format ("RGBA float"),
                   dst_buf,
                   GEGL_AUTO_ROWSTRIDE);

  gegl_free (src_buf);
  gegl_free (dst_buf);

  return TRUE;
}
Пример #15
0
void
gimp_display_shell_render (GimpDisplayShell *shell,
                           cairo_t          *cr,
                           gint              x,
                           gint              y,
                           gint              w,
                           gint              h)
{
  GimpImage       *image;
  GeglBuffer      *buffer;
#ifdef USE_NODE_BLIT
  GeglNode        *node;
#endif
  gdouble          scale_x       = 1.0;
  gdouble          scale_y       = 1.0;
  gdouble          buffer_scale  = 1.0;
  gint             viewport_offset_x;
  gint             viewport_offset_y;
  gint             viewport_width;
  gint             viewport_height;
  gint             scaled_x;
  gint             scaled_y;
  gint             scaled_width;
  gint             scaled_height;
  cairo_surface_t *xfer;
  gint             xfer_src_x;
  gint             xfer_src_y;
  gint             mask_src_x = 0;
  gint             mask_src_y = 0;
  gint             cairo_stride;
  guchar          *cairo_data;
  GeglBuffer      *cairo_buffer;

  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
  g_return_if_fail (cr != NULL);
  g_return_if_fail (w > 0 && h > 0);

  image  = gimp_display_get_image (shell->display);
  buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (image));
#ifdef USE_NODE_BLIT
  node   = gimp_projectable_get_graph (GIMP_PROJECTABLE (image));
#endif

#ifdef GIMP_DISPLAY_RENDER_ENABLE_SCALING
  /* if we had this future API, things would look pretty on hires (retina) */
  scale_x = gdk_window_get_scale_factor (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (shell))));
#endif

  scale_x = MIN (scale_x, GIMP_DISPLAY_RENDER_MAX_SCALE);
  scale_y = scale_x;

  if (shell->scale_x > shell->scale_y)
    {
      scale_y *= (shell->scale_x / shell->scale_y);

      buffer_scale = shell->scale_y * scale_y;
    }
  else if (shell->scale_y > shell->scale_x)
    {
      scale_x *= (shell->scale_y / shell->scale_x);

      buffer_scale = shell->scale_x * scale_x;
    }
  else
    {
      buffer_scale = shell->scale_x * scale_x;
    }

  gimp_display_shell_scroll_get_scaled_viewport (shell,
                                                 &viewport_offset_x,
                                                 &viewport_offset_y,
                                                 &viewport_width,
                                                 &viewport_height);

  scaled_x      = floor ((x + viewport_offset_x) * scale_x);
  scaled_y      = floor ((y + viewport_offset_y) * scale_y);
  scaled_width  = ceil (w * scale_x);
  scaled_height = ceil (h * scale_y);

  if (shell->rotate_transform)
    {
      xfer = cairo_surface_create_similar_image (cairo_get_target (cr),
                                                 CAIRO_FORMAT_ARGB32,
                                                 scaled_width,
                                                 scaled_height);
      cairo_surface_mark_dirty (xfer);
      xfer_src_x = 0;
      xfer_src_y = 0;
    }
  else
    {
      xfer = gimp_display_xfer_get_surface (shell->xfer,
                                            scaled_width,
                                            scaled_height,
                                            &xfer_src_x,
                                            &xfer_src_y);
    }

  cairo_stride = cairo_image_surface_get_stride (xfer);
  cairo_data   = cairo_image_surface_get_data (xfer) +
                 xfer_src_y * cairo_stride + xfer_src_x * 4;

  cairo_buffer = gegl_buffer_linear_new_from_data (cairo_data,
                                                   babl_format ("cairo-ARGB32"),
                                                   GEGL_RECTANGLE (0, 0,
                                                                   scaled_width,
                                                                   scaled_height),
                                                   cairo_stride,
                                                   NULL, NULL);

  if (shell->profile_transform ||
      gimp_display_shell_has_filter (shell))
    {
      gboolean can_convert_to_u8;

      /*  if there is a profile transform or a display filter, we need
       *  to use temp buffers
       */

      can_convert_to_u8 = gimp_display_shell_profile_can_convert_to_u8 (shell);

      /*  create the filter buffer if we have filters
       */
      if ((gimp_display_shell_has_filter (shell) || ! can_convert_to_u8) &&
          ! shell->filter_buffer)
        {
          gint w = GIMP_DISPLAY_RENDER_BUF_WIDTH  * GIMP_DISPLAY_RENDER_MAX_SCALE;
          gint h = GIMP_DISPLAY_RENDER_BUF_HEIGHT * GIMP_DISPLAY_RENDER_MAX_SCALE;

          shell->filter_data =
            gegl_malloc (w * h * babl_format_get_bytes_per_pixel (shell->filter_format));

          shell->filter_stride =
            w * babl_format_get_bytes_per_pixel (shell->filter_format);

          shell->filter_buffer =
            gegl_buffer_linear_new_from_data (shell->filter_data,
                                              shell->filter_format,
                                              GEGL_RECTANGLE (0, 0, w, h),
                                              GEGL_AUTO_ROWSTRIDE,
                                              (GDestroyNotify) gegl_free,
                                              shell->filter_data);
        }

      if (shell->profile_transform)
        {
          /*  if there is a profile transform, load the projection
           *  pixels into the profile_buffer
           */
#ifndef USE_NODE_BLIT
          gegl_buffer_get (buffer,
                           GEGL_RECTANGLE (scaled_x, scaled_y,
                                           scaled_width, scaled_height),
                           buffer_scale,
                           gimp_projectable_get_format (GIMP_PROJECTABLE (image)),
                           shell->profile_data, shell->profile_stride,
                           GEGL_ABYSS_CLAMP);
#else
          gegl_node_blit (node,
                          buffer_scale,
                          GEGL_RECTANGLE (scaled_x, scaled_y,
                                          scaled_width, scaled_height),
                          gimp_projectable_get_format (GIMP_PROJECTABLE (image)),
                          shell->profile_data, shell->profile_stride,
                          GEGL_BLIT_CACHE);
#endif

          if (gimp_display_shell_has_filter (shell) || ! can_convert_to_u8)
            {
              /*  if there are filters, convert the pixels from the
               *  profile_buffer to the filter_buffer
               */
              gimp_display_shell_profile_convert_buffer (shell,
                                                         shell->profile_buffer,
                                                         GEGL_RECTANGLE (0, 0,
                                                                         scaled_width,
                                                                         scaled_height),
                                                         shell->filter_buffer,
                                                         GEGL_RECTANGLE (0, 0,
                                                                         scaled_width,
                                                                         scaled_height));
            }
          else
            {
              /*  otherwise, convert the profile_buffer directly into
               *  the cairo_buffer
               */
              gimp_display_shell_profile_convert_buffer (shell,
                                                         shell->profile_buffer,
                                                         GEGL_RECTANGLE (0, 0,
                                                                         scaled_width,
                                                                         scaled_height),
                                                         cairo_buffer,
                                                         GEGL_RECTANGLE (0, 0,
                                                                         scaled_width,
                                                                         scaled_height));
            }
        }
      else
        {
          /*  otherwise, load the projection pixels directly into the
           *  filter_buffer
           */
#ifndef USE_NODE_BLIT
          gegl_buffer_get (buffer,
                           GEGL_RECTANGLE (scaled_x, scaled_y,
                                           scaled_width, scaled_height),
                           buffer_scale,
                           shell->filter_format,
                           shell->filter_data, shell->filter_stride,
                           GEGL_ABYSS_CLAMP);
#else
          gegl_node_blit (node,
                          buffer_scale,
                          GEGL_RECTANGLE (scaled_x, scaled_y,
                                          scaled_width, scaled_height),
                          shell->filter_format,
                          shell->filter_data, shell->filter_stride,
                          GEGL_BLIT_CACHE);
#endif
        }

      if (gimp_display_shell_has_filter (shell))
        {
          /*  convert the filter_buffer in place
           */
          gimp_color_display_stack_convert_buffer (shell->filter_stack,
                                                   shell->filter_buffer,
                                                   GEGL_RECTANGLE (0, 0,
                                                                   scaled_width,
                                                                   scaled_height));
        }

      if (gimp_display_shell_has_filter (shell) || ! can_convert_to_u8)
        {
          /*  finally, copy the filter buffer to the cairo-ARGB32 buffer
           */
          gegl_buffer_get (shell->filter_buffer,
                           GEGL_RECTANGLE (0, 0,
                                           scaled_width,
                                           scaled_height),
                           1.0,
                           babl_format ("cairo-ARGB32"),
                           cairo_data, cairo_stride,
                           GEGL_ABYSS_CLAMP);
        }
    }
  else
    {
      /*  otherwise we can copy the projection pixels straight to the
       *  cairo-ARGB32 buffer
       */
#ifndef USE_NODE_BLIT
      gegl_buffer_get (buffer,
                       GEGL_RECTANGLE (scaled_x, scaled_y,
                                       scaled_width, scaled_height),
                       buffer_scale,
                       babl_format ("cairo-ARGB32"),
                       cairo_data, cairo_stride,
                       GEGL_ABYSS_CLAMP);
#else
      gegl_node_blit (node,
                      buffer_scale,
                      GEGL_RECTANGLE (scaled_x, scaled_y,
                                      scaled_width, scaled_height),
                      babl_format ("cairo-ARGB32"),
                      cairo_data, cairo_stride,
                      GEGL_BLIT_CACHE);
#endif
    }

  g_object_unref (cairo_buffer);

  if (shell->mask)
    {
      if (! shell->mask_surface)
        {
          shell->mask_surface =
            cairo_image_surface_create (CAIRO_FORMAT_A8,
                                        GIMP_DISPLAY_RENDER_BUF_WIDTH  *
                                        GIMP_DISPLAY_RENDER_MAX_SCALE,
                                        GIMP_DISPLAY_RENDER_BUF_HEIGHT *
                                        GIMP_DISPLAY_RENDER_MAX_SCALE);
        }

      cairo_surface_mark_dirty (shell->mask_surface);

      cairo_stride = cairo_image_surface_get_stride (shell->mask_surface);
      cairo_data   = cairo_image_surface_get_data (shell->mask_surface) +
                     mask_src_y * cairo_stride + mask_src_x * 4;

      gegl_buffer_get (shell->mask,
                       GEGL_RECTANGLE (scaled_x - shell->mask_offset_x,
                                       scaled_y - shell->mask_offset_y,
                                       scaled_width, scaled_height),
                       buffer_scale,
                       babl_format ("Y u8"),
                       cairo_data, cairo_stride,
                       GEGL_ABYSS_NONE);

      if (shell->mask_inverted)
        {
          gint mask_height = scaled_height;

          while (mask_height--)
            {
              gint    mask_width = scaled_width;
              guchar *d          = cairo_data;

              while (mask_width--)
                {
                  guchar inv = 255 - *d;

                  *d++ = inv;
                }

              cairo_data += cairo_stride;
            }
        }
    }

  /*  put it to the screen  */
  cairo_save (cr);

  cairo_rectangle (cr, x, y, w, h);

  cairo_scale (cr, 1.0 / scale_x, 1.0 / scale_y);

  cairo_set_source_surface (cr, xfer,
                            x * scale_x - xfer_src_x,
                            y * scale_y - xfer_src_y);

  if (shell->rotate_transform)
    {
      cairo_pattern_t *pattern;

      pattern = cairo_get_source (cr);
      cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);

      cairo_set_line_width (cr, 1.0);
      cairo_stroke_preserve (cr);

      cairo_surface_destroy (xfer);
    }

  cairo_clip (cr);
  cairo_paint (cr);

  if (shell->mask)
    {
      gimp_cairo_set_source_rgba (cr, &shell->mask_color);
      cairo_mask_surface (cr, shell->mask_surface,
                          (x - mask_src_x) * scale_x,
                          (y - mask_src_y) * scale_y);
    }

  cairo_restore (cr);
}
Пример #16
0
static gboolean
test_operation (const char *operation_name)
{
  gboolean result = FALSE;

  const Babl *format = babl_format ("RGBA u8");
  const gint bpp = babl_format_get_bytes_per_pixel (format);
  const gint out_width = 5 + 10;
  const gint out_height = 5 + 10;

  guchar *output_with_abyss = gegl_malloc (out_width * out_height * bpp);
  guchar *output_no_abyss   = gegl_malloc (out_width * out_height * bpp);

  GeglColor *upper_color = gegl_color_new ("rgb(0.2, 0.8, 0.2)");
  GeglColor *lower_color = gegl_color_new ("rgb(0.0, 0.0, 0.0)");
  GeglColor *transparent = gegl_color_new ("rgba(0.0, 0.0, 0.0, 0.0)");

  {
    /* Using abyss */
    GeglNode *ptn = gegl_node_new();

    GeglNode *test_op, *upper_rect, *lower_rect;

    test_op = gegl_node_new_child (ptn,
                                   "operation", operation_name,
                                   NULL);

    upper_rect = gegl_node_new_child (ptn,
                                   "operation", "gegl:rectangle",
                                   "color", upper_color,
                                   "x", 5.0,
                                   "y", 5.0,
                                   "width", 10.0,
                                   "height", 10.0,
                                   NULL);

    lower_rect = gegl_node_new_child (ptn,
                                   "operation", "gegl:rectangle",
                                   "color", lower_color,
                                   "x", 0.0,
                                   "y", 0.0,
                                   "width", 10.0,
                                   "height", 10.0,
                                   NULL);

    gegl_node_connect_to (lower_rect, "output", test_op, "input");
    gegl_node_connect_to (upper_rect, "output", test_op, "aux");

    {
      int i;
      guchar *out = output_with_abyss;
      for (i = 0; i < out_height; i++)
        {
          gegl_node_blit (test_op,
                          1.0,
                          GEGL_RECTANGLE (0, i, out_width, 1),
                          format,
                          out,
                          GEGL_AUTO_ROWSTRIDE,
                          0);
          out += out_width * bpp;
        }
    }

    g_object_unref (ptn);
  }

  {
    /* Explicit transparency */
    GeglNode *ptn = gegl_node_new();

    GeglNode *test_op, *upper_rect, *lower_rect;
    GeglNode *upper_over, *lower_over;
    GeglNode *background;

    test_op = gegl_node_new_child (ptn,
                                   "operation", operation_name,
                                   NULL);

    background = gegl_node_new_child (ptn,
                                   "operation", "gegl:rectangle",
                                   "color", transparent,
                                   "x", 0.0,
                                   "y", 0.0,
                                   "width", 10.0 + 5.0,
                                   "height", 10.0 + 5.0,
                                   NULL);

    upper_rect = gegl_node_new_child (ptn,
                                   "operation", "gegl:rectangle",
                                   "color", upper_color,
                                   "x", 5.0,
                                   "y", 5.0,
                                   "width", 10.0,
                                   "height", 10.0,
                                   NULL);

    upper_over = gegl_node_new_child (ptn,
                                   "operation", "gegl:over",
                                   NULL);

    lower_rect = gegl_node_new_child (ptn,
                                   "operation", "gegl:rectangle",
                                   "color", lower_color,
                                   "x", 0.0,
                                   "y", 0.0,
                                   "width", 10.0,
                                   "height", 10.0,
                                   NULL);

    lower_over = gegl_node_new_child (ptn,
                                   "operation", "gegl:over",
                                   NULL);

    gegl_node_connect_to (lower_rect, "output", lower_over, "aux");
    gegl_node_connect_to (upper_rect, "output", upper_over, "aux");

    gegl_node_connect_to (background, "output", lower_over, "input");
    gegl_node_connect_to (background, "output", upper_over, "input");

    gegl_node_connect_to (lower_over, "output", test_op, "input");
    gegl_node_connect_to (upper_over, "output", test_op, "aux");

    {
      int i;
      guchar *out = output_no_abyss;
      for (i = 0; i < out_height; i++)
        {
          gegl_node_blit (test_op,
                          1.0,
                          GEGL_RECTANGLE (0, i, out_width, 1),
                          format,
                          out,
                          GEGL_AUTO_ROWSTRIDE,
                          0);
          out += out_width * bpp;
        }
    }

    g_object_unref (ptn);
  }

  if (0 == memcmp (output_with_abyss, output_no_abyss, out_width * out_height * bpp))
    {
      printf (".");
      fflush(stdout);
      result = TRUE;
    }
  else
    {
      printf ("\n %s ... FAIL\n", operation_name);
      result = FALSE;
    }

  if (!result)
    {
      GeglBuffer *linear;
      gchar *filename;

      filename = g_strconcat (operation_name, " - with abyss.png", NULL);
      linear = gegl_buffer_linear_new_from_data (output_with_abyss,
                                                format,
                                                GEGL_RECTANGLE (0, 0, out_width, out_height),
                                                GEGL_AUTO_ROWSTRIDE,
                                                NULL,
                                                NULL);
      dump_to_png (filename, linear);
      g_free (filename);
      g_object_unref (linear);

      filename = g_strconcat (operation_name, " - no abyss.png", NULL);
      linear = gegl_buffer_linear_new_from_data (output_no_abyss,
                                                 format,
                                                 GEGL_RECTANGLE (0, 0, out_width, out_height),
                                                 GEGL_AUTO_ROWSTRIDE,
                                                 NULL,
                                                 NULL);
      dump_to_png (filename, linear);
      g_free (filename);
      g_object_unref (linear);
    }

  gegl_free (output_with_abyss);
  gegl_free (output_no_abyss);

  return result;
}
Пример #17
0
/* FIXME: make this use direct data access in more cases than the
 * case of the base buffer.
 */
gpointer *
gegl_buffer_linear_open (GeglBuffer          *buffer,
                         const GeglRectangle *extent,   /* if NULL, use buf  */
                         gint                *rowstride,/* returns rowstride */
                         const Babl          *format)   /* if NULL, from buf */
{
  if (!format)
    format = buffer->soft_format;

  if (extent == NULL)
    extent=&buffer->extent;

  /*gegl_buffer_lock (buffer);*/
  g_rec_mutex_lock (&buffer->tile_storage->mutex);
  if (extent->x     == buffer->extent.x &&
      extent->y     == buffer->extent.y &&
      extent->width == buffer->tile_width &&
      extent->height <= buffer->tile_height &&
      buffer->soft_format == format)
    {
      GeglTile *tile;

      g_assert (buffer->tile_width <= buffer->tile_storage->tile_width);
      g_assert (buffer->tile_height == buffer->tile_storage->tile_height);

      tile = g_object_get_data (G_OBJECT (buffer), "linear-tile");
      g_assert (tile == NULL); /* We need to reference count returned direct
                                * linear buffers to allow multiple open like
                                * the copying case.
                                */
      tile = gegl_tile_source_get_tile ((GeglTileSource*) (buffer),
                                        0,0,0);
      g_assert (tile);
      gegl_tile_lock (tile);

      g_object_set_data (G_OBJECT (buffer), "linear-tile", tile);

      if(rowstride)*rowstride = buffer->tile_storage->tile_width * babl_format_get_bytes_per_pixel (format);
      return (gpointer)gegl_tile_get_data (tile);
    }
  /* first check if there is a linear buffer, share the existing buffer if one
   * exists.
   */
    {
      GList *linear_buffers;
      GList *iter;
      BufferInfo *info = NULL;
      linear_buffers = g_object_get_data (G_OBJECT (buffer), "linear-buffers");

      for (iter = linear_buffers; iter; iter=iter->next)
        {
          info = iter->data;
          if (info->format        == format           &&
              info->extent.x      == buffer->extent.x &&
              info->extent.y      == buffer->extent.y &&
              info->extent.width  == buffer->extent.width &&
              info->extent.height == buffer->extent.height
              )
            {
              info->refs++;
              g_print ("!!!!!! sharing a linear buffer!!!!!\n");
              return info->buf;
            }
        }
    }

  {
    BufferInfo *info = g_new0 (BufferInfo, 1);
    GList *linear_buffers;
    gint rs;
    linear_buffers = g_object_get_data (G_OBJECT (buffer), "linear-buffers");
    linear_buffers = g_list_append (linear_buffers, info);
    g_object_set_data (G_OBJECT (buffer), "linear-buffers", linear_buffers);

    info->extent = *extent;
    info->format = format;

    rs = info->extent.width * babl_format_get_bytes_per_pixel (format);
    if(rowstride)*rowstride = rs;

    info->buf = gegl_malloc (rs * info->extent.height);
    gegl_buffer_get_unlocked (buffer, 1.0, &info->extent, format, info->buf, rs, GEGL_ABYSS_NONE);
    return info->buf;
  }
  return NULL;
}
Пример #18
0
/**
 * Process the gegl filter
 * @param operation the given Gegl operation
 * @param input the input buffer.
 * @param output the output buffer.
 * @param result the region of interest.
 * @param level the level of detail
 * @return True, if the filter was successfull applied.
 */
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglProperties         *o = GEGL_PROPERTIES (operation);
  const Babl  *input_format = babl_format ("Y float");
  const int bytes_per_pixel = babl_format_get_bytes_per_pixel (input_format);

  GeglDTMetric metric;
  gint     width, height, averaging, i;
  gfloat   threshold_lo, threshold_hi, maxval, *src_buf, *dst_buf;
  gboolean normalize;

  width  = result->width;
  height = result->height;

  threshold_lo = o->threshold_lo;
  threshold_hi = o->threshold_hi;
  normalize    = o->normalize;
  metric       = o->metric;
  averaging    = o->averaging;

  src_buf = gegl_malloc (width * height * bytes_per_pixel);
  dst_buf = gegl_calloc (width * height, bytes_per_pixel);

  gegl_operation_progress (operation, 0.0, "");

  gegl_buffer_get (input, result, 1.0, input_format, src_buf,
                   GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

  if (!averaging)
    {
      binary_dt_1st_pass (operation, width, height, threshold_lo,
                          src_buf, dst_buf);
      binary_dt_2nd_pass (operation, width, height, threshold_lo, metric,
                          src_buf, dst_buf);
    }
  else
    {
      gfloat *tmp_buf;
      gint i, j;

      tmp_buf = gegl_malloc (width * height * bytes_per_pixel);

      for (i = 0; i < averaging; i++)
        {
          gfloat thres;

          thres = (i+1) * (threshold_hi - threshold_lo) / (averaging + 1);
          thres += threshold_lo;

          binary_dt_1st_pass (operation, width, height, thres,
                              src_buf, tmp_buf);
          binary_dt_2nd_pass (operation, width, height, thres, metric,
                              src_buf, tmp_buf);

          for (j = 0; j < width * height; j++)
            dst_buf[j] += tmp_buf[j];
        }

      gegl_free (tmp_buf);
    }

  if (normalize)
    {
      maxval = EPSILON;

      for (i = 0; i < width * height; i++)
        maxval = MAX (dst_buf[i], maxval);
    }
  else
    {
      maxval = averaging;
    }

  if (averaging > 0 || normalize)
    {
      for (i = 0; i < width * height; i++)
        dst_buf[i] = dst_buf[i] * threshold_hi / maxval;
    }

  gegl_buffer_set (output, result, 0, input_format, dst_buf,
                   GEGL_AUTO_ROWSTRIDE);

  gegl_operation_progress (operation, 1.0, "");

  gegl_free (dst_buf);
  gegl_free (src_buf);

  return TRUE;
}
Пример #19
0
void
gimp_display_shell_render (GimpDisplayShell *shell,
                           cairo_t          *cr,
                           gint              x,
                           gint              y,
                           gint              w,
                           gint              h)
{
  GimpImage       *image;
  GimpProjection  *projection;
  GeglBuffer      *buffer;
  gdouble          scale_x      = 1.0;
  gdouble          scale_y      = 1.0;
  gdouble          buffer_scale = 1.0;
  gint             viewport_offset_x;
  gint             viewport_offset_y;
  gint             viewport_width;
  gint             viewport_height;
  gint             scaled_x;
  gint             scaled_y;
  gint             scaled_width;
  gint             scaled_height;
  cairo_surface_t *xfer;
  gint             xfer_src_x;
  gint             xfer_src_y;
  gint             mask_src_x = 0;
  gint             mask_src_y = 0;
  gint             stride;
  guchar          *data;

  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
  g_return_if_fail (cr != NULL);
  g_return_if_fail (w > 0 && h > 0);

  image      = gimp_display_get_image (shell->display);
  projection = gimp_image_get_projection (image);
  buffer     = gimp_pickable_get_buffer (GIMP_PICKABLE (projection));

#ifdef GIMP_DISPLAY_RENDER_ENABLE_SCALING
  /* if we had this future API, things would look pretty on hires (retina) */
  scale_x = gdk_window_get_scale_factor (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (shell))));
#endif

  scale_x = MIN (scale_x, GIMP_DISPLAY_RENDER_MAX_SCALE);
  scale_y = scale_x;

  if (shell->scale_x > shell->scale_y)
    {
      scale_y *= (shell->scale_x / shell->scale_y);

      buffer_scale = shell->scale_y * scale_y;
    }
  else if (shell->scale_y > shell->scale_x)
    {
      scale_x *= (shell->scale_y / shell->scale_x);

      buffer_scale = shell->scale_x * scale_x;
    }
  else
    {
      buffer_scale = shell->scale_x * scale_x;
    }

  gimp_display_shell_scroll_get_scaled_viewport (shell,
                                                 &viewport_offset_x,
                                                 &viewport_offset_y,
                                                 &viewport_width,
                                                 &viewport_height);

  scaled_x      = floor ((x + viewport_offset_x) * scale_x);
  scaled_y      = floor ((y + viewport_offset_y) * scale_y);
  scaled_width  = ceil (w * scale_x);
  scaled_height = ceil (h * scale_y);

  if (shell->rotate_transform)
    {
      xfer = cairo_surface_create_similar_image (cairo_get_target (cr),
                                                 CAIRO_FORMAT_ARGB32,
                                                 scaled_width,
                                                 scaled_height);
      cairo_surface_mark_dirty (xfer);
      xfer_src_x = 0;
      xfer_src_y = 0;
    }
  else
    {
      xfer = gimp_display_xfer_get_surface (shell->xfer,
                                            scaled_width,
                                            scaled_height,
                                            &xfer_src_x,
                                            &xfer_src_y);
    }

  stride = cairo_image_surface_get_stride (xfer);
  data = cairo_image_surface_get_data (xfer);
  data += xfer_src_y * stride + xfer_src_x * 4;

  /*  apply filters to the rendered projection  */
  if (shell->filter_stack)
    {
      const Babl *filter_format = babl_format ("R'G'B'A float");

      if (! shell->filter_buffer)
        {
          gint w = GIMP_DISPLAY_RENDER_BUF_WIDTH  * GIMP_DISPLAY_RENDER_MAX_SCALE;
          gint h = GIMP_DISPLAY_RENDER_BUF_HEIGHT * GIMP_DISPLAY_RENDER_MAX_SCALE;

          shell->filter_data =
            gegl_malloc (w * h * babl_format_get_bytes_per_pixel (filter_format));

          shell->filter_stride = w * babl_format_get_bytes_per_pixel (filter_format);

          shell->filter_buffer =
            gegl_buffer_linear_new_from_data (shell->filter_data,
                                              filter_format,
                                              GEGL_RECTANGLE (0, 0, w, h),
                                              GEGL_AUTO_ROWSTRIDE,
                                              (GDestroyNotify) gegl_free,
                                              shell->filter_data);
        }

      gegl_buffer_get (buffer,
                       GEGL_RECTANGLE (scaled_x, scaled_y,
                                       scaled_width, scaled_height),
                       buffer_scale,
                       filter_format, shell->filter_data,
                       shell->filter_stride, GEGL_ABYSS_CLAMP);


      gimp_color_display_stack_convert_buffer (shell->filter_stack,
                                               shell->filter_buffer,
                                               GEGL_RECTANGLE (0, 0,
                                                               scaled_width,
                                                               scaled_height));

      gegl_buffer_get (shell->filter_buffer,
                       GEGL_RECTANGLE (0, 0,
                                       scaled_width,
                                       scaled_height),
                       1.0,
                       babl_format ("cairo-ARGB32"),
                       data, stride,
                       GEGL_ABYSS_CLAMP);
    }
  else
    {
      gegl_buffer_get (buffer,
                       GEGL_RECTANGLE (scaled_x, scaled_y,
                                       scaled_width, scaled_height),
                       buffer_scale,
                       babl_format ("cairo-ARGB32"),
                       data, stride,
                       GEGL_ABYSS_CLAMP);
    }

  if (shell->mask)
    {
      gint mask_height;

      if (! shell->mask_surface)
        {
          shell->mask_surface =
            cairo_image_surface_create (CAIRO_FORMAT_A8,
                                        GIMP_DISPLAY_RENDER_BUF_WIDTH  *
                                        GIMP_DISPLAY_RENDER_MAX_SCALE,
                                        GIMP_DISPLAY_RENDER_BUF_HEIGHT *
                                        GIMP_DISPLAY_RENDER_MAX_SCALE);
        }

      cairo_surface_mark_dirty (shell->mask_surface);

      stride = cairo_image_surface_get_stride (shell->mask_surface);
      data = cairo_image_surface_get_data (shell->mask_surface);
      data += mask_src_y * stride + mask_src_x * 4;

      gegl_buffer_get (shell->mask,
                       GEGL_RECTANGLE (scaled_x, scaled_y,
                                       scaled_width, scaled_height),
                       buffer_scale,
                       babl_format ("Y u8"),
                       data, stride,
                       GEGL_ABYSS_CLAMP);

      /* invert the mask so what is *not* the foreground object is masked */
      mask_height = scaled_height;
      while (mask_height--)
        {
          gint    mask_width = scaled_width;
          guchar *d          = data;

          while (mask_width--)
            {
              guchar inv = 255 - *d;

              *d++ = inv;
            }

          data += stride;
        }
    }

  /*  put it to the screen  */
  cairo_save (cr);

  cairo_rectangle (cr, x, y, w, h);

  cairo_scale (cr, 1.0 / scale_x, 1.0 / scale_y);

  cairo_set_source_surface (cr, xfer,
                            x * scale_x - xfer_src_x,
                            y * scale_y - xfer_src_y);

  if (shell->rotate_transform)
    {
      cairo_pattern_t *pattern;

      pattern = cairo_get_source (cr);
      cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);

      cairo_set_line_width (cr, 1.0);
      cairo_stroke_preserve (cr);

      cairo_surface_destroy (xfer);
    }

  cairo_clip (cr);
  cairo_paint (cr);

  if (shell->mask)
    {
      gimp_cairo_set_source_rgba (cr, &shell->mask_color);
      cairo_mask_surface (cr, shell->mask_surface,
                          (x - mask_src_x) * scale_x,
                          (y - mask_src_y) * scale_y);
    }

  cairo_restore (cr);
}