]> Pileus Git - ~andy/gtk/blob - gdk/gdkpixbuf-drawable.c
470d450de7c4d84c8a9df5a1b7676b0d76d0c7bd
[~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-pixbuf/gdk-pixbuf.h>
29
30 #include "gdkcolor.h"
31 #include "gdkimage.h"
32 #include "gdkvisual.h"
33 #include "gdkwindow.h"
34 #include "gdkpixbuf.h"
35 #include "gdkpixmap.h"
36 #include "gdkinternals.h"
37
38
39 /* Some convenient names
40  */
41 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
42 #define LITTLE
43 #undef BIG
44 #else
45 #define BIG
46 #undef LITTLE
47 #endif
48 #define d(x)
49
50 #define SWAP16(d) GUINT16_SWAP_LE_BE(d)
51
52 \f
53
54 static const guint32 mask_table[] = {
55   0x00000000, 0x00000001, 0x00000003, 0x00000007,
56   0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
57   0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
58   0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
59   0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
60   0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
61   0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
62   0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
63   0xffffffff
64 };
65
66 \f
67
68 /*
69  * convert bitmap data to pixbuf without alpha,
70  * without using a colormap 
71  */
72 static void
73 bitmap1 (GdkImage    *image,
74          guchar      *pixels,
75          int          rowstride,
76          int          x1,
77          int          y1,
78          int          x2,
79          int          y2)
80 {
81   int xx, yy;
82   int bpl;
83   register guint8 data;
84   guint8 *o;
85   guint8 *srow = (guint8*)image->mem + y1 * image->bpl, *orow = pixels;
86
87   d (printf ("bitmap, no alpha\n"));
88
89   bpl = image->bpl;
90
91   for (yy = y1; yy < y2; yy++)
92     {
93       o = orow;
94       
95       for (xx = x1; xx < x2; xx ++)
96         {
97           /* top 29 bits of xx (xx >> 3) indicate the byte the bit is inside,
98            * bottom 3 bits (xx & 7) indicate bit inside that byte,
99            * we don't bother to canonicalize data to 1 or 0, just
100            * leave the relevant bit in-place.
101            */
102           data = srow[xx >> 3] & (image->byte_order == GDK_MSB_FIRST ?
103                                   (0x80 >> (xx & 7)) :
104                                   (1 << (xx & 7)));
105
106           if (data)
107             {
108               *o++ = 255;
109               *o++ = 255;
110               *o++ = 255;
111             }
112           else
113             {
114               *o++ = 0;
115               *o++ = 0;
116               *o++ = 0;
117             }
118         }
119       srow += bpl;
120       orow += rowstride;
121     }
122 }
123
124 /*
125  * convert bitmap data to pixbuf with alpha,
126  * without using a colormap 
127  */
128 static void
129 bitmap1a (GdkImage    *image,
130           guchar      *pixels,
131           int          rowstride,
132           int          x1,
133           int          y1,
134           int          x2,
135           int          y2)
136 {
137   int xx, yy;
138   int bpl;
139   register guint8 data;
140   guint8 *o;
141   guint8 *srow = (guint8*)image->mem + y1 * image->bpl, *orow = pixels;
142
143   d (printf ("bitmap, with alpha\n"));
144
145   bpl = image->bpl;
146
147   for (yy = y1; yy < y2; yy++)
148     {
149       o = orow;
150       
151       for (xx = x1; xx < x2; xx ++)
152         {
153           /* see comment in bitmap1() */
154           data = srow[xx >> 3] & (image->byte_order == GDK_MSB_FIRST ?
155                                   (0x80 >> (xx & 7)) :
156                                   (1 << (xx & 7)));
157
158           if (data)
159             {
160               *o++ = 255;
161               *o++ = 255;
162               *o++ = 255;
163               *o++ = 255;
164             }
165           else
166             {
167               *o++ = 0;
168               *o++ = 0;
169               *o++ = 0;
170               *o++ = 0;
171             }
172         }
173       srow += bpl;
174       orow += rowstride;
175     }
176 }
177
178 /*
179  * convert 1 bits-pixel data
180  * no alpha
181  */
182 static void
183 rgb1 (GdkImage    *image,
184       guchar      *pixels,
185       int          rowstride,
186       int          x1,
187       int          y1,
188       int          x2,
189       int          y2,
190       GdkColormap *colormap)
191 {
192   int xx, yy;
193   int bpl;
194   register guint8 data;
195   guint8 *o;
196   guint8 *srow = (guint8*)image->mem + y1 * image->bpl, *orow = pixels;
197
198   d (printf ("1 bits/pixel\n"));
199
200   /* convert upto 8 pixels/time */
201   /* its probably not worth trying to make this run very fast, who uses
202    * 1 bit displays anymore?
203    */
204   bpl = image->bpl;
205
206   for (yy = y1; yy < y2; yy++)
207     {
208       o = orow;
209       
210       for (xx = x1; xx < x2; xx ++)
211         {
212           /* see comment in bitmap1() */
213           data = srow[xx >> 3] & (image->byte_order == GDK_MSB_FIRST ?
214                                   (0x80 >> (xx & 7)) :
215                                   (1 << (xx & 7)));
216
217           *o++ = colormap->colors[data].red   >> 8;
218           *o++ = colormap->colors[data].green >> 8;
219           *o++ = colormap->colors[data].blue  >> 8;
220         }
221       srow += bpl;
222       orow += rowstride;
223     }
224 }
225
226 /*
227  * convert 1 bits/pixel data
228  * with alpha
229  */
230 static void
231 rgb1a (GdkImage    *image,
232        guchar      *pixels,
233        int          rowstride,
234        int          x1,
235        int          y1,
236        int          x2,
237        int          y2,
238        GdkColormap *colormap)
239 {
240   int xx, yy;
241   int bpl;
242   register guint8 data;
243   guint8 *o;
244   guint8 *srow = (guint8*)image->mem + y1 * image->bpl, *orow = pixels;
245   
246   d (printf ("1 bits/pixel\n"));
247
248   /* convert upto 8 pixels/time */
249   /* its probably not worth trying to make this run very fast, who uses
250    * 1 bit displays anymore? */
251   bpl = image->bpl;
252
253   for (yy = y1; yy < y2; yy++)
254     {
255       o = orow;
256       
257       for (xx = x1; xx < x2; xx ++)
258         {
259           /* see comment in bitmap1() */
260           data = srow[xx >> 3] & (image->byte_order == GDK_MSB_FIRST ?
261                                   (0x80 >> (xx & 7)) :
262                                   (1 << (xx & 7)));
263
264           *o++ = colormap->colors[data].red   >> 8;
265           *o++ = colormap->colors[data].green >> 8;
266           *o++ = colormap->colors[data].blue  >> 8;
267           *o++ = 255;
268         }
269       srow += bpl;
270       orow += rowstride;
271     }
272 }
273
274 /*
275  * convert 8 bits/pixel data
276  * no alpha
277  */
278 static void
279 rgb8 (GdkImage    *image,
280       guchar      *pixels,
281       int          rowstride,
282       int          x1,
283       int          y1,
284       int          x2,
285       int          y2,
286       GdkColormap *colormap)
287 {
288   int xx, yy;
289   int bpl;
290   guint32 mask;
291   register guint32 data;
292   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
293   register guint8 *s;
294   register guint8 *o;
295
296   bpl = image->bpl;
297
298   d (printf ("8 bit, no alpha output\n"));
299
300   mask = mask_table[image->depth];
301
302   for (yy = y1; yy < y2; yy++)
303     {
304       s = srow;
305       o = orow;
306       for (xx = x1; xx < x2; xx++)
307         {
308           data = *s++ & mask;
309           *o++ = colormap->colors[data].red   >> 8;
310           *o++ = colormap->colors[data].green >> 8;
311           *o++ = colormap->colors[data].blue  >> 8;
312         }
313       srow += bpl;
314       orow += rowstride;
315     }
316 }
317
318 /*
319  * convert 8 bits/pixel data
320  * with alpha
321  */
322 static void
323 rgb8a (GdkImage    *image,
324        guchar      *pixels,
325        int          rowstride,
326        int          x1,
327        int          y1,
328        int          x2,
329        int          y2,
330        GdkColormap *colormap)
331 {
332   int xx, yy;
333   int bpl;
334   guint32 mask;
335   register guint32 data;
336   guint32 remap[256];
337   register guint8 *s;   /* read 2 pixels at once */
338   register guint32 *o;
339   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
340
341   bpl = image->bpl;
342
343   d (printf ("8 bit, with alpha output\n"));
344
345   mask = mask_table[image->depth];
346
347   for (xx = x1; xx < colormap->size; xx++)
348     {
349 #ifdef LITTLE
350       remap[xx] = 0xff000000
351         | (colormap->colors[xx].blue  & 0xff00) << 8
352         | (colormap->colors[xx].green & 0xff00)
353         | (colormap->colors[xx].red   >> 8);
354 #else
355       remap[xx] = 0xff
356         | (colormap->colors[xx].red   & 0xff00) << 16
357         | (colormap->colors[xx].green & 0xff00) << 8
358         | (colormap->colors[xx].blue  & 0xff00);
359 #endif
360     }
361
362   for (yy = y1; yy < y2; yy++)
363     {
364       s = srow;
365       o = (guint32 *) orow;
366       for (xx = x1; xx < x2; xx ++)
367         {
368           data = *s++ & mask;
369           *o++ = remap[data];
370         }
371       srow += bpl;
372       orow += rowstride;
373     }
374 }
375
376 /* Bit shifting for 565 and 555 conversion routines
377  *
378  * RGB565 == rrrr rggg gggb bbbb, 16 bit native endian
379  * RGB555 == xrrr rrgg gggb bbbb
380  * ABGR8888: ARGB, 32-bit native endian
381  * RGBA8888: RGBA, 32-bit native endian
382  */
383 #define R8fromRGB565(d) ((((d) >> 8) & 0xf8) | (((d) >> 13) & 0x7))
384 #define G8fromRGB565(d) ((((d) >> 3) & 0xfc) | (((d) >> 9)  & 0x3))
385 #define B8fromRGB565(d) ((((d) << 3) & 0xf8) | (((d) >> 2)  & 0x7))
386
387 #define ABGR8888fromRGB565(d) (  ((d) & 0xf800) >> 8  | ((d) & 0xe000) >> 13 \
388                                | ((d) & 0x07e0) << 5  | ((d) & 0x0600) >> 1  \
389                                | ((d) & 0x001f) << 19 | ((d) & 0x001c) << 14 \
390                                | 0xff000000)
391 #define RGBA8888fromRGB565(d) (  ((d) & 0xf800) << 16 | ((d) & 0xe000) << 11 \
392                                | ((d) & 0x07e0) << 13 | ((d) & 0x0600) << 7  \
393                                | ((d) & 0x001f) << 11 | ((d) & 0x001c) << 6  \
394                                | 0xff)
395
396 #define R8fromRGB555(d) (((d) & 0x7c00) >> 7 | ((d) & 0x7000) >> 12)
397 #define G8fromRGB555(d) (((d) & 0x03e0) >> 2 | ((d) & 0x0380) >> 7)
398 #define B8fromRGB555(d) (((d) & 0x001f) << 3 | ((d) & 0x001c) >> 2)
399
400 #define ABGR8888fromRGB555(d) (  ((d) & 0x7c00) >> 7  | ((d) & 0x7000) >> 12 \
401                                | ((d) & 0x03e0) << 6  | ((d) & 0x0380) << 1  \
402                                | ((d) & 0x001f) << 19 | ((d) & 0x001c) << 14 \
403                                | 0xff000000)
404 #define RGBA8888fromRGB555(d) (  ((d) & 0x7c00) << 17 | ((d) & 0x7000) << 12 \
405                                | ((d) & 0x03e0) << 14 | ((d) & 0x0380) << 9  \
406                                | ((d) & 0x001f) << 11 | ((d) & 0x001c) << 6  \
407                                | 0xff)
408
409 /*
410  * convert 16 bits/pixel data
411  * no alpha
412  * data in lsb format
413  */
414 static void
415 rgb565lsb (GdkImage    *image,
416            guchar      *pixels,
417            int          rowstride,
418            int          x1,
419            int          y1,
420            int          x2,
421            int          y2,
422            GdkColormap *colormap)
423 {
424   int xx, yy;
425   int bpl;
426
427   register guint16 *s;
428   register guint8 *o;
429
430   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
431
432   bpl = image->bpl;
433
434   for (yy = y1; yy < y2; yy++)
435     {
436       s = (guint16 *) srow;
437       o = (guint8 *) orow;
438       for (xx = x1; xx < x2; xx ++)
439         {
440           register guint32 data = *s++;
441 #ifdef BIG
442           data = SWAP16 (data);
443 #endif    
444           *o++ = R8fromRGB565 (data);
445           *o++ = G8fromRGB565 (data);
446           *o++ = B8fromRGB565 (data);
447         }
448       srow += bpl;
449       orow += rowstride;
450     }
451 }
452
453 /*
454  * convert 16 bits/pixel data
455  * no alpha
456  * data in msb format
457  */
458 static void
459 rgb565msb (GdkImage    *image,
460            guchar      *pixels,
461            int          rowstride,
462            int          x1,
463            int          y1,
464            int          x2,
465            int          y2,
466            GdkColormap *colormap)
467 {
468   int xx, yy;
469   int bpl;
470
471   register guint16 *s;
472   register guint8 *o;
473
474   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
475
476   bpl = image->bpl;
477
478   for (yy = y1; yy < y2; yy++)
479     {
480       s = (guint16 *) srow;
481       o = (guint8 *) orow;
482       for (xx = x1; xx < x2; xx ++)
483         {
484           register guint32 data = *s++;
485 #ifdef LITTLE
486           data = SWAP16 (data);
487 #endif    
488           *o++ = R8fromRGB565 (data);
489           *o++ = G8fromRGB565 (data);
490           *o++ = B8fromRGB565 (data);
491         }
492       srow += bpl;
493       orow += rowstride;
494     }
495 }
496
497 /*
498  * convert 16 bits/pixel data
499  * with alpha
500  * data in lsb format
501  */
502 static void
503 rgb565alsb (GdkImage    *image,
504             guchar      *pixels,
505             int          rowstride,
506             int          x1,
507             int          y1,
508             int          x2,
509             int          y2,
510             GdkColormap *colormap)
511 {
512   int xx, yy;
513   int bpl;
514
515   register guint16 *s;
516   register guint32 *o;
517
518   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
519
520   bpl = image->bpl;
521
522   for (yy = y1; yy < y2; yy++)
523     {
524       s = (guint16 *) srow;
525       o = (guint32 *) orow;
526       for (xx = x1; xx < x2; xx ++)
527         {
528           register guint32 data = *s++;
529 #ifdef LITTLE
530           *o++ = ABGR8888fromRGB565 (data);
531 #else
532           data = SWAP16 (data);
533           *o++ = RGBA8888fromRGB565 (data);
534 #endif
535         }
536       srow += bpl;
537       orow += rowstride;
538     }
539 }
540
541 /*
542  * convert 16 bits/pixel data
543  * with alpha
544  * data in msb format
545  */
546 static void
547 rgb565amsb (GdkImage    *image,
548             guchar      *pixels,
549             int          rowstride,
550             int          x1,
551             int          y1,
552             int          x2,
553             int          y2,
554             GdkColormap *colormap)
555 {
556   int xx, yy;
557   int bpl;
558
559   register guint16 *s;
560   register guint32 *o;
561
562   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
563
564   bpl = image->bpl;
565
566   for (yy = y1; yy < y2; yy++)
567     {
568       s = (guint16 *) srow;
569       o = (guint32 *) orow;
570       for (xx = x1; xx < x2; xx ++)
571         {
572           register guint32 data = *s++;
573 #ifdef LITTLE
574           data = SWAP16 (data);
575           *o++ = ABGR8888fromRGB565 (data);
576 #else
577           *o++ = RGBA8888fromRGB565 (data);
578 #endif
579         }
580       srow += bpl;
581       orow += rowstride;
582     }
583 }
584
585 /*
586  * convert 15 bits/pixel data
587  * no alpha
588  * data in lsb format
589  */
590 static void
591 rgb555lsb (GdkImage     *image,
592            guchar       *pixels,
593            int           rowstride,
594            int          x1,
595            int          y1,
596            int          x2,
597            int          y2,
598            GdkColormap  *colormap)
599 {
600   int xx, yy;
601   int bpl;
602
603   register guint16 *s;
604   register guint8 *o;
605
606   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
607
608   bpl = image->bpl;
609
610   for (yy = y1; yy < y2; yy++)
611     {
612       s = (guint16 *) srow;
613       o = (guint8 *) orow;
614       for (xx = x1; xx < x2; xx ++)
615         {
616           register guint32 data = *s++;
617 #ifdef BIG
618           data = SWAP16 (data);
619 #endif    
620           *o++ = R8fromRGB555 (data);
621           *o++ = G8fromRGB555 (data);
622           *o++ = B8fromRGB555 (data);
623         }
624       srow += bpl;
625       orow += rowstride;
626     }
627 }
628
629 /*
630  * convert 15 bits/pixel data
631  * no alpha
632  * data in msb format
633  */
634 static void
635 rgb555msb (GdkImage    *image,
636            guchar      *pixels,
637            int          rowstride,
638            int          x1,
639            int          y1,
640            int          x2,
641            int          y2,
642            GdkColormap *colormap)
643 {
644   int xx, yy;
645   int bpl;
646
647   register guint16 *s;
648   register guint8 *o;
649
650   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
651
652   bpl = image->bpl;
653
654   for (yy = y1; yy < y2; yy++)
655     {
656       s = (guint16 *) srow;
657       o = (guint8 *) orow;
658       for (xx = x1; xx < x2; xx ++)
659         {
660           register guint32 data = *s++;
661 #ifdef LITTLE
662           data = SWAP16 (data);
663 #endif    
664           *o++ = R8fromRGB555 (data);
665           *o++ = G8fromRGB555 (data);
666           *o++ = B8fromRGB555 (data);
667         }
668       srow += bpl;
669       orow += rowstride;
670     }
671 }
672
673 /*
674  * convert 15 bits/pixel data
675  * with alpha
676  * data in lsb format
677  */
678 static void
679 rgb555alsb (GdkImage    *image,
680             guchar      *pixels,
681             int          rowstride,
682             int          x1,
683             int          y1,
684             int          x2,
685             int          y2,
686             GdkColormap *colormap)
687 {
688   int xx, yy;
689   int bpl;
690
691   register guint16 *s;  /* read 1 pixels at once */
692   register guint32 *o;
693
694   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
695
696   bpl = image->bpl;
697
698   for (yy = y1; yy < y2; yy++)
699     {
700       s = (guint16 *) srow;
701       o = (guint32 *) orow;
702       for (xx = x1; xx < x2; xx++)
703         {
704           register guint32 data = *s++;
705 #ifdef LITTLE
706           *o++ = ABGR8888fromRGB555 (data);
707 #else
708           data = SWAP16 (data);
709           *o++ = RGBA8888fromRGB555 (data);
710 #endif
711         }
712       srow += bpl;
713       orow += rowstride;
714     }
715 }
716
717 /*
718  * convert 15 bits/pixel data
719  * with alpha
720  * data in msb format
721  */
722 static void
723 rgb555amsb (GdkImage    *image,
724             guchar      *pixels,
725             int          rowstride,
726             int          x1,
727             int          y1,
728             int          x2,
729             int          y2,
730             GdkColormap *colormap)
731 {
732   int xx, yy;
733   int bpl;
734
735   register guint16 *s;
736   register guint32 *o;
737
738   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
739
740   bpl = image->bpl;
741
742   for (yy = y1; yy < y2; yy++)
743     {
744       s = (guint16 *) srow;
745       o = (guint32 *) orow;
746       for (xx = x1; xx < x2; xx++)
747         {
748           register guint32 data = *s++;
749 #ifdef LITTLE
750           data = SWAP16 (data);
751           *o++ = ABGR8888fromRGB555 (data);
752 #else
753           *o++ = RGBA8888fromRGB555 (data);
754 #endif
755         }
756       srow += bpl;
757       orow += rowstride;
758     }
759 }
760
761
762 static void
763 rgb888alsb (GdkImage    *image,
764             guchar      *pixels,
765             int          rowstride,
766             int          x1,
767             int          y1,
768             int          x2,
769             int          y2,
770             GdkColormap *colormap)
771 {
772   int xx, yy;
773   int bpl;
774
775   guint8 *s;    /* for byte order swapping */
776   guint8 *o;
777   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
778
779   bpl = image->bpl;
780
781   d (printf ("32 bits/pixel with alpha\n"));
782
783   /* lsb data */
784   for (yy = y1; yy < y2; yy++)
785     {
786       s = srow;
787       o = orow;
788       for (xx = x1; xx < x2; xx++)
789         {
790           *o++ = s[2];
791           *o++ = s[1];
792           *o++ = s[0];
793           *o++ = 0xff;
794           s += 4;
795         }
796       srow += bpl;
797       orow += rowstride;
798     }
799 }
800
801 static void
802 rgb888lsb (GdkImage    *image,
803            guchar      *pixels,
804            int          rowstride,
805            int          x1,
806            int          y1,
807            int          x2,
808            int          y2,
809            GdkColormap *colormap)
810 {
811   int xx, yy;
812   int bpl;
813
814   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
815   guint8 *o, *s;
816
817   bpl = image->bpl;
818
819   d (printf ("32 bit, lsb, no alpha\n"));
820
821   for (yy = y1; yy < y2; yy++)
822     {
823       s = srow;
824       o = orow;
825       for (xx = x1; xx < x2; xx++)
826         {
827           *o++ = s[2];
828           *o++ = s[1];
829           *o++ = s[0];
830           s += 4;
831         }
832       srow += bpl;
833       orow += rowstride;
834     }
835 }
836
837 static void
838 rgb888amsb (GdkImage    *image,
839             guchar      *pixels,
840             int          rowstride,
841             int          x1,
842             int          y1,
843             int          x2,
844             int          y2,
845             GdkColormap *colormap)
846 {
847   int xx, yy;
848   int bpl;
849
850   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
851   guint32 *o;
852   guint32 *s;
853
854   d (printf ("32 bit, msb, with alpha\n"));
855
856   bpl = image->bpl;
857
858   /* msb data */
859   for (yy = y1; yy < y2; yy++)
860     {
861       s = (guint32 *) srow;
862       o = (guint32 *) orow;
863       for (xx = x1; xx < x2; xx++)
864         {
865 #ifdef LITTLE
866           *o++ = (*s++ >> 8) | 0xff000000;
867 #else
868           *o++ = (*s++ << 8) | 0xff;
869 #endif
870         }
871       srow += bpl;
872       orow += rowstride;
873     }
874 }
875
876 static void
877 rgb888msb (GdkImage    *image,
878            guchar      *pixels,
879            int          rowstride,
880            int          x1,
881            int          y1,
882            int          x2,
883            int          y2,
884            GdkColormap *colormap)
885 {
886   int xx, yy;
887   int bpl;
888
889   guint8 *srow = (guint8*)image->mem + y1 * image->bpl + x1 * image->bpp, *orow = pixels;
890   guint8 *s;
891   guint8 *o;
892
893   d (printf ("32 bit, msb, no alpha\n"));
894
895   bpl = image->bpl;
896
897   for (yy = y1; yy < y2; yy++)
898     {
899       s = srow;
900       o = orow;
901       for (xx = x1; xx < x2; xx++)
902         {
903           *o++ = s[1];
904           *o++ = s[2];
905           *o++ = s[3];
906           s += 4;
907         }
908       srow += bpl;
909       orow += rowstride;
910     }
911 }
912
913 /*
914  * This should work correctly with any display/any endianness, but will probably
915  * run quite slow
916  */
917 static void
918 convert_real_slow (GdkImage    *image,
919                    guchar      *pixels,
920                    int          rowstride,
921                    int          x1,
922                    int          y1,
923                    int          x2,
924                    int          y2,
925                    GdkColormap *cmap,
926                    gboolean     alpha)
927 {
928   int xx, yy;
929   guint8 *orow = pixels;
930   guint8 *o;
931   guint32 pixel;
932   GdkVisual *v;
933   guint8 component;
934   int i;
935
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 const 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: (allow-none): 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 (gdk_pixbuf_get_colorspace (dest) == GDK_COLORSPACE_RGB, NULL);
1235       g_return_val_if_fail (gdk_pixbuf_get_n_channels (dest) == 3 ||
1236                             gdk_pixbuf_get_n_channels (dest) == 4, NULL);
1237       g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (dest) == 8, NULL);
1238     }
1239
1240   if (cmap == NULL)
1241     cmap = gdk_drawable_get_colormap (src);
1242
1243   depth = gdk_drawable_get_depth (src);
1244   
1245   if (depth != 1 && cmap == NULL)
1246     {
1247       g_warning ("%s: Source drawable has no colormap; either pass "
1248                  "in a colormap, or set the colormap on the drawable "
1249                  "with gdk_drawable_set_colormap()", G_STRLOC);
1250       return NULL;
1251     }
1252   
1253   if (cmap != NULL && depth != cmap->visual->depth)
1254     {
1255       g_warning ("%s: Depth of the source drawable is %d where as "
1256                  "the visual depth of the colormap passed is %d",
1257                  G_STRLOC, depth, cmap->visual->depth);
1258       return NULL;
1259     } 
1260  
1261   /* Coordinate sanity checks */
1262   
1263   if (GDK_IS_PIXMAP (src))
1264     {
1265       gdk_drawable_get_size (src, &src_width, &src_height);
1266       if (width < 0)
1267         width = src_width;
1268       if (height < 0)
1269         height = src_height;
1270       
1271       g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
1272       g_return_val_if_fail (src_x + width <= src_width && src_y + height <= src_height, NULL);
1273     }
1274
1275   /* Create the pixbuf if needed */
1276   if (!dest)
1277     {
1278       dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
1279       if (dest == NULL)
1280         return NULL;
1281     }
1282   
1283   if (dest)
1284     {
1285       g_return_val_if_fail (dest_x >= 0 && dest_y >= 0, NULL);
1286       g_return_val_if_fail (dest_x + width <= gdk_pixbuf_get_width (dest), NULL);
1287       g_return_val_if_fail (dest_y + height <= gdk_pixbuf_get_height (dest), NULL);
1288     }
1289
1290   for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
1291     {
1292       gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
1293       for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
1294         {
1295           gint xs0, ys0;
1296           
1297           gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
1298           
1299           image = _gdk_image_get_scratch (gdk_drawable_get_screen (src), 
1300                                           width1, height1, depth, &xs0, &ys0);
1301
1302           gdk_drawable_copy_to_image (src, image,
1303                                       src_x + x0, src_y + y0,
1304                                        xs0, ys0, width1, height1);
1305
1306           gdk_pixbuf_get_from_image (dest, image, cmap,
1307                                      xs0, ys0, dest_x + x0, dest_y + y0,
1308                                      width1, height1);
1309         }
1310     }
1311   
1312   return dest;
1313 }
1314         
1315 /**
1316  * gdk_pixbuf_get_from_image:
1317  * @dest: (allow-none): Destination pixbuf, or %NULL if a new pixbuf should be created.
1318  * @src: Source #GdkImage.
1319  * @cmap: (allow-none): A colormap, or %NULL to use the one for @src
1320  * @src_x: Source X coordinate within drawable.
1321  * @src_y: Source Y coordinate within drawable.
1322  * @dest_x: Destination X coordinate in pixbuf, or 0 if @dest is NULL.
1323  * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
1324  * @width: Width in pixels of region to get.
1325  * @height: Height in pixels of region to get.
1326  * 
1327  * Same as gdk_pixbuf_get_from_drawable() but gets the pixbuf from
1328  * an image.
1329  * 
1330  * Return value: @dest, newly-created pixbuf if @dest was %NULL, %NULL on error
1331  **/
1332 GdkPixbuf*
1333 gdk_pixbuf_get_from_image (GdkPixbuf   *dest,
1334                            GdkImage    *src,
1335                            GdkColormap *cmap,
1336                            int          src_x,
1337                            int          src_y,
1338                            int          dest_x,
1339                            int          dest_y,
1340                            int          width,
1341                            int          height)
1342 {
1343   int rowstride, bpp, alpha;
1344   
1345   /* General sanity checks */
1346
1347   g_return_val_if_fail (GDK_IS_IMAGE (src), NULL);
1348
1349   if (!dest)
1350     g_return_val_if_fail (dest_x == 0 && dest_y == 0, NULL);
1351   else
1352     {
1353       g_return_val_if_fail (gdk_pixbuf_get_colorspace (dest) == GDK_COLORSPACE_RGB, NULL);
1354       g_return_val_if_fail (gdk_pixbuf_get_n_channels (dest) == 3 ||
1355                             gdk_pixbuf_get_n_channels (dest) == 4, NULL);
1356       g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (dest) == 8, NULL);
1357     }
1358
1359   if (cmap == NULL)
1360     cmap = gdk_image_get_colormap (src);
1361   
1362   if (src->depth != 1 && cmap == NULL)
1363     {
1364       g_warning ("%s: Source image has no colormap; either pass "
1365                  "in a colormap, or set the colormap on the image "
1366                  "with gdk_image_set_colormap()", G_STRLOC);
1367       return NULL;
1368     }
1369   
1370   if (cmap != NULL && src->depth != cmap->visual->depth)
1371     {
1372       g_warning ("%s: Depth of the Source image is %d where as "
1373                  "the visual depth of the colormap passed is %d",
1374                  G_STRLOC, src->depth, cmap->visual->depth);
1375       return NULL;
1376     } 
1377  
1378   /* Coordinate sanity checks */
1379
1380   g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
1381   g_return_val_if_fail (src_x + width <= src->width && src_y + height <= src->height, NULL);
1382
1383   if (dest)
1384     {
1385       g_return_val_if_fail (dest_x >= 0 && dest_y >= 0, NULL);
1386       g_return_val_if_fail (dest_x + width <= gdk_pixbuf_get_width (dest), NULL);
1387       g_return_val_if_fail (dest_y + height <= gdk_pixbuf_get_height (dest), NULL);
1388     }
1389
1390   /* Create the pixbuf if needed */
1391   if (!dest)
1392     {
1393       dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
1394       if (dest == NULL)
1395         return NULL;
1396     }
1397
1398   alpha = gdk_pixbuf_get_has_alpha (dest);
1399   rowstride = gdk_pixbuf_get_rowstride (dest);
1400   bpp = alpha ? 4 : 3;
1401
1402   /* we offset into the image data based on the position we are
1403    * retrieving from
1404    */
1405   rgbconvert (src, gdk_pixbuf_get_pixels (dest) +
1406               (dest_y * rowstride) + (dest_x * bpp),
1407               rowstride,
1408               alpha,
1409               src_x, src_y,
1410               width,
1411               height,
1412               cmap);
1413   
1414   return dest;
1415 }