]> Pileus Git - ~andy/gtk/blob - gdk/gdkpixbuf-render.c
Mention in the docs that @pixmap_return and @mask_return can be %NULL.
[~andy/gtk] / gdk / gdkpixbuf-render.c
1 /* GdkPixbuf library - Rendering functions
2  *
3  * Copyright (C) 1999 The Free Software Foundation
4  *
5  * Author: Federico Mena-Quintero <federico@gimp.org>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <config.h>
24 #include <gdk/gdk.h>
25 #include "gdkinternals.h" /* _gdk_draw_pixbuf() */
26 #include "gdk-pixbuf-private.h"
27 #include "gdkpixbuf.h"
28 #include "gdkscreen.h"
29
30 \f
31
32 /**
33  * gdk_pixbuf_render_threshold_alpha:
34  * @pixbuf: A pixbuf.
35  * @bitmap: Bitmap where the bilevel mask will be painted to.
36  * @src_x: Source X coordinate.
37  * @src_y: source Y coordinate.
38  * @dest_x: Destination X coordinate.
39  * @dest_y: Destination Y coordinate.
40  * @width: Width of region to threshold, or -1 to use pixbuf width
41  * @height: Height of region to threshold, or -1 to use pixbuf height
42  * @alpha_threshold: Opacity values below this will be painted as zero; all
43  * other values will be painted as one.
44  *
45  * Takes the opacity values in a rectangular portion of a pixbuf and thresholds
46  * them to produce a bi-level alpha mask that can be used as a clipping mask for
47  * a drawable.
48  *
49  **/
50 void
51 gdk_pixbuf_render_threshold_alpha (GdkPixbuf *pixbuf,
52                                    GdkBitmap *bitmap,
53                                    int src_x,  int src_y,
54                                    int dest_x, int dest_y,
55                                    int width,  int height,
56                                    int alpha_threshold)
57 {
58   GdkGC *gc;
59   GdkColor color;
60   int x, y;
61   guchar *p;
62   int start, start_status;
63   int status;
64
65   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
66   g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB);
67   g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4);
68   g_return_if_fail (pixbuf->bits_per_sample == 8);
69
70   if (width == -1) 
71     width = pixbuf->width;
72   if (height == -1)
73     height = pixbuf->height;
74
75   g_return_if_fail (bitmap != NULL);
76   g_return_if_fail (width >= 0 && height >= 0);
77   g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width);
78   g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height);
79
80   g_return_if_fail (alpha_threshold >= 0 && alpha_threshold <= 255);
81
82   if (width == 0 || height == 0)
83     return;
84
85   gc = gdk_gc_new (bitmap);
86
87   if (!pixbuf->has_alpha)
88     {
89       color.pixel = (alpha_threshold == 255) ? 0 : 1;
90       gdk_gc_set_foreground (gc, &color);
91       gdk_draw_rectangle (bitmap, gc, TRUE, dest_x, dest_y, width, height);
92       gdk_gc_unref (gc);
93       return;
94     }
95
96   color.pixel = 0;
97   gdk_gc_set_foreground (gc, &color);
98   gdk_draw_rectangle (bitmap, gc, TRUE, dest_x, dest_y, width, height);
99
100   color.pixel = 1;
101   gdk_gc_set_foreground (gc, &color);
102
103   for (y = 0; y < height; y++)
104     {
105       p = (pixbuf->pixels + (y + src_y) * pixbuf->rowstride + src_x * pixbuf->n_channels
106            + pixbuf->n_channels - 1);
107             
108       start = 0;
109       start_status = *p < alpha_threshold;
110             
111       for (x = 0; x < width; x++)
112         {
113           status = *p < alpha_threshold;
114           
115           if (status != start_status)
116             {
117               if (!start_status)
118                 gdk_draw_line (bitmap, gc,
119                                start + dest_x, y + dest_y,
120                                x - 1 + dest_x, y + dest_y);
121               
122               start = x;
123               start_status = status;
124             }
125           
126           p += pixbuf->n_channels;
127         }
128       
129       if (!start_status)
130         gdk_draw_line (bitmap, gc,
131                        start + dest_x, y + dest_y,
132                        x - 1 + dest_x, y + dest_y);
133     }
134         
135   gdk_gc_unref (gc);
136 }
137
138 \f
139
140 /**
141  * gdk_pixbuf_render_to_drawable:
142  * @pixbuf: A pixbuf.
143  * @drawable: Destination drawable.
144  * @gc: GC used for rendering.
145  * @src_x: Source X coordinate within pixbuf.
146  * @src_y: Source Y coordinate within pixbuf.
147  * @dest_x: Destination X coordinate within drawable.
148  * @dest_y: Destination Y coordinate within drawable.
149  * @width: Width of region to render, in pixels, or -1 to use pixbuf width
150  * @height: Height of region to render, in pixels, or -1 to use pixbuf height
151  * @dither: Dithering mode for GdkRGB.
152  * @x_dither: X offset for dither.
153  * @y_dither: Y offset for dither.
154  *
155  * Renders a rectangular portion of a pixbuf to a drawable while using the
156  * specified GC.  This is done using GdkRGB, so the specified drawable must have
157  * the GdkRGB visual and colormap.  Note that this function will ignore the
158  * opacity information for images with an alpha channel; the GC must already
159  * have the clipping mask set if you want transparent regions to show through.
160  *
161  * For an explanation of dither offsets, see the GdkRGB documentation.  In
162  * brief, the dither offset is important when re-rendering partial regions of an
163  * image to a rendered version of the full image, or for when the offsets to a
164  * base position change, as in scrolling.  The dither matrix has to be shifted
165  * for consistent visual results.  If you do not have any of these cases, the
166  * dither offsets can be both zero.
167  **/
168 void
169 gdk_pixbuf_render_to_drawable (GdkPixbuf   *pixbuf,
170                                GdkDrawable *drawable,
171                                GdkGC       *gc,
172                                int src_x,    int src_y,
173                                int dest_x,   int dest_y,
174                                int width,    int height,
175                                GdkRgbDither dither,
176                                int x_dither, int y_dither)
177 {
178   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
179   g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB);
180   g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4);
181   g_return_if_fail (pixbuf->bits_per_sample == 8);
182
183   g_return_if_fail (drawable != NULL);
184
185   if (width == -1) 
186     width = pixbuf->width;
187   if (height == -1)
188     height = pixbuf->height;
189
190   g_return_if_fail (width >= 0 && height >= 0);
191   g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width);
192   g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height);
193
194   if (width == 0 || height == 0)
195     return;
196
197   _gdk_draw_pixbuf (drawable, gc, pixbuf,
198                     src_x, src_y, dest_x, dest_y, width, height,
199                     dither, x_dither, y_dither);
200 }
201
202 \f
203
204 /**
205  * gdk_pixbuf_render_to_drawable_alpha:
206  * @pixbuf: A pixbuf.
207  * @drawable: Destination drawable.
208  * @src_x: Source X coordinate within pixbuf.
209  * @src_y: Source Y coordinates within pixbuf.
210  * @dest_x: Destination X coordinate within drawable.
211  * @dest_y: Destination Y coordinate within drawable.
212  * @width: Width of region to render, in pixels, or -1 to use pixbuf width.
213  * @height: Height of region to render, in pixels, or -1 to use pixbuf height.
214  * @alpha_mode: Ignored. Present for backwards compatibility.
215  * @alpha_threshold: Ignored. Present for backwards compatibility
216  * @dither: Dithering mode for GdkRGB.
217  * @x_dither: X offset for dither.
218  * @y_dither: Y offset for dither.
219  *
220  * Renders a rectangular portion of a pixbuf to a drawable.  The destination
221  * drawable must have a colormap. All windows have a colormap, however, pixmaps
222  * only have colormap by default if they were created with a non-NULL window argument.
223  * Otherwise a colormap must be set on them with gdk_drawable_set_colormap.
224  *
225  * On older X servers, rendering pixbufs with an alpha channel involves round trips
226  * to the X server, and may be somewhat slow.
227  **/
228 void
229 gdk_pixbuf_render_to_drawable_alpha (GdkPixbuf   *pixbuf,
230                                      GdkDrawable *drawable,
231                                      int src_x,    int src_y,
232                                      int dest_x,   int dest_y,
233                                      int width,    int height,
234                                      GdkPixbufAlphaMode alpha_mode,
235                                      int                alpha_threshold,
236                                      GdkRgbDither       dither,
237                                      int x_dither, int y_dither)
238 {
239   _gdk_draw_pixbuf (drawable, NULL, pixbuf,
240                     src_x, src_y, dest_x, dest_y, width, height,
241                     dither, x_dither, y_dither);
242 }
243
244 /**
245  * gdk_pixbuf_render_pixmap_and_mask:
246  * @pixbuf: A pixbuf.
247  * @pixmap_return: Location to store a pointer to the created pixmap,
248  *   or %NULL if the pixmap is not needed.
249  * @mask_return: Location to store a pointer to the created mask,
250  *   or %NULL if the mask is not needed.
251  * @alpha_threshold: Threshold value for opacity values.
252  *
253  * Creates a pixmap and a mask bitmap which are returned in the @pixmap_return
254  * and @mask_return arguments, respectively, and renders a pixbuf and its
255  * corresponding thresholded alpha mask to them.  This is merely a convenience
256  * function; applications that need to render pixbufs with dither offsets or to
257  * given drawables should use gdk_pixbuf_render_to_drawable_alpha() or
258  * gdk_pixbuf_render_to_drawable(), and gdk_pixbuf_render_threshold_alpha().
259  *
260  * The pixmap that is created is created for the colormap returned
261  * by gdk_rgb_get_colormap(). You normally will want to instead use
262  * the actual colormap for a widget, and use
263  * gdk_pixbuf_render_pixmap_and_mask_for_colormap.
264  *
265  * If the pixbuf does not have an alpha channel, then *@mask_return will be set
266  * to NULL.
267  **/
268 void
269 gdk_pixbuf_render_pixmap_and_mask (GdkPixbuf  *pixbuf,
270                                    GdkPixmap **pixmap_return,
271                                    GdkBitmap **mask_return,
272                                    int         alpha_threshold)
273 {
274   gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf,
275                                                   gdk_rgb_get_colormap (),
276                                                   pixmap_return, mask_return,
277                                                   alpha_threshold);
278 }
279
280 /**
281  * gdk_pixbuf_render_pixmap_and_mask_for_colormap:
282  * @pixbuf: A pixbuf.
283  * @colormap: A #GdkColormap
284  * @pixmap_return: Location to store a pointer to the created pixmap,
285  *   or %NULL if the pixmap is not needed.
286  * @mask_return: Location to store a pointer to the created mask,
287  *   or %NULL if the mask is not needed.
288  * @alpha_threshold: Threshold value for opacity values.
289  *
290  * Creates a pixmap and a mask bitmap which are returned in the @pixmap_return
291  * and @mask_return arguments, respectively, and renders a pixbuf and its
292  * corresponding tresholded alpha mask to them.  This is merely a convenience
293  * function; applications that need to render pixbufs with dither offsets or to
294  * given drawables should use gdk_pixbuf_render_to_drawable_alpha() or
295  * gdk_pixbuf_render_to_drawable(), and gdk_pixbuf_render_threshold_alpha().
296  *
297  * The pixmap that is created uses the #GdkColormap specified by @colormap.
298  * This colormap must match the colormap of the window where the pixmap
299  * will eventually be used or an error will result.
300  *
301  * If the pixbuf does not have an alpha channel, then *@mask_return will be set
302  * to NULL.
303  **/
304 void
305 gdk_pixbuf_render_pixmap_and_mask_for_colormap (GdkPixbuf   *pixbuf,
306                                                 GdkColormap *colormap,
307                                                 GdkPixmap  **pixmap_return,
308                                                 GdkBitmap  **mask_return,
309                                                 int          alpha_threshold)
310 {
311   GdkScreen *screen;
312
313   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
314   g_return_if_fail (GDK_IS_COLORMAP (colormap));
315
316   screen = gdk_colormap_get_screen (colormap);
317   
318   if (pixmap_return)
319     {
320       GdkGC *gc;
321       *pixmap_return = gdk_pixmap_new (gdk_screen_get_root_window (screen),
322                                        gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf),
323                                        gdk_colormap_get_visual (colormap)->depth);
324
325       gdk_drawable_set_colormap (GDK_DRAWABLE (*pixmap_return), colormap);
326       gc = gdk_gc_new (*pixmap_return);
327       gdk_pixbuf_render_to_drawable (pixbuf, *pixmap_return, gc,
328                                      0, 0, 0, 0,
329                                      gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf),
330                                      GDK_RGB_DITHER_NORMAL,
331                                      0, 0);
332       gdk_gc_unref (gc);
333     }
334   
335   if (mask_return)
336     {
337       if (gdk_pixbuf_get_has_alpha (pixbuf))
338         {
339           *mask_return = gdk_pixmap_new (gdk_screen_get_root_window (screen),
340                                          gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), 1);
341
342           gdk_pixbuf_render_threshold_alpha (pixbuf, *mask_return,
343                                              0, 0, 0, 0,
344                                              gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf),
345                                              alpha_threshold);
346         }
347       else
348         *mask_return = NULL;
349     }
350 }