New comit of SDL2
[supertux.git] / src / SDL2 / IMG_xcf.c
1 /*
2   SDL_image:  An example image loading library for use with SDL
3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21
22 /* This is a XCF image file loading framework */
23
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <stdlib.h>
28
29 #include "SDL_endian.h"
30 #include "SDL_image.h"
31
32 #ifdef LOAD_XCF
33
34 #if DEBUG
35 static char prop_names [][30] = {
36   "end",
37   "colormap",
38   "active_layer",
39   "active_channel",
40   "selection",
41   "floating_selection",
42   "opacity",
43   "mode",
44   "visible",
45   "linked",
46   "preserve_transparency",
47   "apply_mask",
48   "edit_mask",
49   "show_mask",
50   "show_masked",
51   "offsets",
52   "color",
53   "compression",
54   "guides",
55   "resolution",
56   "tattoo",
57   "parasites",
58   "unit",
59   "paths",
60   "user_unit"
61 };
62 #endif
63
64
65 typedef enum
66 {
67   PROP_END = 0,
68   PROP_COLORMAP = 1,
69   PROP_ACTIVE_LAYER = 2,
70   PROP_ACTIVE_CHANNEL = 3,
71   PROP_SELECTION = 4,
72   PROP_FLOATING_SELECTION = 5,
73   PROP_OPACITY = 6,
74   PROP_MODE = 7,
75   PROP_VISIBLE = 8,
76   PROP_LINKED = 9,
77   PROP_PRESERVE_TRANSPARENCY = 10,
78   PROP_APPLY_MASK = 11,
79   PROP_EDIT_MASK = 12,
80   PROP_SHOW_MASK = 13,
81   PROP_SHOW_MASKED = 14,
82   PROP_OFFSETS = 15,
83   PROP_COLOR = 16,
84   PROP_COMPRESSION = 17,
85   PROP_GUIDES = 18,
86   PROP_RESOLUTION = 19,
87   PROP_TATTOO = 20,
88   PROP_PARASITES = 21,
89   PROP_UNIT = 22,
90   PROP_PATHS = 23,
91   PROP_USER_UNIT = 24
92 } xcf_prop_type;
93
94 typedef enum {
95   COMPR_NONE    = 0,
96   COMPR_RLE     = 1,
97   COMPR_ZLIB    = 2,
98   COMPR_FRACTAL = 3
99 } xcf_compr_type;
100
101 typedef enum {
102   IMAGE_RGB       = 0,
103   IMAGE_GREYSCALE = 1,
104   IMAGE_INDEXED   = 2
105 } xcf_image_type;
106
107 typedef struct {
108   Uint32 id;
109   Uint32 length;
110   union {
111     struct {
112       Uint32 num;
113       char * cmap;
114     } colormap; // 1
115     struct {
116       Uint32 drawable_offset;
117     } floating_selection; // 5
118     Sint32 opacity;
119     Sint32 mode;
120     int    visible;
121     int    linked;
122     int    preserve_transparency;
123     int    apply_mask;
124     int    show_mask;
125     struct {
126       Sint32 x;
127       Sint32 y;
128     } offset;
129     unsigned char color [3];
130     Uint8 compression;
131     struct {
132       Sint32 x;
133       Sint32 y;
134     } resolution;
135     struct {
136       char * name;
137       Uint32 flags;
138       Uint32 size;
139       char * data;
140     } parasite;
141   } data;
142 } xcf_prop;
143
144 typedef struct {
145   char   sign [14];
146   Uint32 width;
147   Uint32 height;
148   Sint32 image_type;
149   xcf_prop * properties;
150
151   Uint32 * layer_file_offsets;
152   Uint32 * channel_file_offsets;
153
154   xcf_compr_type compr;
155   Uint32         cm_num;
156   unsigned char * cm_map;
157 } xcf_header;
158
159 typedef struct {
160   Uint32 width;
161   Uint32 height;
162   Sint32 layer_type;
163   char * name;
164   xcf_prop * properties;
165
166   Uint32 hierarchy_file_offset;
167   Uint32 layer_mask_offset;
168
169   Uint32 offset_x;
170   Uint32 offset_y;
171   int visible;
172 } xcf_layer;
173
174 typedef struct {
175   Uint32 width;
176   Uint32 height;
177   char * name;
178   xcf_prop * properties;
179
180   Uint32 hierarchy_file_offset;
181
182   Uint32 color;
183   Uint32 opacity;
184   int selection;
185   int visible;
186 } xcf_channel;
187
188 typedef struct {
189   Uint32 width;
190   Uint32 height;
191   Uint32 bpp;
192
193   Uint32 * level_file_offsets;
194 } xcf_hierarchy;
195
196 typedef struct {
197   Uint32 width;
198   Uint32 height;
199
200   Uint32 * tile_file_offsets;
201 } xcf_level;
202
203 typedef unsigned char * xcf_tile;
204
205 typedef unsigned char * (* load_tile_type) (SDL_RWops *, Uint32, int, int, int);
206
207
208 /* See if an image is contained in a data source */
209 int IMG_isXCF(SDL_RWops *src)
210 {
211     Sint64 start;
212     int is_XCF;
213     char magic[14];
214
215     if ( !src )
216         return 0;
217     start = SDL_RWtell(src);
218     is_XCF = 0;
219     if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
220         if (SDL_strncmp(magic, "gimp xcf ", 9) == 0) {
221             is_XCF = 1;
222         }
223     }
224     SDL_RWseek(src, start, RW_SEEK_SET);
225     return(is_XCF);
226 }
227
228 static char * read_string (SDL_RWops * src) {
229   Uint32 tmp;
230   char * data;
231
232   tmp = SDL_ReadBE32 (src);
233   if (tmp > 0) {
234     data = (char *) SDL_malloc (sizeof (char) * tmp);
235     SDL_RWread (src, data, tmp, 1);
236   }
237   else {
238     data = NULL;
239   }
240
241   return data;
242 }
243
244
245 static Uint32 Swap32 (Uint32 v) {
246   return
247     ((v & 0x000000FF) << 16)
248     |  ((v & 0x0000FF00))
249     |  ((v & 0x00FF0000) >> 16)
250     |  ((v & 0xFF000000));
251 }
252
253 static void xcf_read_property (SDL_RWops * src, xcf_prop * prop) {
254   prop->id = SDL_ReadBE32 (src);
255   prop->length = SDL_ReadBE32 (src);
256
257 #if DEBUG
258   printf ("%.8X: %s: %d\n", SDL_RWtell (src), prop->id < 25 ? prop_names [prop->id] : "unknown", prop->length);
259 #endif
260
261   switch (prop->id) {
262   case PROP_COLORMAP:
263     prop->data.colormap.num = SDL_ReadBE32 (src);
264     prop->data.colormap.cmap = (char *) SDL_malloc (sizeof (char) * prop->data.colormap.num * 3);
265     SDL_RWread (src, prop->data.colormap.cmap, prop->data.colormap.num*3, 1);
266     break;
267
268   case PROP_OFFSETS:
269     prop->data.offset.x = SDL_ReadBE32 (src);
270     prop->data.offset.y = SDL_ReadBE32 (src);
271     break;
272   case PROP_OPACITY:
273     prop->data.opacity = SDL_ReadBE32 (src);
274     break;
275   case PROP_COMPRESSION:
276   case PROP_COLOR:
277     SDL_RWread (src, &prop->data, prop->length, 1);
278     break;
279   case PROP_VISIBLE:
280     prop->data.visible = SDL_ReadBE32 (src);
281     break;
282   default:
283     //    SDL_RWread (src, &prop->data, prop->length, 1);
284     SDL_RWseek (src, prop->length, RW_SEEK_CUR);
285   }
286 }
287
288 static void free_xcf_header (xcf_header * h) {
289   if (h->cm_num)
290     SDL_free (h->cm_map);
291   if (h->layer_file_offsets)
292     SDL_free (h->layer_file_offsets);
293   SDL_free (h);
294 }
295
296 static xcf_header * read_xcf_header (SDL_RWops * src) {
297   xcf_header * h;
298   xcf_prop prop;
299
300   h = (xcf_header *) SDL_malloc (sizeof (xcf_header));
301   SDL_RWread (src, h->sign, 14, 1);
302   h->width       = SDL_ReadBE32 (src);
303   h->height      = SDL_ReadBE32 (src);
304   h->image_type  = SDL_ReadBE32 (src);
305
306   h->properties = NULL;
307   h->layer_file_offsets = NULL;
308   h->compr      = COMPR_NONE;
309   h->cm_num = 0;
310   h->cm_map = NULL;
311
312   // Just read, don't save
313   do {
314     xcf_read_property (src, &prop);
315     if (prop.id == PROP_COMPRESSION)
316       h->compr = (xcf_compr_type)prop.data.compression;
317     else if (prop.id == PROP_COLORMAP) {
318       // unused var: int i;
319
320       h->cm_num = prop.data.colormap.num;
321       h->cm_map = (unsigned char *) SDL_malloc (sizeof (unsigned char) * 3 * h->cm_num);
322       SDL_memcpy (h->cm_map, prop.data.colormap.cmap, 3*sizeof (char)*h->cm_num);
323       SDL_free (prop.data.colormap.cmap);
324     }
325   } while (prop.id != PROP_END);
326
327   return h;
328 }
329
330 static void free_xcf_layer (xcf_layer * l) {
331   SDL_free (l->name);
332   SDL_free (l);
333 }
334
335 static xcf_layer * read_xcf_layer (SDL_RWops * src) {
336   xcf_layer * l;
337   xcf_prop    prop;
338
339   l = (xcf_layer *) SDL_malloc (sizeof (xcf_layer));
340   l->width  = SDL_ReadBE32 (src);
341   l->height = SDL_ReadBE32 (src);
342   l->layer_type = SDL_ReadBE32 (src);
343
344   l->name = read_string (src);
345
346   do {
347     xcf_read_property (src, &prop);
348     if (prop.id == PROP_OFFSETS) {
349       l->offset_x = prop.data.offset.x;
350       l->offset_y = prop.data.offset.y;
351     } else if (prop.id == PROP_VISIBLE) {
352       l->visible = prop.data.visible ? 1 : 0;
353     }
354   } while (prop.id != PROP_END);
355
356   l->hierarchy_file_offset = SDL_ReadBE32 (src);
357   l->layer_mask_offset     = SDL_ReadBE32 (src);
358
359   return l;
360 }
361
362 static void free_xcf_channel (xcf_channel * c) {
363   SDL_free (c->name);
364   SDL_free (c);
365 }
366
367 static xcf_channel * read_xcf_channel (SDL_RWops * src) {
368   xcf_channel * l;
369   xcf_prop    prop;
370
371   l = (xcf_channel *) SDL_malloc (sizeof (xcf_channel));
372   l->width  = SDL_ReadBE32 (src);
373   l->height = SDL_ReadBE32 (src);
374
375   l->name = read_string (src);
376
377   l->selection = 0;
378   do {
379     xcf_read_property (src, &prop);
380     switch (prop.id) {
381     case PROP_OPACITY:
382       l->opacity = prop.data.opacity << 24;
383       break;
384     case PROP_COLOR:
385       l->color = ((Uint32) prop.data.color[0] << 16)
386     | ((Uint32) prop.data.color[1] << 8)
387     | ((Uint32) prop.data.color[2]);
388       break;
389     case PROP_SELECTION:
390       l->selection = 1;
391       break;
392     case PROP_VISIBLE:
393       l->visible = prop.data.visible ? 1 : 0;
394       break;
395     default:
396         ;
397     }
398   } while (prop.id != PROP_END);
399
400   l->hierarchy_file_offset = SDL_ReadBE32 (src);
401
402   return l;
403 }
404
405 static void free_xcf_hierarchy (xcf_hierarchy * h) {
406   SDL_free (h->level_file_offsets);
407   SDL_free (h);
408 }
409
410 static xcf_hierarchy * read_xcf_hierarchy (SDL_RWops * src) {
411   xcf_hierarchy * h;
412   int i;
413
414   h = (xcf_hierarchy *) SDL_malloc (sizeof (xcf_hierarchy));
415   h->width  = SDL_ReadBE32 (src);
416   h->height = SDL_ReadBE32 (src);
417   h->bpp    = SDL_ReadBE32 (src);
418
419   h->level_file_offsets = NULL;
420   i = 0;
421   do {
422     h->level_file_offsets = (Uint32 *) SDL_realloc (h->level_file_offsets, sizeof (Uint32) * (i+1));
423     h->level_file_offsets [i] = SDL_ReadBE32 (src);
424   } while (h->level_file_offsets [i++]);
425
426   return h;
427 }
428
429 static void free_xcf_level (xcf_level * l) {
430   SDL_free (l->tile_file_offsets);
431   SDL_free (l);
432 }
433
434 static xcf_level * read_xcf_level (SDL_RWops * src) {
435   xcf_level * l;
436   int i;
437
438   l = (xcf_level *) SDL_malloc (sizeof (xcf_level));
439   l->width  = SDL_ReadBE32 (src);
440   l->height = SDL_ReadBE32 (src);
441
442   l->tile_file_offsets = NULL;
443   i = 0;
444   do {
445     l->tile_file_offsets = (Uint32 *) SDL_realloc (l->tile_file_offsets, sizeof (Uint32) * (i+1));
446     l->tile_file_offsets [i] = SDL_ReadBE32 (src);
447   } while (l->tile_file_offsets [i++]);
448
449   return l;
450 }
451
452 static void free_xcf_tile (unsigned char * t) {
453   SDL_free (t);
454 }
455
456 static unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
457   unsigned char * load;
458
459   load = (unsigned char *) SDL_malloc (len); // expect this is okay
460   SDL_RWread (src, load, len, 1);
461
462   return load;
463 }
464
465 static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
466   unsigned char * load, * t, * data, * d;
467   Uint32 reallen;
468   int i, size, count, j, length;
469   unsigned char val;
470
471   t = load = (unsigned char *) SDL_malloc (len);
472   reallen = SDL_RWread (src, t, 1, len);
473
474   data = (unsigned char *) SDL_malloc (x*y*bpp);
475   for (i = 0; i < bpp; i++) {
476     d    = data + i;
477     size = x*y;
478     count = 0;
479
480     while (size > 0) {
481       val = *t++;
482
483       length = val;
484       if (length >= 128) {
485     length = 255 - (length - 1);
486     if (length == 128) {
487       length = (*t << 8) + t[1];
488       t += 2;
489     }
490
491     count += length;
492     size -= length;
493
494     while (length-- > 0) {
495       *d = *t++;
496       d += bpp;
497     }
498       }
499       else {
500     length += 1;
501     if (length == 128) {
502       length = (*t << 8) + t[1];
503       t += 2;
504     }
505
506     count += length;
507     size -= length;
508
509     val = *t++;
510
511     for (j = 0; j < length; j++) {
512       *d = val;
513       d += bpp;
514     }
515       }
516     }
517   }
518
519   SDL_free (load);
520   return (data);
521 }
522
523 static Uint32 rgb2grey (Uint32 a) {
524   Uint8 l;
525   l = (Uint8)(0.2990 * ((a & 0x00FF0000) >> 16)
526     + 0.5870 * ((a & 0x0000FF00) >>  8)
527     + 0.1140 * ((a & 0x000000FF)));
528
529   return (l << 16) | (l << 8) | l;
530 }
531
532 static void create_channel_surface (SDL_Surface * surf, xcf_image_type itype, Uint32 color, Uint32 opacity) {
533   Uint32 c = 0;
534
535   switch (itype) {
536   case IMAGE_RGB:
537   case IMAGE_INDEXED:
538     c = opacity | color;
539     break;
540   case IMAGE_GREYSCALE:
541     c = opacity | rgb2grey (color);
542     break;
543   }
544   SDL_FillRect (surf, NULL, c);
545 }
546
547 static int do_layer_surface (SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_layer * layer, load_tile_type load_tile) {
548   xcf_hierarchy * hierarchy;
549   xcf_level     * level;
550   unsigned char * tile;
551   Uint8  * p8;
552   Uint16 * p16;
553   Uint32 * p;
554   int i, j;
555   Uint32 x, y, tx, ty, ox, oy;
556   Uint32 *row;
557
558   SDL_RWseek (src, layer->hierarchy_file_offset, RW_SEEK_SET);
559   hierarchy = read_xcf_hierarchy (src);
560
561   level = NULL;
562   for (i = 0; hierarchy->level_file_offsets [i]; i++) {
563     SDL_RWseek (src, hierarchy->level_file_offsets [i], RW_SEEK_SET);
564     level = read_xcf_level (src);
565
566     ty = tx = 0;
567     for (j = 0; level->tile_file_offsets [j]; j++) {
568       SDL_RWseek (src, level->tile_file_offsets [j], RW_SEEK_SET);
569       ox = tx+64 > level->width ? level->width % 64 : 64;
570       oy = ty+64 > level->height ? level->height % 64 : 64;
571
572       if (level->tile_file_offsets [j+1]) {
573     tile = load_tile
574       (src,
575        level->tile_file_offsets [j+1] - level->tile_file_offsets [j],
576        hierarchy->bpp,
577        ox, oy);
578       }
579       else {
580     tile = load_tile
581       (src,
582        ox*oy*6,
583        hierarchy->bpp,
584        ox, oy);
585       }
586
587       p8  = tile;
588       p16 = (Uint16 *) p8;
589       p   = (Uint32 *) p8;
590       for (y=ty; y < ty+oy; y++) {
591     row = (Uint32 *)((Uint8 *)surface->pixels + y*surface->pitch + tx*4);
592     switch (hierarchy->bpp) {
593     case 4:
594       for (x=tx; x < tx+ox; x++)
595         *row++ = Swap32 (*p++);
596       break;
597     case 3:
598       for (x=tx; x < tx+ox; x++) {
599         *row = 0xFF000000;
600         *row |= ((Uint32) *(p8++) << 16);
601         *row |= ((Uint32) *(p8++) << 8);
602         *row |= ((Uint32) *(p8++) << 0);
603         row++;
604       }
605       break;
606     case 2: // Indexed/Greyscale + Alpha
607       switch (head->image_type) {
608       case IMAGE_INDEXED:
609         for (x=tx; x < tx+ox; x++) {
610           *row =  ((Uint32) (head->cm_map [*p8*3])     << 16);
611           *row |= ((Uint32) (head->cm_map [*p8*3+1])   << 8);
612           *row |= ((Uint32) (head->cm_map [*p8++*3+2]) << 0);
613           *row |= ((Uint32) *p8++ << 24);;
614           row++;
615         }
616         break;
617       case IMAGE_GREYSCALE:
618         for (x=tx; x < tx+ox; x++) {
619           *row = ((Uint32) *p8 << 16);
620           *row |= ((Uint32) *p8 << 8);
621           *row |= ((Uint32) *p8++ << 0);
622           *row |= ((Uint32) *p8++ << 24);;
623           row++;
624         }
625         break;
626       default:
627         fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
628         if (hierarchy)
629         {
630           if (hierarchy->level_file_offsets)
631             SDL_free(hierarchy->level_file_offsets);
632          
633           free_xcf_hierarchy(hierarchy);
634         }
635         if (level)     
636           free_xcf_level (level);
637         return 1;
638       }
639       break;
640     case 1: // Indexed/Greyscale
641       switch (head->image_type) {
642       case IMAGE_INDEXED:
643         for (x = tx; x < tx+ox; x++) {
644           *row++ = 0xFF000000
645         | ((Uint32) (head->cm_map [*p8*3]) << 16)
646         | ((Uint32) (head->cm_map [*p8*3+1]) << 8)
647         | ((Uint32) (head->cm_map [*p8*3+2]) << 0);
648           p8++;
649         }
650         break;
651       case IMAGE_GREYSCALE:
652         for (x=tx; x < tx+ox; x++) {
653           *row++ = 0xFF000000
654         | (((Uint32) (*p8)) << 16)
655         | (((Uint32) (*p8)) << 8)
656         | (((Uint32) (*p8)) << 0);
657             ++p8;
658         }
659         break;
660       default:
661         fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
662         if (tile)
663           free_xcf_tile (tile);
664         if (level)
665           free_xcf_level (level);
666         if (hierarchy)
667           free_xcf_hierarchy (hierarchy);
668         return 1;
669       }
670       break;
671     }
672       }
673       tx += 64;
674       if (tx >= level->width) {
675     tx = 0;
676     ty += 64;
677       }
678       if (ty >= level->height) {
679     break;
680       }
681
682       free_xcf_tile (tile);
683     }
684     free_xcf_level (level);
685   }
686
687   free_xcf_hierarchy (hierarchy);
688
689   return 0;
690 }
691
692 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
693 {
694   Sint64 start;
695   const char *error = NULL;
696   SDL_Surface *surface, *lays;
697   xcf_header * head;
698   xcf_layer  * layer;
699   xcf_channel ** channel;
700   int chnls, i, offsets;
701   Sint64 offset, fp;
702
703   unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int);
704
705   if ( !src ) {
706     /* The error message has been set in SDL_RWFromFile */
707     return NULL;
708   }
709   start = SDL_RWtell(src);
710
711   /* Initialize the data we will clean up when we're done */
712   surface = NULL;
713
714   head = read_xcf_header (src);
715
716   switch (head->compr) {
717   case COMPR_NONE:
718     load_tile = load_xcf_tile_none;
719     break;
720   case COMPR_RLE:
721     load_tile = load_xcf_tile_rle;
722     break;
723   default:
724     fprintf (stderr, "Unsupported Compression.\n");
725     free_xcf_header (head);
726     return NULL;
727   }
728
729   /* Create the surface of the appropriate type */
730   surface = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
731                  0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
732
733   if ( surface == NULL ) {
734     error = "Out of memory";
735     goto done;
736   }
737
738   offsets = 0;
739
740   while ((offset = SDL_ReadBE32 (src))) {
741     head->layer_file_offsets = (Uint32 *) SDL_realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1));
742     head->layer_file_offsets [offsets] = (Uint32)offset;
743     offsets++;
744   }
745   fp = SDL_RWtell (src);
746
747   lays = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
748               0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
749
750   if ( lays == NULL ) {
751     error = "Out of memory";
752     goto done;
753   }
754
755   // Blit layers backwards, because Gimp saves them highest first
756   for (i = offsets; i > 0; i--) {
757     SDL_Rect rs, rd;
758     SDL_RWseek (src, head->layer_file_offsets [i-1], RW_SEEK_SET);
759
760     layer = read_xcf_layer (src);
761     do_layer_surface (lays, src, head, layer, load_tile);
762     rs.x = 0;
763     rs.y = 0;
764     rs.w = layer->width;
765     rs.h = layer->height;
766     rd.x = layer->offset_x;
767     rd.y = layer->offset_y;
768     rd.w = layer->width;
769     rd.h = layer->height;
770
771     if (layer->visible)
772       SDL_BlitSurface (lays, &rs, surface, &rd);
773     free_xcf_layer (layer);
774   }
775
776   SDL_FreeSurface (lays);
777
778   SDL_RWseek (src, fp, RW_SEEK_SET);
779
780   // read channels
781   channel = NULL;
782   chnls   = 0;
783   while ((offset = SDL_ReadBE32 (src))) {
784     channel = (xcf_channel **) SDL_realloc (channel, sizeof (xcf_channel *) * (chnls+1));
785     fp = SDL_RWtell (src);
786     SDL_RWseek (src, offset, RW_SEEK_SET);
787     channel [chnls++] = (read_xcf_channel (src));
788     SDL_RWseek (src, fp, RW_SEEK_SET);
789   }
790
791   if (chnls) {
792     SDL_Surface * chs;
793
794     chs = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
795                0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
796
797     if (chs == NULL) {
798       error = "Out of memory";
799       goto done;
800     }
801     for (i = 0; i < chnls; i++) {
802       //      printf ("CNLBLT %i\n", i);
803       if (!channel [i]->selection && channel [i]->visible) {
804     create_channel_surface (chs, (xcf_image_type)head->image_type, channel [i]->color, channel [i]->opacity);
805     SDL_BlitSurface (chs, NULL, surface, NULL);
806       }
807       free_xcf_channel (channel [i]);
808     }
809
810     SDL_FreeSurface (chs);
811   }
812
813 done:
814   free_xcf_header (head);
815   if ( error ) {
816     SDL_RWseek(src, start, RW_SEEK_SET);
817     if ( surface ) {
818       SDL_FreeSurface(surface);
819       surface = NULL;
820     }
821     IMG_SetError(error);
822   }
823
824   return(surface);
825 }
826
827 #else
828
829 /* See if an image is contained in a data source */
830 int IMG_isXCF(SDL_RWops *src)
831 {
832   return(0);
833 }
834
835 /* Load a XCF type image from an SDL datasource */
836 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
837 {
838   return(NULL);
839 }
840
841 #endif /* LOAD_XCF */