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