1 /* GdkPixbuf library - convert X drawable information to RGB
3 * Copyright (C) 1999 Michael Zucchi
5 * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
6 * Cody Russell <bratsche@dfw.net>
7 * Federico Mena-Quintero <federico@gimp.org>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 #include <gdk-pixbuf/gdk-pixbuf.h>
29 #include "gdkwindow.h"
30 #include "gdkpixbuf.h"
31 #include "gdkpixmap.h"
32 #include "gdkinternals.h"
35 /* Exported functions */
38 * gdk_pixbuf_get_from_drawable:
39 * @dest: (allow-none): Destination pixbuf, or %NULL if a new pixbuf should be created.
40 * @src: Source drawable.
41 * @cmap: A colormap if @src doesn't have one set.
42 * @src_x: Source X coordinate within drawable.
43 * @src_y: Source Y coordinate within drawable.
44 * @dest_x: Destination X coordinate in pixbuf, or 0 if @dest is NULL.
45 * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
46 * @width: Width in pixels of region to get.
47 * @height: Height in pixels of region to get.
49 * Transfers image data from a #GdkDrawable and converts it to an RGB(A)
50 * representation inside a #GdkPixbuf. In other words, copies
51 * image data from a server-side drawable to a client-side RGB(A) buffer.
52 * This allows you to efficiently read individual pixels on the client side.
54 * If the drawable @src has no colormap (gdk_drawable_get_colormap()
55 * returns %NULL), then a suitable colormap must be specified.
56 * Typically a #GdkWindow or a pixmap created by passing a #GdkWindow
57 * to gdk_pixmap_new() will already have a colormap associated with
58 * it. If the drawable has a colormap, the @cmap argument will be
59 * ignored. If the drawable is a bitmap (1 bit per pixel pixmap),
60 * then a colormap is not required; pixels with a value of 1 are
61 * assumed to be white, and pixels with a value of 0 are assumed to be
62 * black. For taking screenshots, gdk_colormap_get_system() returns
63 * the correct colormap to use.
65 * If the specified destination pixbuf @dest is %NULL, then this
66 * function will create an RGB pixbuf with 8 bits per channel and no
67 * alpha, with the same size specified by the @width and @height
68 * arguments. In this case, the @dest_x and @dest_y arguments must be
69 * specified as 0. If the specified destination pixbuf is not %NULL
70 * and it contains alpha information, then the filled pixels will be
71 * set to full opacity (alpha = 255).
73 * If the specified drawable is a pixmap, then the requested source
74 * rectangle must be completely contained within the pixmap, otherwise
75 * the function will return %NULL. For pixmaps only (not for windows)
76 * passing -1 for width or height is allowed to mean the full width
77 * or height of the pixmap.
79 * If the specified drawable is a window, and the window is off the
80 * screen, then there is no image data in the obscured/offscreen
81 * regions to be placed in the pixbuf. The contents of portions of the
82 * pixbuf corresponding to the offscreen region are undefined.
84 * If the window you're obtaining data from is partially obscured by
85 * other windows, then the contents of the pixbuf areas corresponding
86 * to the obscured regions are undefined.
88 * If the target drawable is not mapped (typically because it's
89 * iconified/minimized or not on the current workspace), then %NULL
92 * If memory can't be allocated for the return value, %NULL will be returned
95 * (In short, there are several ways this function can fail, and if it fails
96 * it returns %NULL; so check the return value.)
98 * Return value: The same pixbuf as @dest if it was non-%NULL, or a newly-created
99 * pixbuf with a reference count of 1 if no destination pixbuf was specified, or %NULL on error
102 gdk_pixbuf_get_from_drawable (GdkPixbuf *dest,
105 int src_x, int src_y,
106 int dest_x, int dest_y,
107 int width, int height)
109 int src_width, src_height;
110 cairo_surface_t *surface;
113 /* General sanity checks */
115 g_return_val_if_fail (src != NULL, NULL);
117 if (GDK_IS_WINDOW (src))
118 /* FIXME: this is not perfect, since is_viewable() only tests
119 * recursively up the Gdk parent window tree, but stops at
120 * foreign windows or Gdk toplevels. I.e. if a window manager
121 * unmapped one of its own windows, this won't work.
123 g_return_val_if_fail (gdk_window_is_viewable (src), NULL);
126 g_return_val_if_fail (dest_x == 0 && dest_y == 0, NULL);
129 g_return_val_if_fail (gdk_pixbuf_get_colorspace (dest) == GDK_COLORSPACE_RGB, NULL);
130 g_return_val_if_fail (gdk_pixbuf_get_n_channels (dest) == 3 ||
131 gdk_pixbuf_get_n_channels (dest) == 4, NULL);
132 g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (dest) == 8, NULL);
136 cmap = gdk_drawable_get_colormap (src);
138 depth = gdk_drawable_get_depth (src);
140 if (depth != 1 && cmap == NULL)
142 g_warning ("%s: Source drawable has no colormap; either pass "
143 "in a colormap, or set the colormap on the drawable "
144 "with gdk_drawable_set_colormap()", G_STRLOC);
148 if (cmap != NULL && depth != cmap->visual->depth)
150 g_warning ("%s: Depth of the source drawable is %d where as "
151 "the visual depth of the colormap passed is %d",
152 G_STRLOC, depth, cmap->visual->depth);
156 /* Coordinate sanity checks */
158 if (GDK_IS_PIXMAP (src))
160 gdk_drawable_get_size (src, &src_width, &src_height);
166 g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
167 g_return_val_if_fail (src_x + width <= src_width && src_y + height <= src_height, NULL);
170 surface = _gdk_drawable_ref_cairo_surface (src);
171 dest = gdk_pixbuf_get_from_surface (dest,
176 cairo_surface_destroy (surface);
181 static cairo_format_t
182 gdk_cairo_format_for_content (cairo_content_t content)
186 case CAIRO_CONTENT_COLOR:
187 return CAIRO_FORMAT_RGB24;
188 case CAIRO_CONTENT_ALPHA:
189 return CAIRO_FORMAT_A8;
190 case CAIRO_CONTENT_COLOR_ALPHA:
192 return CAIRO_FORMAT_ARGB32;
196 static cairo_surface_t *
197 gdk_cairo_surface_coerce_to_image (cairo_surface_t *surface,
198 cairo_content_t content,
202 cairo_surface_t *copy;
205 if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE &&
206 cairo_surface_get_content (surface) == content &&
207 cairo_image_surface_get_width (surface) >= width &&
208 cairo_image_surface_get_height (surface) >= height)
209 return cairo_surface_reference (surface);
211 copy = cairo_image_surface_create (gdk_cairo_format_for_content (content),
215 cr = cairo_create (copy);
216 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
217 cairo_set_source_surface (cr, surface, 0, 0);
225 convert_alpha (guchar *dest_data,
238 dest_data += dest_stride * dest_y + dest_x * 4;
239 src_data += src_stride * src_y + src_x * 4;
241 for (y = 0; y < height; y++) {
242 guint32 *src = (guint32 *) src_data;
244 for (x = 0; x < width; x++) {
245 guint alpha = src[x] >> 24;
249 dest_data[x * 4 + 0] = 0;
250 dest_data[x * 4 + 1] = 0;
251 dest_data[x * 4 + 2] = 0;
255 dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
256 dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
257 dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
259 dest_data[x * 4 + 3] = alpha;
262 src_data += src_stride;
263 dest_data += dest_stride;
268 convert_no_alpha (guchar *dest_data,
281 dest_data += dest_stride * dest_y + dest_x * 3;
282 src_data += src_stride * src_y + src_x * 4;
284 for (y = 0; y < height; y++) {
285 guint32 *src = (guint32 *) src_data;
287 for (x = 0; x < width; x++) {
288 dest_data[x * 3 + 0] = src[x] >> 16;
289 dest_data[x * 3 + 1] = src[x] >> 8;
290 dest_data[x * 3 + 2] = src[x];
293 src_data += src_stride;
294 dest_data += dest_stride;
299 * gdk_pixbuf_get_from_surface:
300 * @dest: (allow-none): Destination pixbuf, or %NULL if a new pixbuf should be created.
301 * @surface: surface to copy from
302 * @src_x: Source X coordinate within drawable.
303 * @src_y: Source Y coordinate within drawable.
304 * @dest_x: Destination X coordinate in pixbuf, or 0 if @dest is NULL.
305 * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
306 * @width: Width in pixels of region to get.
307 * @height: Height in pixels of region to get.
309 * Transfers image data from a #cairo_surface_t and converts it to an RGB(A)
310 * representation inside a #GdkPixbuf. This allows you to efficiently read individual
311 * pixels from Cairo surfaces. For #GdkWindows, use gdk_pixbuf_get_from_drawable()
314 * If the specified destination pixbuf @dest is %NULL, then this
315 * function will create an RGB pixbuf with 8 bits per channel. The pixbuf will
316 * contain an alpha channel if the @surface contains one. In this case, the @dest_x
317 * and @dest_y arguments must be specified as 0.
319 * If the specified drawable is a window, and the window is off the
320 * screen, then there is no image data in the obscured/offscreen
321 * regions to be placed in the pixbuf. The contents of portions of the
322 * pixbuf corresponding to the offscreen region are undefined.
324 * If the window you're obtaining data from is partially obscured by
325 * other windows, then the contents of the pixbuf areas corresponding
326 * to the obscured regions are undefined.
328 * If memory can't be allocated for the return value, %NULL will be returned
331 * (In short, there are several ways this function can fail, and if it fails
332 * it returns %NULL; so check the return value.)
334 * Return value: The same pixbuf as @dest if it was non-%NULL, or a newly-created
335 * pixbuf with a reference count of 1 if no destination pixbuf was specified, or %NULL on error
338 gdk_pixbuf_get_from_surface (GdkPixbuf *dest,
339 cairo_surface_t *surface,
347 cairo_content_t content;
349 /* General sanity checks */
350 g_return_val_if_fail (surface != NULL, NULL);
351 g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
352 g_return_val_if_fail (width > 0 && height > 0, NULL);
356 g_return_val_if_fail (dest_x == 0 && dest_y == 0, NULL);
358 content = cairo_surface_get_content (surface) | CAIRO_CONTENT_COLOR;
359 dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
360 !!(content & CAIRO_CONTENT_ALPHA),
366 g_return_val_if_fail (gdk_pixbuf_get_colorspace (dest) == GDK_COLORSPACE_RGB, NULL);
367 g_return_val_if_fail (gdk_pixbuf_get_n_channels (dest) == 3 ||
368 gdk_pixbuf_get_n_channels (dest) == 4, NULL);
369 g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (dest) == 8, NULL);
370 g_return_val_if_fail (dest_x >= 0 && dest_y >= 0, NULL);
371 g_return_val_if_fail (dest_x + width <= gdk_pixbuf_get_width (dest), NULL);
372 g_return_val_if_fail (dest_y + height <= gdk_pixbuf_get_height (dest), NULL);
374 content = gdk_pixbuf_get_has_alpha (dest) ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR;
377 surface = gdk_cairo_surface_coerce_to_image (surface, content, src_x + width, src_y + height);
378 cairo_surface_flush (surface);
379 if (cairo_surface_status (surface) || dest == NULL)
381 cairo_surface_destroy (surface);
385 if (gdk_pixbuf_get_has_alpha (dest))
386 convert_alpha (gdk_pixbuf_get_pixels (dest),
387 gdk_pixbuf_get_rowstride (dest),
388 cairo_image_surface_get_data (surface),
389 cairo_image_surface_get_stride (surface),
394 convert_no_alpha (gdk_pixbuf_get_pixels (dest),
395 gdk_pixbuf_get_rowstride (dest),
396 cairo_image_surface_get_data (surface),
397 cairo_image_surface_get_stride (surface),
402 cairo_surface_destroy (surface);