]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/gdk-pixbuf-util.c
Add hidden aliases for exported symbols which are used internally in order
[~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-alias.h"
26 #include "gdk-pixbuf-private.h"
27 #include <string.h>
28
29 \f
30
31 /**
32  * gdk_pixbuf_add_alpha:
33  * @pixbuf: A #GdkPixbuf.
34  * @substitute_color: Whether to set a color to zero opacity.  If this
35  * is %FALSE, then the (@r, @g, @b) arguments will be ignored.
36  * @r: Red value to substitute.
37  * @g: Green value to substitute.
38  * @b: Blue value to substitute.
39  *
40  * Takes an existing pixbuf and adds an alpha channel to it.
41  * If the existing pixbuf already had an alpha channel, the channel
42  * values are copied from the original; otherwise, the alpha channel
43  * is initialized to 255 (full opacity).
44  * 
45  * If @substitute_color is %TRUE, then the color specified by (@r, @g, @b) will be
46  * assigned zero opacity. That is, if you pass (255, 255, 255) for the
47  * substitute color, all white pixels will become fully transparent.
48  *
49  * Return value: A newly-created pixbuf with a reference count of 1.
50  **/
51 GdkPixbuf *
52 gdk_pixbuf_add_alpha (const GdkPixbuf *pixbuf,
53                       gboolean substitute_color, guchar r, guchar g, guchar b)
54 {
55         GdkPixbuf *new_pixbuf;
56         int x, y;
57
58         g_return_val_if_fail (pixbuf != NULL, NULL);
59         g_return_val_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB, NULL);
60         g_return_val_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4, NULL);
61         g_return_val_if_fail (pixbuf->bits_per_sample == 8, NULL);
62
63         if (pixbuf->has_alpha) {
64                 new_pixbuf = gdk_pixbuf_copy (pixbuf);
65                 if (!new_pixbuf)
66                         return NULL;
67
68                 if (!substitute_color)
69                         return new_pixbuf;
70         } else {
71                 new_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, pixbuf->width, pixbuf->height);
72         }
73         
74         if (!new_pixbuf)
75                 return NULL;
76
77         for (y = 0; y < pixbuf->height; y++) {
78                 guchar *src, *dest;
79                 guchar tr, tg, tb;
80
81                 src = pixbuf->pixels + y * pixbuf->rowstride;
82                 dest = new_pixbuf->pixels + y * new_pixbuf->rowstride;
83                 
84                 if (pixbuf->has_alpha) {
85                         /* Just subst color, we already copied everything else */
86                         for (x = 0; x < pixbuf->width; x++) {
87                                 if (src[0] == r && src[1] == g && src[2] == b)
88                                         dest[3] = 0;
89                                 src += 4;
90                                 dest += 4;
91                         }
92                 } else {                        
93                         for (x = 0; x < pixbuf->width; x++) {
94                                 tr = *dest++ = *src++;
95                                 tg = *dest++ = *src++;
96                                 tb = *dest++ = *src++;
97                                 
98                                 if (substitute_color && tr == r && tg == g && tb == b)
99                                         *dest++ = 0;
100                                 else
101                                         *dest++ = 255;
102                         }
103                 }
104         }
105
106         return new_pixbuf;
107 }
108
109 /**
110  * gdk_pixbuf_copy_area:
111  * @src_pixbuf: Source pixbuf.
112  * @src_x: Source X coordinate within @src_pixbuf.
113  * @src_y: Source Y coordinate within @src_pixbuf.
114  * @width: Width of the area to copy.
115  * @height: Height of the area to copy.
116  * @dest_pixbuf: Destination pixbuf.
117  * @dest_x: X coordinate within @dest_pixbuf.
118  * @dest_y: Y coordinate within @dest_pixbuf.
119  *
120  * Copies a rectangular area from @src_pixbuf to @dest_pixbuf.  Conversion of
121  * pixbuf formats is done automatically.
122  **/
123 void
124 gdk_pixbuf_copy_area (const GdkPixbuf *src_pixbuf,
125                       int src_x, int src_y,
126                       int width, int height,
127                       GdkPixbuf *dest_pixbuf,
128                       int dest_x, int dest_y)
129 {
130         g_return_if_fail (src_pixbuf != NULL);
131         g_return_if_fail (dest_pixbuf != NULL);
132
133         g_return_if_fail (src_x >= 0 && src_x + width <= src_pixbuf->width);
134         g_return_if_fail (src_y >= 0 && src_y + height <= src_pixbuf->height);
135
136         g_return_if_fail (dest_x >= 0 && dest_x + width <= dest_pixbuf->width);
137         g_return_if_fail (dest_y >= 0 && dest_y + height <= dest_pixbuf->height);
138
139         g_return_if_fail (!(gdk_pixbuf_get_has_alpha (src_pixbuf) && !gdk_pixbuf_get_has_alpha (dest_pixbuf)));
140         
141         /* This will perform format conversions automatically */
142
143         gdk_pixbuf_scale (src_pixbuf,
144                           dest_pixbuf,
145                           dest_x, dest_y,
146                           width, height,
147                           (double) (dest_x - src_x),
148                           (double) (dest_y - src_y),
149                           1.0, 1.0,
150                           GDK_INTERP_NEAREST);
151 }
152
153
154
155 /**
156  * gdk_pixbuf_saturate_and_pixelate:
157  * @src: source image
158  * @dest: place to write modified version of @src
159  * @saturation: saturation factor
160  * @pixelate: whether to pixelate
161  *
162  * Modifies saturation and optionally pixelates @src, placing the
163  * result in @dest. @src and @dest may be the same pixbuf with no ill
164  * effects.  If @saturation is 1.0 then saturation is not changed. If
165  * it's less than 1.0, saturation is reduced (the image is darkened);
166  * if greater than 1.0, saturation is increased (the image is
167  * brightened). If @pixelate is %TRUE, then pixels are faded in a
168  * checkerboard pattern to create a pixelated image. @src and @dest
169  * must have the same image format, size, and rowstride.
170  * 
171  **/
172 void
173 gdk_pixbuf_saturate_and_pixelate(const GdkPixbuf *src,
174                                  GdkPixbuf *dest,
175                                  gfloat saturation,
176                                  gboolean pixelate)
177 {
178         /* NOTE that src and dest MAY be the same pixbuf! */
179   
180         g_return_if_fail (GDK_IS_PIXBUF (src));
181         g_return_if_fail (GDK_IS_PIXBUF (dest));
182         g_return_if_fail (gdk_pixbuf_get_height (src) == gdk_pixbuf_get_height (dest));
183         g_return_if_fail (gdk_pixbuf_get_width (src) == gdk_pixbuf_get_width (dest));
184         g_return_if_fail (gdk_pixbuf_get_has_alpha (src) == gdk_pixbuf_get_has_alpha (dest));
185         g_return_if_fail (gdk_pixbuf_get_colorspace (src) == gdk_pixbuf_get_colorspace (dest));
186   
187         if (saturation == 1.0 && !pixelate) {
188                 if (dest != src)
189                         memcpy (gdk_pixbuf_get_pixels (dest),
190                                 gdk_pixbuf_get_pixels (src),
191                                 gdk_pixbuf_get_height (src) * gdk_pixbuf_get_rowstride (src));
192         } else {
193                 int i, j, t;
194                 int width, height, has_alpha, src_rowstride, dest_rowstride, bytes_per_pixel;
195                 guchar *src_line;
196                 guchar *dest_line;
197                 guchar *src_pixel;
198                 guchar *dest_pixel;
199                 guchar intensity;
200
201                 has_alpha = gdk_pixbuf_get_has_alpha (src);
202                 bytes_per_pixel = has_alpha ? 4 : 3;
203                 width = gdk_pixbuf_get_width (src);
204                 height = gdk_pixbuf_get_height (src);
205                 src_rowstride = gdk_pixbuf_get_rowstride (src);
206                 dest_rowstride = gdk_pixbuf_get_rowstride (dest);
207                 
208                 src_line = gdk_pixbuf_get_pixels (src);
209                 dest_line = gdk_pixbuf_get_pixels (dest);
210                 
211 #define DARK_FACTOR 0.7
212 #define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
213 #define CLAMP_UCHAR(v) (t = (v), CLAMP (t, 0, 255))
214 #define SATURATE(v) ((1.0 - saturation) * intensity + saturation * (v))
215
216                 for (i = 0 ; i < height ; i++) {
217                         src_pixel = src_line;
218                         src_line += src_rowstride;
219                         dest_pixel = dest_line;
220                         dest_line += dest_rowstride;
221
222                         for (j = 0 ; j < width ; j++) {
223                                 intensity = INTENSITY (src_pixel[0], src_pixel[1], src_pixel[2]);
224                                 if (pixelate && (i + j) % 2 == 0) {
225                                         dest_pixel[0] = intensity / 2 + 127;
226                                         dest_pixel[1] = intensity / 2 + 127;
227                                         dest_pixel[2] = intensity / 2 + 127;
228                                 } else if (pixelate) {
229                                         dest_pixel[0] = CLAMP_UCHAR ((SATURATE (src_pixel[0])) * DARK_FACTOR);
230                                         dest_pixel[1] = CLAMP_UCHAR ((SATURATE (src_pixel[1])) * DARK_FACTOR);
231                                         dest_pixel[2] = CLAMP_UCHAR ((SATURATE (src_pixel[2])) * DARK_FACTOR);
232                                 } else {
233                                         dest_pixel[0] = CLAMP_UCHAR (SATURATE (src_pixel[0]));
234                                         dest_pixel[1] = CLAMP_UCHAR (SATURATE (src_pixel[1]));
235                                         dest_pixel[2] = CLAMP_UCHAR (SATURATE (src_pixel[2]));
236                                 }
237                                 
238                                 if (has_alpha)
239                                         dest_pixel[3] = src_pixel[3];
240
241                                 src_pixel += bytes_per_pixel;
242                                 dest_pixel += bytes_per_pixel;
243                         }
244                 }
245         }
246 }