]> Pileus Git - ~andy/gtk/blob - gdk/gdkpixbuf-drawable.c
Fixed the LSB -> MSB case. Fixes #79463.
[~andy/gtk] / gdk / gdkpixbuf-drawable.c
1 /* GdkPixbuf library - convert X drawable information to RGB
2  *
3  * Copyright (C) 1999 Michael Zucchi
4  *
5  * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
6  *          Cody Russell <bratsche@dfw.net>
7  *          Federico Mena-Quintero <federico@gimp.org>
8  *
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.
13  *
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.
18  *
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.
23  */
24
25 #include <config.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include "gdkcolor.h"
29 #include "gdkimage.h"
30 #include "gdkvisual.h"
31 #include "gdkwindow.h"
32 #include "gdkpixbuf.h"
33 #include "gdkpixmap.h"
34 #include "gdk-pixbuf-private.h"
35 #include "gdkinternals.h"
36
37 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
38 #define LITTLE
39 #endif
40 #define d(x)
41
42 \f
43
44 static guint32 mask_table[] = {
45   0x00000000, 0x00000001, 0x00000003, 0x00000007,
46   0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
47   0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
48   0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
49   0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
50   0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
51   0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
52   0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
53   0xffffffff
54 };
55
56 \f
57
58 /*
59  * convert bitmap data to pixbuf without alpha,
60  * without using a colormap 
61  */
62 static void
63 bitmap1 (GdkImage    *image,
64          guchar      *pixels,
65          int          rowstride,
66          int          x1,
67          int          y1,
68          int          x2,
69          int          y2)
70 {
71   int xx, yy;
72   int bpl;
73   register guint8 data;
74   guint8 *o;
75   guint8 *srow = (guint8*)image->mem + y1 * image->bpl, *orow = pixels;
76
77   d (printf ("bitmap, no alpha\n"));
78
79   bpl = image->bpl;
80
81   for (yy = y1; yy < y2; yy++)
82     {
83       o = orow;
84       
85       for (xx = x1; xx < x2; xx ++)
86         {
87           /* top 29 bits of xx (xx >> 3) indicate the byte the bit is inside,
88            * bottom 3 bits (xx & 7) indicate bit inside that byte,
89            * we don't bother to canonicalize data to 1 or 0, just
90            * leave the relevant bit in-place.
91            */
92           data = srow[xx >> 3] & (image->byte_order == GDK_MSB_FIRST ?
93                                   (0x80 >> (xx & 7)) :
94                                   (1 << (xx & 7)));
95
96           if (data)
97             {
98               *o++ = 255;
99               *o++ = 255;
100               *o++ = 255;
101             }
102           else
103             {
104               *o++ = 0;
105               *o++ = 0;
106               *o++ = 0;
107             }
108         }
109       srow += bpl;
110       orow += rowstride;
111     }
112 }
113
114 /*
115  * convert bitmap data to pixbuf with alpha,
116  * without using a colormap 
117  */
118 static void
119 bitmap1a (GdkImage    *image,
120           guchar      *pixels,
121           int          rowstride,
122           int          x1,
123           int          y1,
124           int          x2,
125           int          y2)
126 {
127   int xx, yy;
128   int bpl;
129   register guint8 data;
130   guint8 *o;
131   guint8 *srow = (guint8*)image->mem + y1 * image->bpl, *orow = pixels;
132
133   d (printf ("bitmap, with alpha\n"));
134
135   bpl = image->bpl;
136
137   for (yy = y1; yy < y2; yy++)
138     {
139       o = orow;
140       
141       for (xx = x1; xx < x2; xx ++)
142         {
143           /* see comment in bitmap1() */
144           data = srow[xx >> 3] & (image->byte_order == GDK_MSB_FIRST ?
145                                   (0x80 >> (xx & 7)) :
146                                   (1 << (xx & 7)));
147
148           if (data)
149             {
150               *o++ = 255;
151               *o++ = 255;
152               *o++ = 255;
153               *o++ = 255;
154             }
155           else
156             {
157               *o++ = 0;
158               *o++ = 0;
159               *o++ = 0;
160               *o++ = 0;
161             }
162         }
163       srow += bpl;
164       orow += rowstride;
165     }
166 }
167
168 /*
169  * convert 1 bits-pixel data
170  * no alpha
171  */
172 static void
173 rgb1 (GdkImage    *image,
174       guchar      *pixels,
175       int          rowstride,
176       int          x1,
177       int          y1,
178       int          x2,
179       int          y2,
180       GdkColormap *colormap)
181 {
182   int xx, yy;
183   int bpl;
184   register guint8 data;
185   guint8 *o;
186   guint8 *srow = (guint8*)image->mem + y1 * image->bpl, *orow = pixels;
187
188   d (printf ("1 bits/pixel\n"));
189
190   /* convert upto 8 pixels/time */
191   /* its probably not worth trying to make this run very fast, who uses
192    * 1 bit displays anymore?
193    */
194   bpl = image->bpl;
195
196   for (yy = y1; yy < y2; yy++)
197     {
198       o = orow;
199       
200       for (xx = x1; xx < x2; xx ++)
201         {
202           /* see comment in bitmap1() */
203           data = srow[xx >> 3] & (image->byte_order == GDK_MSB_FIRST ?
204                                   (0x80 >> (xx & 7)) :
205                                   (1 << (xx & 7)));
206
207           *o++ = colormap->colors[data].red;
208           *o++ = colormap->colors[data].green;
209           *o++ = colormap->colors[data].blue;
210         }
211       srow += bpl;
212       orow += rowstride;
213     }
214 }
215
216 /*
217  * convert 1 bits/pixel data
218  * with alpha
219  */
220 static void
221 rgb1a (GdkImage    *image,
222        guchar      *pixels,
223        int          rowstride,
224        int          x1,
225        int          y1,
226        int          x2,
227        int          y2,
228        GdkColormap *colormap)
229 {
230   int xx, yy;
231   int bpl;
232   register guint8 data;
233   guint8 *o;
234   guint8 *srow = (guint8*)image->mem + y1 * image->bpl, *orow = pixels;
235   
236   d (printf ("1 bits/pixel\n"));
237
238   /* convert upto 8 pixels/time */
239   /* its probably not worth trying to make this run very fast, who uses
240    * 1 bit displays anymore? */
241   bpl = image->bpl;
242
243   for (yy = y1; yy < y2; yy++)
244     {
245       o = orow;
246       
247       for (xx = x1; xx < x2; xx ++)
248         {
249           /* see comment in bitmap1() */
250           data = srow[xx >> 3] & (image->byte_order == GDK_MSB_FIRST ?
251                                   (0x80 >> (xx & 7)) :
252                                   (1 << (xx & 7)));
253
254           *o++ = colormap->colors[data].red;
255           *o++ = colormap->colors[data].green;
256           *o++ = colormap->colors[data].blue;
257           *o++ = 255;
258         }
259       srow += bpl;
260       orow += rowstride;
261     }
262 }
263
264 /*
265  * convert 8 bits/pixel data
266  * no alpha
267  */
268 static void
269 rgb8 (GdkImage    *image,
270       guchar      *pixels,
271       int          rowstride,
272       int          x1,
273       int          y1,
274       int          x2,
275       int          y2,
276       GdkColormap *colormap)
277 {
278   int xx, yy;
279   int bpl;
280   guint32 mask;
281   register guint32 data;
282   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
283   register guint8 *s;
284   register guint8 *o;
285
286   bpl = image->bpl;
287
288   d (printf ("8 bit, no alpha output\n"));
289
290   mask = mask_table[image->depth];
291
292   for (yy = y1; yy < y2; yy++)
293     {
294       s = srow;
295       o = orow;
296       for (xx = x1; xx < x2; xx++)
297         {
298           data = *s++ & mask;
299           *o++ = colormap->colors[data].red;
300           *o++ = colormap->colors[data].green;
301           *o++ = colormap->colors[data].blue;
302         }
303       srow += bpl;
304       orow += rowstride;
305     }
306 }
307
308 /*
309  * convert 8 bits/pixel data
310  * with alpha
311  */
312 static void
313 rgb8a (GdkImage    *image,
314        guchar      *pixels,
315        int          rowstride,
316        int          x1,
317        int          y1,
318        int          x2,
319        int          y2,
320        GdkColormap *colormap)
321 {
322   int xx, yy;
323   int bpl;
324   guint32 mask;
325   register guint32 data;
326   guint32 remap[256];
327   register guint8 *s;   /* read 2 pixels at once */
328   register guint32 *o;
329   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
330
331   bpl = image->bpl;
332
333   d (printf ("8 bit, with alpha output\n"));
334
335   mask = mask_table[image->depth];
336
337   for (xx = x1; xx < colormap->size; xx++)
338     {
339 #ifdef LITTLE
340       remap[xx] = 0xff000000
341         | colormap->colors[xx].blue << 16
342         | colormap->colors[xx].green << 8
343         | colormap->colors[xx].red;
344 #else
345       remap[xx] = 0xff
346         | colormap->colors[xx].red << 24
347         | colormap->colors[xx].green << 16
348         | colormap->colors[xx].blue << 8;
349 #endif
350     }
351
352   for (yy = y1; yy < y2; yy++)
353     {
354       s = srow;
355       o = (guint32 *) orow;
356       for (xx = x1; xx < x2; xx ++)
357         {
358           data = *s++ & mask;
359           *o++ = remap[data];
360         }
361       srow += bpl;
362       orow += rowstride;
363     }
364 }
365
366 /*
367  * convert 16 bits/pixel data
368  * no alpha
369  * data in lsb format
370  */
371 static void
372 rgb565lsb (GdkImage    *image,
373            guchar      *pixels,
374            int          rowstride,
375            int          x1,
376            int          y1,
377            int          x2,
378            int          y2,
379            GdkColormap *colormap)
380 {
381   int xx, yy;
382   int bpl;
383
384 #ifdef LITTLE
385   register guint32 *s;  /* read 2 pixels at once */
386 #else
387   register guint8 *s;   /* read 2 pixels at once */
388 #endif
389   register guint16 *o;
390   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
391   
392   bpl = image->bpl;
393   
394   for (yy = y1; yy < y2; yy++)
395     {
396 #ifdef LITTLE
397       s = (guint32 *) srow;
398 #else
399       s = srow;
400 #endif
401       o = (guint16 *) orow;
402
403       /* check for first pixel odd */
404       xx = x1;
405       if (xx & 1)
406         {
407           register guint16 data;
408 #ifdef LITTLE
409           data = *((short *) s);
410 #else
411           data = *((short *) s);
412           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
413 #endif
414           ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
415           ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
416           ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
417           o = (guint16 *) (((char *) o) + 3);
418           ++xx;
419         }
420
421       g_assert (!(xx & 1));
422
423       /* if x2 is even, then the -1 does nothing to number of
424        * loop iterations, if x2 is odd then the -1 reduces
425        * iterations by one
426        */
427       for (; xx < (x2 - 1); xx += 2)
428         {
429           register guint32 data;
430 #ifdef LITTLE
431           data = *s++;
432           *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
433             | (data & 0x7e0) << 5 | (data & 0x600) >> 1;
434           *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
435             | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21;
436           *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25
437             | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
438 #else
439           /* swap endianness first */
440           data = s[1] << 24 | s[0] << 16 | s[3] << 8 | s[2];
441           s += 4;
442
443           *o++ = (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21
444             | (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25;
445           *o++ = (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10
446             | (data & 0xf800) >> 8 | (data & 0xe000) >> 13;
447           *o++ = (data & 0x7e0) << 5 | (data & 0x600) >> 1
448             | (data & 0x1f) << 3 | (data & 0x1c) >> 2;
449 #endif
450         }
451       /* check for last remaining pixel */
452       if (x2 & 1)
453         {
454           register guint16 data;
455 #ifdef LITTLE
456           data = *((short *) s);
457 #else
458           data = *((short *) s);
459           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
460 #endif
461           ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
462           ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
463           ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
464         }
465       srow += bpl;
466       orow += rowstride;
467     }
468 }
469
470 /*
471  * convert 16 bits/pixel data
472  * no alpha
473  * data in msb format
474  */
475 static void
476 rgb565msb (GdkImage    *image,
477            guchar      *pixels,
478            int          rowstride,
479            int          x1,
480            int          y1,
481            int          x2,
482            int          y2,
483            GdkColormap *colormap)
484 {
485   int xx, yy;
486   int bpl;
487
488 #ifdef LITTLE
489   register guint8 *s;   /* need to swap data order */
490 #else
491   register guint32 *s;  /* read 2 pixels at once */
492 #endif
493   register guint16 *o;
494   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
495
496   bpl = image->bpl;
497
498   for (yy = y1; yy < y2; yy++)
499     {
500 #ifdef LITTLE
501       s = srow;
502 #else
503       s = (guint32 *) srow;
504 #endif
505       o = (guint16 *) orow;
506
507       xx = x1;
508       
509       /* check for first pixel odd */
510       if (xx & 1)
511         {
512           register guint16 data;
513 #ifdef LITTLE
514           data = *((short *) s);
515           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
516 #else
517           data = *((short *) s);
518 #endif
519           ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
520           ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
521           ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
522
523           o = (guint16 *) (((char *) o) + 3);
524           ++xx;
525         }
526
527       g_assert (!(xx & 1));
528
529       /* if x2 is even, then the -1 does nothing to number of
530        * loop iterations, if x2 is odd then the -1 reduces
531        * iterations by one
532        */
533       for (; xx < (x2 - 1); xx += 2)
534         {
535           register guint32 data;
536 #ifdef LITTLE
537           /* swap endianness first */
538           data = s[1] | s[0] << 8 | s[3] << 16 | s[2] << 24;
539           s += 4;
540           *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
541             | (data & 0x7e0) << 5 | (data & 0x600) >> 1;
542           *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
543             | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21;
544           *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25
545             | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
546 #else
547           data = *s++;
548           *o++ = (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21
549             | (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25;
550           *o++ = (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10
551             | (data & 0xf800) >> 8 | (data & 0xe000) >> 13;
552           *o++ = (data & 0x7e0) << 5 | (data & 0x600) >> 1
553             | (data & 0x1f) << 3 | (data & 0x1c) >> 2;
554 #endif
555         }
556       /* check for last remaining pixel */
557       if (x2 & 1)
558         {
559           register guint16 data;
560 #ifdef LITTLE
561           data = *((short *) s);
562           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
563 #else
564           data = *((short *) s);
565 #endif
566           ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
567           ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
568           ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
569         }
570       srow += bpl;
571       orow += rowstride;
572     }
573 }
574
575 /*
576  * convert 16 bits/pixel data
577  * with alpha
578  * data in lsb format
579  */
580 static void
581 rgb565alsb (GdkImage    *image,
582             guchar      *pixels,
583             int          rowstride,
584             int          x1,
585             int          y1,
586             int          x2,
587             int          y2,
588             GdkColormap *colormap)
589 {
590   int xx, yy;
591   int bpl;
592
593 #ifdef LITTLE
594   register guint16 *s;  /* read 1 pixels at once */
595 #else
596   register guint8 *s;
597 #endif
598   register guint32 *o;
599
600   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
601
602   bpl = image->bpl;
603
604   for (yy = y1; yy < y2; yy++)
605     {
606 #ifdef LITTLE
607       s = (guint16 *) srow;
608 #else
609       s = (guint8 *) srow;
610 #endif
611       o = (guint32 *) orow;
612       for (xx = x1; xx < x2; xx ++)
613         {
614           register guint32 data;
615           /*  rrrrrggg gggbbbbb -> rrrrrRRR ggggggGG bbbbbBBB aaaaaaaa */
616           /*  little endian: aaaaaaaa bbbbbBBB ggggggGG rrrrrRRR */
617 #ifdef LITTLE
618           data = *s++;
619           *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
620             | (data & 0x7e0) << 5 | (data & 0x600) >> 1
621             | (data & 0x1f) << 19 | (data & 0x1c) << 14
622             | 0xff000000;
623 #else
624           /* swap endianness first */
625           data = s[0] | s[1] << 8;
626           s += 2;
627           *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11
628             | (data & 0x7e0) << 13 | (data & 0x600) << 7
629             | (data & 0x1f) << 11 | (data & 0x1c) << 6
630             | 0xff;
631 #endif
632         }
633       srow += bpl;
634       orow += rowstride;
635     }
636 }
637
638 /*
639  * convert 16 bits/pixel data
640  * with alpha
641  * data in msb format
642  */
643 static void
644 rgb565amsb (GdkImage    *image,
645             guchar      *pixels,
646             int          rowstride,
647             int          x1,
648             int          y1,
649             int          x2,
650             int          y2,
651             GdkColormap *colormap)
652 {
653   int xx, yy;
654   int bpl;
655
656 #ifdef LITTLE
657   register guint8 *s;
658 #else
659   register guint16 *s;  /* read 1 pixels at once */
660 #endif
661   register guint32 *o;
662
663   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
664
665   bpl = image->bpl;
666
667   for (yy = y1; yy < y2; yy++)
668     {
669       s = srow;
670       o = (guint32 *) orow;
671       for (xx = x1; xx < x2; xx ++)
672         {
673           register guint32 data;
674           /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggg00 bbbbbBBB aaaaaaaa */
675           /*  little endian: aaaaaaaa bbbbbBBB gggggg00 rrrrrRRR */
676 #ifdef LITTLE
677           /* swap endianness first */
678           data = s[0] | s[1] << 8;
679           s += 2;
680           *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
681             | (data & 0x7e0) << 5 | (data & 0x600) >> 1
682             | (data & 0x1f) << 19 | (data & 0x1c) << 14
683             | 0xff000000;
684 #else
685           data = *s++;
686           *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11
687             | (data & 0x7e0) << 13 | (data & 0x600) << 7
688             | (data & 0x1f) << 11 | (data & 0x1c) << 6
689             | 0xff;
690 #endif
691         }
692       srow += bpl;
693       orow += rowstride;
694     }
695 }
696
697 /*
698  * convert 15 bits/pixel data
699  * no alpha
700  * data in lsb format
701  */
702 static void
703 rgb555lsb (GdkImage     *image,
704            guchar       *pixels,
705            int           rowstride,
706            int          x1,
707            int          y1,
708            int          x2,
709            int          y2,
710            GdkColormap  *colormap)
711 {
712   int xx, yy;
713   int bpl;
714
715 #ifdef LITTLE
716   register guint32 *s;  /* read 2 pixels at once */
717 #else
718   register guint8 *s;   /* read 2 pixels at once */
719 #endif
720   register guint16 *o;
721   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
722
723   bpl = image->bpl;
724
725   for (yy = y1; yy < y2; yy++)
726     {
727 #ifdef LITTLE
728       s = (guint32 *) srow;
729 #else
730       s = srow;
731 #endif
732       o = (guint16 *) orow;
733
734       xx = x1;
735       
736       /* check for first odd pixel */
737       if (xx & 1)
738         {
739           register guint16 data;
740 #ifdef LITTLE
741           data = *((short *) s);
742 #else
743           data = *((short *) s);
744           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
745 #endif
746           ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
747           ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
748           ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
749           o = (guint16 *) (((char *) o) + 3);
750           ++xx;
751         }
752
753       g_assert (!(xx & 1));
754
755       /* if x2 is even, then the -1 does nothing to number of
756        * loop iterations, if x2 is odd then the -1 reduces
757        * iterations by one
758        */
759       for (; xx < (x2 - 1); xx += 2)
760         {
761           register guint32 data;
762 #ifdef LITTLE
763           data = *s++;
764           *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
765             | (data & 0x3e0) << 6 | (data & 0x380) << 1;
766           *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
767             | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20;
768           *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23
769             | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
770 #else
771           /* swap endianness first */
772           data = s[1] | s[0] << 8 | s[3] << 16 | s[2] << 24;
773           s += 4;
774           *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4
775             | (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
776           *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
777             | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28;
778           *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15
779             | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
780 #endif
781         }
782       /* check for last remaining pixel */
783       if (x2 & 1)
784         {
785           register guint16 data;
786 #ifdef LITTLE
787           data = *((short *) s);
788 #else
789           data = *((short *) s);
790           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
791 #endif
792           ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
793           ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
794           ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
795         }
796       srow += bpl;
797       orow += rowstride;
798     }
799 }
800
801 /*
802  * convert 15 bits/pixel data
803  * no alpha
804  * data in msb format
805  */
806 static void
807 rgb555msb (GdkImage    *image,
808            guchar      *pixels,
809            int          rowstride,
810            int          x1,
811            int          y1,
812            int          x2,
813            int          y2,
814            GdkColormap *colormap)
815 {
816   int xx, yy;
817   int bpl;
818
819 #ifdef LITTLE
820   register guint8 *s;   /* read 2 pixels at once */
821 #else
822   register guint32 *s;  /* read 2 pixels at once */
823 #endif
824   register guint16 *o;
825   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
826
827   bpl = image->bpl;
828
829   for (yy = y1; yy < y2; yy++)
830     {
831       s = srow;
832       o = (guint16 *) orow;
833
834       xx = x1;
835       /* See if first pixel is odd */
836       if (xx & 1)
837         {
838           register guint16 data;
839 #ifdef LITTLE
840           data = *((short *) s);
841           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
842 #else
843           data = *((short *) s);
844 #endif
845           ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
846           ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
847           ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
848
849           o = (guint16 *) (((char *) o) + 3);
850           ++xx;
851         }
852
853       g_assert (!(xx & 1));
854
855       /* if x2 is even, then the -1 does nothing to number of
856        * loop iterations, if x2 is odd then the -1 reduces
857        * iterations by one
858        */
859       for (; xx < (x2 - 1); xx += 2)
860         {
861           register guint32 data;
862 #ifdef LITTLE
863           /* swap endianness first */
864           data = s[1] | s[0] << 8 | s[3] << 16 | s[2] << 24;
865           s += 4;
866           *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
867             | (data & 0x3e0) << 6 | (data & 0x380) << 1;
868           *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
869             | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20;
870           *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23
871             | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
872 #else
873           data = *s++;
874           *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4
875             | (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
876           *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
877             | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28;
878           *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15
879             | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
880 #endif
881         }
882       /* check for last remaining pixel */
883       if (x2 & 1)
884         {
885           register guint16 data;
886 #ifdef LITTLE
887           data = *((short *) s);
888           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
889 #else
890           data = *((short *) s);
891 #endif
892           ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
893           ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
894           ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
895         }
896       srow += bpl;
897       orow += rowstride;
898     }
899 }
900
901 /*
902  * convert 15 bits/pixel data
903  * with alpha
904  * data in lsb format
905  */
906 static void
907 rgb555alsb (GdkImage    *image,
908             guchar      *pixels,
909             int          rowstride,
910             int          x1,
911             int          y1,
912             int          x2,
913             int          y2,
914             GdkColormap *colormap)
915 {
916   int xx, yy;
917   int bpl;
918
919 #ifdef LITTLE
920   register guint16 *s;  /* read 1 pixels at once */
921 #else
922   register guint8 *s;
923 #endif
924   register guint32 *o;
925
926   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
927
928   bpl = image->bpl;
929
930   for (yy = y1; yy < y2; yy++)
931     {
932 #ifdef LITTLE
933       s = (guint16 *) srow;
934 #else
935       s = srow;
936 #endif
937       o = (guint32 *) orow;
938       for (xx = x1; xx < x2; xx++)
939         {
940           register guint32 data;
941           /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
942           /*  little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */
943 #ifdef LITTLE
944           data = *s++;
945           *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
946             | (data & 0x3e0) << 6 | (data & 0x380) << 1
947             | (data & 0x1f) << 19 | (data & 0x1c) << 14
948             | 0xff000000;
949 #else
950           /* swap endianness first */
951           data = s[0] | s[1] << 8;
952           s += 2;
953           *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12
954             | (data & 0x3e0) << 14 | (data & 0x380) << 9
955             | (data & 0x1f) << 11 | (data & 0x1c) << 6
956             | 0xff;
957 #endif
958         }
959       srow += bpl;
960       orow += rowstride;
961     }
962 }
963
964 /*
965  * convert 15 bits/pixel data
966  * with alpha
967  * data in msb format
968  */
969 static void
970 rgb555amsb (GdkImage    *image,
971             guchar      *pixels,
972             int          rowstride,
973             int          x1,
974             int          y1,
975             int          x2,
976             int          y2,
977             GdkColormap *colormap)
978 {
979   int xx, yy;
980   int bpl;
981
982 #ifdef LITTLE
983   register guint16 *s;  /* read 1 pixels at once */
984 #else
985   register guint8 *s;
986 #endif
987   register guint32 *o;
988
989   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
990
991   bpl = image->bpl;
992
993   for (yy = y1; yy < y2; yy++)
994     {
995 #ifdef LITTLE
996       s = (guint16 *) srow;
997 #else
998       s = srow;
999 #endif
1000       o = (guint32 *) orow;
1001       for (xx = x1; xx < x2; xx++)
1002         {
1003           register guint32 data;
1004           /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
1005           /*  little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */
1006 #ifdef LITTLE
1007           /* swap endianness first */
1008           data = s[0] | s[1] << 8;
1009           s += 2;
1010           *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
1011             | (data & 0x3e0) << 6 | (data & 0x380) << 1
1012             | (data & 0x1f) << 19 | (data & 0x1c) << 14
1013             | 0xff000000;
1014 #else
1015           data = *s++;
1016           *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12
1017             | (data & 0x3e0) << 14 | (data & 0x380) << 9
1018             | (data & 0x1f) << 11 | (data & 0x1c) << 6
1019             | 0xff;
1020 #endif
1021         }
1022       srow += bpl;
1023       orow += rowstride;
1024     }
1025 }
1026
1027
1028 static void
1029 rgb888alsb (GdkImage    *image,
1030             guchar      *pixels,
1031             int          rowstride,
1032             int          x1,
1033             int          y1,
1034             int          x2,
1035             int          y2,
1036             GdkColormap *colormap)
1037 {
1038   int xx, yy;
1039   int bpl;
1040
1041   guint8 *s;    /* for byte order swapping */
1042   guint8 *o;
1043   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
1044
1045   bpl = image->bpl;
1046
1047   d (printf ("32 bits/pixel with alpha\n"));
1048
1049   /* lsb data */
1050   for (yy = y1; yy < y2; yy++)
1051     {
1052       s = srow;
1053       o = orow;
1054       for (xx = x1; xx < x2; xx++)
1055         {
1056           *o++ = s[2];
1057           *o++ = s[1];
1058           *o++ = s[0];
1059           *o++ = 0xff;
1060           s += 4;
1061         }
1062       srow += bpl;
1063       orow += rowstride;
1064     }
1065 }
1066
1067 static void
1068 rgb888lsb (GdkImage    *image,
1069            guchar      *pixels,
1070            int          rowstride,
1071            int          x1,
1072            int          y1,
1073            int          x2,
1074            int          y2,
1075            GdkColormap *colormap)
1076 {
1077   int xx, yy;
1078   int bpl;
1079
1080   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
1081   guint8 *o, *s;
1082
1083   bpl = image->bpl;
1084
1085   d (printf ("32 bit, lsb, no alpha\n"));
1086
1087   for (yy = y1; yy < y2; yy++)
1088     {
1089       s = srow;
1090       o = orow;
1091       for (xx = x1; xx < x2; xx++)
1092         {
1093           *o++ = s[2];
1094           *o++ = s[1];
1095           *o++ = s[0];
1096           s += 4;
1097         }
1098       srow += bpl;
1099       orow += rowstride;
1100     }
1101 }
1102
1103 static void
1104 rgb888amsb (GdkImage    *image,
1105             guchar      *pixels,
1106             int          rowstride,
1107             int          x1,
1108             int          y1,
1109             int          x2,
1110             int          y2,
1111             GdkColormap *colormap)
1112 {
1113   int xx, yy;
1114   int bpl;
1115
1116   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
1117 #ifdef LITTLE
1118   guint32 *o;
1119   guint32 *s;
1120 #else
1121   guint8 *s;    /* for byte order swapping */
1122   guint8 *o;
1123 #endif
1124
1125   d (printf ("32 bit, msb, with alpha\n"));
1126
1127   bpl = image->bpl;
1128
1129   /* msb data */
1130   for (yy = y1; yy < y2; yy++)
1131     {
1132 #ifdef LITTLE
1133       s = (guint32 *) srow;
1134       o = (guint32 *) orow;
1135 #else
1136       s = srow;
1137       o = orow;
1138 #endif
1139       for (xx = x1; xx < x2; xx++)
1140         {
1141 #ifdef LITTLE
1142           *o++ = s[1];
1143           *o++ = s[2];
1144           *o++ = s[3];
1145           *o++ = 0xff;
1146           s += 4;
1147 #else
1148           *o++ = (*s << 8) | 0xff; /* untested */
1149           s++;
1150 #endif
1151         }
1152       srow += bpl;
1153       orow += rowstride;
1154     }
1155 }
1156
1157 static void
1158 rgb888msb (GdkImage    *image,
1159            guchar      *pixels,
1160            int          rowstride,
1161            int          x1,
1162            int          y1,
1163            int          x2,
1164            int          y2,
1165            GdkColormap *colormap)
1166 {
1167   int xx, yy;
1168   int bpl;
1169
1170   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
1171   guint8 *s;
1172   guint8 *o;
1173
1174   d (printf ("32 bit, msb, no alpha\n"));
1175
1176   bpl = image->bpl;
1177
1178   for (yy = y1; yy < y2; yy++)
1179     {
1180       s = srow;
1181       o = orow;
1182       for (xx = x1; xx < x2; xx++)
1183         {
1184           *o++ = s[1];
1185           *o++ = s[2];
1186           *o++ = s[3];
1187           s += 4;
1188         }
1189       srow += bpl;
1190       orow += rowstride;
1191     }
1192 }
1193
1194 /*
1195  * This should work correctly with any display/any endianness, but will probably
1196  * run quite slow
1197  */
1198 static void
1199 convert_real_slow (GdkImage    *image,
1200                    guchar      *pixels,
1201                    int          rowstride,
1202                    int          x1,
1203                    int          y1,
1204                    int          x2,
1205                    int          y2,
1206                    GdkColormap *cmap,
1207                    gboolean     alpha)
1208 {
1209   int xx, yy;
1210   int bpl;
1211   guint8 *orow = pixels;
1212   guint8 *o;
1213   guint32 pixel;
1214   GdkVisual *v;
1215   guint8 component;
1216   int i;
1217
1218   bpl = image->bpl;
1219   v = gdk_colormap_get_visual(cmap);
1220
1221   d(printf("rgb  mask/shift/prec = %x:%x:%x %d:%d:%d  %d:%d:%d\n",
1222            v->red_mask, v->green_mask, v->blue_mask,
1223            v->red_shift, v->green_shift, v->blue_shift,
1224            v->red_prec, v->green_prec, v->blue_prec));
1225
1226   for (yy = y1; yy < y2; yy++)
1227     {
1228       o = orow;
1229       for (xx = x1; xx < x2; xx++)
1230         {
1231           pixel = gdk_image_get_pixel(image, xx, yy);
1232           switch (v->type)
1233             {
1234                                 /* I assume this is right for static & greyscale's too? */
1235             case GDK_VISUAL_STATIC_GRAY:
1236             case GDK_VISUAL_GRAYSCALE:
1237             case GDK_VISUAL_STATIC_COLOR:
1238             case GDK_VISUAL_PSEUDO_COLOR:
1239               *o++ = cmap->colors[pixel].red;
1240               *o++ = cmap->colors[pixel].green;
1241               *o++ = cmap->colors[pixel].blue;
1242               break;
1243             case GDK_VISUAL_TRUE_COLOR:
1244                                 /* This is odd because it must sometimes shift left (otherwise
1245                                  * I'd just shift >> (*_shift - 8 + *_prec + <0-7>). This logic
1246                                  * should work for all bit sizes/shifts/etc.
1247                                  */
1248               component = 0;
1249               for (i = 24; i < 32; i += v->red_prec)
1250                 component |= ((pixel & v->red_mask) << (32 - v->red_shift - v->red_prec)) >> i;
1251               *o++ = component;
1252               component = 0;
1253               for (i = 24; i < 32; i += v->green_prec)
1254                 component |= ((pixel & v->green_mask) << (32 - v->green_shift - v->green_prec)) >> i;
1255               *o++ = component;
1256               component = 0;
1257               for (i = 24; i < 32; i += v->blue_prec)
1258                 component |= ((pixel & v->blue_mask) << (32 - v->blue_shift - v->blue_prec)) >> i;
1259               *o++ = component;
1260               break;
1261             case GDK_VISUAL_DIRECT_COLOR:
1262               *o++ = cmap->colors[((pixel & v->red_mask) << (32 - v->red_shift - v->red_prec)) >> 24].red;
1263               *o++ = cmap->colors[((pixel & v->green_mask) << (32 - v->green_shift - v->green_prec)) >> 24].green;
1264               *o++ = cmap->colors[((pixel & v->blue_mask) << (32 - v->blue_shift - v->blue_prec)) >> 24].blue;
1265               break;
1266             }
1267           if (alpha)
1268             *o++ = 0xff;
1269         }
1270       orow += rowstride;
1271     }
1272 }
1273
1274 typedef void (* cfunc) (GdkImage    *image,
1275                         guchar      *pixels,
1276                         int          rowstride,
1277                         int          x1,
1278                         int          y1,
1279                         int          x2,
1280                         int          y2,
1281                         GdkColormap *cmap);
1282
1283 static cfunc convert_map[] = {
1284   rgb1,rgb1,rgb1a,rgb1a,
1285   rgb8,rgb8,rgb8a,rgb8a,
1286   rgb555lsb,rgb555msb,rgb555alsb,rgb555amsb,
1287   rgb565lsb,rgb565msb,rgb565alsb,rgb565amsb,
1288   rgb888lsb,rgb888msb,rgb888alsb,rgb888amsb
1289 };
1290
1291 /*
1292  * perform actual conversion
1293  *
1294  *  If we can, try and use the optimised code versions, but as a default
1295  * fallback, and always for direct colour, use the generic/slow but complete
1296  * conversion function.
1297  */
1298 static void
1299 rgbconvert (GdkImage    *image,
1300             guchar      *pixels,
1301             int          rowstride,
1302             gboolean     alpha,
1303             int          x,
1304             int          y,
1305             int          width,
1306             int          height,
1307             GdkColormap *cmap)
1308 {
1309   int index;
1310   int bank;
1311   GdkVisual *v;
1312
1313   g_assert ((x + width) <= image->width);
1314   g_assert ((y + height) <= image->height);
1315   
1316   if (cmap == NULL)
1317     {
1318       /* Only allowed for bitmaps */
1319       g_return_if_fail (image->depth == 1);
1320       
1321       if (alpha)
1322         bitmap1a (image, pixels, rowstride,
1323                   x, y, x + width, y + height);
1324       else
1325         bitmap1 (image, pixels, rowstride,
1326                   x, y, x + width, y + height);
1327       
1328       return;
1329     }
1330   
1331   v = gdk_colormap_get_visual (cmap);
1332   bank = 5; /* default fallback converter */
1333   index = (image->byte_order == GDK_MSB_FIRST) | (alpha != 0) << 1;
1334   
1335   d(printf("masks = %x:%x:%x\n", v->red_mask, v->green_mask, v->blue_mask));
1336   d(printf("image depth = %d, bits per pixel = %d\n", image->depth, image->bits_per_pixel));
1337   
1338   switch (v->type)
1339     {
1340                                 /* I assume this is right for static & greyscale's too? */
1341     case GDK_VISUAL_STATIC_GRAY:
1342     case GDK_VISUAL_GRAYSCALE:
1343     case GDK_VISUAL_STATIC_COLOR:
1344     case GDK_VISUAL_PSEUDO_COLOR:
1345       switch (image->bits_per_pixel)
1346         {
1347         case 1:
1348           bank = 0;
1349           break;
1350         case 8:
1351           if (image->depth == 8)
1352             bank = 1;
1353           break;
1354         }
1355       break;
1356     case GDK_VISUAL_TRUE_COLOR:
1357       switch (image->depth)
1358         {
1359         case 15:
1360           if (v->red_mask == 0x7c00 && v->green_mask == 0x3e0 && v->blue_mask == 0x1f
1361               && image->bits_per_pixel == 16)
1362             bank = 2;
1363           break;
1364         case 16:
1365           if (v->red_mask == 0xf800 && v->green_mask == 0x7e0 && v->blue_mask == 0x1f
1366               && image->bits_per_pixel == 16)
1367             bank = 3;
1368           break;
1369         case 24:
1370         case 32:
1371           if (v->red_mask == 0xff0000 && v->green_mask == 0xff00 && v->blue_mask == 0xff
1372               && image->bits_per_pixel == 32)
1373             bank = 4;
1374           break;
1375         }
1376       break;
1377     case GDK_VISUAL_DIRECT_COLOR:
1378       /* always use the slow version */
1379       break;
1380     }
1381
1382   d (g_print ("converting using conversion function in bank %d\n", bank));
1383
1384   if (bank == 5)
1385     {
1386       convert_real_slow (image, pixels, rowstride,
1387                          x, y, x + width, y + height,                         
1388                          cmap, alpha);
1389     }
1390   else
1391     {
1392       index |= bank << 2;
1393       d (g_print ("converting with index %d\n", index));
1394       (* convert_map[index]) (image, pixels, rowstride,
1395                               x, y, x + width, y + height,
1396                               cmap);
1397     }
1398 }
1399
1400
1401 /* Exported functions */
1402
1403 /**
1404  * gdk_pixbuf_get_from_drawable:
1405  * @dest: Destination pixbuf, or %NULL if a new pixbuf should be created.
1406  * @src: Source drawable.
1407  * @cmap: A colormap if @src doesn't have one set.
1408  * @src_x: Source X coordinate within drawable.
1409  * @src_y: Source Y coordinate within drawable.
1410  * @dest_x: Destination X coordinate in pixbuf, or 0 if @dest is NULL.
1411  * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
1412  * @width: Width in pixels of region to get.
1413  * @height: Height in pixels of region to get.
1414  *
1415  * Transfers image data from a #GdkDrawable and converts it to an RGB(A)
1416  * representation inside a #GdkPixbuf. In other words, copies
1417  * image data from a server-side drawable to a client-side RGB(A) buffer.
1418  * This allows you to efficiently read individual pixels on the client side.
1419  * 
1420  * If the drawable @src has no colormap (gdk_drawable_get_colormap()
1421  * returns %NULL), then a suitable colormap must be specified.
1422  * Typically a #GdkWindow or a pixmap created by passing a #GdkWindow
1423  * to gdk_pixmap_new() will already have a colormap associated with
1424  * it.  If the drawable has a colormap, the @cmap argument will be
1425  * ignored.  If the drawable is a bitmap (1 bit per pixel pixmap),
1426  * then a colormap is not required; pixels with a value of 1 are
1427  * assumed to be white, and pixels with a value of 0 are assumed to be
1428  * black. For taking screenshots, gdk_colormap_get_system() returns
1429  * the correct colormap to use.
1430  *
1431  * If the specified destination pixbuf @dest is %NULL, then this
1432  * function will create an RGB pixbuf with 8 bits per channel and no
1433  * alpha, with the same size specified by the @width and @height
1434  * arguments.  In this case, the @dest_x and @dest_y arguments must be
1435  * specified as 0.  If the specified destination pixbuf is not %NULL
1436  * and it contains alpha information, then the filled pixels will be
1437  * set to full opacity (alpha = 255).
1438  *
1439  * If the specified drawable is a pixmap, then the requested source
1440  * rectangle must be completely contained within the pixmap, otherwise
1441  * the function will return %NULL. For pixmaps only (not for windows)
1442  * passing -1 for width or height is allowed to mean the full width
1443  * or height of the pixmap.
1444  *
1445  * If the specified drawable is a window, and the window is off the
1446  * screen, then there is no image data in the obscured/offscreen
1447  * regions to be placed in the pixbuf. The contents of portions of the
1448  * pixbuf corresponding to the offscreen region are undefined.
1449  *
1450  * If the window you're obtaining data from is partially obscured by
1451  * other windows, then the contents of the pixbuf areas corresponding
1452  * to the obscured regions are undefined.
1453  * 
1454  * If the target drawable is not mapped (typically because it's
1455  * iconified/minimized or not on the current workspace), then %NULL
1456  * will be returned.
1457  *
1458  * If memory can't be allocated for the return value, %NULL will be returned
1459  * instead.
1460  *
1461  * (In short, there are several ways this function can fail, and if it fails
1462  *  it returns %NULL; so check the return value.)
1463  *
1464  * This function calls gdk_drawable_get_image() internally and
1465  * converts the resulting image to a #GdkPixbuf, so the
1466  * documentation for gdk_drawable_get_image() may also be relevant.
1467  * 
1468  * Return value: The same pixbuf as @dest if it was non-%NULL, or a newly-created
1469  * pixbuf with a reference count of 1 if no destination pixbuf was specified, or %NULL on error
1470  **/
1471 GdkPixbuf *
1472 gdk_pixbuf_get_from_drawable (GdkPixbuf   *dest,
1473                               GdkDrawable *src,
1474                               GdkColormap *cmap,
1475                               int src_x,  int src_y,
1476                               int dest_x, int dest_y,
1477                               int width,  int height)
1478 {
1479   int src_width, src_height;
1480   GdkImage *image;
1481   int depth;
1482   int x0, y0;
1483   
1484   /* General sanity checks */
1485
1486   g_return_val_if_fail (src != NULL, NULL);
1487
1488   if (GDK_IS_WINDOW (src))
1489     /* FIXME: this is not perfect, since is_viewable() only tests
1490      * recursively up the Gdk parent window tree, but stops at
1491      * foreign windows or Gdk toplevels.  I.e. if a window manager
1492      * unmapped one of its own windows, this won't work.
1493      */
1494     g_return_val_if_fail (gdk_window_is_viewable (src), NULL);
1495
1496   if (!dest)
1497     g_return_val_if_fail (dest_x == 0 && dest_y == 0, NULL);
1498   else
1499     {
1500       g_return_val_if_fail (dest->colorspace == GDK_COLORSPACE_RGB, NULL);
1501       g_return_val_if_fail (dest->n_channels == 3 || dest->n_channels == 4, NULL);
1502       g_return_val_if_fail (dest->bits_per_sample == 8, NULL);
1503     }
1504
1505   if (cmap == NULL)
1506     cmap = gdk_drawable_get_colormap (src);
1507
1508   depth = gdk_drawable_get_depth (src);
1509   
1510   if (depth != 1 && cmap == NULL)
1511     {
1512       g_warning ("%s: Source drawable has no colormap; either pass "
1513                  "in a colormap, or set the colormap on the drawable "
1514                  "with gdk_drawable_set_colormap()", G_STRLOC);
1515       return NULL;
1516     }
1517   
1518   /* Coordinate sanity checks */
1519   
1520   if (GDK_IS_PIXMAP (src))
1521     {
1522       gdk_drawable_get_size (src, &src_width, &src_height);
1523       if (width < 0)
1524         width = src_width;
1525       if (height < 0)
1526         height = src_height;
1527       
1528       g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
1529       g_return_val_if_fail (src_x + width <= src_width && src_y + height <= src_height, NULL);
1530     }
1531
1532   /* Create the pixbuf if needed */
1533   if (!dest)
1534     {
1535       dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
1536       if (dest == NULL)
1537         return NULL;
1538     }
1539   
1540   if (dest)
1541     {
1542       g_return_val_if_fail (dest_x >= 0 && dest_y >= 0, NULL);
1543       g_return_val_if_fail (dest_x + width <= dest->width, NULL);
1544       g_return_val_if_fail (dest_y + height <= dest->height, NULL);
1545     }
1546
1547   for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
1548     {
1549       gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
1550       for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
1551         {
1552           gint xs0, ys0;
1553           
1554           gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
1555           
1556           image = _gdk_image_get_scratch (gdk_drawable_get_screen (src), 
1557                                           width1, height1, depth, &xs0, &ys0);
1558
1559           _gdk_drawable_copy_to_image (src, image,
1560                                        src_x + x0, src_y + y0,
1561                                        xs0, ys0, width1, height1);
1562
1563           gdk_pixbuf_get_from_image (dest, image, cmap,
1564                                      xs0, ys0, dest_x + x0, dest_y + y0,
1565                                      width1, height1);
1566         }
1567     }
1568   
1569   return dest;
1570 }
1571         
1572 /**
1573  * gdk_pixbuf_get_from_image:
1574  * @dest: Destination pixbuf, or %NULL if a new pixbuf should be created.
1575  * @src: Source #GdkImage.
1576  * @cmap: A colormap, or %NULL to use the one for @src
1577  * @src_x: Source X coordinate within drawable.
1578  * @src_y: Source Y coordinate within drawable.
1579  * @dest_x: Destination X coordinate in pixbuf, or 0 if @dest is NULL.
1580  * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
1581  * @width: Width in pixels of region to get.
1582  * @height: Height in pixels of region to get.
1583  * 
1584  * Same as gdk_pixbuf_get_from_drawable() but gets the pixbuf from
1585  * an image.
1586  * 
1587  * Return value: @dest, newly-created pixbuf if @dest was %NULL, %NULL on error
1588  **/
1589 GdkPixbuf*
1590 gdk_pixbuf_get_from_image (GdkPixbuf   *dest,
1591                            GdkImage    *src,
1592                            GdkColormap *cmap,
1593                            int          src_x,
1594                            int          src_y,
1595                            int          dest_x,
1596                            int          dest_y,
1597                            int          width,
1598                            int          height)
1599 {
1600   int rowstride, bpp, alpha;
1601   
1602   /* General sanity checks */
1603
1604   g_return_val_if_fail (GDK_IS_IMAGE (src), NULL);
1605
1606   if (!dest)
1607     g_return_val_if_fail (dest_x == 0 && dest_y == 0, NULL);
1608   else
1609     {
1610       g_return_val_if_fail (dest->colorspace == GDK_COLORSPACE_RGB, NULL);
1611       g_return_val_if_fail (dest->n_channels == 3 || dest->n_channels == 4, NULL);
1612       g_return_val_if_fail (dest->bits_per_sample == 8, NULL);
1613     }
1614
1615   if (cmap == NULL)
1616     cmap = gdk_image_get_colormap (src);
1617   
1618   if (src->depth != 1 && cmap == NULL)
1619     {
1620       g_warning ("%s: Source image has no colormap; either pass "
1621                  "in a colormap, or set the colormap on the image "
1622                  "with gdk_image_set_colormap()", G_STRLOC);
1623       return NULL;
1624     }
1625   
1626   /* Coordinate sanity checks */
1627
1628   g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
1629   g_return_val_if_fail (src_x + width <= src->width && src_y + height <= src->height, NULL);
1630
1631   if (dest)
1632     {
1633       g_return_val_if_fail (dest_x >= 0 && dest_y >= 0, NULL);
1634       g_return_val_if_fail (dest_x + width <= dest->width, NULL);
1635       g_return_val_if_fail (dest_y + height <= dest->height, NULL);
1636     }
1637
1638   /* Create the pixbuf if needed */
1639   if (!dest)
1640     {
1641       dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
1642       if (dest == NULL)
1643         return NULL;
1644     }
1645
1646   alpha = dest->has_alpha;
1647   rowstride = dest->rowstride;
1648   bpp = alpha ? 4 : 3;
1649
1650   /* we offset into the image data based on the position we are
1651    * retrieving from
1652    */
1653   rgbconvert (src, dest->pixels +
1654               (dest_y * rowstride) + (dest_x * bpp),
1655               rowstride,
1656               alpha,
1657               src_x, src_y,
1658               width,
1659               height,
1660               cmap);
1661   
1662   return dest;
1663 }