示例#1
0
GeglBuffer *
gimp_drawable_transform_buffer_flip (GimpDrawable         *drawable,
                                     GimpContext          *context,
                                     GeglBuffer           *orig_buffer,
                                     gint                  orig_offset_x,
                                     gint                  orig_offset_y,
                                     GimpOrientationType   flip_type,
                                     gdouble               axis,
                                     gboolean              clip_result,
                                     GimpColorProfile    **buffer_profile,
                                     gint                 *new_offset_x,
                                     gint                 *new_offset_y)
{
  const Babl         *format;
  GeglBuffer         *new_buffer;
  GeglBufferIterator *iter;
  GeglRectangle       src_rect;
  GeglRectangle       dest_rect;
  gint                bpp;
  gint                orig_x, orig_y;
  gint                orig_width, orig_height;
  gint                new_x, new_y;
  gint                new_width, new_height;
  gint                x, y;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);
  g_return_val_if_fail (buffer_profile != NULL, NULL);
  g_return_val_if_fail (new_offset_x != NULL, NULL);
  g_return_val_if_fail (new_offset_y != NULL, NULL);

  *buffer_profile =
    gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (drawable));

  orig_x      = orig_offset_x;
  orig_y      = orig_offset_y;
  orig_width  = gegl_buffer_get_width (orig_buffer);
  orig_height = gegl_buffer_get_height (orig_buffer);

  new_x      = orig_x;
  new_y      = orig_y;
  new_width  = orig_width;
  new_height = orig_height;

  switch (flip_type)
    {
    case GIMP_ORIENTATION_HORIZONTAL:
      new_x = RINT (-((gdouble) orig_x +
                      (gdouble) orig_width - axis) + axis);
      break;

    case GIMP_ORIENTATION_VERTICAL:
      new_y = RINT (-((gdouble) orig_y +
                      (gdouble) orig_height - axis) + axis);
      break;

    case GIMP_ORIENTATION_UNKNOWN:
      g_return_val_if_reached (NULL);
      break;
    }

  format = gegl_buffer_get_format (orig_buffer);
  bpp    = babl_format_get_bytes_per_pixel (format);

  new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                new_width, new_height),
                                format);

  if (clip_result && (new_x != orig_x || new_y != orig_y))
    {
      GimpRGB    bg;
      GeglColor *color;
      gint       clip_x, clip_y;
      gint       clip_width, clip_height;

      *new_offset_x = orig_x;
      *new_offset_y = orig_y;

      /*  Use transparency, rather than the bg color, as the "outside" color of
       *  channels, and drawables with an alpha channel.
       */
      if (GIMP_IS_CHANNEL (drawable) || babl_format_has_alpha (format))
        {
          gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0);
        }
      else
        {
          gimp_context_get_background (context, &bg);
          gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable),
                                             &bg, &bg);
        }

      color = gimp_gegl_color_new (&bg, gimp_drawable_get_space (drawable));
      gegl_buffer_set_color (new_buffer, NULL, color);
      g_object_unref (color);

      if (gimp_rectangle_intersect (orig_x, orig_y, orig_width, orig_height,
                                    new_x, new_y, new_width, new_height,
                                    &clip_x, &clip_y,
                                    &clip_width, &clip_height))
        {
          orig_x = new_x = clip_x - orig_x;
          orig_y = new_y = clip_y - orig_y;
        }

      orig_width  = new_width  = clip_width;
      orig_height = new_height = clip_height;
    }
  else
    {
      *new_offset_x = new_x;
      *new_offset_y = new_y;

      orig_x = 0;
      orig_y = 0;
      new_x  = 0;
      new_y  = 0;
    }

  if (new_width == 0 && new_height == 0)
    return new_buffer;

  dest_rect.x      = new_x;
  dest_rect.y      = new_y;
  dest_rect.width  = new_width;
  dest_rect.height = new_height;

  iter = gegl_buffer_iterator_new (new_buffer, &dest_rect, 0, NULL,
                                   GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE, 1);

  switch (flip_type)
    {
    case GIMP_ORIENTATION_HORIZONTAL:
      while (gegl_buffer_iterator_next (iter))
        {
          gint stride = iter->items[0].roi.width * bpp;

          src_rect = iter->items[0].roi;

          src_rect.x = (orig_x + orig_width)          -
                       (iter->items[0].roi.x - dest_rect.x) -
                       iter->items[0].roi.width;

          gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, iter->items[0].data,
                           stride, GEGL_ABYSS_NONE);

          for (y = 0; y < iter->items[0].roi.height; y++)
            {
              guint8 *left  = iter->items[0].data;
              guint8 *right = iter->items[0].data;

              left  += y * stride;
              right += y * stride + (iter->items[0].roi.width - 1) * bpp;

              for (x = 0; x < iter->items[0].roi.width / 2; x++)
                {
                  guint8 temp[bpp];

                  memcpy (temp,  left,  bpp);
                  memcpy (left,  right, bpp);
                  memcpy (right, temp,  bpp);

                  left  += bpp;
                  right -= bpp;
                }
            }
        }
      break;

    case GIMP_ORIENTATION_VERTICAL:
      while (gegl_buffer_iterator_next (iter))
        {
          gint stride = iter->items[0].roi.width * bpp;

          src_rect = iter->items[0].roi;

          src_rect.y = (orig_y + orig_height)         -
                       (iter->items[0].roi.y - dest_rect.y) -
                       iter->items[0].roi.height;

          gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, iter->items[0].data,
                           stride, GEGL_ABYSS_NONE);

          for (x = 0; x < iter->items[0].roi.width; x++)
            {
              guint8 *top    = iter->items[0].data;
              guint8 *bottom = iter->items[0].data;

              top    += x * bpp;
              bottom += x * bpp + (iter->items[0].roi.height - 1) * stride;

              for (y = 0; y < iter->items[0].roi.height / 2; y++)
                {
                  guint8 temp[bpp];

                  memcpy (temp,   top,    bpp);
                  memcpy (top,    bottom, bpp);
                  memcpy (bottom, temp,   bpp);

                  top    += stride;
                  bottom -= stride;
                }
            }
        }
      break;

    case GIMP_ORIENTATION_UNKNOWN:
      gegl_buffer_iterator_stop (iter);
      break;
    }

  return new_buffer;
}
示例#2
0
GeglBuffer *
gimp_drawable_transform_buffer_rotate (GimpDrawable      *drawable,
                                       GimpContext       *context,
                                       GeglBuffer        *orig_buffer,
                                       gint               orig_offset_x,
                                       gint               orig_offset_y,
                                       GimpRotationType   rotate_type,
                                       gdouble            center_x,
                                       gdouble            center_y,
                                       gboolean           clip_result,
                                       GimpColorProfile **buffer_profile,
                                       gint              *new_offset_x,
                                       gint              *new_offset_y)
{
  const Babl    *format;
  GeglBuffer    *new_buffer;
  GeglRectangle  src_rect;
  GeglRectangle  dest_rect;
  gint           orig_x, orig_y;
  gint           orig_width, orig_height;
  gint           orig_bpp;
  gint           new_x, new_y;
  gint           new_width, new_height;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);
  g_return_val_if_fail (buffer_profile != NULL, NULL);
  g_return_val_if_fail (new_offset_x != NULL, NULL);
  g_return_val_if_fail (new_offset_y != NULL, NULL);

  *buffer_profile =
    gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (drawable));

  orig_x      = orig_offset_x;
  orig_y      = orig_offset_y;
  orig_width  = gegl_buffer_get_width (orig_buffer);
  orig_height = gegl_buffer_get_height (orig_buffer);
  orig_bpp    = babl_format_get_bytes_per_pixel (gegl_buffer_get_format (orig_buffer));

  switch (rotate_type)
    {
    case GIMP_ROTATE_90:
      gimp_drawable_transform_rotate_point (orig_x,
                                            orig_y + orig_height,
                                            rotate_type, center_x, center_y,
                                            &new_x, &new_y);
      new_width  = orig_height;
      new_height = orig_width;
      break;

    case GIMP_ROTATE_180:
      gimp_drawable_transform_rotate_point (orig_x + orig_width,
                                            orig_y + orig_height,
                                            rotate_type, center_x, center_y,
                                            &new_x, &new_y);
      new_width  = orig_width;
      new_height = orig_height;
      break;

    case GIMP_ROTATE_270:
      gimp_drawable_transform_rotate_point (orig_x + orig_width,
                                            orig_y,
                                            rotate_type, center_x, center_y,
                                            &new_x, &new_y);
      new_width  = orig_height;
      new_height = orig_width;
      break;

    default:
      g_return_val_if_reached (NULL);
      break;
    }

  format = gegl_buffer_get_format (orig_buffer);

  if (clip_result && (new_x != orig_x || new_y != orig_y ||
                      new_width != orig_width || new_height != orig_height))

    {
      GimpRGB    bg;
      GeglColor *color;
      gint       clip_x, clip_y;
      gint       clip_width, clip_height;

      new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                    orig_width, orig_height),
                                    format);

      *new_offset_x = orig_x;
      *new_offset_y = orig_y;

      /*  Use transparency, rather than the bg color, as the "outside" color of
       *  channels, and drawables with an alpha channel.
       */
      if (GIMP_IS_CHANNEL (drawable) || babl_format_has_alpha (format))
        {
          gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0);
        }
      else
        {
          gimp_context_get_background (context, &bg);
          gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable),
                                             &bg, &bg);
        }

      color = gimp_gegl_color_new (&bg, gimp_drawable_get_space (drawable));
      gegl_buffer_set_color (new_buffer, NULL, color);
      g_object_unref (color);

      if (gimp_rectangle_intersect (orig_x, orig_y, orig_width, orig_height,
                                    new_x, new_y, new_width, new_height,
                                    &clip_x, &clip_y,
                                    &clip_width, &clip_height))
        {
          gint saved_orig_x = orig_x;
          gint saved_orig_y = orig_y;

          new_x = clip_x - orig_x;
          new_y = clip_y - orig_y;

          switch (rotate_type)
            {
            case GIMP_ROTATE_90:
              gimp_drawable_transform_rotate_point (clip_x + clip_width,
                                                    clip_y,
                                                    GIMP_ROTATE_270,
                                                    center_x,
                                                    center_y,
                                                    &orig_x,
                                                    &orig_y);
              orig_x      -= saved_orig_x;
              orig_y      -= saved_orig_y;
              orig_width   = clip_height;
              orig_height  = clip_width;
              break;

            case GIMP_ROTATE_180:
              orig_x      = clip_x - orig_x;
              orig_y      = clip_y - orig_y;
              orig_width  = clip_width;
              orig_height = clip_height;
              break;

            case GIMP_ROTATE_270:
              gimp_drawable_transform_rotate_point (clip_x,
                                                    clip_y + clip_height,
                                                    GIMP_ROTATE_90,
                                                    center_x,
                                                    center_y,
                                                    &orig_x,
                                                    &orig_y);
              orig_x      -= saved_orig_x;
              orig_y      -= saved_orig_y;
              orig_width   = clip_height;
              orig_height  = clip_width;
              break;
            }

          new_width  = clip_width;
          new_height = clip_height;
        }
      else
        {
          new_width  = 0;
          new_height = 0;
        }
    }
  else
    {
      new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                    new_width, new_height),
                                    format);

      *new_offset_x = new_x;
      *new_offset_y = new_y;

      orig_x = 0;
      orig_y = 0;
      new_x  = 0;
      new_y  = 0;
    }

  if (new_width < 1 || new_height < 1)
    return new_buffer;

  src_rect.x      = orig_x;
  src_rect.y      = orig_y;
  src_rect.width  = orig_width;
  src_rect.height = orig_height;

  dest_rect.x      = new_x;
  dest_rect.y      = new_y;
  dest_rect.width  = new_width;
  dest_rect.height = new_height;

  switch (rotate_type)
    {
    case GIMP_ROTATE_90:
      {
        guchar *buf = g_new (guchar, new_height * orig_bpp);
        gint    i;

        /* Not cool, we leak memory if we return, but anyway that is
         * never supposed to happen. If we see this warning, a bug has
         * to be fixed!
         */
        g_return_val_if_fail (new_height == orig_width, NULL);

        src_rect.y      = orig_y + orig_height - 1;
        src_rect.height = 1;

        dest_rect.x     = new_x;
        dest_rect.width = 1;

        for (i = 0; i < orig_height; i++)
          {
            src_rect.y  = orig_y + orig_height - 1 - i;
            dest_rect.x = new_x + i;

            gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
            gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE);
          }

        g_free (buf);
      }
      break;

    case GIMP_ROTATE_180:
      {
        guchar *buf = g_new (guchar, new_width * orig_bpp);
        gint    i, j, k;

        /* Not cool, we leak memory if we return, but anyway that is
         * never supposed to happen. If we see this warning, a bug has
         * to be fixed!
         */
        g_return_val_if_fail (new_width == orig_width, NULL);

        src_rect.y      = orig_y + orig_height - 1;
        src_rect.height = 1;

        dest_rect.y      = new_y;
        dest_rect.height = 1;

        for (i = 0; i < orig_height; i++)
          {
            src_rect.y  = orig_y + orig_height - 1 - i;
            dest_rect.y = new_y + i;

            gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

            for (j = 0; j < orig_width / 2; j++)
              {
                guchar *left  = buf + j * orig_bpp;
                guchar *right = buf + (orig_width - 1 - j) * orig_bpp;

                for (k = 0; k < orig_bpp; k++)
                  {
                    guchar tmp = left[k];
                    left[k]    = right[k];
                    right[k]   = tmp;
                  }
              }

            gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE);
          }

        g_free (buf);
      }
      break;

    case GIMP_ROTATE_270:
      {
        guchar *buf = g_new (guchar, new_width * orig_bpp);
        gint    i;

        /* Not cool, we leak memory if we return, but anyway that is
         * never supposed to happen. If we see this warning, a bug has
         * to be fixed!
         */
        g_return_val_if_fail (new_width == orig_height, NULL);

        src_rect.x     = orig_x + orig_width - 1;
        src_rect.width = 1;

        dest_rect.y      = new_y;
        dest_rect.height = 1;

        for (i = 0; i < orig_width; i++)
          {
            src_rect.x  = orig_x + orig_width - 1 - i;
            dest_rect.y = new_y + i;

            gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
            gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE);
          }

        g_free (buf);
      }
      break;
    }

  return new_buffer;
}
示例#3
0
void
gimp_drawable_offset (GimpDrawable   *drawable,
                      GimpContext    *context,
                      gboolean        wrap_around,
                      GimpOffsetType  fill_type,
                      gint            offset_x,
                      gint            offset_y)
{
  GimpItem      *item;
  GeglBuffer    *src_buffer;
  GeglBuffer    *new_buffer;
  GeglRectangle  src_rect;
  GeglRectangle  dest_rect;
  gint           width, height;
  gint           src_x, src_y;
  gint           dest_x, dest_y;

  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
  g_return_if_fail (GIMP_IS_CONTEXT (context));

  item = GIMP_ITEM (drawable);

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

  if (wrap_around)
    {
      /*  avoid modulo operation on negative values  */
      while (offset_x < 0)
        offset_x += width;
      while (offset_y < 0)
        offset_y += height;

      offset_x %= width;
      offset_y %= height;
    }
  else
    {
      offset_x = CLAMP (offset_x, -width, width);
      offset_y = CLAMP (offset_y, -height, height);
    }

  if (offset_x == 0 && offset_y == 0)
    return;

  src_buffer = gimp_drawable_get_buffer (drawable);

  new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
                                gimp_drawable_get_format (drawable));

  if (! wrap_around)
    {
      if (fill_type == GIMP_OFFSET_BACKGROUND)
        {
          GimpRGB    bg;
          GeglColor *color;

          gimp_context_get_background (context, &bg);
          gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable),
                                             &bg, &bg);

          color = gimp_gegl_color_new (&bg);
          gegl_buffer_set_color (new_buffer, NULL, color);
          g_object_unref (color);
        }
    }

  if (offset_x >= 0)
    {
      src_x = 0;
      dest_x = offset_x;
      width = CLAMP ((width - offset_x), 0, width);
    }
  else
    {
      src_x = -offset_x;
      dest_x = 0;
      width = CLAMP ((width + offset_x), 0, width);
    }

  if (offset_y >= 0)
    {
      src_y = 0;
      dest_y = offset_y;
      height = CLAMP ((height - offset_y), 0, height);
    }
  else
    {
      src_y = -offset_y;
      dest_y = 0;
      height = CLAMP ((height + offset_y), 0, height);
    }

  /*  Copy the center region  */
  if (width && height)
    {
      gegl_buffer_copy (src_buffer,
                        GEGL_RECTANGLE (src_x,  src_y,  width, height),
                        GEGL_ABYSS_NONE,
                        new_buffer,
                        GEGL_RECTANGLE (dest_x,dest_y,  width, height));
    }

  if (wrap_around)
    {
      /*  Copy appropriately for wrap around  */

      if (offset_x >= 0 && offset_y >= 0)
        {
          src_x = gimp_item_get_width  (item) - offset_x;
          src_y = gimp_item_get_height (item) - offset_y;
        }
      else if (offset_x >= 0 && offset_y < 0)
        {
          src_x = gimp_item_get_width (item) - offset_x;
          src_y = 0;
        }
      else if (offset_x < 0 && offset_y >= 0)
        {
          src_x = 0;
          src_y = gimp_item_get_height (item) - offset_y;
        }
      else if (offset_x < 0 && offset_y < 0)
        {
          src_x = 0;
          src_y = 0;
        }

      dest_x = (src_x + offset_x) % gimp_item_get_width (item);
      if (dest_x < 0)
        dest_x = gimp_item_get_width (item) + dest_x;

      dest_y = (src_y + offset_y) % gimp_item_get_height (item);
      if (dest_y < 0)
        dest_y = gimp_item_get_height (item) + dest_y;

      /*  intersecting region  */
      if (offset_x != 0 && offset_y != 0)
        {
          gegl_buffer_copy (src_buffer,
                            GEGL_RECTANGLE (src_x, src_y,
                                            ABS (offset_x), ABS (offset_y)),
                            GEGL_ABYSS_NONE,
                            new_buffer,
                            GEGL_RECTANGLE (dest_x, dest_y, 0, 0));
        }

      /*  X offset  */
      if (offset_x != 0)
        {
          if (offset_y >= 0)
            {
              src_rect.x      = src_x;
              src_rect.y      = 0;
              src_rect.width  = ABS (offset_x);
              src_rect.height = gimp_item_get_height (item) - ABS (offset_y);

              dest_rect.x = dest_x;
              dest_rect.y = dest_y + offset_y;
            }
          else if (offset_y < 0)
            {
              src_rect.x      = src_x;
              src_rect.y      = src_y - offset_y;
              src_rect.width  = ABS (offset_x);
              src_rect.height = gimp_item_get_height (item) - ABS (offset_y);

              dest_rect.x = dest_x;
              dest_rect.y = 0;
            }

          gegl_buffer_copy (src_buffer, &src_rect, GEGL_ABYSS_NONE,
                            new_buffer, &dest_rect);
        }

      /*  X offset  */
      if (offset_y != 0)
        {
          if (offset_x >= 0)
            {
              src_rect.x      = 0;
              src_rect.y      = src_y;
              src_rect.width  = gimp_item_get_width (item) - ABS (offset_x);
              src_rect.height = ABS (offset_y);

              dest_rect.x = dest_x + offset_x;
              dest_rect.y = dest_y;
            }
          else if (offset_x < 0)
            {
              src_rect.x      = src_x - offset_x;
              src_rect.y      = src_y;
              src_rect.width  = gimp_item_get_width (item) - ABS (offset_x);
              src_rect.height = ABS (offset_y);

              dest_rect.x = 0;
              dest_rect.y = dest_y;
            }

          gegl_buffer_copy (src_buffer, &src_rect, GEGL_ABYSS_NONE,
                            new_buffer, &dest_rect);
        }
    }

  gimp_drawable_set_buffer (drawable,
                            gimp_item_is_attached (item),
                            C_("undo-type", "Offset Drawable"),
                            new_buffer);
  g_object_unref (new_buffer);
}