simple rotation support for gdk-pixbuf



Since a full transformation api a la 
http://mail.gnome.org/archives/gtk-devel-list/2003-February/msg00157.html
will probably have to wait for Cairo, here is what I intend to add to
gdk-pixbuf in the 2.6 timeframe:

typedef enum {
	GDK_PIXBUF_ANGLE_0   =   0,
	GDK_PIXBUF_ANGLE_90  =  90,
	GDK_PIXBUF_ANGLE_180 = 180,
	GDK_PIXBUF_ANGLE_270 = 270
} GdkPixbufAngle;

GdkPixbuf *gdk_pixbuf_rotate_simple (const GdkPixbuf *src,
				     GdkPixbufAngle   angle);
GdkPixbuf *gdk_pixbuf_flip          (const GdkPixbuf *src,
				     gboolean         horizontal,
				     gboolean         vertical);


Does this look reasonable ? Full implementation attached below.

Matthias



#define OFFSET(pb, x, y) ((x) * (pb)->n_channels + (y) * (pb)->rowstride)

/**
 * gdk_pixbuf_rotate_simple:
 * @src: a #GdkPixbuf
 * @angle: the angle to rotate by
 *
 * Rotates a pixbuf by a multiple of 90 degrees, and returns the
 * result in a new pixbuf.
 *
 * Returns: a new pixbuf
 *
 * Since: 2.6
 */
GdkPixbuf *
gdk_pixbuf_rotate_simple (const GdkPixbuf *src,
			  GdkPixbufAngle   angle)
{
  GdkPixbuf *dest;
  guchar *p, *q;
  gint x, y;
  
  if (angle == 0)
    return gdk_pixbuf_copy (src);

  if (angle == 180)
    dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, src->has_alpha, 
			   8, src->width, src->height);
  else
    dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, src->has_alpha, 
			   8, src->height, src->width);
    
  if (!dest)
    return NULL;
  
  switch (angle % 360)
    {
    case 90:
      for (y = 0; y < src->height; y++) 
	{ 
	  for (x = 0; x < src->width; x++) 
	    { 
	      p = src->pixels + OFFSET (src, x, y); 
	      q = dest->pixels + OFFSET (dest, y, src->width - x - 1); 
	      memcpy (q, p, dest->n_channels);
	    }
	} 
      break;
    case 180:
      for (y = 0; y < src->height; y++) 
	{ 
	  for (x = 0; x < src->width; x++) 
	    { 
	      p = src->pixels + OFFSET (src, x, y); 
	      q = dest->pixels + OFFSET (dest, src->width - x - 1, src->height - y - 1); 
	      memcpy (q, p, dest->n_channels);
	    }
	} 
      break;
    case 270:
      for (y = 0; y < src->height; y++) 
	{ 
	  for (x = 0; x < src->width; x++) 
	    { 
	      p = src->pixels + OFFSET (src, x, y); 
	      q = dest->pixels + OFFSET (dest, src->height - y - 1, x); 
	      memcpy (q, p, dest->n_channels);
	    }
	} 
      break;
    default:
      g_assert_not_reached ();
  } 

  return dest;
}

/**
 * gdk_pixbuf_flip:
 * @src: a #GdkPixbuf
 * @horizontal: %TRUE to flip horizontally
 * @vertical: %TRUE to flip vertically
 *
 * Flips a pixbuf horizontally and/or vertically and returns the
 * result in a new pixbuf.
 *
 * Returns: a new pixbuf.
 *
 * Since: 2.6
 */
GdkPixbuf *
gdk_pixbuf_flip (const GdkPixbuf *src,
		 gboolean         horizontal,
		 gboolean         vertical)
{
  GdkPixbuf *dest;
  guchar *p, *q;
  gint x, y;

  if (!horizontal && !vertical)
    return gdk_pixbuf_copy (src);

  dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, src->has_alpha, 
			 8, src->width, src->height);
  if (!dest)
    return NULL;

  if (!horizontal) /* flip vertical */
    {
      for (y = 0; y < dest->height; y++)
	{
	  p = src->pixels + OFFSET (src, 0, y);
	  q = dest->pixels + OFFSET (dest, 0, dest->height - y - 1);
	  memcpy (q, p, dest->rowstride);
	}
    }
  else if (!vertical) /* flip horizontal */
    {
      for (y = 0; y < dest->height; y++)
	{
	  for (x = 0; x < dest->width; x++)
	    {
	      p = src->pixels + OFFSET (src, x, y);
	      q = dest->pixels + OFFSET (dest, dest->width - x - 1, y);
	      memcpy (q, p, dest->n_channels);
	    }
	}
    }
  else /* flip both */
    {
      for (y = 0; y < dest->height; y++)
	{
	  for (x = 0; x < dest->width; x++)
	    {
	      p = src->pixels + OFFSET (src, x, y);
	      q = dest->pixels + OFFSET (dest, dest->width - x - 1, dest->height - y - 1);
	      memcpy (q, p, dest->n_channels);
	    }
	}
    }

  return dest;
}
				     


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]