]> Pileus Git - ~andy/gtk/blob - gdk/gdkpixbuf-drawable.c
s/unsigned long/guint32/g, s/unsigned short/guint16/g, s/unsigned
[~andy/gtk] / gdk / gdkpixbuf-drawable.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* GdkPixbuf library - convert X drawable information to RGB
3  *
4  * Copyright (C) 1999 Michael Zucchi
5  *
6  * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
7  *          Cody Russell <bratsche@dfw.net>
8  *          Federico Mena-Quintero <federico@gimp.org>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25
26 #include <config.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include "gdk-pixbuf.h"
30
31 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
32 #define LITTLE
33 #endif
34 #define d(x)
35
36 \f
37
38 static guint32 mask_table[] = {
39         0x00000000, 0x00000001, 0x00000003, 0x00000007,
40         0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
41         0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
42         0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
43         0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
44         0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
45         0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
46         0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
47         0xffffffff
48 };
49
50 \f
51
52 /*
53   convert 1 bits-pixel data
54   no alpha
55 */
56 static void
57 rgb1 (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
58 {
59         int xx, yy;
60         int width, height;
61         int bpl;
62         guint8 *s;
63         register guint8 data;
64         guint8 *o;
65         guint8 *srow = image->mem, *orow = pixels;
66
67         d (printf ("1 bits/pixel\n"));
68
69         /* convert upto 8 pixels/time */
70         /* its probably not worth trying to make this run very fast, who uses
71            1 bit displays anymore? */
72         width = image->width;
73         height = image->height;
74         bpl = image->bpl;
75
76         for (yy = 0; yy < height; yy++) {
77                 s = srow;
78                 o = orow;
79
80                 for (xx = 0; xx < width; xx ++) {
81                         data = srow[xx >> 3] >> (7 - (xx & 7)) & 1;
82                         *o++ = colormap->colors[data].red;
83                         *o++ = colormap->colors[data].green;
84                         *o++ = colormap->colors[data].blue;
85                 }
86                 srow += bpl;
87                 orow += rowstride;
88         }
89 }
90
91 /*
92   convert 1 bits/pixel data
93   with alpha
94 */
95 static void
96 rgb1a (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
97 {
98         int xx, yy;
99         int width, height;
100         int bpl;
101         guint8 *s;
102         register guint8 data;
103         guint8 *o;
104         guint8 *srow = image->mem, *orow = pixels;
105         guint32 remap[2];
106
107         d (printf ("1 bits/pixel\n"));
108
109         /* convert upto 8 pixels/time */
110         /* its probably not worth trying to make this run very fast, who uses
111            1 bit displays anymore? */
112         width = image->width;
113         height = image->height;
114         bpl = image->bpl;
115
116         for (xx = 0; xx < 2; xx++) {
117 #ifdef LITTLE
118                 remap[xx] = 0xff000000
119                         | colormap->colors[xx].blue << 16
120                         | colormap->colors[xx].green << 8
121                         | colormap->colors[xx].red;
122 #else
123                 remap[xx] = 0xff
124                         | colormap->colors[xx].red << 24
125                         | colormap->colors[xx].green << 16
126                         | colormap->colors[xx].blue << 8;
127 #endif
128         }
129
130         for (yy = 0; yy < height; yy++) {
131                 s = srow;
132                 o = orow;
133
134                 for (xx = 0; xx < width; xx ++) {
135                         data = srow[xx >> 3] >> (7 - (xx & 7)) & 1;
136                         *o++ = remap[data];
137                 }
138                 srow += bpl;
139                 orow += rowstride;
140         }
141 }
142
143 /*
144   convert 8 bits/pixel data
145   no alpha
146 */
147 static void
148 rgb8 (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
149 {
150         int xx, yy;
151         int width, height;
152         int bpl;
153         guint32 mask;
154         register guint32 data;
155         guint8 *srow = image->mem, *orow = pixels;
156         register guint8 *s;
157         register guint8 *o;
158
159         width = image->width;
160         height = image->height;
161         bpl = image->bpl;
162
163         d (printf ("8 bit, no alpha output\n"));
164
165         mask = mask_table[image->depth];
166
167         for (yy = 0; yy < height; yy++) {
168                 s = srow;
169                 o = orow;
170                 for (xx = 0; xx < width; xx++) {
171                         data = *s++ & mask;
172                         *o++ = colormap->colors[data].red;
173                         *o++ = colormap->colors[data].green;
174                         *o++ = colormap->colors[data].blue;
175                 }
176                 srow += bpl;
177                 orow += rowstride;
178         }
179 }
180
181 /*
182   convert 8 bits/pixel data
183   with alpha
184 */
185 static void
186 rgb8a (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
187 {
188         int xx, yy;
189         int width, height;
190         int bpl;
191         guint32 mask;
192         register guint32 data;
193         guint32 remap[256];
194         register guint8 *s;     /* read 2 pixels at once */
195         register guint32 *o;
196         guint8 *srow = image->mem, *orow = pixels;
197
198         width = image->width;
199         height = image->height;
200         bpl = image->bpl;
201
202         d (printf ("8 bit, with alpha output\n"));
203
204         mask = mask_table[image->depth];
205
206         for (xx = 0; xx < colormap->size; xx++) {
207 #ifdef LITTLE
208                 remap[xx] = 0xff000000
209                         | colormap->colors[xx].blue << 16
210                         | colormap->colors[xx].green << 8
211                         | colormap->colors[xx].red;
212 #else
213                 remap[xx] = 0xff
214                         | colormap->colors[xx].red << 24
215                         | colormap->colors[xx].green << 16
216                         | colormap->colors[xx].blue << 8;
217 #endif
218         }
219
220         for (yy = 0; yy < height; yy++) {
221                 s = srow;
222                 o = (guint32 *) orow;
223                 for (xx = 0; xx < width; xx ++) {
224                         data = *s++ & mask;
225                         *o++ = remap[data];
226                 }
227                 srow += bpl;
228                 orow += rowstride;
229         }
230 }
231
232 /*
233   convert 16 bits/pixel data
234   no alpha
235   data in lsb format
236 */
237 static void
238 rgb565lsb (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
239 {
240         int xx, yy;
241         int width, height;
242         int bpl;
243
244 #ifdef LITTLE
245         register guint32 *s;    /* read 2 pixels at once */
246 #else
247         register guint8 *s;     /* read 2 pixels at once */
248 #endif
249         register guint16 *o;
250         guint8 *srow = image->mem, *orow = pixels;
251
252         width = image->width;
253         height = image->height;
254         bpl = image->bpl;
255
256         for (yy = 0; yy < height; yy++) {
257 #ifdef LITTLE
258                 s = (guint32 *) srow;
259 #else
260                 s = (guint32 *) srow;
261 #endif
262                 o = (guint16 *) orow;
263                 for (xx = 1; xx < width; xx += 2) {
264                         register guint32 data;
265 #ifdef LITTLE
266                         data = *s++;
267                         *o++ = (data & 0xf800) >> 8 | (data & 0x7e0) << 5;
268                         *o++ = (data & 0x1f) << 3 | (data & 0xf8000000) >> 16;
269                         *o++ = ((data & 0x7e00000) >> 19) | (data & 0x1f0000) >> 5;
270 #else
271                         /* swap endianness first */
272                         data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
273                         s += 4;
274                         *o++ = (data & 0xf800) | (data & 0x7e0) >> 3;
275                         *o++ = (data & 0x1f) << 11 | (data & 0xf8000000) >> 24;
276                         *o++ = ((data & 0x7e00000) >> 11) | (data & 0x1f0000) >> 13;
277 #endif
278                 }
279                 /* check for last remaining pixel */
280                 if (width & 1) {
281                         register guint16 data;
282 #ifdef LITTLE
283                         data = *((short *) s);
284 #else
285                         data = *((short *) s);
286                         data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
287 #endif
288                         ((char *) o)[0] = (data >> 8) & 0xf8;
289                         ((char *) o)[1] = (data >> 3) & 0xfc;
290                         ((char *) o)[2] = (data << 3) & 0xf8;
291                 }
292                 srow += bpl;
293                 orow += rowstride;
294         }
295 }
296
297 /*
298   convert 16 bits/pixel data
299   no alpha
300   data in msb format
301 */
302 static void
303 rgb565msb (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
304 {
305         int xx, yy;
306         int width, height;
307         int bpl;
308
309 #ifdef LITTLE
310         register guint8 *s;     /* need to swap data order */
311 #else
312         register guint32 *s;    /* read 2 pixels at once */
313 #endif
314         register guint16 *o;
315         guint8 *srow = image->mem, *orow = pixels;
316
317         width = image->width;
318         height = image->height;
319         bpl = image->bpl;
320
321         for (yy = 0; yy < height; yy++) {
322 #ifdef LITTLE
323                 s = srow;
324 #else
325                 s = (guint32 *) srow;
326 #endif
327                 o = (guint16 *) orow;
328                 for (xx = 1; xx < width; xx += 2) {
329                         register guint32 data;
330 #ifdef LITTLE
331                         /* swap endianness first */
332                         data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
333                         s += 4;
334                         *o++ = (data & 0xf800) >> 8 | (data & 0x7e0) << 5;
335                         *o++ = (data & 0x1f) << 3 | (data & 0xf8000000) >> 16;
336                         *o++ = ((data & 0x7e00000) >> 19) | (data & 0x1f0000) >> 5;
337 #else
338                         data = *s++;
339                         *o++ = (data & 0xf800) | (data & 0x7e0) >> 3;
340                         *o++ = (data & 0x1f) << 11 | (data & 0xf8000000) >> 24;
341                         *o++ = ((data & 0x7e00000) >> 11) | (data & 0x1f0000) >> 13;
342 #endif
343                 }
344                 /* check for last remaining pixel */
345                 if (width & 1) {
346                         register guint16 data;
347 #ifdef LITTLE
348                         data = *((short *) s);
349                         data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
350 #else
351                         data = *((short *) s);
352 #endif
353                         ((char *) o)[0] = (data >> 8) & 0xf8;
354                         ((char *) o)[1] = (data >> 3) & 0xfc;
355                         ((char *) o)[2] = (data << 3) & 0xf8;
356                 }
357                 srow += bpl;
358                 orow += rowstride;
359         }
360 }
361
362 /*
363   convert 16 bits/pixel data
364   with alpha
365   data in lsb format
366 */
367 static void
368 rgb565alsb (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
369 {
370         int xx, yy;
371         int width, height;
372         int bpl;
373
374 #ifdef LITTLE
375         register guint16 *s;    /* read 1 pixels at once */
376 #else
377         register guint8 *s;
378 #endif
379         register guint32 *o;
380
381         guint8 *srow = image->mem, *orow = pixels;
382
383         width = image->width;
384         height = image->height;
385         bpl = image->bpl;
386
387         for (yy = 0; yy < height; yy++) {
388 #ifdef LITTLE
389                 s = (guint16 *) srow;
390 #else
391                 s = (guint8 *) srow;
392 #endif
393                 o = (guint32 *) orow;
394                 for (xx = 0; xx < width; xx ++) {
395                         register guint32 data;
396                         /*  rrrrrggg gggbbbbb -> rrrrr000 gggggg00 bbbbb000 aaaaaaaa */
397                         /*  little endian: aaaaaaaa bbbbb000 gggggg00 rrrrr000 */
398 #ifdef LITTLE
399                         data = *s++;
400                         *o++ = (data & 0xf800) >> 8 | (data & 0x7e0) << 5
401                                 | (data & 0x1f) << 19 | 0xff000000;
402 #else
403                         /* swap endianness first */
404                         data = s[0] | s[1] << 8;
405                         s += 2;
406                         *o++ = (data & 0xf800) << 16 | (data & 0x7e0) << 13
407                                 | (data & 0x1f) <<  11 | 0xff;
408 #endif
409                 }
410                 srow += bpl;
411                 orow += rowstride;
412         }
413 }
414
415 /*
416   convert 16 bits/pixel data
417   with alpha
418   data in msb format
419 */
420 static void
421 rgb565amsb (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
422 {
423         int xx, yy;
424         int width, height;
425         int bpl;
426
427 #ifdef LITTLE
428         register guint8 *s;
429 #else
430         register guint16 *s;    /* read 1 pixels at once */
431 #endif
432         register guint32 *o;
433
434         guint8 *srow = image->mem, *orow = pixels;
435
436         width = image->width;
437         height = image->height;
438         bpl = image->bpl;
439
440         for (yy = 0; yy < height; yy++) {
441                 s = srow;
442                 o = (guint32 *) orow;
443                 for (xx = 0; xx < width; xx ++) {
444                         register guint32 data;
445                         /*  rrrrrggg gggbbbbb -> rrrrr000 gggggg00 bbbbb000 aaaaaaaa */
446                         /*  little endian: aaaaaaaa bbbbb000 gggggg00 rrrrr000 */
447 #ifdef LITTLE
448                         /* swap endianness first */
449                         data = s[0] | s[1] << 8;
450                         s += 2;
451                         *o++ = (data & 0xf800) >> 8 | (data & 0x7e0) << 5
452                                 | (data & 0x1f) << 19 | 0xff000000;
453 #else
454                         data = *s++;
455                         *o++ = (data & 0xf800) << 16 | (data & 0x7e0) << 13
456                                 | (data & 0x1f) <<  11 | 0xff;
457 #endif
458                 }
459                 srow += bpl;
460                 orow += rowstride;
461         }
462 }
463
464 /*
465   convert 15 bits/pixel data
466   no alpha
467   data in lsb format
468 */
469 static void
470 rgb555lsb (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
471 {
472         int xx, yy;
473         int width, height;
474         int bpl;
475
476 #ifdef LITTLE
477         register guint32 *s;    /* read 2 pixels at once */
478 #else
479         register guint8 *s;     /* read 2 pixels at once */
480 #endif
481         register guint16 *o;
482         guint8 *srow = image->mem, *orow = pixels;
483
484         width = image->width;
485         height = image->height;
486         bpl = image->bpl;
487
488         for (yy = 0; yy < height; yy++) {
489 #ifdef LITTLE
490                 s = (guint32 *) srow;
491 #else
492                 s = srow;
493 #endif
494                 o = (guint16 *) orow;
495                 for (xx = 1; xx < width; xx += 2) {
496                         register guint32 data;
497 #ifdef LITTLE
498                         data = *s++;
499                         *o++ = (data & 0x7c00) >> 7 | (data & 0x3e0) << 6;
500                         *o++ = (data & 0x1f) << 3 | (data & 0x7c000000) >> 15;
501                         *o++ = ((data & 0x3e00000) >> 18) | (data & 0x1f0000) >> 5;
502 #else
503                         /* swap endianness first */
504                         data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
505                         s += 4;
506                         *o++ = (data & 0x7c00) << 1 | (data & 0x3e0) >> 2;
507                         *o++ = (data & 0x1f) << 11 | (data & 0x7c000000) >> 23;
508                         *o++ = ((data & 0x3e00000) >> 10) | (data & 0x1f0000) >> 13;
509 #endif
510                 }
511                 /* check for last remaining pixel */
512                 if (width & 1) {
513                         register guint16 data;
514 #ifdef LITTLE
515                         data = *((short *) s);
516 #else
517                         data = *((short *) s);
518                         data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
519 #endif
520                         ((char *) o)[0] = (data & 0x7c0) >> 7;
521                         ((char *) o)[1] = (data & 0x3e0) >> 2;
522                         ((char *) o)[2] = (data & 0x1f) << 3;
523                 }
524                 srow += bpl;
525                 orow += rowstride;
526         }
527 }
528
529 /*
530   convert 15 bits/pixel data
531   no alpha
532   data in msb format
533 */
534 static void
535 rgb555msb (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
536 {
537         int xx, yy;
538         int width, height;
539         int bpl;
540
541 #ifdef LITTLE
542         register guint8 *s;     /* read 2 pixels at once */
543 #else
544         register guint32 *s;    /* read 2 pixels at once */
545 #endif
546         register guint16 *o;
547         guint8 *srow = image->mem, *orow = pixels;
548
549         width = image->width;
550         height = image->height;
551         bpl = image->bpl;
552
553         for (yy = 0; yy < height; yy++) {
554                 s = srow;
555                 o = (guint16 *) orow;
556                 for (xx = 1; xx < width; xx += 2) {
557                         register guint32 data;
558 #ifdef LITTLE
559                         /* swap endianness first */
560                         data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
561                         s += 4;
562                         *o++ = (data & 0x7c00) >> 7 | (data & 0x3e0) << 6;
563                         *o++ = (data & 0x1f) << 3 | (data & 0x7c000000) >> 15;
564                         *o++ = ((data & 0x3e00000) >> 18) | (data & 0x1f0000) >> 5;
565 #else
566                         data = *s++;
567                         *o++ = (data & 0x7c00) << 1 | (data & 0x3e0) >> 2;
568                         *o++ = (data & 0x1f) << 11 | (data & 0x7c000000) >> 23;
569                         *o++ = ((data & 0x3e00000) >> 10) | (data & 0x1f0000) >> 13;
570 #endif
571                 }
572                 /* check for last remaining pixel */
573                 if (width & 1) {
574                         register guint16 data;
575 #ifdef LITTLE
576                         data = *((short *) s);
577                         data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
578 #else
579                         data = *((short *) s);
580 #endif
581                         ((char *) o)[0] = (data & 0x7c0) >> 7;
582                         ((char *) o)[1] = (data & 0x3e0) >> 2;
583                         ((char *) o)[2] = (data & 0x1f) << 3;
584                 }
585                 srow += bpl;
586                 orow += rowstride;
587         }
588 }
589
590 /*
591   convert 15 bits/pixel data
592   with alpha
593   data in lsb format
594 */
595 static void
596 rgb555alsb (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
597 {
598         int xx, yy;
599         int width, height;
600         int bpl;
601
602 #ifdef LITTLE
603         register guint16 *s;    /* read 1 pixels at once */
604 #else
605         register guint8 *s;
606 #endif
607         register guint32 *o;
608
609         guint8 *srow = image->mem, *orow = pixels;
610
611         width = image->width;
612         height = image->height;
613         bpl = image->bpl;
614
615         for (yy = 0; yy < height; yy++) {
616 #ifdef LITTLE
617                 s = (guint16 *) srow;
618 #else
619                 s = srow;
620 #endif
621                 o = (guint32 *) orow;
622                 for (xx = 0; xx < width; xx++) {
623                         register guint32 data;
624                         /*  rrrrrggg gggbbbbb -> rrrrr000 gggggg00 bbbbb000 aaaaaaaa */
625                         /*  little endian: aaaaaaaa bbbbb000 gggggg00 rrrrr000 */
626 #ifdef LITTLE
627                         data = *s++;
628                         *o++ = (data & 0x7c00) >> 7 | (data & 0x3e0) << 6
629                                 | (data & 0x1f) << 19 | 0xff000000;
630 #else
631                         /* swap endianness first */
632                         data = s[0] | s[1] << 8;
633                         s += 2;
634                         *o++ = (data & 0x7c00) << 17 | (data & 0x3e0) << 14
635                                 | (data & 0x1f) <<  11 | 0xff;
636 #endif
637                 }
638                 srow += bpl;
639                 orow += rowstride;
640         }
641 }
642
643 /*
644   convert 15 bits/pixel data
645   with alpha
646   data in msb format
647 */
648 static void
649 rgb555amsb (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
650 {
651         int xx, yy;
652         int width, height;
653         int bpl;
654
655 #ifdef LITTLE
656         register guint16 *s;    /* read 1 pixels at once */
657 #else
658         register guint8 *s;
659 #endif
660         register guint32 *o;
661
662         guint8 *srow = image->mem, *orow = pixels;
663
664         width = image->width;
665         height = image->height;
666         bpl = image->bpl;
667
668         for (yy = 0; yy < height; yy++) {
669 #ifdef LITTLE
670                 s = (guint16 *) srow;
671 #else
672                 s = srow;
673 #endif
674                 o = (guint32 *) orow;
675                 for (xx = 0; xx < width; xx++) {
676                         register guint32 data;
677                         /*  rrrrrggg gggbbbbb -> rrrrr000 gggggg00 bbbbb000 aaaaaaaa */
678                         /*  little endian: aaaaaaaa bbbbb000 gggggg00 rrrrr000 */
679 #ifdef LITTLE
680                         /* swap endianness first */
681                         data = s[0] | s[1] << 8;
682                         s += 2;
683                         *o++ = (data & 0x7c00) >>7 | (data & 0x3e0) << 6
684                                 | (data & 0x1f) << 19 | 0xff000000;
685 #else
686                         data = *s++;
687                         *o++ = (data & 0x7c00) << 17 | (data & 0x3e0) << 14
688                                 | (data & 0x1f) <<  11 | 0xff;
689 #endif
690                 }
691                 srow += bpl;
692                 orow += rowstride;
693         }
694 }
695
696
697 static void
698 rgb888alsb (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
699 {
700         int xx, yy;
701         int width, height;
702         int bpl;
703
704         guint8 *s;      /* for byte order swapping */
705         guint8 *o;
706         guint8 *srow = image->mem, *orow = pixels;
707
708         width = image->width;
709         height = image->height;
710         bpl = image->bpl;
711
712         d (printf ("32 bits/pixel with alpha\n"));
713
714         /* lsb data */
715         for (yy = 0; yy < height; yy++) {
716                 s = srow;
717                 o = orow;
718                 for (xx = 0; xx < width; xx++) {
719                         *o++ = s[2];
720                         *o++ = s[1];
721                         *o++ = s[0];
722                         *o++ = 0xff;
723                         s += 4;
724                 }
725                 srow += bpl;
726                 orow += rowstride;
727         }
728 }
729
730 static void
731 rgb888lsb (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
732 {
733         int xx, yy;
734         int width, height;
735         int bpl;
736
737         guint8 *srow = image->mem, *orow = pixels;
738         guint8 *o, *s;
739
740         width = image->width;
741         height = image->height;
742         bpl = image->bpl;
743
744         d (printf ("32 bit, lsb, no alpha\n"));
745
746         for (yy = 0; yy < height; yy++) {
747                 s = srow;
748                 o = orow;
749                 for (xx = 0; xx < width; xx++) {
750                         *o++ = s[2];
751                         *o++ = s[1];
752                         *o++ = s[0];
753                         s += 4;
754                 }
755                 srow += bpl;
756                 orow += rowstride;
757         }
758 }
759
760 static void
761 rgb888amsb (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
762 {
763         int xx, yy;
764         int width, height;
765         int bpl;
766
767         guint8 *srow = image->mem, *orow = pixels;
768 #ifdef LITTLE
769         guint32 *o;
770         guint32 *s;
771 #else
772         guint8 *s;      /* for byte order swapping */
773         guint8 *o;
774 #endif
775
776         d (printf ("32 bit, msb, with alpha\n"));
777
778         width = image->width;
779         height = image->height;
780         bpl = image->bpl;
781
782         /* msb data */
783         for (yy = 0; yy < height; yy++) {
784 #ifdef LITTLE
785                 s = (guint32 *) srow;
786                 o = (guint32 *) orow;
787 #else
788                 s = srow;
789                 o = orow;
790 #endif
791                 for (xx = 0; xx < width; xx++) {
792 #ifdef LITTLE
793                         *o++ = s[1];
794                         *o++ = s[2];
795                         *o++ = s[3];
796                         *o++ = 0xff;
797                         s += 4;
798 #else
799                         *o++ = (*s << 8) | 0xff; /* untested */
800                         s++;
801 #endif
802                 }
803                 srow += bpl;
804                 orow += rowstride;
805         }
806 }
807
808 static void
809 rgb888msb (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *colormap)
810 {
811         int xx, yy;
812         int width, height;
813         int bpl;
814
815         guint8 *srow = image->mem, *orow = pixels;
816         guint8 *s;
817         guint8 *o;
818
819         d (printf ("32 bit, msb, no alpha\n"));
820
821         width = image->width;
822         height = image->height;
823         bpl = image->bpl;
824
825         for (yy = 0; yy < height; yy++) {
826                 s = srow;
827                 o = orow;
828                 for (xx = 0; xx < width; xx++) {
829                         *o++ = s[1];
830                         *o++ = s[2];
831                         *o++ = s[3];
832                         s += 4;
833                 }
834                 srow += bpl;
835                 orow += rowstride;
836         }
837 }
838
839 /*
840   This should work correctly with any display/any endianness, but will probably
841   run quite slow
842 */
843 static void
844 convert_real_slow (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *cmap, int alpha)
845 {
846         int xx, yy;
847         int width, height;
848         int bpl;
849         guint8 *srow = image->mem, *orow = pixels;
850         guint8 *s;
851         guint8 *o;
852         guint32 pixel;
853         GdkVisual *v;
854
855         width = image->width;
856         height = image->height;
857         bpl = image->bpl;
858         v = gdk_colormap_get_visual(cmap);
859
860         d(printf("rgb  mask/shift/prec = %x:%x:%x %d:%d:%d  %d:%d:%d\n",
861                  v->red_mask, v->green_mask, v->blue_mask,
862                  v->red_shift, v->green_shift, v->blue_shift,
863                  v->red_prec, v->green_prec, v->blue_prec));
864
865         for (yy = 0; yy < height; yy++) {
866                 s = srow;
867                 o = orow;
868                 for (xx = 0; xx < width; xx++) {
869                         pixel = gdk_image_get_pixel(image, xx, yy);
870                         switch (v->type) {
871                                 /* I assume this is right for static & greyscale's too? */
872                         case GDK_VISUAL_STATIC_GRAY:
873                         case GDK_VISUAL_GRAYSCALE:
874                         case GDK_VISUAL_STATIC_COLOR:
875                         case GDK_VISUAL_PSEUDO_COLOR:
876                                 *o++ = cmap->colors[pixel].red;
877                                 *o++ = cmap->colors[pixel].green;
878                                 *o++ = cmap->colors[pixel].blue;
879                                 break;
880                         case GDK_VISUAL_TRUE_COLOR:
881                                 /* this is odd because it must sometimes shift left (otherwise
882                                    i'd just shift >> *_shift - 8 + *_prec), so this logic
883                                    should work for all bit sizes/shifts/etc */
884                                 *o++ = ((pixel & v->red_mask) << (32 - v->red_shift - v->red_prec)) >> 24;
885                                 *o++ = ((pixel & v->green_mask) << (32 - v->green_shift - v->green_prec)) >> 24;
886                                 *o++ = ((pixel & v->blue_mask) << (32 - v->blue_shift - v->blue_prec)) >> 24;
887                                 break;
888                         case GDK_VISUAL_DIRECT_COLOR:
889                                 *o++ = cmap->colors[((pixel & v->red_mask) << (32 - v->red_shift - v->red_prec)) >> 24].red;
890                                 *o++ = cmap->colors[((pixel & v->green_mask) << (32 - v->green_shift - v->green_prec)) >> 24].green;
891                                 *o++ = cmap->colors[((pixel & v->blue_mask) << (32 - v->blue_shift - v->blue_prec)) >> 24].blue;
892                                 break;
893                         }
894                         if (alpha)
895                                 *o++ = 0xff;
896                 }
897                 srow += bpl;
898                 orow += rowstride;
899         }
900 }
901
902 typedef void (* cfunc) (GdkImage *image, art_u8 *pixels, int rowstride, GdkColormap *cmap);
903
904 static cfunc convert_map[] = {
905         rgb1,rgb1,rgb1a,rgb1a,
906         rgb8,rgb8,rgb8a,rgb8a,
907         rgb555lsb,rgb555msb,rgb555alsb,rgb555amsb,
908         rgb565lsb,rgb565msb,rgb565alsb,rgb565amsb,
909         rgb888lsb,rgb888msb,rgb888alsb,rgb888amsb
910 };
911
912 /*
913   perform actual conversion
914
915   If we can, try and use the optimised code versions, but as a default
916   fallback, and always for direct colour, use the generic/slow but complete
917   conversion function.
918 */
919 static void
920 rgbconvert (GdkImage *image, art_u8 *pixels, int rowstride, int alpha, GdkColormap *cmap)
921 {
922         int index = (image->byte_order == GDK_MSB_FIRST) | (alpha != 0) << 1;
923         int bank=5;             /* default fallback converter */
924         GdkVisual *v = gdk_colormap_get_visual(cmap);
925
926         d(printf("masks = %x:%x:%x\n", v->red_mask, v->green_mask, v->blue_mask));
927         d(printf("image depth = %d, bpp = %d\n", image->depth, image->bpp));
928
929         switch (v->type) {
930                                 /* I assume this is right for static & greyscale's too? */
931         case GDK_VISUAL_STATIC_GRAY:
932         case GDK_VISUAL_GRAYSCALE:
933         case GDK_VISUAL_STATIC_COLOR:
934         case GDK_VISUAL_PSEUDO_COLOR:
935                 switch (image->bpp) {
936                 case 1:
937                         bank = 0;
938                         break;
939                 case 8:
940                         bank = 1;
941                         break;
942                 }
943                 break;
944         case GDK_VISUAL_TRUE_COLOR:
945                 switch (image->depth) {
946                 case 15:
947                         if (v->red_mask == 0x7c00 && v->green_mask == 0x3e0 && v->blue_mask == 0x1f
948                             && image->bpp == 16)
949                                 bank = 2;
950                         break;
951                 case 16:
952                         if (v->red_mask == 0xf800 && v->green_mask == 0x7e0 && v->blue_mask == 0x1f
953                             && image->bpp == 16)
954                                 bank = 3;
955                         break;
956                 case 24:
957                 case 32:
958                         if (v->red_mask == 0xff0000 && v->green_mask == 0xff00 && v->blue_mask == 0xff
959                             && image->bpp == 32)
960                                 bank = 4;
961                         break;
962                 }
963                 break;
964         case GDK_VISUAL_DIRECT_COLOR:
965                 /* always use the slow version */
966                 break;
967         }
968
969         d(printf("converting using conversion function in bank %d\n", bank));
970
971         if (bank==5) {
972                 convert_real_slow(image, pixels, rowstride, cmap, alpha);
973         } else {
974                 index |= bank << 2;
975                 (* convert_map[index]) (image, pixels, rowstride, cmap);
976         }
977 }
978
979
980 /* Exported functions */
981
982 /**
983  * gdk_pixbuf_get_from_drawable:
984  * @dest: Destination pixbuf, or NULL if a new pixbuf should be created.
985  * @src: Source drawable.
986  * @cmap: A colormap if @src is a pixmap.  If it is a window, this argument will
987  * be ignored.
988  * @src_x: Source X coordinate within drawable.
989  * @src_y: Source Y coordinate within drawable.
990  * @dest_x: Destination X coordinate in pixbuf, or 0 if @dest is NULL.
991  * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
992  * @width: Width in pixels of region to get.
993  * @height: Height in pixels of region to get.
994  *
995  * Transfers image data from a Gdk drawable and converts it to an RGB(A)
996  * representation inside a GdkPixbuf.
997  *
998  * If the drawable @src is a pixmap, then a suitable colormap must be specified,
999  * since pixmaps are just blocks of pixel data without an associated colormap.
1000  * If the drawable is a window, the @cmap argument will be ignored and the
1001  * window's own colormap will be used instead.
1002  *
1003  * If the specified destination pixbuf @dest is #NULL, then this function will
1004  * create an RGB pixbuf with 8 bits per channel and no alpha, with the same size
1005  * specified by the @width and @height arguments.  In this case, the @dest_x and
1006  * @dest_y arguments must be specified as 0, otherwise the function will return
1007  * #NULL.  If the specified destination pixbuf is not NULL and it contains alpha
1008  * information, then the filled pixels will be set to full opacity.
1009  *
1010  * If the specified drawable is a pixmap, then the requested source rectangle
1011  * must be completely contained within the pixmap, otherwise the function will
1012  * return #NULL.
1013  *
1014  * If the specified drawable is a window, then it must be viewable, i.e. all of
1015  * its ancestors up to the root window must be mapped.  Also, the specified
1016  * source rectangle must be completely contained within the window and within
1017  * the screen.  If regions of the window are obscured by noninferior windows, the
1018  * contents of those regions are undefined.  The contents of regions obscured by
1019  * inferior windows of a different depth than that of the source window will also
1020  * be undefined.
1021  *
1022  * Return value: The same pixbuf as @dest if it was non-NULL, or a newly-created
1023  * pixbuf with a reference count of 1 if no destination pixbuf was specified.
1024  **/
1025 GdkPixbuf *
1026 gdk_pixbuf_get_from_drawable (GdkPixbuf *dest,
1027                               GdkDrawable *src, GdkColormap *cmap,
1028                               int src_x, int src_y,
1029                               int dest_x, int dest_y,
1030                               int width, int height)
1031 {
1032         GdkWindowType window_type;
1033         int src_width, src_height;
1034         ArtPixBuf *apb = NULL;
1035         GdkImage *image;
1036         int rowstride, bpp, alpha;
1037
1038         /* General sanity checks */
1039
1040         g_return_val_if_fail (src != NULL, NULL);
1041
1042         window_type = gdk_window_get_type (src);
1043
1044         if (window_type == GDK_WINDOW_PIXMAP)
1045                 g_return_val_if_fail (cmap != NULL, NULL);
1046         else
1047                 /* FIXME: this is not perfect, since is_viewable() only tests
1048                  * recursively up the Gdk parent window tree, but stops at
1049                  * foreign windows or Gdk toplevels.  I.e. if a window manager
1050                  * unmapped one of its own windows, this won't work.
1051                  */
1052                 g_return_val_if_fail (gdk_window_is_viewable (src), NULL);
1053
1054         if (!dest)
1055                 g_return_val_if_fail (dest_x == 0 && dest_y == 0, NULL);
1056         else {
1057                 apb = dest->art_pixbuf;
1058
1059                 g_return_val_if_fail (apb->format == ART_PIX_RGB, NULL);
1060                 g_return_val_if_fail (apb->n_channels == 3 || apb->n_channels == 4, NULL);
1061                 g_return_val_if_fail (apb->bits_per_sample == 8, NULL);
1062         }
1063
1064         /* Coordinate sanity checks */
1065
1066         gdk_window_get_size (src, &src_width, &src_height);
1067
1068         g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
1069         g_return_val_if_fail (src_x + width <= src_width && src_y + height <= src_height, NULL);
1070
1071         if (dest) {
1072                 g_return_val_if_fail (dest_x >= 0 && dest_y >= 0, NULL);
1073                 g_return_val_if_fail (dest_x + width <= apb->width, NULL);
1074                 g_return_val_if_fail (dest_y + height <= apb->height, NULL);
1075         }
1076
1077         if (window_type != GDK_WINDOW_PIXMAP) {
1078                 int ret;
1079                 int src_xorigin, src_yorigin;
1080                 int screen_width, screen_height;
1081                 int screen_srcx, screen_srcy;
1082
1083                 ret = gdk_window_get_origin (src, &src_xorigin, &src_yorigin);
1084                 g_return_val_if_fail (ret != FALSE, NULL);
1085
1086                 screen_width = gdk_screen_width ();
1087                 screen_height = gdk_screen_height ();
1088
1089                 screen_srcx = src_xorigin + src_x;
1090                 screen_srcy = src_yorigin + src_y;
1091
1092                 g_return_val_if_fail (screen_srcx >= 0 && screen_srcy >= 0, NULL);
1093                 g_return_val_if_fail (screen_srcx + width <= screen_width, NULL);
1094                 g_return_val_if_fail (screen_srcy + height <= screen_height, NULL);
1095         }
1096
1097         /* Get Image in ZPixmap format (packed bits). */
1098         image = gdk_image_get (src, src_x, src_y, width, height);
1099         g_return_val_if_fail( image != NULL, NULL);
1100
1101         /* Create the pixbuf if needed */
1102         if (!dest) {
1103                 dest = gdk_pixbuf_new (ART_PIX_RGB, FALSE, 8, width, height);
1104                 if (!dest) {
1105                         gdk_image_destroy(image);
1106                         return NULL;
1107                 }
1108
1109                 apb = dest->art_pixbuf;
1110         }
1111
1112         /* Get the colormap if needed */
1113         if (window_type != GDK_WINDOW_PIXMAP)
1114                 cmap = gdk_window_get_colormap (src);
1115
1116         alpha = gdk_pixbuf_get_has_alpha(dest);
1117         rowstride = gdk_pixbuf_get_rowstride(dest);
1118         bpp = alpha?4:3;
1119
1120         /* we offset into the image data based on the position we are retrieving from */
1121         rgbconvert(image, gdk_pixbuf_get_pixels(dest) +
1122                    (dest_y * rowstride) + (dest_x * bpp),
1123                    rowstride,
1124                    alpha,
1125                    cmap);
1126
1127         gdk_image_destroy(image);
1128
1129         return dest;
1130 }