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