X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gdk-pixbuf%2Fgdk-pixbuf-util.c;h=9ee844a28dd1502c44a43ae7cf1e4574fd878d3e;hb=250fd7cc43af62578cbcd58a90e1fe0fb706eed1;hp=2bc7e98b06f165ac74b2b7d14bf6d84d0fcbaee5;hpb=7bfdf70ae137731c64249f0aecc34023dff74cf8;p=~andy%2Fgtk diff --git a/gdk-pixbuf/gdk-pixbuf-util.c b/gdk-pixbuf/gdk-pixbuf-util.c index 2bc7e98b0..9ee844a28 100644 --- a/gdk-pixbuf/gdk-pixbuf-util.c +++ b/gdk-pixbuf/gdk-pixbuf-util.c @@ -3,92 +3,102 @@ * Copyright (C) 1999 The Free Software Foundation * * Authors: Federico Mena-Quintero - * Cody Russell + * Cody Russell * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public + * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public + * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include -#include "gdk-pixbuf.h" +#include "gdk-pixbuf-private.h" +#include /** * gdk_pixbuf_add_alpha: - * @pixbuf: A pixbuf. - * @substitute_color: Whether to substitute a color for zero opacity. If this - * is #FALSE, then the (@r, @g, @b) arguments will be ignored. + * @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 original - * pixbuf already had alpha information, then the contents of the new pixbuf are - * exactly the same as the original's. Otherwise, the new pixbuf will have all - * pixels with full opacity if @substitute_color is #FALSE. If - * @substitute_color is #TRUE, then the color specified by (@r, @g, @b) will be - * substituted for zero opacity. + * 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: A newly-created pixbuf with a reference count of 1. **/ GdkPixbuf * -gdk_pixbuf_add_alpha (GdkPixbuf *pixbuf, gboolean substitute_color, guchar r, guchar g, guchar b) +gdk_pixbuf_add_alpha (const GdkPixbuf *pixbuf, + gboolean substitute_color, guchar r, guchar g, guchar b) { - ArtPixBuf *apb; - ArtPixBuf *new_apb; GdkPixbuf *new_pixbuf; int x, y; g_return_val_if_fail (pixbuf != NULL, 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); - apb = pixbuf->art_pixbuf; - g_return_val_if_fail (apb->format == ART_PIX_RGB, NULL); - g_return_val_if_fail (apb->n_channels == 3 || apb->n_channels == 4, NULL); - g_return_val_if_fail (apb->bits_per_sample == 8, NULL); - - if (apb->has_alpha) { - new_apb = art_pixbuf_duplicate (apb); - if (!new_apb) + if (pixbuf->has_alpha) { + new_pixbuf = gdk_pixbuf_copy (pixbuf); + if (!new_pixbuf) return NULL; - return gdk_pixbuf_new_from_art_pixbuf (new_apb); - } - - new_pixbuf = gdk_pixbuf_new (ART_PIX_RGB, TRUE, 8, apb->width, apb->height); + 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; - new_apb = new_pixbuf->art_pixbuf; - - for (y = 0; y < apb->height; y++) { + for (y = 0; y < pixbuf->height; y++) { guchar *src, *dest; guchar tr, tg, tb; - src = apb->pixels + y * apb->rowstride; - dest = new_apb->pixels + y * new_apb->rowstride; - - for (x = 0; x < apb->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; + src = pixbuf->pixels + y * pixbuf->rowstride; + dest = new_pixbuf->pixels + y * new_pixbuf->rowstride; + + 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; + } } } @@ -97,58 +107,139 @@ gdk_pixbuf_add_alpha (GdkPixbuf *pixbuf, gboolean substitute_color, guchar r, gu /** * gdk_pixbuf_copy_area: - * @src_pixbuf: The pixbuf to be copied. - * @src_x: The X coordinate of the upper left corner of the area to copy. - * @src_y: The Y coordinate of the upper left corner of the area to copy. - * @width: The width of the area to copy. - * @height: The height of the area to copy. - * @dest_pixbuf: The pixbuf to store the copy in. - * @dest_x: X coordinate for the upper left corner of the rectangle to draw to in @dest_pixbuf. - * @dest_y: Y coordinate for the upper left corner of the rectangle to draw to in @dest_pixbuf. + * @src_pixbuf: Source pixbuf. + * @src_x: Source X coordinate within @src_pixbuf. + * @src_y: Source Y coordinate within @src_pixbuf. + * @width: Width of the area to copy. + * @height: Height of the area to copy. + * @dest_pixbuf: Destination pixbuf. + * @dest_x: X coordinate within @dest_pixbuf. + * @dest_y: Y coordinate within @dest_pixbuf. * - * Takes a rectangle area beginning at (@src_x, @src_y) @width pixels wide - * and @height pixels high from @src_pixbuf and copy it into @dest_pixbuf - * at (@dest_x, @dest_y). @dest_pixbuf must already be created and must be - * large enough to hold the requested area. + * Copies a rectangular area from @src_pixbuf to @dest_pixbuf. Conversion of + * pixbuf formats is done automatically. + **/ +void +gdk_pixbuf_copy_area (const GdkPixbuf *src_pixbuf, + int src_x, int src_y, + int width, int height, + GdkPixbuf *dest_pixbuf, + int dest_x, int dest_y) +{ + g_return_if_fail (src_pixbuf != NULL); + g_return_if_fail (dest_pixbuf != NULL); + + g_return_if_fail (src_x >= 0 && src_x + width <= src_pixbuf->width); + g_return_if_fail (src_y >= 0 && src_y + height <= src_pixbuf->height); + + g_return_if_fail (dest_x >= 0 && dest_x + width <= dest_pixbuf->width); + g_return_if_fail (dest_y >= 0 && dest_y + height <= dest_pixbuf->height); + + g_return_if_fail (!(gdk_pixbuf_get_has_alpha (src_pixbuf) && !gdk_pixbuf_get_has_alpha (dest_pixbuf))); + + /* This will perform format conversions automatically */ + + gdk_pixbuf_scale (src_pixbuf, + dest_pixbuf, + dest_x, dest_y, + width, height, + (double) (dest_x - src_x), + (double) (dest_y - src_y), + 1.0, 1.0, + GDK_INTERP_NEAREST); +} + + + +/** + * gdk_pixbuf_saturate_and_pixelate: + * @src: source image + * @dest: place to write modified version of @src + * @saturation: saturation factor + * @pixelate: whether to pixelate * - * Return value: void + * 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 is darkened); + * if greater than 1.0, saturation is increased (the image is + * brightened). 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_copy_area(GdkPixbuf *src_pixbuf, - gint src_x, gint src_y, - gint width, gint height, - GdkPixbuf *dest_pixbuf, - gint dest_x, gint dest_y) +void +gdk_pixbuf_saturate_and_pixelate(const GdkPixbuf *src, + GdkPixbuf *dest, + gfloat saturation, + gboolean pixelate) { - gint src_width, src_height, dest_width, dest_height; - - /* Ensure that we have a source pixbuf, and that the requested - * area is not larger than that pixbuf. - */ - g_return_if_fail(src_pixbuf != NULL); - - src_width = gdk_pixbuf_get_width(src_pixbuf); - src_height = gdk_pixbuf_get_height(src_pixbuf); - - g_return_if_fail(src_x >= 0 && width <= src_width); - g_return_if_fail(src_y >= 0 && height <= src_height); - - /* Ensure that we have a destination pixbuf, and that the - * requested area is not larger than that pixbuf. - */ - g_return_if_fail(dest_pixbuf != NULL); - - dest_width = gdk_pixbuf_get_width(dest_pixbuf); - dest_height = gdk_pixbuf_get_height(dest_pixbuf); - - g_return_if_fail(dest_x >= 0 && width <= dest_width); - g_return_if_fail(dest_y >= 0 && height <= dest_height); - - /* Scale 1:1 the source pixbuf into the destination pixbuf. */ - gdk_pixbuf_scale(src_pixbuf, - dest_pixbuf, - dest_x, dest_y, - width, height, - (double)(dest_x - src_x), - (double)(dest_y - src_y), - 1., 1., ART_FILTER_NEAREST); + /* 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) + memcpy (gdk_pixbuf_get_pixels (dest), + gdk_pixbuf_get_pixels (src), + gdk_pixbuf_get_height (src) * gdk_pixbuf_get_rowstride (src)); + } else { + int i, j, t; + int width, height, has_alpha, src_rowstride, dest_rowstride, bytes_per_pixel; + guchar *src_line; + guchar *dest_line; + 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); + + src_line = gdk_pixbuf_get_pixels (src); + dest_line = gdk_pixbuf_get_pixels (dest); + +#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; + } + } + } }