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