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