pixbuf from drawable



Hi,

Re: this bug:
  http://bugzilla.gnome.org/show_bug.cgi?id=50080
(read the linked mails from Owen and Tim in particular)

Here is a patch which:

 - fixes pixbuf_from_drawable() to avoid X errors (hopefully)
 - adds gdk_pixbuf_get_from_image() which is just the guts of 
   get_from_drawable() exposed, so you can get image contents
 - adds gdk_image_set/get_colormap() so get_from_image() 
   can take a NULL cmap
 - only gets an image from the area of the drawable covered
   by the begin_paint rect, for efficiency

The pixbuf-from-drawable mails linked in the bug mention a couple
other issues I haven't addressed.

First, adding this API:
 GdkImage*       gdk_image_new_shared_with_pixmap (GdkWindow  *window,
                                                  gint        width,
                                                  gint        height,
                                                  GdkPixmap **pixmap_p);

Second, using the above API to speed up pixbuf_get_from_image();

Third, the issue of whether to disable shared memory permanently when
shmget() fails. 

Re: the shared pixmap API, I think it might be X-specific; if so it
should maybe be in gdkx.h. Alternatively, Owen suggested that
begin_paint() could maybe just use shared pixmaps for the backing
store. Alternatively, maybe it would be interesting to use XRender to
speed this stuff up. 

Anyway, I think these three issues should remain in bugzilla, but they
are mostly optimizations, I'd like to go ahead and get the fixes in to
pixbuf_get_from_drawable() since we are spewing warnings and X errors
all over the place at the moment. Please check this patch carefully
for correctness, I'm not too familiar with the issues.

We should sort out the shared pixmap API as soon as possible if we
want to get it in.

Havoc

2001-05-05  Havoc Pennington  <hp pobox com>

        * gdk/gdkwindow.c (gdk_window_get_clip_region): fix infinite
          loop screwup

        * gdk/x11/gdkwindow-x11.c (gdk_window_impl_x11_get_colormap):
        error trap around getting the colormap

        * gdk/gdkpixbuf-render.c
          (gdk_pixbuf_render_to_drawable_alpha): 
        clip the render area to the drawable's clip region in advance,
        so we don't get data from the server that we don't need.

        * gdk/x11/gdkimage-x11.c (_gdk_x11_get_image): push an error
        trap around XGetImage()

        * gdk/gdkpixbuf-render.c
          (gdk_pixbuf_render_to_drawable_alpha):
        check return value of gdk_pixbuf_get_from_drawable(), fall
          back 
        to bilevel alpha if we can't get the pixbuf to composite
          against.

        * gdk/gdkdraw.c (gdk_drawable_get_image): set the image
          colormap

        * gdk/gdkimage.c (gdk_image_get_colormap): add
        gdk_image_set_colormap, gdk_image_get_colormap

        * gdk/gdkpixbuf-drawable.c (rgbconvert): always use the
          fallback
        converter if the dest pixbuf has alpha, the fast converters
          don't
        handle it. Change all converters to take a region of the
          image,
        instead of converting the entire image.

Index: gdkdraw.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkdraw.c,v
retrieving revision 1.25
diff -u -u -r1.25 gdkdraw.c
--- gdkdraw.c	2001/03/07 21:10:43	1.25
+++ gdkdraw.c	2001/05/06 05:30:22
@@ -611,6 +611,7 @@
   gint composite_x_offset = 0;
   gint composite_y_offset = 0;
   GdkImage *retval;
+  GdkColormap *cmap;
   
   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
   g_return_val_if_fail (x >= 0, NULL);
@@ -639,6 +640,11 @@
 
   g_object_unref (G_OBJECT (composite));
 
+  cmap = gdk_drawable_get_colormap (drawable);
+  
+  if (retval && cmap)
+    gdk_image_set_colormap (retval, cmap);                            
+  
   return retval;
 }
 
Index: gdkimage.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkimage.c,v
retrieving revision 1.23
diff -u -u -r1.23 gdkimage.c
--- gdkimage.c	2000/10/24 00:15:12	1.23
+++ gdkimage.c	2001/05/06 05:30:22
@@ -59,3 +59,51 @@
   
   return gdk_drawable_get_image (window, x, y, width, height);
 }
+
+/**
+ * gdk_image_set_colormap:
+ * @image: a #GdkImage
+ * @colormap: a #GdkColormap
+ * 
+ * Sets the colormap for the image to the given colormap.  Normally
+ * there's no need to use this function, images are born with the
+ * correct colormap if you get the image from a drawable. If you
+ * create the image from scratch, set the colormap of the drawable you
+ * intend to render the image to.
+ **/
+void
+gdk_image_set_colormap (GdkImage       *image,
+                        GdkColormap    *colormap)
+{
+  g_return_if_fail (GDK_IS_IMAGE (image));
+  g_return_if_fail (GDK_IS_COLORMAP (colormap));
+
+  if (image->colormap != colormap)
+    {
+      if (image->colormap)
+	g_object_unref (G_OBJECT (image->colormap));
+
+      image->colormap = colormap;
+      g_object_ref (G_OBJECT (image->colormap));
+    }
+    
+}
+
+/**
+ * gdk_image_get_colormap:
+ * @image: a #GdkImage
+ * 
+ * Retrieves the colormap for a given image, if it exists.  An image
+ * will have a colormap if the drawable from which it was created has
+ * a colormap, or if a colormap was set explicitely with
+ * gdk_image_set_colormap().
+ * 
+ * Return value: colormap for the image
+ **/
+GdkColormap *
+gdk_image_get_colormap (GdkImage *image)
+{
+  g_return_val_if_fail (GDK_IS_IMAGE (image), NULL);
+
+  return image->colormap;
+}
Index: gdkimage.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkimage.h,v
retrieving revision 1.9
diff -u -u -r1.9 gdkimage.h
--- gdkimage.h	2001/04/28 20:18:24	1.9
+++ gdkimage.h	2001/05/06 05:30:22
@@ -49,6 +49,8 @@
   guint16       bits_per_pixel; /* bits per pixel */
   gpointer	mem;
 
+  GdkColormap  *colormap;
+  
   gpointer windowing_data;
 };
 
@@ -80,6 +82,11 @@
 guint32	   gdk_image_get_pixel (GdkImage     *image,
 				gint	      x,
 				gint	      y);
+
+void       gdk_image_set_colormap (GdkImage    *image,
+                                   GdkColormap *colormap);
+GdkColormap* gdk_image_get_colormap (GdkImage    *image);
+
 
 #ifdef GDK_ENABLE_BROKEN
 GdkImage* gdk_image_new_bitmap (GdkVisual     *visual,
Index: gdkpixbuf-drawable.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkpixbuf-drawable.c,v
retrieving revision 1.25
diff -u -u -r1.25 gdkpixbuf-drawable.c
--- gdkpixbuf-drawable.c	2001/02/02 22:19:29	1.25
+++ gdkpixbuf-drawable.c	2001/05/06 05:30:22
@@ -62,10 +62,13 @@
 rgb1 (GdkImage    *image,
       guchar      *pixels,
       int          rowstride,
+      int          x1,
+      int          y1,
+      int          x2,
+      int          y2,
       GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
   guint8 *s;
   register guint8 data;
@@ -78,16 +81,14 @@
   /* its probably not worth trying to make this run very fast, who uses
    * 1 bit displays anymore?
    */
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
       s = srow;
       o = orow;
       
-      for (xx = 0; xx < width; xx ++)
+      for (xx = x1; xx < x2; xx ++)
 	{
 	  data = srow[xx >> 3] >> (7 - (xx & 7)) & 1;
 	  *o++ = colormap->colors[data].red;
@@ -107,10 +108,13 @@
 rgb1a (GdkImage    *image,
        guchar      *pixels,
        int          rowstride,
+       int          x1,
+       int          y1,
+       int          x2,
+       int          y2,
        GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
   guint8 *s;
   register guint8 data;
@@ -123,11 +127,9 @@
   /* convert upto 8 pixels/time */
   /* its probably not worth trying to make this run very fast, who uses
    * 1 bit displays anymore? */
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
-  for (xx = 0; xx < 2; xx++)
+  for (xx = x1; xx < 2; xx++)
     {
 #ifdef LITTLE
       remap[xx] = 0xff000000
@@ -142,12 +144,12 @@
 #endif
     }
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
       s = srow;
       o = orow;
       
-      for (xx = 0; xx < width; xx ++)
+      for (xx = x1; xx < x2; xx ++)
 	{
 	  data = srow[xx >> 3] >> (7 - (xx & 7)) & 1;
 	  *o++ = remap[data];
@@ -165,10 +167,13 @@
 rgb8 (GdkImage    *image,
       guchar      *pixels,
       int          rowstride,
+      int          x1,
+      int          y1,
+      int          x2,
+      int          y2,
       GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
   guint32 mask;
   register guint32 data;
@@ -176,19 +181,17 @@
   register guint8 *s;
   register guint8 *o;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
   d (printf ("8 bit, no alpha output\n"));
 
   mask = mask_table[image->depth];
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
       s = srow;
       o = orow;
-      for (xx = 0; xx < width; xx++) {
+      for (xx = x1; xx < x2; xx++) {
 	data = *s++ & mask;
 	*o++ = colormap->colors[data].red;
 	*o++ = colormap->colors[data].green;
@@ -207,10 +210,13 @@
 rgb8a (GdkImage    *image,
        guchar      *pixels,
        int          rowstride,
+       int          x1,
+       int          y1,
+       int          x2,
+       int          y2,
        GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
   guint32 mask;
   register guint32 data;
@@ -219,15 +225,13 @@
   register guint32 *o;
   guint8 *srow = image->mem, *orow = pixels;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
   d (printf ("8 bit, with alpha output\n"));
 
   mask = mask_table[image->depth];
 
-  for (xx = 0; xx < colormap->size; xx++)
+  for (xx = x1; xx < colormap->size; xx++)
     {
 #ifdef LITTLE
       remap[xx] = 0xff000000
@@ -242,11 +246,11 @@
 #endif
     }
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
       s = srow;
       o = (guint32 *) orow;
-      for (xx = 0; xx < width; xx ++)
+      for (xx = x1; xx < x2; xx ++)
 	{
 	  data = *s++ & mask;
 	  *o++ = remap[data];
@@ -265,10 +269,13 @@
 rgb565lsb (GdkImage    *image,
 	   guchar      *pixels,
 	   int          rowstride,
+           int          x1,
+           int          y1,
+           int          x2,
+           int          y2,
 	   GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
 
 #ifdef LITTLE
@@ -279,11 +286,9 @@
   register guint16 *o;
   guint8 *srow = image->mem, *orow = pixels;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
 #ifdef LITTLE
       s = (guint32 *) srow;
@@ -291,7 +296,7 @@
       s = srow;
 #endif
       o = (guint16 *) orow;
-      for (xx = 1; xx < width; xx += 2)
+      for (xx = x1; xx < x2; xx += 2)
 	{
 	  register guint32 data;
 #ifdef LITTLE
@@ -315,7 +320,7 @@
 #endif
 	}
       /* check for last remaining pixel */
-      if (width & 1)
+      if (x2 > xx)
 	{
 	  register guint16 data;
 #ifdef LITTLE
@@ -342,10 +347,13 @@
 rgb565msb (GdkImage    *image,
 	   guchar      *pixels,
 	   int          rowstride,
+           int          x1,
+           int          y1,
+           int          x2,
+           int          y2,
 	   GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
 
 #ifdef LITTLE
@@ -356,11 +364,9 @@
   register guint16 *o;
   guint8 *srow = image->mem, *orow = pixels;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
 #ifdef LITTLE
       s = srow;
@@ -368,7 +374,7 @@
       s = (guint32 *) srow;
 #endif
       o = (guint16 *) orow;
-      for (xx = 1; xx < width; xx += 2)
+      for (xx = x1; xx < x2; xx += 2)
 	{
 	  register guint32 data;
 #ifdef LITTLE
@@ -392,7 +398,7 @@
 #endif
 	}
       /* check for last remaining pixel */
-      if (width & 1)
+      if (x2 > xx)
 	{
 	  register guint16 data;
 #ifdef LITTLE
@@ -419,10 +425,13 @@
 rgb565alsb (GdkImage    *image,
 	    guchar      *pixels,
 	    int          rowstride,
+            int          x1,
+            int          y1,
+            int          x2,
+            int          y2,
 	    GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
 
 #ifdef LITTLE
@@ -434,11 +443,9 @@
 
   guint8 *srow = image->mem, *orow = pixels;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
 #ifdef LITTLE
       s = (guint16 *) srow;
@@ -446,7 +453,7 @@
       s = (guint8 *) srow;
 #endif
       o = (guint32 *) orow;
-      for (xx = 0; xx < width; xx ++)
+      for (xx = x1; xx < x2; xx ++)
 	{
 	  register guint32 data;
 	  /*  rrrrrggg gggbbbbb -> rrrrrRRR ggggggGG bbbbbBBB aaaaaaaa */
@@ -481,10 +488,13 @@
 rgb565amsb (GdkImage    *image,
 	    guchar      *pixels,
 	    int          rowstride,
+            int          x1,
+            int          y1,
+            int          x2,
+            int          y2,
 	    GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
 
 #ifdef LITTLE
@@ -496,15 +506,13 @@
 
   guint8 *srow = image->mem, *orow = pixels;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
       s = srow;
       o = (guint32 *) orow;
-      for (xx = 0; xx < width; xx ++)
+      for (xx = x1; xx < x2; xx ++)
 	{
 	  register guint32 data;
 	  /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggg00 bbbbbBBB aaaaaaaa */
@@ -539,10 +547,13 @@
 rgb555lsb (GdkImage     *image,
 	   guchar       *pixels,
 	   int           rowstride,
+           int          x1,
+           int          y1,
+           int          x2,
+           int          y2,
 	   GdkColormap  *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
 
 #ifdef LITTLE
@@ -553,11 +564,9 @@
   register guint16 *o;
   guint8 *srow = image->mem, *orow = pixels;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
 #ifdef LITTLE
       s = (guint32 *) srow;
@@ -565,7 +574,7 @@
       s = srow;
 #endif
       o = (guint16 *) orow;
-      for (xx = 1; xx < width; xx += 2)
+      for (xx = x1; xx < x2; xx += 2)
 	{
 	  register guint32 data;
 #ifdef LITTLE
@@ -589,7 +598,7 @@
 #endif
 	}
       /* check for last remaining pixel */
-      if (width & 1)
+      if (x2 > xx)
 	{
 	  register guint16 data;
 #ifdef LITTLE
@@ -616,10 +625,13 @@
 rgb555msb (GdkImage    *image,
 	   guchar      *pixels,
 	   int          rowstride,
+           int          x1,
+           int          y1,
+           int          x2,
+           int          y2,
 	   GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
 
 #ifdef LITTLE
@@ -630,15 +642,13 @@
   register guint16 *o;
   guint8 *srow = image->mem, *orow = pixels;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
       s = srow;
       o = (guint16 *) orow;
-      for (xx = 1; xx < width; xx += 2)
+      for (xx = x1; xx < x2; xx += 2)
 	{
 	  register guint32 data;
 #ifdef LITTLE
@@ -662,7 +672,7 @@
 #endif
 	}
       /* check for last remaining pixel */
-      if (width & 1)
+      if (x2 > xx)
 	{
 	  register guint16 data;
 #ifdef LITTLE
@@ -689,10 +699,13 @@
 rgb555alsb (GdkImage    *image,
 	    guchar      *pixels,
 	    int          rowstride,
+            int          x1,
+            int          y1,
+            int          x2,
+            int          y2,
 	    GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
 
 #ifdef LITTLE
@@ -704,11 +717,9 @@
 
   guint8 *srow = image->mem, *orow = pixels;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
 #ifdef LITTLE
       s = (guint16 *) srow;
@@ -716,7 +727,7 @@
       s = srow;
 #endif
       o = (guint32 *) orow;
-      for (xx = 0; xx < width; xx++)
+      for (xx = x1; xx < x2; xx++)
 	{
 	  register guint32 data;
 	  /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
@@ -751,10 +762,13 @@
 rgb555amsb (GdkImage    *image,
 	    guchar      *pixels,
 	    int          rowstride,
+            int          x1,
+            int          y1,
+            int          x2,
+            int          y2,
 	    GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
 
 #ifdef LITTLE
@@ -766,11 +780,9 @@
 
   guint8 *srow = image->mem, *orow = pixels;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
 #ifdef LITTLE
       s = (guint16 *) srow;
@@ -778,7 +790,7 @@
       s = srow;
 #endif
       o = (guint32 *) orow;
-      for (xx = 0; xx < width; xx++)
+      for (xx = x1; xx < x2; xx++)
 	{
 	  register guint32 data;
 	  /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
@@ -809,28 +821,29 @@
 rgb888alsb (GdkImage    *image,
 	    guchar      *pixels,
 	    int          rowstride,
+            int          x1,
+            int          y1,
+            int          x2,
+            int          y2,
 	    GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
 
   guint8 *s;	/* for byte order swapping */
   guint8 *o;
   guint8 *srow = image->mem, *orow = pixels;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
   d (printf ("32 bits/pixel with alpha\n"));
 
   /* lsb data */
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
       s = srow;
       o = orow;
-      for (xx = 0; xx < width; xx++)
+      for (xx = x1; xx < x2; xx++)
 	{
 	  *o++ = s[2];
 	  *o++ = s[1];
@@ -847,26 +860,27 @@
 rgb888lsb (GdkImage    *image,
 	   guchar      *pixels,
 	   int          rowstride,
+           int          x1,
+           int          y1,
+           int          x2,
+           int          y2,
 	   GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
 
   guint8 *srow = image->mem, *orow = pixels;
   guint8 *o, *s;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
   d (printf ("32 bit, lsb, no alpha\n"));
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
       s = srow;
       o = orow;
-      for (xx = 0; xx < width; xx++)
+      for (xx = x1; xx < x2; xx++)
 	{
 	  *o++ = s[2];
 	  *o++ = s[1];
@@ -882,10 +896,13 @@
 rgb888amsb (GdkImage    *image,
 	    guchar      *pixels,
 	    int          rowstride,
+            int          x1,
+            int          y1,
+            int          x2,
+            int          y2,
 	    GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
 
   guint8 *srow = image->mem, *orow = pixels;
@@ -899,12 +916,10 @@
 
   d (printf ("32 bit, msb, with alpha\n"));
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
   /* msb data */
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
 #ifdef LITTLE
       s = (guint32 *) srow;
@@ -913,7 +928,7 @@
       s = srow;
       o = orow;
 #endif
-      for (xx = 0; xx < width; xx++)
+      for (xx = x1; xx < x2; xx++)
 	{
 #ifdef LITTLE
 	  *o++ = s[1];
@@ -935,10 +950,13 @@
 rgb888msb (GdkImage    *image,
 	   guchar      *pixels,
 	   int          rowstride,
+           int          x1,
+           int          y1,
+           int          x2,
+           int          y2,
 	   GdkColormap *colormap)
 {
   int xx, yy;
-  int width, height;
   int bpl;
 
   guint8 *srow = image->mem, *orow = pixels;
@@ -947,15 +965,13 @@
 
   d (printf ("32 bit, msb, no alpha\n"));
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
       s = srow;
       o = orow;
-      for (xx = 0; xx < width; xx++)
+      for (xx = x1; xx < x2; xx++)
 	{
 	  *o++ = s[1];
 	  *o++ = s[2];
@@ -975,11 +991,14 @@
 convert_real_slow (GdkImage    *image,
 		   guchar      *pixels,
 		   int          rowstride,
+                   int          x1,
+                   int          y1,
+                   int          x2,
+                   int          y2,
 		   GdkColormap *cmap,
-		   int          alpha)
+		   gboolean     alpha)
 {
   int xx, yy;
-  int width, height;
   int bpl;
   guint8 *srow = image->mem, *orow = pixels;
   guint8 *s;
@@ -989,8 +1008,6 @@
   guint8 component;
   int i;
 
-  width = image->width;
-  height = image->height;
   bpl = image->bpl;
   v = gdk_colormap_get_visual(cmap);
 
@@ -999,11 +1016,11 @@
 	   v->red_shift, v->green_shift, v->blue_shift,
 	   v->red_prec, v->green_prec, v->blue_prec));
 
-  for (yy = 0; yy < height; yy++)
+  for (yy = y1; yy < y2; yy++)
     {
       s = srow;
       o = orow;
-      for (xx = 0; xx < width; xx++)
+      for (xx = x1; xx < x2; xx++)
 	{
 	  pixel = gdk_image_get_pixel(image, xx, yy);
 	  switch (v->type)
@@ -1049,7 +1066,14 @@
     }
 }
 
-typedef void (* cfunc) (GdkImage *image, guchar *pixels, int rowstride, GdkColormap *cmap);
+typedef void (* cfunc) (GdkImage    *image,
+                        guchar      *pixels,
+                        int          rowstride,
+                        int          x1,
+                        int          y1,
+                        int          x2,
+                        int          y2,
+                        GdkColormap *cmap);
 
 static cfunc convert_map[] = {
   rgb1,rgb1,rgb1a,rgb1a,
@@ -1070,16 +1094,23 @@
 rgbconvert (GdkImage    *image,
 	    guchar      *pixels,
 	    int          rowstride,
-	    int          alpha,
+	    gboolean     alpha,
+            int          x,
+            int          y,
+            int          width,
+            int          height,
 	    GdkColormap *cmap)
 {
   int index = (image->byte_order == GDK_MSB_FIRST) | (alpha != 0) << 1;
-  int bank=5;		/* default fallback converter */
-  GdkVisual *v = gdk_colormap_get_visual(cmap);
+  int bank = 5;		/* default fallback converter */
+  GdkVisual *v = gdk_colormap_get_visual (cmap);
 
   d(printf("masks = %x:%x:%x\n", v->red_mask, v->green_mask, v->blue_mask));
   d(printf("image depth = %d, bits per pixel = %d\n", image->depth, image->bits_per_pixel));
 
+  g_assert ((x + width) <= image->width);
+  g_assert ((y + height) <= image->height);
+  
   switch (v->type)
     {
 				/* I assume this is right for static & greyscale's too? */
@@ -1126,14 +1157,18 @@
 
   d(printf("converting using conversion function in bank %d\n", bank));
 
-  if (bank==5)
+  if (alpha || bank == 5)
     {
-      convert_real_slow(image, pixels, rowstride, cmap, alpha);
+      convert_real_slow (image, pixels, rowstride,
+                         x, y, x + width, y + height,                         
+                         cmap, alpha);
     }
   else
     {
       index |= bank << 2;
-      (* convert_map[index]) (image, pixels, rowstride, cmap);
+      (* convert_map[index]) (image, pixels, rowstride,
+                              x, y, x + width, y + height,
+                              cmap);
     }
 }
 
@@ -1142,7 +1177,7 @@
 
 /**
  * gdk_pixbuf_get_from_drawable:
- * @dest: Destination pixbuf, or NULL if a new pixbuf should be created.
+ * @dest: Destination pixbuf, or %NULL if a new pixbuf should be created.
  * @src: Source drawable.
  * @cmap: A colormap if @src is a pixmap.  If it is a window, this argument will
  * be ignored.
@@ -1152,38 +1187,44 @@
  * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
  * @width: Width in pixels of region to get.
  * @height: Height in pixels of region to get.
+ *
+ * Transfers image data from a #GdkDrawable and converts it to an RGB(A)
+ * representation inside a #GdkPixbuf. In other words, copies
+ * image data from a server-side drawable to a client-side RGB(A) buffer.
+ * This allows you to efficiently read individual pixels.
  *
- * Transfers image data from a Gdk drawable and converts it to an RGB(A)
- * representation inside a GdkPixbuf.
+ * If the drawable @src is a pixmap, then a suitable colormap must be
+ * specified, since pixmaps are just blocks of pixel data without an
+ * associated colormap.  If the drawable is a window, the @cmap
+ * argument will be ignored and the window's own colormap will be used
+ * instead.
  *
- * If the drawable @src is a pixmap, then a suitable colormap must be specified,
- * since pixmaps are just blocks of pixel data without an associated colormap.
- * If the drawable is a window, the @cmap argument will be ignored and the
- * window's own colormap will be used instead.
+ * If the specified destination pixbuf @dest is %NULL, then this
+ * function will create an RGB pixbuf with 8 bits per channel and no
+ * alpha, with the same size specified by the @width and @height
+ * arguments.  In this case, the @dest_x and @dest_y arguments must be
+ * specified as 0.  If the specified destination pixbuf is not %NULL
+ * and it contains alpha information, then the filled pixels will be
+ * set to full opacity (alpha = 255).
  *
- * If the specified destination pixbuf @dest is #NULL, then this function will
- * create an RGB pixbuf with 8 bits per channel and no alpha, with the same size
- * specified by the @width and @height arguments.  In this case, the @dest_x and
- * @dest_y arguments must be specified as 0, otherwise the function will return
- * #NULL.  If the specified destination pixbuf is not NULL and it contains alpha
- * information, then the filled pixels will be set to full opacity.
+ * If the specified drawable is a pixmap, then the requested source
+ * rectangle must be completely contained within the pixmap, otherwise
+ * the function will return %NULL.
  *
- * If the specified drawable is a pixmap, then the requested source rectangle
- * must be completely contained within the pixmap, otherwise the function will
- * return #NULL.
+ * If the specified drawable is a window, and the window is off the
+ * screen or obscured by other windows, then there is no image data in
+ * the obscured/offscreen regions to be placed in the pixbuf. In these
+ * cases, the pixbuf may either contain partially undefined contents,
+ * or %NULL may be returned.
  *
- * If the specified drawable is a window, then it must be viewable, i.e. all of
- * its ancestors up to the root window must be mapped.  Also, the specified
- * source rectangle must be completely contained within the window and within
- * the screen.  If regions of the window are obscured by noninferior windows, the
- * contents of those regions are undefined.  The contents of regions obscured by
- * inferior windows of a different depth than that of the source window will also
- * be undefined.
+ * If memory can't be allocated for the return value, %NULL will be returned
+ * instead.
  *
- * Return value: The same pixbuf as @dest if it was non-NULL, or a newly-created
- * pixbuf with a reference count of 1 if no destination pixbuf was specified; in
- * the latter case, NULL will be returned if not enough memory could be
- * allocated for the pixbuf to be created.
+ * (In short, there are many ways this function can fail, and if it fails
+ *  it returns %NULL; so check the return value.)
+ * 
+ * Return value: The same pixbuf as @dest if it was non-%NULL, or a newly-created
+ * pixbuf with a reference count of 1 if no destination pixbuf was specified, or %NULL on error
  **/
 GdkPixbuf *
 gdk_pixbuf_get_from_drawable (GdkPixbuf   *dest,
@@ -1195,7 +1236,6 @@
 {
   int src_width, src_height;
   GdkImage *image;
-  int rowstride, bpp, alpha;
   
   /* General sanity checks */
 
@@ -1230,11 +1270,14 @@
     }
   
   /* Coordinate sanity checks */
-
-  gdk_drawable_get_size (src, &src_width, &src_height);
 
-  g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
-  g_return_val_if_fail (src_x + width <= src_width && src_y + height <= src_height, NULL);
+  if (GDK_IS_PIXMAP (src))
+    {
+      gdk_drawable_get_size (src, &src_width, &src_height);
+      
+      g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
+      g_return_val_if_fail (src_x + width <= src_width && src_y + height <= src_height, NULL);
+    }
 
   if (dest)
     {
@@ -1243,54 +1286,110 @@
       g_return_val_if_fail (dest_y + height <= dest->height, NULL);
     }
 
-  if (GDK_IS_WINDOW (src))
+  /* Get Image in ZPixmap format (packed bits). */
+  image = gdk_image_get (src, src_x, src_y, width, height);
+
+  if (image == NULL)
+    return NULL;
+
+  dest = gdk_pixbuf_get_from_image (dest, image, cmap,
+                                    0, 0, dest_x, dest_y,
+                                    width, height);
+
+  gdk_image_destroy (image);
+
+  return dest;
+}
+
+/**
+ * gdk_pixbuf_get_from_image:
+ * @dest: Destination pixbuf, or %NULL if a new pixbuf should be created.
+ * @src: Source #GdkImage.
+ * @cmap: A colormap, or %NULL to use the one for @src
+ * @src_x: Source X coordinate within drawable.
+ * @src_y: Source Y coordinate within drawable.
+ * @dest_x: Destination X coordinate in pixbuf, or 0 if @dest is NULL.
+ * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
+ * @width: Width in pixels of region to get.
+ * @height: Height in pixels of region to get.
+ * 
+ * Same as gdk_pixbuf_get_from_drawable() but gets the pixbuf from
+ * an image.
+ * 
+ * Return value: @dest, newly-created pixbuf if @dest was %NULL, %NULL on error
+ **/
+GdkPixbuf*
+gdk_pixbuf_get_from_image (GdkPixbuf   *dest,
+                           GdkImage    *src,
+                           GdkColormap *cmap,
+                           int          src_x,
+                           int          src_y,
+                           int          dest_x,
+                           int          dest_y,
+                           int          width,
+                           int          height)
+{
+  int rowstride, bpp, alpha;
+  
+  /* General sanity checks */
+
+  g_return_val_if_fail (GDK_IS_IMAGE (src), NULL);
+
+  if (!dest)
+    g_return_val_if_fail (dest_x == 0 && dest_y == 0, NULL);
+  else
     {
-      int ret;
-      int src_xorigin, src_yorigin;
-      int screen_width, screen_height;
-      int screen_srcx, screen_srcy;
-
-      ret = gdk_window_get_origin (src, &src_xorigin, &src_yorigin);
-      g_return_val_if_fail (ret != FALSE, NULL);
-
-      screen_width = gdk_screen_width ();
-      screen_height = gdk_screen_height ();
-
-      screen_srcx = src_xorigin + src_x;
-      screen_srcy = src_yorigin + src_y;
-
-      g_return_val_if_fail (screen_srcx >= 0 && screen_srcy >= 0, NULL);
-      g_return_val_if_fail (screen_srcx + width <= screen_width, NULL);
-      g_return_val_if_fail (screen_srcy + height <= screen_height, NULL);
+      g_return_val_if_fail (dest->colorspace == GDK_COLORSPACE_RGB, NULL);
+      g_return_val_if_fail (dest->n_channels == 3 || dest->n_channels == 4, NULL);
+      g_return_val_if_fail (dest->bits_per_sample == 8, NULL);
     }
 
-  /* Get Image in ZPixmap format (packed bits). */
-  image = gdk_image_get (src, src_x, src_y, width, height);
-  g_return_val_if_fail (image != NULL, NULL);
+  if (cmap == NULL)
+    cmap = gdk_image_get_colormap (src);
+
+  if (cmap == NULL)
+    {
+      g_warning ("%s: Source image has no colormap; either pass "
+                 "in a colormap, or set the colormap on the image "
+                 "with gdk_image_set_colormap()", G_STRLOC);
+      return NULL;
+    }
+  
+  /* Coordinate sanity checks */
+
+  g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
+  g_return_val_if_fail (src_x + width <= src->width && src_y + height <= src->height, NULL);
 
+  if (dest)
+    {
+      g_return_val_if_fail (dest_x >= 0 && dest_y >= 0, NULL);
+      g_return_val_if_fail (dest_x + width <= dest->width, NULL);
+      g_return_val_if_fail (dest_y + height <= dest->height, NULL);
+    }
+
   /* Create the pixbuf if needed */
   if (!dest)
     {
       dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
-      if (!dest)
-	{
-	  gdk_image_destroy(image);
-	  return NULL;
-	}
+      if (dest == NULL)
+        return NULL;
     }
 
   alpha = dest->has_alpha;
   rowstride = dest->rowstride;
   bpp = alpha ? 4 : 3;
 
-  /* we offset into the image data based on the position we are retrieving from */
-  rgbconvert (image, dest->pixels +
+  /* we offset into the image data based on the position we are
+   * retrieving from
+   */
+  rgbconvert (src, dest->pixels +
 	      (dest_y * rowstride) + (dest_x * bpp),
 	      rowstride,
 	      alpha,
+              src_x, src_y,
+              src_x + width,
+              src_y + height,
 	      cmap);
-
-  gdk_image_destroy(image);
 
   return dest;
 }
Index: gdkpixbuf-render.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkpixbuf-render.c,v
retrieving revision 1.22
diff -u -u -r1.22 gdkpixbuf-render.c
--- gdkpixbuf-render.c	2000/11/01 16:34:23	1.22
+++ gdkpixbuf-render.c	2001/05/06 05:30:22
@@ -267,7 +267,9 @@
   GdkGC *gc;
   GdkPixbuf *composited = NULL;
   gint dwidth, dheight;
-
+  GdkRegion *clip;
+  GdkRegion *drect;
+  GdkRectangle tmp_rect;
   
   g_return_if_fail (pixbuf != NULL);
   g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB);
@@ -308,26 +310,37 @@
   if (width <= 0 || height <= 0)
     return;
 
+  /* Clip to the clip region; this avoids getting more
+   * image data from the server than we need to.
+   */
+  
+  tmp_rect.x = dest_x;
+  tmp_rect.y = dest_y;
+  tmp_rect.width = width;
+  tmp_rect.height = height;
+
+  drect = gdk_region_rectangle (&tmp_rect);
+  clip = gdk_drawable_get_clip_region (drawable);
+
+  gdk_region_intersect (drect, clip);
+
+  gdk_region_get_clipbox (drect, &tmp_rect);
+  
+  gdk_region_destroy (drect);
+  gdk_region_destroy (clip);
+
+  if (tmp_rect.width == 0 ||
+      tmp_rect.height == 0)
+    return;
+  
   /* Actually draw */
   
   gc = gdk_gc_new (drawable);
 
   if (pixbuf->has_alpha)
     {
-      if (alpha_mode == GDK_PIXBUF_ALPHA_BILEVEL)
+      if (alpha_mode == GDK_PIXBUF_ALPHA_FULL)
         {
-          bitmap = gdk_pixmap_new (NULL, width, height, 1);
-          gdk_pixbuf_render_threshold_alpha (pixbuf, bitmap,
-                                             src_x, src_y,
-                                             0, 0,
-                                             width, height,
-                                             alpha_threshold);
-          
-          gdk_gc_set_clip_mask (gc, bitmap);
-          gdk_gc_set_clip_origin (gc, dest_x, dest_y);
-        }
-      else if (alpha_mode == GDK_PIXBUF_ALPHA_FULL)
-        {
           GdkPixbuf *sub = NULL;
           
           composited = gdk_pixbuf_get_from_drawable (NULL,
@@ -337,23 +350,41 @@
                                                      0, 0,
                                                      width, height);
 
-          if (src_x != 0 || src_y != 0)
+          if (composited)
             {
-              sub = gdk_pixbuf_new_subpixbuf (pixbuf, src_x, src_y,
-                                              width, height);
+              if (src_x != 0 || src_y != 0)
+                {
+                  sub = gdk_pixbuf_new_subpixbuf (pixbuf, src_x, src_y,
+                                                  width, height);
+                }
+              
+              gdk_pixbuf_composite (sub ? sub : pixbuf,
+                                    composited,
+                                    0, 0,
+                                    width, height,
+                                    0, 0,
+                                    1.0, 1.0,
+                                    GDK_INTERP_BILINEAR,
+                                    255);
+              
+              if (sub)
+                g_object_unref (G_OBJECT (sub));
             }
-          
-          gdk_pixbuf_composite (sub ? sub : pixbuf,
-                                composited,
-                                0, 0,
-                                width, height,
-                                0, 0,
-                                1.0, 1.0,
-                                GDK_INTERP_BILINEAR,
-                                255);
+          else
+            alpha_mode = GDK_PIXBUF_ALPHA_BILEVEL; /* fall back */
+        }
 
-          if (sub)
-            g_object_unref (G_OBJECT (sub));
+      if (alpha_mode == GDK_PIXBUF_ALPHA_BILEVEL)
+        {
+          bitmap = gdk_pixmap_new (NULL, width, height, 1);
+          gdk_pixbuf_render_threshold_alpha (pixbuf, bitmap,
+                                             src_x, src_y,
+                                             0, 0,
+                                             width, height,
+                                             alpha_threshold);
+          
+          gdk_gc_set_clip_mask (gc, bitmap);
+          gdk_gc_set_clip_origin (gc, dest_x, dest_y);
         }
     }
 
Index: gdkpixbuf.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkpixbuf.h,v
retrieving revision 1.3
diff -u -u -r1.3 gdkpixbuf.h
--- gdkpixbuf.h	2000/10/09 17:22:19	1.3
+++ gdkpixbuf.h	2001/05/06 05:30:22
@@ -61,6 +61,16 @@
 					 int          width,
 					 int          height);
 
+GdkPixbuf *gdk_pixbuf_get_from_image    (GdkPixbuf   *dest,
+                                         GdkImage    *src,
+                                         GdkColormap *cmap,
+                                         int          src_x,
+                                         int          src_y,
+                                         int          dest_x,
+                                         int          dest_y,
+                                         int          width,
+                                         int          height);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
Index: gdkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkwindow.c,v
retrieving revision 1.115
diff -u -u -r1.115 gdkwindow.c
--- gdkwindow.c	2001/04/18 18:28:17	1.115
+++ gdkwindow.c	2001/05/06 05:30:24
@@ -1317,6 +1317,8 @@
 	  GdkWindowPaint *paint = tmp_list->data;
 	  
 	  gdk_region_union (paint_region, paint->region);
+
+          tmp_list = tmp_list->next;
 	}
 
       gdk_region_intersect (result, paint_region);
Index: x11/gdkimage-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkimage-x11.c,v
retrieving revision 1.31
diff -u -u -r1.31 gdkimage-x11.c
--- x11/gdkimage-x11.c	2001/04/18 18:28:18	1.31
+++ x11/gdkimage-x11.c	2001/05/06 05:30:24
@@ -398,12 +398,17 @@
     }
   
   impl = GDK_DRAWABLE_IMPL_X11 (drawable);
-  
+
+  gdk_error_trap_push ();
   ximage = XGetImage (impl->xdisplay,
 		      impl->xid,
 		      x, y, width, height,
 		      AllPlanes, ZPixmap);
 
+  XSync (impl->xdisplay, False);
+  if (gdk_error_trap_pop ())
+    return NULL;
+  
   if (!ximage)
     return NULL;
 
Index: x11/gdkwindow-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkwindow-x11.c,v
retrieving revision 1.115
diff -u -u -r1.115 gdkwindow-x11.c
--- x11/gdkwindow-x11.c	2001/05/02 21:31:52	1.115
+++ x11/gdkwindow-x11.c	2001/05/06 05:30:24
@@ -193,12 +193,16 @@
       drawable_impl->colormap == NULL)
     {
       XWindowAttributes window_attributes;
-      
+
+      gdk_error_trap_push ();
       XGetWindowAttributes (drawable_impl->xdisplay,
                             drawable_impl->xid,
                             &window_attributes);
-      drawable_impl->colormap =
-        gdk_colormap_lookup (window_attributes.colormap);
+      if (!gdk_error_trap_pop ())
+        {
+          drawable_impl->colormap =
+            gdk_colormap_lookup (window_attributes.colormap);
+        }
     }
   
   return drawable_impl->colormap;





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]