]> Pileus Git - ~andy/gtk/blob - gdk/gdkpixbuf-drawable.c
Merge from gdk-pixbuf stable.
[~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 "gdk.h"                /* For gdk_screen_width/gdk_screen_height */
29 #include "gdkcolor.h"
30 #include "gdkimage.h"
31 #include "gdkvisual.h"
32 #include "gdkwindow.h"
33 #include "gdkpixbuf.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           ((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] | s[0] << 8 | s[3] << 16 | s[2] << 24;
441           s += 4;
442           *o++ = (data & 0xf800) | (data & 0xe000) >> 5
443             | (data & 0x7e0) >> 3 | (data & 0x600) >> 9;
444           *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
445             | (data & 0xf8000000) >> 24 | (data & 0xe0000000) >> 29;
446           *o++ = (data & 0x7e00000) >> 11 | (data & 0x6000000) >> 17
447             | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
448 #endif
449         }
450       /* check for last remaining pixel */
451       if (x2 & 1)
452         {
453           register guint16 data;
454 #ifdef LITTLE
455           data = *((short *) s);
456 #else
457           data = *((short *) s);
458           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
459 #endif
460           ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
461           ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
462           ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
463         }
464       srow += bpl;
465       orow += rowstride;
466     }
467 }
468
469 /*
470  * convert 16 bits/pixel data
471  * no alpha
472  * data in msb format
473  */
474 static void
475 rgb565msb (GdkImage    *image,
476            guchar      *pixels,
477            int          rowstride,
478            int          x1,
479            int          y1,
480            int          x2,
481            int          y2,
482            GdkColormap *colormap)
483 {
484   int xx, yy;
485   int bpl;
486
487 #ifdef LITTLE
488   register guint8 *s;   /* need to swap data order */
489 #else
490   register guint32 *s;  /* read 2 pixels at once */
491 #endif
492   register guint16 *o;
493   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
494
495   bpl = image->bpl;
496
497   for (yy = y1; yy < y2; yy++)
498     {
499 #ifdef LITTLE
500       s = srow;
501 #else
502       s = (guint32 *) srow;
503 #endif
504       o = (guint16 *) orow;
505
506       xx = x1;
507       
508       /* check for first pixel odd */
509       if (xx & 1)
510         {
511           register guint16 data;
512 #ifdef LITTLE
513           data = *((short *) s);
514           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
515 #else
516           data = *((short *) s);
517 #endif
518           ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
519           ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
520           ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
521
522           ((char *) o) += 3;
523           ++xx;
524         }
525
526       g_assert (!(xx & 1));
527
528       /* if x2 is even, then the -1 does nothing to number of
529        * loop iterations, if x2 is odd then the -1 reduces
530        * iterations by one
531        */
532       for (; xx < (x2 - 1); xx += 2)
533         {
534           register guint32 data;
535 #ifdef LITTLE
536           /* swap endianness first */
537           data = s[1] | s[0] << 8 | s[3] << 16 | s[2] << 24;
538           s += 4;
539           *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
540             | (data & 0x7e0) << 5 | (data & 0x600) >> 1;
541           *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
542             | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21;
543           *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25
544             | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
545 #else
546           data = *s++;
547           *o++ = (data & 0xf800) | (data & 0xe000) >> 5
548             | (data & 0x7e0) >> 3 | (data & 0x600) >> 9;
549           *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
550             | (data & 0xf8000000) >> 24 | (data & 0xe0000000) >> 29;
551           *o++ = (data & 0x7e00000) >> 11 | (data & 0x6000000) >> 17
552             | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
553 #endif
554         }
555       /* check for last remaining pixel */
556       if (x2 & 1)
557         {
558           register guint16 data;
559 #ifdef LITTLE
560           data = *((short *) s);
561           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
562 #else
563           data = *((short *) s);
564 #endif
565           ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
566           ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
567           ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
568         }
569       srow += bpl;
570       orow += rowstride;
571     }
572 }
573
574 /*
575  * convert 16 bits/pixel data
576  * with alpha
577  * data in lsb format
578  */
579 static void
580 rgb565alsb (GdkImage    *image,
581             guchar      *pixels,
582             int          rowstride,
583             int          x1,
584             int          y1,
585             int          x2,
586             int          y2,
587             GdkColormap *colormap)
588 {
589   int xx, yy;
590   int bpl;
591
592 #ifdef LITTLE
593   register guint16 *s;  /* read 1 pixels at once */
594 #else
595   register guint8 *s;
596 #endif
597   register guint32 *o;
598
599   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
600
601   bpl = image->bpl;
602
603   for (yy = y1; yy < y2; yy++)
604     {
605 #ifdef LITTLE
606       s = (guint16 *) srow;
607 #else
608       s = (guint8 *) srow;
609 #endif
610       o = (guint32 *) orow;
611       for (xx = x1; xx < x2; xx ++)
612         {
613           register guint32 data;
614           /*  rrrrrggg gggbbbbb -> rrrrrRRR ggggggGG bbbbbBBB aaaaaaaa */
615           /*  little endian: aaaaaaaa bbbbbBBB ggggggGG rrrrrRRR */
616 #ifdef LITTLE
617           data = *s++;
618           *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
619             | (data & 0x7e0) << 5 | (data & 0x600) >> 1
620             | (data & 0x1f) << 19 | (data & 0x1c) << 14
621             | 0xff000000;
622 #else
623           /* swap endianness first */
624           data = s[0] | s[1] << 8;
625           s += 2;
626           *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11
627             | (data & 0x7e0) << 13 | (data & 0x600) << 7
628             | (data & 0x1f) << 11 | (data & 0x1c) << 6
629             | 0xff;
630 #endif
631         }
632       srow += bpl;
633       orow += rowstride;
634     }
635 }
636
637 /*
638  * convert 16 bits/pixel data
639  * with alpha
640  * data in msb format
641  */
642 static void
643 rgb565amsb (GdkImage    *image,
644             guchar      *pixels,
645             int          rowstride,
646             int          x1,
647             int          y1,
648             int          x2,
649             int          y2,
650             GdkColormap *colormap)
651 {
652   int xx, yy;
653   int bpl;
654
655 #ifdef LITTLE
656   register guint8 *s;
657 #else
658   register guint16 *s;  /* read 1 pixels at once */
659 #endif
660   register guint32 *o;
661
662   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
663
664   bpl = image->bpl;
665
666   for (yy = y1; yy < y2; yy++)
667     {
668       s = srow;
669       o = (guint32 *) orow;
670       for (xx = x1; xx < x2; xx ++)
671         {
672           register guint32 data;
673           /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggg00 bbbbbBBB aaaaaaaa */
674           /*  little endian: aaaaaaaa bbbbbBBB gggggg00 rrrrrRRR */
675 #ifdef LITTLE
676           /* swap endianness first */
677           data = s[0] | s[1] << 8;
678           s += 2;
679           *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
680             | (data & 0x7e0) << 5 | (data & 0x600) >> 1
681             | (data & 0x1f) << 19 | (data & 0x1c) << 14
682             | 0xff000000;
683 #else
684           data = *s++;
685           *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11
686             | (data & 0x7e0) << 13 | (data & 0x600) << 7
687             | (data & 0x1f) << 11 | (data & 0x1c) << 6
688             | 0xff;
689 #endif
690         }
691       srow += bpl;
692       orow += rowstride;
693     }
694 }
695
696 /*
697  * convert 15 bits/pixel data
698  * no alpha
699  * data in lsb format
700  */
701 static void
702 rgb555lsb (GdkImage     *image,
703            guchar       *pixels,
704            int           rowstride,
705            int          x1,
706            int          y1,
707            int          x2,
708            int          y2,
709            GdkColormap  *colormap)
710 {
711   int xx, yy;
712   int bpl;
713
714 #ifdef LITTLE
715   register guint32 *s;  /* read 2 pixels at once */
716 #else
717   register guint8 *s;   /* read 2 pixels at once */
718 #endif
719   register guint16 *o;
720   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
721
722   bpl = image->bpl;
723
724   for (yy = y1; yy < y2; yy++)
725     {
726 #ifdef LITTLE
727       s = (guint32 *) srow;
728 #else
729       s = srow;
730 #endif
731       o = (guint16 *) orow;
732
733       xx = x1;
734       
735       /* check for first odd pixel */
736       if (xx & 1)
737         {
738           register guint16 data;
739 #ifdef LITTLE
740           data = *((short *) s);
741 #else
742           data = *((short *) s);
743           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
744 #endif
745           ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
746           ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
747           ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
748           ((char *) o) += 3;
749           ++xx;
750         }
751
752       g_assert (!(xx & 1));
753
754       /* if x2 is even, then the -1 does nothing to number of
755        * loop iterations, if x2 is odd then the -1 reduces
756        * iterations by one
757        */
758       for (; xx < (x2 - 1); xx += 2)
759         {
760           register guint32 data;
761 #ifdef LITTLE
762           data = *s++;
763           *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
764             | (data & 0x3e0) << 6 | (data & 0x380) << 1;
765           *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
766             | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20;
767           *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23
768             | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
769 #else
770           /* swap endianness first */
771           data = s[1] | s[0] << 8 | s[3] << 16 | s[2] << 24;
772           s += 4;
773           *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4
774             | (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
775           *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
776             | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28;
777           *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15
778             | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
779 #endif
780         }
781       /* check for last remaining pixel */
782       if (x2 & 1)
783         {
784           register guint16 data;
785 #ifdef LITTLE
786           data = *((short *) s);
787 #else
788           data = *((short *) s);
789           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
790 #endif
791           ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
792           ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
793           ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
794         }
795       srow += bpl;
796       orow += rowstride;
797     }
798 }
799
800 /*
801  * convert 15 bits/pixel data
802  * no alpha
803  * data in msb format
804  */
805 static void
806 rgb555msb (GdkImage    *image,
807            guchar      *pixels,
808            int          rowstride,
809            int          x1,
810            int          y1,
811            int          x2,
812            int          y2,
813            GdkColormap *colormap)
814 {
815   int xx, yy;
816   int bpl;
817
818 #ifdef LITTLE
819   register guint8 *s;   /* read 2 pixels at once */
820 #else
821   register guint32 *s;  /* read 2 pixels at once */
822 #endif
823   register guint16 *o;
824   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
825
826   bpl = image->bpl;
827
828   for (yy = y1; yy < y2; yy++)
829     {
830       s = srow;
831       o = (guint16 *) orow;
832
833       xx = x1;
834       /* See if first pixel is odd */
835       if (xx & 1)
836         {
837           register guint16 data;
838 #ifdef LITTLE
839           data = *((short *) s);
840           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
841 #else
842           data = *((short *) s);
843 #endif
844           ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
845           ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
846           ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
847
848           ((char *) o) += 3;
849           ++xx;
850         }
851
852       g_assert (!(xx & 1));
853
854       /* if x2 is even, then the -1 does nothing to number of
855        * loop iterations, if x2 is odd then the -1 reduces
856        * iterations by one
857        */
858       for (; xx < (x2 - 1); xx += 2)
859         {
860           register guint32 data;
861 #ifdef LITTLE
862           /* swap endianness first */
863           data = s[1] | s[0] << 8 | s[3] << 16 | s[2] << 24;
864           s += 4;
865           *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
866             | (data & 0x3e0) << 6 | (data & 0x380) << 1;
867           *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
868             | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20;
869           *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23
870             | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
871 #else
872           data = *s++;
873           *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4
874             | (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
875           *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
876             | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28;
877           *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15
878             | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
879 #endif
880         }
881       /* check for last remaining pixel */
882       if (x2 & 1)
883         {
884           register guint16 data;
885 #ifdef LITTLE
886           data = *((short *) s);
887           data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
888 #else
889           data = *((short *) s);
890 #endif
891           ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
892           ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
893           ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
894         }
895       srow += bpl;
896       orow += rowstride;
897     }
898 }
899
900 /*
901  * convert 15 bits/pixel data
902  * with alpha
903  * data in lsb format
904  */
905 static void
906 rgb555alsb (GdkImage    *image,
907             guchar      *pixels,
908             int          rowstride,
909             int          x1,
910             int          y1,
911             int          x2,
912             int          y2,
913             GdkColormap *colormap)
914 {
915   int xx, yy;
916   int bpl;
917
918 #ifdef LITTLE
919   register guint16 *s;  /* read 1 pixels at once */
920 #else
921   register guint8 *s;
922 #endif
923   register guint32 *o;
924
925   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
926
927   bpl = image->bpl;
928
929   for (yy = y1; yy < y2; yy++)
930     {
931 #ifdef LITTLE
932       s = (guint16 *) srow;
933 #else
934       s = srow;
935 #endif
936       o = (guint32 *) orow;
937       for (xx = x1; xx < x2; xx++)
938         {
939           register guint32 data;
940           /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
941           /*  little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */
942 #ifdef LITTLE
943           data = *s++;
944           *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
945             | (data & 0x3e0) << 6 | (data & 0x380) << 1
946             | (data & 0x1f) << 19 | (data & 0x1c) << 14
947             | 0xff000000;
948 #else
949           /* swap endianness first */
950           data = s[0] | s[1] << 8;
951           s += 2;
952           *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12
953             | (data & 0x3e0) << 14 | (data & 0x380) << 9
954             | (data & 0x1f) << 11 | (data & 0x1c) << 6
955             | 0xff;
956 #endif
957         }
958       srow += bpl;
959       orow += rowstride;
960     }
961 }
962
963 /*
964  * convert 15 bits/pixel data
965  * with alpha
966  * data in msb format
967  */
968 static void
969 rgb555amsb (GdkImage    *image,
970             guchar      *pixels,
971             int          rowstride,
972             int          x1,
973             int          y1,
974             int          x2,
975             int          y2,
976             GdkColormap *colormap)
977 {
978   int xx, yy;
979   int bpl;
980
981 #ifdef LITTLE
982   register guint16 *s;  /* read 1 pixels at once */
983 #else
984   register guint8 *s;
985 #endif
986   register guint32 *o;
987
988   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
989
990   bpl = image->bpl;
991
992   for (yy = y1; yy < y2; yy++)
993     {
994 #ifdef LITTLE
995       s = (guint16 *) srow;
996 #else
997       s = srow;
998 #endif
999       o = (guint32 *) orow;
1000       for (xx = x1; xx < x2; xx++)
1001         {
1002           register guint32 data;
1003           /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
1004           /*  little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */
1005 #ifdef LITTLE
1006           /* swap endianness first */
1007           data = s[0] | s[1] << 8;
1008           s += 2;
1009           *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
1010             | (data & 0x3e0) << 6 | (data & 0x380) << 1
1011             | (data & 0x1f) << 19 | (data & 0x1c) << 14
1012             | 0xff000000;
1013 #else
1014           data = *s++;
1015           *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12
1016             | (data & 0x3e0) << 14 | (data & 0x380) << 9
1017             | (data & 0x1f) << 11 | (data & 0x1c) << 6
1018             | 0xff;
1019 #endif
1020         }
1021       srow += bpl;
1022       orow += rowstride;
1023     }
1024 }
1025
1026
1027 static void
1028 rgb888alsb (GdkImage    *image,
1029             guchar      *pixels,
1030             int          rowstride,
1031             int          x1,
1032             int          y1,
1033             int          x2,
1034             int          y2,
1035             GdkColormap *colormap)
1036 {
1037   int xx, yy;
1038   int bpl;
1039
1040   guint8 *s;    /* for byte order swapping */
1041   guint8 *o;
1042   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
1043
1044   bpl = image->bpl;
1045
1046   d (printf ("32 bits/pixel with alpha\n"));
1047
1048   /* lsb data */
1049   for (yy = y1; yy < y2; yy++)
1050     {
1051       s = srow;
1052       o = orow;
1053       for (xx = x1; xx < x2; xx++)
1054         {
1055           *o++ = s[2];
1056           *o++ = s[1];
1057           *o++ = s[0];
1058           *o++ = 0xff;
1059           s += 4;
1060         }
1061       srow += bpl;
1062       orow += rowstride;
1063     }
1064 }
1065
1066 static void
1067 rgb888lsb (GdkImage    *image,
1068            guchar      *pixels,
1069            int          rowstride,
1070            int          x1,
1071            int          y1,
1072            int          x2,
1073            int          y2,
1074            GdkColormap *colormap)
1075 {
1076   int xx, yy;
1077   int bpl;
1078
1079   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
1080   guint8 *o, *s;
1081
1082   bpl = image->bpl;
1083
1084   d (printf ("32 bit, lsb, no alpha\n"));
1085
1086   for (yy = y1; yy < y2; yy++)
1087     {
1088       s = srow;
1089       o = orow;
1090       for (xx = x1; xx < x2; xx++)
1091         {
1092           *o++ = s[2];
1093           *o++ = s[1];
1094           *o++ = s[0];
1095           s += 4;
1096         }
1097       srow += bpl;
1098       orow += rowstride;
1099     }
1100 }
1101
1102 static void
1103 rgb888amsb (GdkImage    *image,
1104             guchar      *pixels,
1105             int          rowstride,
1106             int          x1,
1107             int          y1,
1108             int          x2,
1109             int          y2,
1110             GdkColormap *colormap)
1111 {
1112   int xx, yy;
1113   int bpl;
1114
1115   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
1116 #ifdef LITTLE
1117   guint32 *o;
1118   guint32 *s;
1119 #else
1120   guint8 *s;    /* for byte order swapping */
1121   guint8 *o;
1122 #endif
1123
1124   d (printf ("32 bit, msb, with alpha\n"));
1125
1126   bpl = image->bpl;
1127
1128   /* msb data */
1129   for (yy = y1; yy < y2; yy++)
1130     {
1131 #ifdef LITTLE
1132       s = (guint32 *) srow;
1133       o = (guint32 *) orow;
1134 #else
1135       s = srow;
1136       o = orow;
1137 #endif
1138       for (xx = x1; xx < x2; xx++)
1139         {
1140 #ifdef LITTLE
1141           *o++ = s[1];
1142           *o++ = s[2];
1143           *o++ = s[3];
1144           *o++ = 0xff;
1145           s += 4;
1146 #else
1147           *o++ = (*s << 8) | 0xff; /* untested */
1148           s++;
1149 #endif
1150         }
1151       srow += bpl;
1152       orow += rowstride;
1153     }
1154 }
1155
1156 static void
1157 rgb888msb (GdkImage    *image,
1158            guchar      *pixels,
1159            int          rowstride,
1160            int          x1,
1161            int          y1,
1162            int          x2,
1163            int          y2,
1164            GdkColormap *colormap)
1165 {
1166   int xx, yy;
1167   int bpl;
1168
1169   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
1170   guint8 *s;
1171   guint8 *o;
1172
1173   d (printf ("32 bit, msb, no alpha\n"));
1174
1175   bpl = image->bpl;
1176
1177   for (yy = y1; yy < y2; yy++)
1178     {
1179       s = srow;
1180       o = orow;
1181       for (xx = x1; xx < x2; xx++)
1182         {
1183           *o++ = s[1];
1184           *o++ = s[2];
1185           *o++ = s[3];
1186           s += 4;
1187         }
1188       srow += bpl;
1189       orow += rowstride;
1190     }
1191 }
1192
1193 /*
1194  * This should work correctly with any display/any endianness, but will probably
1195  * run quite slow
1196  */
1197 static void
1198 convert_real_slow (GdkImage    *image,
1199                    guchar      *pixels,
1200                    int          rowstride,
1201                    int          x1,
1202                    int          y1,
1203                    int          x2,
1204                    int          y2,
1205                    GdkColormap *cmap,
1206                    gboolean     alpha)
1207 {
1208   int xx, yy;
1209   int bpl;
1210   guint8 *orow = pixels;
1211   guint8 *o;
1212   guint32 pixel;
1213   GdkVisual *v;
1214   guint8 component;
1215   int i;
1216
1217   bpl = image->bpl;
1218   v = gdk_colormap_get_visual(cmap);
1219
1220   d(printf("rgb  mask/shift/prec = %x:%x:%x %d:%d:%d  %d:%d:%d\n",
1221            v->red_mask, v->green_mask, v->blue_mask,
1222            v->red_shift, v->green_shift, v->blue_shift,
1223            v->red_prec, v->green_prec, v->blue_prec));
1224
1225   for (yy = y1; yy < y2; yy++)
1226     {
1227       o = orow;
1228       for (xx = x1; xx < x2; xx++)
1229         {
1230           pixel = gdk_image_get_pixel(image, xx, yy);
1231           switch (v->type)
1232             {
1233                                 /* I assume this is right for static & greyscale's too? */
1234             case GDK_VISUAL_STATIC_GRAY:
1235             case GDK_VISUAL_GRAYSCALE:
1236             case GDK_VISUAL_STATIC_COLOR:
1237             case GDK_VISUAL_PSEUDO_COLOR:
1238               *o++ = cmap->colors[pixel].red;
1239               *o++ = cmap->colors[pixel].green;
1240               *o++ = cmap->colors[pixel].blue;
1241               break;
1242             case GDK_VISUAL_TRUE_COLOR:
1243                                 /* This is odd because it must sometimes shift left (otherwise
1244                                  * I'd just shift >> (*_shift - 8 + *_prec + <0-7>). This logic
1245                                  * should work for all bit sizes/shifts/etc.
1246                                  */
1247               component = 0;
1248               for (i = 24; i < 32; i += v->red_prec)
1249                 component |= ((pixel & v->red_mask) << (32 - v->red_shift - v->red_prec)) >> i;
1250               *o++ = component;
1251               component = 0;
1252               for (i = 24; i < 32; i += v->green_prec)
1253                 component |= ((pixel & v->green_mask) << (32 - v->green_shift - v->green_prec)) >> i;
1254               *o++ = component;
1255               component = 0;
1256               for (i = 24; i < 32; i += v->blue_prec)
1257                 component |= ((pixel & v->blue_mask) << (32 - v->blue_shift - v->blue_prec)) >> i;
1258               *o++ = component;
1259               break;
1260             case GDK_VISUAL_DIRECT_COLOR:
1261               *o++ = cmap->colors[((pixel & v->red_mask) << (32 - v->red_shift - v->red_prec)) >> 24].red;
1262               *o++ = cmap->colors[((pixel & v->green_mask) << (32 - v->green_shift - v->green_prec)) >> 24].green;
1263               *o++ = cmap->colors[((pixel & v->blue_mask) << (32 - v->blue_shift - v->blue_prec)) >> 24].blue;
1264               break;
1265             }
1266           if (alpha)
1267             *o++ = 0xff;
1268         }
1269       orow += rowstride;
1270     }
1271 }
1272
1273 typedef void (* cfunc) (GdkImage    *image,
1274                         guchar      *pixels,
1275                         int          rowstride,
1276                         int          x1,
1277                         int          y1,
1278                         int          x2,
1279                         int          y2,
1280                         GdkColormap *cmap);
1281
1282 static cfunc convert_map[] = {
1283   rgb1,rgb1,rgb1a,rgb1a,
1284   rgb8,rgb8,rgb8a,rgb8a,
1285   rgb555lsb,rgb555msb,rgb555alsb,rgb555amsb,
1286   rgb565lsb,rgb565msb,rgb565alsb,rgb565amsb,
1287   rgb888lsb,rgb888msb,rgb888alsb,rgb888amsb
1288 };
1289
1290 /*
1291  * perform actual conversion
1292  *
1293  *  If we can, try and use the optimised code versions, but as a default
1294  * fallback, and always for direct colour, use the generic/slow but complete
1295  * conversion function.
1296  */
1297 static void
1298 rgbconvert (GdkImage    *image,
1299             guchar      *pixels,
1300             int          rowstride,
1301             gboolean     alpha,
1302             int          x,
1303             int          y,
1304             int          width,
1305             int          height,
1306             GdkColormap *cmap)
1307 {
1308   int index;
1309   int bank;
1310   GdkVisual *v;
1311
1312   g_assert ((x + width) <= image->width);
1313   g_assert ((y + height) <= image->height);
1314   
1315   if (cmap == NULL)
1316     {
1317       /* Only allowed for bitmaps */
1318       g_return_if_fail (image->depth == 1);
1319       
1320       if (alpha)
1321         bitmap1a (image, pixels, rowstride,
1322                   x, y, x + width, y + height);
1323       else
1324         bitmap1 (image, pixels, rowstride,
1325                   x, y, x + width, y + height);
1326       
1327       return;
1328     }
1329   
1330   v = gdk_colormap_get_visual (cmap);
1331   bank = 5; /* default fallback converter */
1332   index = (image->byte_order == GDK_MSB_FIRST) | (alpha != 0) << 1;
1333   
1334   d(printf("masks = %x:%x:%x\n", v->red_mask, v->green_mask, v->blue_mask));
1335   d(printf("image depth = %d, bits per pixel = %d\n", image->depth, image->bits_per_pixel));
1336   
1337   switch (v->type)
1338     {
1339                                 /* I assume this is right for static & greyscale's too? */
1340     case GDK_VISUAL_STATIC_GRAY:
1341     case GDK_VISUAL_GRAYSCALE:
1342     case GDK_VISUAL_STATIC_COLOR:
1343     case GDK_VISUAL_PSEUDO_COLOR:
1344       switch (image->bits_per_pixel)
1345         {
1346         case 1:
1347           bank = 0;
1348           break;
1349         case 8:
1350           if (image->depth == 8)
1351             bank = 1;
1352           break;
1353         }
1354       break;
1355     case GDK_VISUAL_TRUE_COLOR:
1356       switch (image->depth)
1357         {
1358         case 15:
1359           if (v->red_mask == 0x7c00 && v->green_mask == 0x3e0 && v->blue_mask == 0x1f
1360               && image->bits_per_pixel == 16)
1361             bank = 2;
1362           break;
1363         case 16:
1364           if (v->red_mask == 0xf800 && v->green_mask == 0x7e0 && v->blue_mask == 0x1f
1365               && image->bits_per_pixel == 16)
1366             bank = 3;
1367           break;
1368         case 24:
1369         case 32:
1370           if (v->red_mask == 0xff0000 && v->green_mask == 0xff00 && v->blue_mask == 0xff
1371               && image->bits_per_pixel == 32)
1372             bank = 4;
1373           break;
1374         }
1375       break;
1376     case GDK_VISUAL_DIRECT_COLOR:
1377       /* always use the slow version */
1378       break;
1379     }
1380
1381   d (g_print ("converting using conversion function in bank %d\n", bank));
1382
1383   if (bank == 5)
1384     {
1385       convert_real_slow (image, pixels, rowstride,
1386                          x, y, x + width, y + height,                         
1387                          cmap, alpha);
1388     }
1389   else
1390     {
1391       index |= bank << 2;
1392       d (g_print ("converting with index %d\n", index));
1393       (* convert_map[index]) (image, pixels, rowstride,
1394                               x, y, x + width, y + height,
1395                               cmap);
1396     }
1397 }
1398
1399
1400 /* Exported functions */
1401
1402 /**
1403  * gdk_pixbuf_get_from_drawable:
1404  * @dest: Destination pixbuf, or %NULL if a new pixbuf should be created.
1405  * @src: Source drawable.
1406  * @cmap: A colormap if @src doesn't have one set.
1407  * @src_x: Source X coordinate within drawable.
1408  * @src_y: Source Y coordinate within drawable.
1409  * @dest_x: Destination X coordinate in pixbuf, or 0 if @dest is NULL.
1410  * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
1411  * @width: Width in pixels of region to get.
1412  * @height: Height in pixels of region to get.
1413  *
1414  * Transfers image data from a #GdkDrawable and converts it to an RGB(A)
1415  * representation inside a #GdkPixbuf. In other words, copies
1416  * image data from a server-side drawable to a client-side RGB(A) buffer.
1417  * This allows you to efficiently read individual pixels on the client side.
1418  * 
1419  * If the drawable @src has no colormap (gdk_drawable_get_colormap()
1420  * returns %NULL), then a suitable colormap must be specified.
1421  * Typically a #GdkWindow or a pixmap created by passing a #GdkWindow
1422  * to gdk_pixmap_new() will already have a colormap associated with
1423  * it.  If the drawable has a colormap, the @cmap argument will be
1424  * ignored.  If the drawable is a bitmap (1 bit per pixel pixmap),
1425  * then a colormap is not required; pixels with a value of 1 are
1426  * assumed to be white, and pixels with a value of 0 are assumed to be
1427  * black. For taking screenshots, gdk_colormap_get_system() returns
1428  * the correct colormap to use.
1429  *
1430  * If the specified destination pixbuf @dest is %NULL, then this
1431  * function will create an RGB pixbuf with 8 bits per channel and no
1432  * alpha, with the same size specified by the @width and @height
1433  * arguments.  In this case, the @dest_x and @dest_y arguments must be
1434  * specified as 0.  If the specified destination pixbuf is not %NULL
1435  * and it contains alpha information, then the filled pixels will be
1436  * set to full opacity (alpha = 255).
1437  *
1438  * If the specified drawable is a pixmap, then the requested source
1439  * rectangle must be completely contained within the pixmap, otherwise
1440  * the function will return %NULL. For pixmaps only (not for windows)
1441  * passing -1 for width or height is allowed to mean the full width
1442  * or height of the pixmap.
1443  *
1444  * If the specified drawable is a window, and the window is off the
1445  * screen, then there is no image data in the obscured/offscreen
1446  * regions to be placed in the pixbuf. The contents of portions of the
1447  * pixbuf corresponding to the offscreen region are undefined.
1448  *
1449  * If the window you're obtaining data from is partially obscured by
1450  * other windows, then the contents of the pixbuf areas corresponding
1451  * to the obscured regions are undefined.
1452  * 
1453  * If the target drawable is not mapped (typically because it's
1454  * iconified/minimized or not on the current workspace), then %NULL
1455  * will be returned.
1456  *
1457  * If memory can't be allocated for the return value, %NULL will be returned
1458  * instead.
1459  *
1460  * (In short, there are several ways this function can fail, and if it fails
1461  *  it returns %NULL; so check the return value.)
1462  *
1463  * This function calls gdk_drawable_get_image() internally and
1464  * converts the resulting image to a #GdkPixbuf, so the
1465  * documentation for gdk_drawable_get_image() may also be relevant.
1466  * 
1467  * Return value: The same pixbuf as @dest if it was non-%NULL, or a newly-created
1468  * pixbuf with a reference count of 1 if no destination pixbuf was specified, or %NULL on error
1469  **/
1470 GdkPixbuf *
1471 gdk_pixbuf_get_from_drawable (GdkPixbuf   *dest,
1472                               GdkDrawable *src,
1473                               GdkColormap *cmap,
1474                               int src_x,  int src_y,
1475                               int dest_x, int dest_y,
1476                               int width,  int height)
1477 {
1478   int src_width, src_height;
1479   GdkImage *image;
1480   int depth;
1481   int x0, y0;
1482   
1483   /* General sanity checks */
1484
1485   g_return_val_if_fail (src != NULL, NULL);
1486
1487   if (GDK_IS_WINDOW (src))
1488     /* FIXME: this is not perfect, since is_viewable() only tests
1489      * recursively up the Gdk parent window tree, but stops at
1490      * foreign windows or Gdk toplevels.  I.e. if a window manager
1491      * unmapped one of its own windows, this won't work.
1492      */
1493     g_return_val_if_fail (gdk_window_is_viewable (src), NULL);
1494
1495   if (!dest)
1496     g_return_val_if_fail (dest_x == 0 && dest_y == 0, NULL);
1497   else
1498     {
1499       g_return_val_if_fail (dest->colorspace == GDK_COLORSPACE_RGB, NULL);
1500       g_return_val_if_fail (dest->n_channels == 3 || dest->n_channels == 4, NULL);
1501       g_return_val_if_fail (dest->bits_per_sample == 8, NULL);
1502     }
1503
1504   /* Create the pixbuf if needed */
1505   if (!dest)
1506     {
1507       dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
1508       if (dest == NULL)
1509         return NULL;
1510     }
1511
1512   if (cmap == NULL)
1513     cmap = gdk_drawable_get_colormap (src);
1514
1515   depth = gdk_drawable_get_depth (src);
1516   
1517   if (depth != 1 && cmap == NULL)
1518     {
1519       g_warning ("%s: Source drawable has no colormap; either pass "
1520                  "in a colormap, or set the colormap on the drawable "
1521                  "with gdk_drawable_set_colormap()", G_STRLOC);
1522       return NULL;
1523     }
1524   
1525   /* Coordinate sanity checks */
1526   
1527   if (GDK_IS_PIXMAP (src))
1528     {
1529       gdk_drawable_get_size (src, &src_width, &src_height);
1530       if (width < 0)
1531         width = src_width;
1532       if (height < 0)
1533         height = src_height;
1534       
1535       g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
1536       g_return_val_if_fail (src_x + width <= src_width && src_y + height <= src_height, NULL);
1537     }
1538
1539   if (dest)
1540     {
1541       g_return_val_if_fail (dest_x >= 0 && dest_y >= 0, NULL);
1542       g_return_val_if_fail (dest_x + width <= dest->width, NULL);
1543       g_return_val_if_fail (dest_y + height <= dest->height, NULL);
1544     }
1545
1546   for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
1547     {
1548       gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
1549       for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
1550         {
1551           gint xs0, ys0;
1552           
1553           gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
1554           
1555           image = _gdk_image_get_scratch (width1, height1, depth, &xs0, &ys0);
1556
1557           _gdk_drawable_copy_to_image (src, image,
1558                                        src_x + x0, src_y + y0,
1559                                        xs0, ys0, width1, height1);
1560
1561           gdk_pixbuf_get_from_image (dest, image, cmap,
1562                                      xs0, ys0, dest_x + x0, dest_y + y0,
1563                                      width1, height1);
1564         }
1565     }
1566   
1567   return dest;
1568 }
1569         
1570 /**
1571  * gdk_pixbuf_get_from_image:
1572  * @dest: Destination pixbuf, or %NULL if a new pixbuf should be created.
1573  * @src: Source #GdkImage.
1574  * @cmap: A colormap, or %NULL to use the one for @src
1575  * @src_x: Source X coordinate within drawable.
1576  * @src_y: Source Y coordinate within drawable.
1577  * @dest_x: Destination X coordinate in pixbuf, or 0 if @dest is NULL.
1578  * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
1579  * @width: Width in pixels of region to get.
1580  * @height: Height in pixels of region to get.
1581  * 
1582  * Same as gdk_pixbuf_get_from_drawable() but gets the pixbuf from
1583  * an image.
1584  * 
1585  * Return value: @dest, newly-created pixbuf if @dest was %NULL, %NULL on error
1586  **/
1587 GdkPixbuf*
1588 gdk_pixbuf_get_from_image (GdkPixbuf   *dest,
1589                            GdkImage    *src,
1590                            GdkColormap *cmap,
1591                            int          src_x,
1592                            int          src_y,
1593                            int          dest_x,
1594                            int          dest_y,
1595                            int          width,
1596                            int          height)
1597 {
1598   int rowstride, bpp, alpha;
1599   
1600   /* General sanity checks */
1601
1602   g_return_val_if_fail (GDK_IS_IMAGE (src), NULL);
1603
1604   if (!dest)
1605     g_return_val_if_fail (dest_x == 0 && dest_y == 0, NULL);
1606   else
1607     {
1608       g_return_val_if_fail (dest->colorspace == GDK_COLORSPACE_RGB, NULL);
1609       g_return_val_if_fail (dest->n_channels == 3 || dest->n_channels == 4, NULL);
1610       g_return_val_if_fail (dest->bits_per_sample == 8, NULL);
1611     }
1612
1613   if (cmap == NULL)
1614     cmap = gdk_image_get_colormap (src);
1615   
1616   if (src->depth != 1 && cmap == NULL)
1617     {
1618       g_warning ("%s: Source image has no colormap; either pass "
1619                  "in a colormap, or set the colormap on the image "
1620                  "with gdk_image_set_colormap()", G_STRLOC);
1621       return NULL;
1622     }
1623   
1624   /* Coordinate sanity checks */
1625
1626   g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
1627   g_return_val_if_fail (src_x + width <= src->width && src_y + height <= src->height, NULL);
1628
1629   if (dest)
1630     {
1631       g_return_val_if_fail (dest_x >= 0 && dest_y >= 0, NULL);
1632       g_return_val_if_fail (dest_x + width <= dest->width, NULL);
1633       g_return_val_if_fail (dest_y + height <= dest->height, NULL);
1634     }
1635
1636   /* Create the pixbuf if needed */
1637   if (!dest)
1638     {
1639       dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
1640       if (dest == NULL)
1641         return NULL;
1642     }
1643
1644   alpha = dest->has_alpha;
1645   rowstride = dest->rowstride;
1646   bpp = alpha ? 4 : 3;
1647
1648   /* we offset into the image data based on the position we are
1649    * retrieving from
1650    */
1651   rgbconvert (src, dest->pixels +
1652               (dest_y * rowstride) + (dest_x * bpp),
1653               rowstride,
1654               alpha,
1655               src_x, src_y,
1656               width,
1657               height,
1658               cmap);
1659   
1660   return dest;
1661 }