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