コード例 #1
0
ファイル: gdk-pixbuf.c プロジェクト: GNOME/gdk-pixbuf
/**
 * gdk_pixbuf_copy:
 * @pixbuf: A pixbuf.
 * 
 * Creates a new #GdkPixbuf with a copy of the information in the specified
 * @pixbuf. Note that this does not copy the options set on the original #GdkPixbuf,
 * use gdk_pixbuf_copy_options() for this.
 * 
 * Return value: (nullable) (transfer full): A newly-created pixbuf with a reference count of 1, or %NULL if
 * not enough memory could be allocated.
 **/
GdkPixbuf *
gdk_pixbuf_copy (const GdkPixbuf *pixbuf)
{
	guchar *buf;
	int size;

	g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);

	/* Calculate a semi-exact size.  Here we copy with full rowstrides;
	 * maybe we should copy each row individually with the minimum
	 * rowstride?
	 */

	size = gdk_pixbuf_get_byte_length (pixbuf);

	buf = g_try_malloc (size);
	if (!buf)
		return NULL;

	memcpy (buf, gdk_pixbuf_read_pixels (pixbuf), size);

	return gdk_pixbuf_new_from_data (buf,
					 pixbuf->colorspace, pixbuf->has_alpha,
					 pixbuf->bits_per_sample,
					 pixbuf->width, pixbuf->height,
					 pixbuf->rowstride,
					 free_buffer,
					 NULL);
}
コード例 #2
0
/**
 * gdk_pixbuf_scale:
 * @src: a #GdkPixbuf
 * @dest: the #GdkPixbuf into which to render the results
 * @dest_x: the left coordinate for region to render
 * @dest_y: the top coordinate for region to render
 * @dest_width: the width of the region to render
 * @dest_height: the height of the region to render
 * @offset_x: the offset in the X direction (currently rounded to an integer)
 * @offset_y: the offset in the Y direction (currently rounded to an integer)
 * @scale_x: the scale factor in the X direction
 * @scale_y: the scale factor in the Y direction
 * @interp_type: the interpolation type for the transformation.
 * 
 * Creates a transformation of the source image @src by scaling by
 * @scale_x and @scale_y then translating by @offset_x and @offset_y,
 * then renders the rectangle (@dest_x, @dest_y, @dest_width,
 * @dest_height) of the resulting image onto the destination image
 * replacing the previous contents.
 *
 * Try to use gdk_pixbuf_scale_simple() first, this function is
 * the industrial-strength power tool you can fall back to if
 * gdk_pixbuf_scale_simple() isn't powerful enough.
 *
 * If the source rectangle overlaps the destination rectangle on the
 * same pixbuf, it will be overwritten during the scaling which
 * results in rendering artifacts.
 **/
void
gdk_pixbuf_scale (const GdkPixbuf *src,
		  GdkPixbuf       *dest,
		  int              dest_x,
		  int              dest_y,
		  int              dest_width,
		  int              dest_height,
		  double           offset_x,
		  double           offset_y,
		  double           scale_x,
		  double           scale_y,
		  GdkInterpType    interp_type)
{
  const guint8 *src_pixels;
  guint8 *dest_pixels;

  g_return_if_fail (GDK_IS_PIXBUF (src));
  g_return_if_fail (GDK_IS_PIXBUF (dest));
  g_return_if_fail (dest_x >= 0 && dest_x + dest_width <= dest->width);
  g_return_if_fail (dest_y >= 0 && dest_y + dest_height <= dest->height);

  offset_x = floor (offset_x + 0.5);
  offset_y = floor (offset_y + 0.5);

  /* Force an implicit copy */
  dest_pixels = gdk_pixbuf_get_pixels (dest);
  src_pixels = gdk_pixbuf_read_pixels (src);

  _pixops_scale (dest_pixels, dest->width, dest->height, dest->rowstride,
                 dest->n_channels, dest->has_alpha, src_pixels, src->width,
                 src->height, src->rowstride, src->n_channels, src->has_alpha,
                 dest_x, dest_y, dest_width, dest_height, offset_x, offset_y,
                 scale_x, scale_y, (PixopsInterpType)interp_type);
}
コード例 #3
0
ファイル: gdk-pixbuf-scale.c プロジェクト: GNOME/gdk-pixbuf
/**
 * gdk_pixbuf_flip:
 * @src: a #GdkPixbuf
 * @horizontal: %TRUE to flip horizontally, %FALSE to flip vertically
 *
 * Flips a pixbuf horizontally or vertically and returns the
 * result in a new pixbuf.
 *
 * Returns: (nullable) (transfer full): the new #GdkPixbuf, or %NULL
 * if not enough memory could be allocated for it.
 *
 * Since: 2.6
 */
GdkPixbuf *
gdk_pixbuf_flip (const GdkPixbuf *src,
		 gboolean         horizontal)
{
  const guint8 *src_pixels;
  guint8 *dest_pixels;
  GdkPixbuf *dest;
  const guchar *p;
  guchar *q;
  gint x, y;

  g_return_val_if_fail (GDK_IS_PIXBUF (src), NULL);
  dest = gdk_pixbuf_new (src->colorspace, 
			 src->has_alpha, 
			 src->bits_per_sample, 
			 src->width, 
			 src->height);
  if (!dest)
    return NULL;

  dest_pixels = gdk_pixbuf_get_pixels (dest);
  src_pixels = gdk_pixbuf_read_pixels (src);

  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 /* 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);
	    }
	}
    }

  return dest;
}
コード例 #4
0
/**
 * gdk_pixbuf_composite_color:
 * @src: a #GdkPixbuf
 * @dest: the #GdkPixbuf into which to render the results
 * @dest_x: the left coordinate for region to render
 * @dest_y: the top coordinate for region to render
 * @dest_width: the width of the region to render
 * @dest_height: the height of the region to render
 * @offset_x: the offset in the X direction (currently rounded to an integer)
 * @offset_y: the offset in the Y direction (currently rounded to an integer)
 * @scale_x: the scale factor in the X direction
 * @scale_y: the scale factor in the Y direction
 * @interp_type: the interpolation type for the transformation.
 * @overall_alpha: overall alpha for source image (0..255)
 * @check_x: the X offset for the checkboard (origin of checkboard is at -@check_x, -@check_y)
 * @check_y: the Y offset for the checkboard 
 * @check_size: the size of checks in the checkboard (must be a power of two)
 * @color1: the color of check at upper left
 * @color2: the color of the other check
 * 
 * Creates a transformation of the source image @src by scaling by
 * @scale_x and @scale_y then translating by @offset_x and @offset_y,
 * then composites the rectangle (@dest_x ,@dest_y, @dest_width,
 * @dest_height) of the resulting image with a checkboard of the
 * colors @color1 and @color2 and renders it onto the destination
 * image.
 *
 * See gdk_pixbuf_composite_color_simple() for a simpler variant of this
 * function suitable for many tasks.
 * 
 **/
void
gdk_pixbuf_composite_color (const GdkPixbuf *src,
			    GdkPixbuf       *dest,
			    int              dest_x,
			    int              dest_y,
			    int              dest_width,
			    int              dest_height,
			    double           offset_x,
			    double           offset_y,
			    double           scale_x,
			    double           scale_y,
			    GdkInterpType    interp_type,
			    int              overall_alpha,
			    int              check_x,
			    int              check_y,
			    int              check_size,
			    guint32          color1,
			    guint32          color2)
{
  const guint8 *src_pixels;
  guint8 *dest_pixels;

  g_return_if_fail (GDK_IS_PIXBUF (src));
  g_return_if_fail (GDK_IS_PIXBUF (dest));
  g_return_if_fail (dest_x >= 0 && dest_x + dest_width <= dest->width);
  g_return_if_fail (dest_y >= 0 && dest_y + dest_height <= dest->height);
  g_return_if_fail (overall_alpha >= 0 && overall_alpha <= 255);

  offset_x = floor (offset_x + 0.5);
  offset_y = floor (offset_y + 0.5);
  
  /* Force an implicit copy */
  dest_pixels = gdk_pixbuf_get_pixels (dest);
  src_pixels = gdk_pixbuf_read_pixels (src);

  _pixops_composite_color (dest_pixels, dest_width, dest_height,
			   dest->rowstride, dest->n_channels, dest->has_alpha,
			   src_pixels, src->width, src->height,
			   src->rowstride, src->n_channels, src->has_alpha,
			   dest_x, dest_y, dest_width, dest_height, offset_x,
			   offset_y, scale_x, scale_y,
			   (PixopsInterpType)interp_type, overall_alpha,
			   check_x, check_y, check_size, color1, color2);
}
コード例 #5
0
ファイル: DockItem.cpp プロジェクト: yoosamui/DockLight
/**
 * This function will not work for pixbufs with images that are other than 8 bits 
 * per sample or channel, but it will work for most of the pixbufs that GTK+ uses.
 * @param GdkPixbuf* pixbuf
 * @return true is a movement detected or false is none.
 */
gboolean DockItem::isMovementDetected(GdkPixbuf* pixbuf)
{
    gint x, y;
    int w = gdk_pixbuf_get_width(pixbuf);
    int h = gdk_pixbuf_get_height(pixbuf);
    int channels = 3; //gdk_pixbuf_get_n_channels(pixbuf);
    gint rowstride = gdk_pixbuf_get_rowstride(pixbuf);
    gint pixel_offset;

    // Returns a read-only pointer to the raw pixel data;
    // must not be modified. This function allows skipping the 
    // implicit copy that must be made if gdk_pixbuf_get_pixels()
    // is called on a read-only pixbuf.
    const guint8* pixels = gdk_pixbuf_read_pixels(pixbuf);

    if (!m_pixbufPreviousPass) {
        for (y = 0; y < h; y++) {
            for (x = 0; x < w; x++) {
                pixel_offset = y * rowstride + x * channels;
                this->m_pixelsbuf[pixel_offset] = pixels[ pixel_offset];
            }
        }
        m_pixbufPreviousPass = true;
        return FALSE;
    }

    for (y = 0; y < h; y++) {
        for (x = 0; x < w; x++) {
            pixel_offset = y * rowstride + x * channels;
            if (this->m_pixelsbuf[pixel_offset] != pixels[pixel_offset]) {
                m_pixbufPreviousPass = FALSE;
                return TRUE;
            }
        }
    }

    m_pixbufPreviousPass = FALSE;
    return FALSE;
}
コード例 #6
0
/**
 * 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: (nullable) (transfer full): the new #GdkPixbuf, or %NULL
 * if not enough memory could be allocated for it.
 *
 * Since: 2.6
 */
GdkPixbuf *
gdk_pixbuf_rotate_simple (const GdkPixbuf   *src,
			  GdkPixbufRotation  angle)
{
  const guint8 *src_pixels;
  guint8 *dest_pixels;
  GdkPixbuf *dest;
  const guchar *p;
  guchar *q;
  gint x, y;

  src_pixels = gdk_pixbuf_read_pixels (src);

  switch (angle % 360)
    {
    case 0:
      dest = gdk_pixbuf_copy (src);
      break;
    case 90:
      dest = gdk_pixbuf_new (src->colorspace, 
			     src->has_alpha, 
			     src->bits_per_sample, 
			     src->height, 
			     src->width);
      if (!dest)
	return NULL;

      dest_pixels = gdk_pixbuf_get_pixels (dest);

      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:
      dest = gdk_pixbuf_new (src->colorspace, 
			     src->has_alpha, 
			     src->bits_per_sample, 
			     src->width, 
			     src->height);
      if (!dest)
	return NULL;

      dest_pixels = gdk_pixbuf_get_pixels (dest);

      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:
      dest = gdk_pixbuf_new (src->colorspace, 
			     src->has_alpha, 
			     src->bits_per_sample, 
			     src->height, 
			     src->width);
      if (!dest)
	return NULL;

      dest_pixels = gdk_pixbuf_get_pixels (dest);

      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:
      dest = NULL;
      g_warning ("gdk_pixbuf_rotate_simple() can only rotate "
		 "by multiples of 90 degrees");
      g_assert_not_reached ();
  } 

  return dest;
}
コード例 #7
0
ファイル: gdk-pixbuf-util.c プロジェクト: payload/gdk-pixbuf
/**
 * gdk_pixbuf_add_alpha:
 * @pixbuf: A #GdkPixbuf.
 * @substitute_color: Whether to set a color to zero opacity.  If this
 * is %FALSE, then the (@r, @g, @b) arguments will be ignored.
 * @r: Red value to substitute.
 * @g: Green value to substitute.
 * @b: Blue value to substitute.
 *
 * Takes an existing pixbuf and adds an alpha channel to it.
 * If the existing pixbuf already had an alpha channel, the channel
 * values are copied from the original; otherwise, the alpha channel
 * is initialized to 255 (full opacity).
 * 
 * If @substitute_color is %TRUE, then the color specified by (@r, @g, @b) will be
 * assigned zero opacity. That is, if you pass (255, 255, 255) for the
 * substitute color, all white pixels will become fully transparent.
 *
 * Return value: (transfer full): A newly-created pixbuf with a reference count of 1.
 **/
GdkPixbuf *
gdk_pixbuf_add_alpha (const GdkPixbuf *pixbuf,
		      gboolean substitute_color, guchar r, guchar g, guchar b)
{
	GdkPixbuf *new_pixbuf;
	int x, y;
	const guint8 *src_pixels;
	guint8 *ret_pixels;
	const guchar *src;
	guchar *dest;

	g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
	g_return_val_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB, NULL);
	g_return_val_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4, NULL);
	g_return_val_if_fail (pixbuf->bits_per_sample == 8, NULL);

	src_pixels = gdk_pixbuf_read_pixels (pixbuf);

	if (pixbuf->has_alpha) {
		new_pixbuf = gdk_pixbuf_copy (pixbuf);
		if (!new_pixbuf)
			return NULL;

                if (!substitute_color)
                        return new_pixbuf;
	} else {
                new_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, pixbuf->width, pixbuf->height);
        }

	if (!new_pixbuf)
		return NULL;

	ret_pixels = gdk_pixbuf_get_pixels (new_pixbuf);

	for (y = 0; y < pixbuf->height; y++, src_pixels += pixbuf->rowstride, ret_pixels += new_pixbuf->rowstride) {
		guchar tr, tg, tb;

                src = src_pixels;
                dest = ret_pixels;

                if (pixbuf->has_alpha) {
                        /* Just subst color, we already copied everything else */
                        for (x = 0; x < pixbuf->width; x++) {
                                if (src[0] == r && src[1] == g && src[2] == b)
                                        dest[3] = 0;
                                src += 4;
                                dest += 4;
                        }
                } else {
                        for (x = 0; x < pixbuf->width; x++) {
                                tr = *dest++ = *src++;
                                tg = *dest++ = *src++;
                                tb = *dest++ = *src++;

                                if (substitute_color && tr == r && tg == g && tb == b)
                                        *dest++ = 0;
                                else
                                        *dest++ = 255;
                        }
		}
	}

	return new_pixbuf;
}
コード例 #8
0
ファイル: gdk-pixbuf-util.c プロジェクト: payload/gdk-pixbuf
/**
 * gdk_pixbuf_saturate_and_pixelate:
 * @src: source image
 * @dest: place to write modified version of @src
 * @saturation: saturation factor
 * @pixelate: whether to pixelate
 *
 * Modifies saturation and optionally pixelates @src, placing the result in
 * @dest. @src and @dest may be the same pixbuf with no ill effects.  If
 * @saturation is 1.0 then saturation is not changed. If it's less than 1.0,
 * saturation is reduced (the image turns toward grayscale); if greater than
 * 1.0, saturation is increased (the image gets more vivid colors). If @pixelate
 * is %TRUE, then pixels are faded in a checkerboard pattern to create a
 * pixelated image. @src and @dest must have the same image format, size, and
 * rowstride.
 * 
 **/
void
gdk_pixbuf_saturate_and_pixelate(const GdkPixbuf *src,
                                 GdkPixbuf *dest,
                                 gfloat saturation,
                                 gboolean pixelate)
{
        /* NOTE that src and dest MAY be the same pixbuf! */
  
        g_return_if_fail (GDK_IS_PIXBUF (src));
        g_return_if_fail (GDK_IS_PIXBUF (dest));
        g_return_if_fail (gdk_pixbuf_get_height (src) == gdk_pixbuf_get_height (dest));
        g_return_if_fail (gdk_pixbuf_get_width (src) == gdk_pixbuf_get_width (dest));
        g_return_if_fail (gdk_pixbuf_get_has_alpha (src) == gdk_pixbuf_get_has_alpha (dest));
        g_return_if_fail (gdk_pixbuf_get_colorspace (src) == gdk_pixbuf_get_colorspace (dest));
  
        if (saturation == 1.0 && !pixelate) {
                if (dest != src)
                        gdk_pixbuf_copy_area (src, 0, 0, 
                                              gdk_pixbuf_get_width (src),
                                              gdk_pixbuf_get_height (src),
                                              dest, 0, 0);
        } else {
                int i, j, t;
                int width, height, has_alpha, src_rowstride, dest_rowstride, bytes_per_pixel;
		const guchar *src_line;
		guchar *dest_line;
                const guchar *src_pixel;
		guchar *dest_pixel;
                guchar intensity;

                has_alpha = gdk_pixbuf_get_has_alpha (src);
		bytes_per_pixel = has_alpha ? 4 : 3;
                width = gdk_pixbuf_get_width (src);
                height = gdk_pixbuf_get_height (src);
                src_rowstride = gdk_pixbuf_get_rowstride (src);
                dest_rowstride = gdk_pixbuf_get_rowstride (dest);
                
                dest_line = gdk_pixbuf_get_pixels (dest);
                src_line = gdk_pixbuf_read_pixels (src);
		
#define DARK_FACTOR 0.7
#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
#define CLAMP_UCHAR(v) (t = (v), CLAMP (t, 0, 255))
#define SATURATE(v) ((1.0 - saturation) * intensity + saturation * (v))

		for (i = 0 ; i < height ; i++) {
			src_pixel = src_line;
			src_line += src_rowstride;
			dest_pixel = dest_line;
			dest_line += dest_rowstride;

			for (j = 0 ; j < width ; j++) {
                                intensity = INTENSITY (src_pixel[0], src_pixel[1], src_pixel[2]);
                                if (pixelate && (i + j) % 2 == 0) {
                                        dest_pixel[0] = intensity / 2 + 127;
                                        dest_pixel[1] = intensity / 2 + 127;
                                        dest_pixel[2] = intensity / 2 + 127;
                                } else if (pixelate) {
                                        dest_pixel[0] = CLAMP_UCHAR ((SATURATE (src_pixel[0])) * DARK_FACTOR);
					dest_pixel[1] = CLAMP_UCHAR ((SATURATE (src_pixel[1])) * DARK_FACTOR);
                                        dest_pixel[2] = CLAMP_UCHAR ((SATURATE (src_pixel[2])) * DARK_FACTOR);
                                } else {
                                        dest_pixel[0] = CLAMP_UCHAR (SATURATE (src_pixel[0]));
                                        dest_pixel[1] = CLAMP_UCHAR (SATURATE (src_pixel[1]));
                                        dest_pixel[2] = CLAMP_UCHAR (SATURATE (src_pixel[2]));
                                }
				
                                if (has_alpha)
                                        dest_pixel[3] = src_pixel[3];

				src_pixel += bytes_per_pixel;
				dest_pixel += bytes_per_pixel;
			}
                }
        }
}
コード例 #9
0
ファイル: cairo.c プロジェクト: zartstrom/sway
cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf(const GdkPixbuf *gdkbuf) {
    int chan = gdk_pixbuf_get_n_channels(gdkbuf);
    if (chan < 3) return NULL;

#if GDK_PIXBUF_CHECK_VERSION(2,32,0)
    const guint8* gdkpix = gdk_pixbuf_read_pixels(gdkbuf);
#else
    const guint8* gdkpix = gdk_pixbuf_get_pixels(gdkbuf);
#endif
    if (!gdkpix) {
        return NULL;
    }
    gint w = gdk_pixbuf_get_width(gdkbuf);
    gint h = gdk_pixbuf_get_height(gdkbuf);
    int stride = gdk_pixbuf_get_rowstride(gdkbuf);

    cairo_format_t fmt = (chan == 3) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32;
    cairo_surface_t * cs = cairo_image_surface_create (fmt, w, h);
    cairo_surface_flush (cs);
    if ( !cs || cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) {
        return NULL;
    }

    int cstride = cairo_image_surface_get_stride(cs);
    unsigned char * cpix = cairo_image_surface_get_data(cs);

    if (chan == 3) {
        int i;
        for (i = h; i; --i) {
            const guint8 *gp = gdkpix;
            unsigned char *cp = cpix;
            const guint8* end = gp + 3*w;
            while (gp < end) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
                cp[0] = gp[2];
                cp[1] = gp[1];
                cp[2] = gp[0];
#else
                cp[1] = gp[0];
                cp[2] = gp[1];
                cp[3] = gp[2];
#endif
                gp += 3;
                cp += 4;
            }
            gdkpix += stride;
            cpix += cstride;
        }
    } else {
        /* premul-color = alpha/255 * color/255 * 255 = (alpha*color)/255
         * (z/255) = z/256 * 256/255     = z/256 (1 + 1/255)
         *         = z/256 + (z/256)/255 = (z + z/255)/256
         *         # recurse once
         *         = (z + (z + z/255)/256)/256
         *         = (z + z/256 + z/256/255) / 256
         *         # only use 16bit uint operations, loose some precision,
         *         # result is floored.
         *       ->  (z + z>>8)>>8
         *         # add 0x80/255 = 0.5 to convert floor to round
         *       =>  (z+0x80 + (z+0x80)>>8 ) >> 8
         * ------
         * tested as equal to lround(z/255.0) for uint z in [0..0xfe02]
         */
#define PREMUL_ALPHA(x,a,b,z) G_STMT_START { z = a * b + 0x80; x = (z + (z >> 8)) >> 8; } G_STMT_END
        int i;
        for (i = h; i; --i) {
            const guint8 *gp = gdkpix;
            unsigned char *cp = cpix;
            const guint8* end = gp + 4*w;
            guint z1, z2, z3;
            while (gp < end) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
                PREMUL_ALPHA(cp[0], gp[2], gp[3], z1);
                PREMUL_ALPHA(cp[1], gp[1], gp[3], z2);
                PREMUL_ALPHA(cp[2], gp[0], gp[3], z3);
                cp[3] = gp[3];
#else
                PREMUL_ALPHA(cp[1], gp[0], gp[3], z1);
                PREMUL_ALPHA(cp[2], gp[1], gp[3], z2);
                PREMUL_ALPHA(cp[3], gp[2], gp[3], z3);
                cp[0] = gp[3];
#endif
                gp += 4;
                cp += 4;
            }
            gdkpix += stride;
            cpix += cstride;
        }
#undef PREMUL_ALPHA
    }
    cairo_surface_mark_dirty(cs);
    return cs;
}