]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/gdk-pixbuf-util.c
Handle case where we need to parse the xsetting as if it were an RC file
[~andy/gtk] / gdk-pixbuf / gdk-pixbuf-util.c
1 /* GdkPixbuf library - Utilities and miscellaneous convenience functions
2  *
3  * Copyright (C) 1999 The Free Software Foundation
4  *
5  * Authors: Federico Mena-Quintero <federico@gimp.org>
6  *          Cody Russell  <bratsche@gnome.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include <config.h>
25 #include "gdk-pixbuf-private.h"
26 #include <string.h>
27
28 \f
29
30 /**
31  * gdk_pixbuf_add_alpha:
32  * @pixbuf: A pixbuf.
33  * @substitute_color: Whether to set a color to zero opacity.  If this
34  * is #FALSE, then the (@r, @g, @b) arguments will be ignored.
35  * @r: Red value to substitute.
36  * @g: Green value to substitute.
37  * @b: Blue value to substitute.
38  *
39  * Takes an existing pixbuf and adds an alpha channel to it.
40  * If the existing pixbuf already had an alpha channel, the channel
41  * values are copied from the original; otherwise, the alpha channel
42  * is initialized to 255 (full opacity).
43  * 
44  * If @substitute_color is #TRUE, then the color specified by (@r, @g, @b) will be
45  * assigned zero opacity. That is, if you pass (255, 255, 255) for the
46  * substitute color, all white pixels will become fully transparent.
47  *
48  * Return value: A newly-created pixbuf with a reference count of 1.
49  **/
50 GdkPixbuf *
51 gdk_pixbuf_add_alpha (const GdkPixbuf *pixbuf,
52                       gboolean substitute_color, guchar r, guchar g, guchar b)
53 {
54         GdkPixbuf *new_pixbuf;
55         int x, y;
56
57         g_return_val_if_fail (pixbuf != NULL, NULL);
58         g_return_val_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB, NULL);
59         g_return_val_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4, NULL);
60         g_return_val_if_fail (pixbuf->bits_per_sample == 8, NULL);
61
62         if (pixbuf->has_alpha) {
63                 new_pixbuf = gdk_pixbuf_copy (pixbuf);
64                 if (!new_pixbuf)
65                         return NULL;
66
67                 if (!substitute_color)
68                         return new_pixbuf;
69         } else {
70                 new_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, pixbuf->width, pixbuf->height);
71         }
72         
73         if (!new_pixbuf)
74                 return NULL;
75
76         for (y = 0; y < pixbuf->height; y++) {
77                 guchar *src, *dest;
78                 guchar tr, tg, tb;
79
80                 src = pixbuf->pixels + y * pixbuf->rowstride;
81                 dest = new_pixbuf->pixels + y * new_pixbuf->rowstride;
82                 
83                 if (pixbuf->has_alpha) {
84                         /* Just subst color, we already copied everything else */
85                         for (x = 0; x < pixbuf->width; x++) {
86                                 if (src[0] == r && src[1] == g && src[2] == b)
87                                         dest[3] = 0;
88                                 src += 4;
89                                 dest += 4;
90                         }
91                 } else {                        
92                         for (x = 0; x < pixbuf->width; x++) {
93                                 tr = *dest++ = *src++;
94                                 tg = *dest++ = *src++;
95                                 tb = *dest++ = *src++;
96                                 
97                                 if (substitute_color && tr == r && tg == g && tb == b)
98                                         *dest++ = 0;
99                                 else
100                                         *dest++ = 255;
101                         }
102                 }
103         }
104
105         return new_pixbuf;
106 }
107
108 /**
109  * gdk_pixbuf_copy_area:
110  * @src_pixbuf: Source pixbuf.
111  * @src_x: Source X coordinate within @src_pixbuf.
112  * @src_y: Source Y coordinate within @src_pixbuf.
113  * @width: Width of the area to copy.
114  * @height: Height of the area to copy.
115  * @dest_pixbuf: Destination pixbuf.
116  * @dest_x: X coordinate within @dest_pixbuf.
117  * @dest_y: Y coordinate within @dest_pixbuf.
118  *
119  * Copies a rectangular area from @src_pixbuf to @dest_pixbuf.  Conversion of
120  * pixbuf formats is done automatically.
121  **/
122 void
123 gdk_pixbuf_copy_area (const GdkPixbuf *src_pixbuf,
124                       int src_x, int src_y,
125                       int width, int height,
126                       GdkPixbuf *dest_pixbuf,
127                       int dest_x, int dest_y)
128 {
129         g_return_if_fail (src_pixbuf != NULL);
130         g_return_if_fail (dest_pixbuf != NULL);
131
132         g_return_if_fail (src_x >= 0 && src_x + width <= src_pixbuf->width);
133         g_return_if_fail (src_y >= 0 && src_y + height <= src_pixbuf->height);
134
135         g_return_if_fail (dest_x >= 0 && dest_x + width <= dest_pixbuf->width);
136         g_return_if_fail (dest_y >= 0 && dest_y + height <= dest_pixbuf->height);
137
138         g_return_if_fail (!(gdk_pixbuf_get_has_alpha (src_pixbuf) && !gdk_pixbuf_get_has_alpha (dest_pixbuf)));
139         
140         /* This will perform format conversions automatically */
141
142         gdk_pixbuf_scale (src_pixbuf,
143                           dest_pixbuf,
144                           dest_x, dest_y,
145                           width, height,
146                           (double) (dest_x - src_x),
147                           (double) (dest_y - src_y),
148                           1.0, 1.0,
149                           GDK_INTERP_NEAREST);
150 }
151
152
153
154 #define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
155
156 /**
157  * gdk_pixbuf_saturate_and_pixelate:
158  * @src: source image
159  * @dest: place to write modified version of @src
160  * @saturation: saturation factor
161  * @pixelate: whether to pixelate
162  *
163  * Modifies saturation and optionally pixelates @src, placing the
164  * result in @dest. @src and @dest may be the same pixbuf with no ill
165  * effects.  If @saturation is 1.0 then saturation is not changed. If
166  * it's less than 1.0, saturation is reduced (the image is darkened);
167  * if greater than 1.0, saturation is increased (the image is
168  * brightened). If @pixelate is TRUE, then pixels are faded in a
169  * checkerboard pattern to create a pixelated image. @src and @dest
170  * must have the same image format, size, and rowstride.
171  * 
172  **/
173 void
174 gdk_pixbuf_saturate_and_pixelate(const GdkPixbuf *src,
175                                  GdkPixbuf *dest,
176                                  gfloat saturation,
177                                  gboolean pixelate)
178 {
179         /* NOTE that src and dest MAY be the same pixbuf! */
180   
181         g_return_if_fail (GDK_IS_PIXBUF (src));
182         g_return_if_fail (GDK_IS_PIXBUF (dest));
183         g_return_if_fail (gdk_pixbuf_get_height (src) == gdk_pixbuf_get_height (dest));
184         g_return_if_fail (gdk_pixbuf_get_width (src) == gdk_pixbuf_get_width (dest));
185         g_return_if_fail (gdk_pixbuf_get_rowstride (src) == gdk_pixbuf_get_rowstride (dest));
186         g_return_if_fail (gdk_pixbuf_get_colorspace (src) == gdk_pixbuf_get_colorspace (dest));
187   
188         if (saturation == 1.0 && !pixelate) {
189                 if (dest != src)
190                         memcpy (gdk_pixbuf_get_pixels (dest),
191                                 gdk_pixbuf_get_pixels (src),
192                                 gdk_pixbuf_get_height (src) * gdk_pixbuf_get_rowstride (src));
193
194                 return;
195         } else {
196                 gint i, j;
197                 gint width, height, has_alpha, rowstride;
198                 guchar *target_pixels;
199                 guchar *original_pixels;
200                 guchar *current_pixel;
201                 guchar intensity;
202
203                 has_alpha = gdk_pixbuf_get_has_alpha (src);
204                 width = gdk_pixbuf_get_width (src);
205                 height = gdk_pixbuf_get_height (src);
206                 rowstride = gdk_pixbuf_get_rowstride (src);
207                 
208                 target_pixels = gdk_pixbuf_get_pixels (dest);
209                 original_pixels = gdk_pixbuf_get_pixels (src);
210
211                 for (i = 0; i < height; i++) {
212                         for (j = 0; j < width; j++) {
213                                 current_pixel = original_pixels + i*rowstride + j*(has_alpha?4:3);
214                                 intensity = INTENSITY (*(current_pixel), *(current_pixel + 1), *(current_pixel + 2));
215                                 if (pixelate && (i+j)%2 == 0) {
216                                         *(target_pixels + i*rowstride + j*(has_alpha?4:3)) = intensity/2 + 127;
217                                         *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 1) = intensity/2 + 127;
218                                         *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 2) = intensity/2 + 127;
219                                 } else if (pixelate) {
220 #define DARK_FACTOR 0.7
221                                         *(target_pixels + i*rowstride + j*(has_alpha?4:3)) =
222                                                 (guchar) (((1.0 - saturation) * intensity
223                                                            + saturation * (*(current_pixel)))) * DARK_FACTOR;
224                                         *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 1) =
225                                                 (guchar) (((1.0 - saturation) * intensity
226                                                            + saturation * (*(current_pixel + 1)))) * DARK_FACTOR;
227                                         *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 2) =
228                                                 (guchar) (((1.0 - saturation) * intensity
229                                                            + saturation * (*(current_pixel + 2)))) * DARK_FACTOR;
230                                 } else {
231                                         *(target_pixels + i*rowstride + j*(has_alpha?4:3)) =
232                                                 (guchar) ((1.0 - saturation) * intensity
233                                                           + saturation * (*(current_pixel)));
234                                         *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 1) =
235                                                 (guchar) ((1.0 - saturation) * intensity
236                                                           + saturation * (*(current_pixel + 1)));
237                                         *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 2) =
238                                                 (guchar) ((1.0 - saturation) * intensity
239                                                           + saturation * (*(current_pixel + 2)));
240                                 }
241               
242                                 if (has_alpha)
243                                         *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 3) = *(current_pixel + 3);
244                         }
245                 }
246
247                 return;
248         }
249 }