]> Pileus Git - ~andy/gtk/blob - gdk/gdkpixbuf-render.c
Fix bug reported by Nam SungHyun.
[~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 "gdk-pixbuf-private.h"
26 #include "gdkpixbuf.h"
27 #include "gdkscreen.h"
28 #include "gdkinternals.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       g_object_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   g_object_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  * Deprecated: This function is obsolete. Use gdk_draw_pixbuf() instead.
169  **/
170 void
171 gdk_pixbuf_render_to_drawable (GdkPixbuf   *pixbuf,
172                                GdkDrawable *drawable,
173                                GdkGC       *gc,
174                                int src_x,    int src_y,
175                                int dest_x,   int dest_y,
176                                int width,    int height,
177                                GdkRgbDither dither,
178                                int x_dither, int y_dither)
179 {
180   gdk_draw_pixbuf (drawable, gc, pixbuf,
181                    src_x, src_y, dest_x, dest_y, width, height,
182                    dither, x_dither, y_dither);
183 }
184
185 \f
186
187 /**
188  * gdk_pixbuf_render_to_drawable_alpha:
189  * @pixbuf: A pixbuf.
190  * @drawable: Destination drawable.
191  * @src_x: Source X coordinate within pixbuf.
192  * @src_y: Source Y coordinates within pixbuf.
193  * @dest_x: Destination X coordinate within drawable.
194  * @dest_y: Destination Y coordinate within drawable.
195  * @width: Width of region to render, in pixels, or -1 to use pixbuf width.
196  * @height: Height of region to render, in pixels, or -1 to use pixbuf height.
197  * @alpha_mode: Ignored. Present for backwards compatibility.
198  * @alpha_threshold: Ignored. Present for backwards compatibility
199  * @dither: Dithering mode for GdkRGB.
200  * @x_dither: X offset for dither.
201  * @y_dither: Y offset for dither.
202  *
203  * Renders a rectangular portion of a pixbuf to a drawable.  The destination
204  * drawable must have a colormap. All windows have a colormap, however, pixmaps
205  * only have colormap by default if they were created with a non-NULL window argument.
206  * Otherwise a colormap must be set on them with gdk_drawable_set_colormap.
207  *
208  * On older X servers, rendering pixbufs with an alpha channel involves round trips
209  * to the X server, and may be somewhat slow.
210  *
211  * Deprecated: This function is obsolete. Use gdk_draw_pixbuf() instead.
212  **/
213 void
214 gdk_pixbuf_render_to_drawable_alpha (GdkPixbuf   *pixbuf,
215                                      GdkDrawable *drawable,
216                                      int src_x,    int src_y,
217                                      int dest_x,   int dest_y,
218                                      int width,    int height,
219                                      GdkPixbufAlphaMode alpha_mode,
220                                      int                alpha_threshold,
221                                      GdkRgbDither       dither,
222                                      int x_dither, int y_dither)
223 {
224   gdk_draw_pixbuf (drawable, NULL, pixbuf,
225                    src_x, src_y, dest_x, dest_y, width, height,
226                    dither, x_dither, y_dither);
227 }
228
229 /**
230  * gdk_pixbuf_render_pixmap_and_mask:
231  * @pixbuf: A pixbuf.
232  * @pixmap_return: Location to store a pointer to the created pixmap,
233  *   or %NULL if the pixmap is not needed.
234  * @mask_return: Location to store a pointer to the created mask,
235  *   or %NULL if the mask is not needed.
236  * @alpha_threshold: Threshold value for opacity values.
237  *
238  * Creates a pixmap and a mask bitmap which are returned in the @pixmap_return
239  * and @mask_return arguments, respectively, and renders a pixbuf and its
240  * corresponding thresholded alpha mask to them.  This is merely a convenience
241  * function; applications that need to render pixbufs with dither offsets or to
242  * given drawables should use gdk_draw_pixbuf() and gdk_pixbuf_render_threshold_alpha().
243  *
244  * The pixmap that is created is created for the colormap returned
245  * by gdk_rgb_get_colormap(). You normally will want to instead use
246  * the actual colormap for a widget, and use
247  * gdk_pixbuf_render_pixmap_and_mask_for_colormap.
248  *
249  * If the pixbuf does not have an alpha channel, then *@mask_return will be set
250  * to NULL.
251  **/
252 void
253 gdk_pixbuf_render_pixmap_and_mask (GdkPixbuf  *pixbuf,
254                                    GdkPixmap **pixmap_return,
255                                    GdkBitmap **mask_return,
256                                    int         alpha_threshold)
257 {
258   gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf,
259                                                   gdk_rgb_get_colormap (),
260                                                   pixmap_return, mask_return,
261                                                   alpha_threshold);
262 }
263
264 /**
265  * gdk_pixbuf_render_pixmap_and_mask_for_colormap:
266  * @pixbuf: A pixbuf.
267  * @colormap: A #GdkColormap
268  * @pixmap_return: Location to store a pointer to the created pixmap,
269  *   or %NULL if the pixmap is not needed.
270  * @mask_return: Location to store a pointer to the created mask,
271  *   or %NULL if the mask is not needed.
272  * @alpha_threshold: Threshold value for opacity values.
273  *
274  * Creates a pixmap and a mask bitmap which are returned in the @pixmap_return
275  * and @mask_return arguments, respectively, and renders a pixbuf and its
276  * corresponding tresholded alpha mask to them.  This is merely a convenience
277  * function; applications that need to render pixbufs with dither offsets or to
278  * given drawables should use gdk_draw_pixbuf(), and gdk_pixbuf_render_threshold_alpha().
279  *
280  * The pixmap that is created uses the #GdkColormap specified by @colormap.
281  * This colormap must match the colormap of the window where the pixmap
282  * will eventually be used or an error will result.
283  *
284  * If the pixbuf does not have an alpha channel, then *@mask_return will be set
285  * to NULL.
286  **/
287 void
288 gdk_pixbuf_render_pixmap_and_mask_for_colormap (GdkPixbuf   *pixbuf,
289                                                 GdkColormap *colormap,
290                                                 GdkPixmap  **pixmap_return,
291                                                 GdkBitmap  **mask_return,
292                                                 int          alpha_threshold)
293 {
294   GdkScreen *screen;
295
296   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
297   g_return_if_fail (GDK_IS_COLORMAP (colormap));
298
299   screen = gdk_colormap_get_screen (colormap);
300   
301   if (pixmap_return)
302     {
303       GdkGC *gc;
304       *pixmap_return = gdk_pixmap_new (gdk_screen_get_root_window (screen),
305                                        gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf),
306                                        gdk_colormap_get_visual (colormap)->depth);
307
308       gdk_drawable_set_colormap (GDK_DRAWABLE (*pixmap_return), colormap);
309       gc = _gdk_drawable_get_scratch_gc (*pixmap_return, FALSE);
310       gdk_draw_pixbuf (*pixmap_return, gc, pixbuf, 
311                        0, 0, 0, 0,
312                        gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf),
313                        GDK_RGB_DITHER_NORMAL,
314                        0, 0);
315     }
316   
317   if (mask_return)
318     {
319       if (gdk_pixbuf_get_has_alpha (pixbuf))
320         {
321           *mask_return = gdk_pixmap_new (gdk_screen_get_root_window (screen),
322                                          gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), 1);
323
324           gdk_pixbuf_render_threshold_alpha (pixbuf, *mask_return,
325                                              0, 0, 0, 0,
326                                              gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf),
327                                              alpha_threshold);
328         }
329       else
330         *mask_return = NULL;
331     }
332 }