IMG_xcf.c
author Sam Lantinga <slouken@lokigames.com>
Wed, 07 Mar 2001 17:16:38 +0000
changeset 26 d51719e1b5d9
child 53 96b084473b47
permissions -rw-r--r--
Berni - Wed Mar 7 09:18:02 PST 2001
* Added initial GIMP XCF support (disabled by default)
     1 /*
     2     IMGLIB:  An example image loading library for use with SDL
     3     Copyright (C) 1999  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 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     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     5635-34 Springhouse Dr.
    21     Pleasanton, CA 94588 (USA)
    22     slouken@devolution.com
    23 
    24     XCF support by Bernhard J. Pietsch <bjtp@gmx.net>
    25 */
    26 
    27 /* This is a XCF image file loading framework */
    28 
    29 #include <stdio.h>
    30 #include <ctype.h>
    31 #include <string.h>
    32 
    33 #include "SDL_image.h"
    34 
    35 #ifdef LOAD_XCF
    36 
    37 static char prop_names [][30] = {
    38   "end",
    39   "colormap",
    40   "active_layer",
    41   "active_channel",
    42   "selection",
    43   "floating_selection",
    44   "opacity",
    45   "mode",
    46   "visible",
    47   "linked",
    48   "preserve_transparency",
    49   "apply_mask",
    50   "edit_mask",
    51   "show_mask",
    52   "show_masked",
    53   "offsets",
    54   "color",
    55   "compression",
    56   "guides",
    57   "resolution",
    58   "tattoo",
    59   "parasites",
    60   "unit",
    61   "paths",
    62   "user_unit"
    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 } xcf_layer;
   172 
   173 typedef struct {
   174   Uint32 width;
   175   Uint32 height;
   176   char * name;
   177   xcf_prop * properties;
   178 
   179   Uint32 hierarchy_file_offset;
   180 
   181   Uint32 color;
   182   Uint32 opacity;
   183   int selection : 1;
   184 } xcf_channel;
   185 
   186 typedef struct {
   187   Uint32 width;
   188   Uint32 height;
   189   Uint32 bpp;
   190 
   191   Uint32 * level_file_offsets;
   192 } xcf_hierarchy;
   193 
   194 typedef struct {
   195   Uint32 width;
   196   Uint32 height;
   197 
   198   Uint32 * tile_file_offsets;
   199 } xcf_level;
   200 
   201 typedef unsigned char * xcf_tile;
   202 
   203 typedef unsigned char * (* load_tile_type) (SDL_RWops *, Uint32, int, int, int);
   204 
   205 
   206 /* See if an image is contained in a data source */
   207 int IMG_isXCF(SDL_RWops *src) {
   208   int is_XCF;
   209   char magic[14];
   210 
   211   is_XCF = 0;
   212   if ( SDL_RWread(src, magic, 14, 1) ) {
   213     if (strncmp(magic, "gimp xcf ", 9) == 0) {
   214       is_XCF = 1;
   215     }
   216   }
   217 
   218   return(is_XCF);
   219 }
   220 
   221 static char * read_string (SDL_RWops * src) {
   222   Uint32 tmp;
   223   char * data;
   224 
   225   tmp = SDL_ReadBE32 (src);
   226   if (tmp > 0) {
   227     data = (char *) malloc (sizeof (char) * tmp);
   228     SDL_RWread (src, data, tmp, 1);
   229   }
   230   else {
   231     data = NULL;
   232   }
   233 
   234   return data;
   235 }
   236 
   237 
   238 static Uint32 Swap32 (Uint32 v) {
   239   return
   240     ((v & 0x000000FF) << 16)
   241     |  ((v & 0x0000FF00))
   242     |  ((v & 0x00FF0000) >> 16)
   243     |  ((v & 0xFF000000));
   244 }
   245 
   246 void xcf_read_property (SDL_RWops * src, xcf_prop * prop) {
   247   prop->id = SDL_ReadBE32 (src);
   248   prop->length = SDL_ReadBE32 (src);
   249 
   250   printf ("%.8X: %s: %d\n", SDL_RWtell (src), prop->id < 25 ? prop_names [prop->id] : "unknown", prop->length);
   251 
   252   switch (prop->id) {
   253   case PROP_COLORMAP:
   254     prop->data.colormap.num = SDL_ReadBE32 (src);
   255     prop->data.colormap.cmap = (char *) malloc (sizeof (char) * prop->data.colormap.num * 3);
   256     SDL_RWread (src, prop->data.colormap.cmap, prop->data.colormap.num*3, 1);
   257     break;
   258 
   259   case PROP_OFFSETS:
   260     prop->data.offset.x = SDL_ReadBE32 (src);
   261     prop->data.offset.y = SDL_ReadBE32 (src);
   262     break;
   263   case PROP_OPACITY:
   264     prop->data.opacity = SDL_ReadBE32 (src);
   265     break;
   266   case PROP_COMPRESSION:
   267   case PROP_COLOR:
   268     SDL_RWread (src, &prop->data, prop->length, 1);
   269     break;
   270   default:
   271     //    SDL_RWread (src, &prop->data, prop->length, 1);
   272     SDL_RWseek (src, prop->length, SEEK_CUR);
   273   }
   274 }
   275 
   276 void free_xcf_header (xcf_header * h) {
   277   if (h->cm_num)
   278     free (h->cm_map);
   279 
   280   free (h);
   281 }
   282 
   283 xcf_header * read_xcf_header (SDL_RWops * src) {
   284   xcf_header * h;
   285   xcf_prop prop;
   286 
   287   h = (xcf_header *) malloc (sizeof (xcf_header));
   288   SDL_RWread (src, h->sign, 14, 1);
   289   h->width       = SDL_ReadBE32 (src);
   290   h->height      = SDL_ReadBE32 (src);
   291   h->image_type  = SDL_ReadBE32 (src);
   292 
   293   h->properties = NULL;
   294   h->compr      = COMPR_NONE;
   295   h->cm_num = 0;
   296   h->cm_map = NULL;
   297 
   298   // Just read, don't save
   299   do {
   300     xcf_read_property (src, &prop);
   301     if (prop.id == PROP_COMPRESSION)
   302       h->compr = prop.data.compression;
   303     else if (prop.id == PROP_COLORMAP) {
   304       int i;
   305 
   306       h->cm_num = prop.data.colormap.num;
   307       h->cm_map = (char *) malloc (sizeof (char) * 3 * h->cm_num);
   308       memcpy (h->cm_map, prop.data.colormap.cmap, 3*sizeof (char)*h->cm_num);
   309       free (prop.data.colormap.cmap);
   310     }
   311   } while (prop.id != PROP_END);
   312 
   313   return h;
   314 }
   315 
   316 void free_xcf_layer (xcf_layer * l) {
   317   free (l->name);
   318   free (l);
   319 }
   320 
   321 xcf_layer * read_xcf_layer (SDL_RWops * src) {
   322   xcf_layer * l;
   323   xcf_prop    prop;
   324 
   325   l = (xcf_layer *) malloc (sizeof (xcf_layer));
   326   l->width  = SDL_ReadBE32 (src);
   327   l->height = SDL_ReadBE32 (src);
   328   l->layer_type = SDL_ReadBE32 (src);
   329 
   330   l->name = read_string (src);
   331 
   332   do {
   333     xcf_read_property (src, &prop);
   334     if (prop.id == PROP_OFFSETS) {
   335       l->offset_x = prop.data.offset.x;
   336       l->offset_y = prop.data.offset.y;
   337     }
   338   } while (prop.id != PROP_END);
   339 
   340   l->hierarchy_file_offset = SDL_ReadBE32 (src);
   341   l->layer_mask_offset     = SDL_ReadBE32 (src);
   342 
   343   return l;
   344 }
   345 
   346 void free_xcf_channel (xcf_channel * c) {
   347   free (c->name);
   348   free (c);
   349 }
   350 
   351 xcf_channel * read_xcf_channel (SDL_RWops * src) {
   352   xcf_channel * l;
   353   xcf_prop    prop;
   354 
   355   l = (xcf_channel *) malloc (sizeof (xcf_channel));
   356   l->width  = SDL_ReadBE32 (src);
   357   l->height = SDL_ReadBE32 (src);
   358 
   359   l->name = read_string (src);
   360 
   361   l->selection = 0;
   362   do {
   363     xcf_read_property (src, &prop);
   364     switch (prop.id) {
   365     case PROP_OPACITY:
   366       l->opacity = prop.data.opacity << 24;
   367       break;
   368     case PROP_COLOR:
   369       l->color = ((Uint32) prop.data.color[0] << 16)
   370 	| ((Uint32) prop.data.color[1] << 8)
   371 	| ((Uint32) prop.data.color[2]);
   372       break;
   373     case PROP_SELECTION:
   374       l->selection = 1;
   375       break;
   376     default:
   377     }
   378   } while (prop.id != PROP_END);
   379 
   380   l->hierarchy_file_offset = SDL_ReadBE32 (src);
   381 
   382   return l;
   383 }
   384 
   385 void free_xcf_hierarchy (xcf_hierarchy * h) {
   386   free (h->level_file_offsets);
   387   free (h);
   388 }
   389 
   390 xcf_hierarchy * read_xcf_hierarchy (SDL_RWops * src) {
   391   xcf_hierarchy * h;
   392   int i;
   393 
   394   h = (xcf_hierarchy *) malloc (sizeof (xcf_hierarchy));
   395   h->width  = SDL_ReadBE32 (src);
   396   h->height = SDL_ReadBE32 (src);
   397   h->bpp    = SDL_ReadBE32 (src);
   398 
   399   h->level_file_offsets = NULL;
   400   i = 0;
   401   do {
   402     h->level_file_offsets = (Uint32 *) realloc (h->level_file_offsets, sizeof (Uint32) * (i+1));
   403     h->level_file_offsets [i] = SDL_ReadBE32 (src);
   404   } while (h->level_file_offsets [i++]);
   405 
   406   return h;
   407 }
   408 
   409 void free_xcf_level (xcf_level * l) {
   410   free (l->tile_file_offsets);
   411   free (l);
   412 }
   413 
   414 xcf_level * read_xcf_level (SDL_RWops * src) {
   415   xcf_level * l;
   416   int i;
   417 
   418   l = (xcf_level *) malloc (sizeof (xcf_level));
   419   l->width  = SDL_ReadBE32 (src);
   420   l->height = SDL_ReadBE32 (src);
   421 
   422   l->tile_file_offsets = NULL;
   423   i = 0;
   424   do {
   425     l->tile_file_offsets = (Uint32 *) realloc (l->tile_file_offsets, sizeof (Uint32) * (i+1));
   426     l->tile_file_offsets [i] = SDL_ReadBE32 (src);
   427   } while (l->tile_file_offsets [i++]);
   428 
   429   return l;
   430 }
   431 
   432 void free_xcf_tile (unsigned char * t) {
   433   free (t);
   434 }
   435 
   436 unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   437   unsigned char * load;
   438 
   439   load = (char *) malloc (len); // expect this is okay
   440   SDL_RWread (src, load, len, 1);
   441 
   442   return load;
   443 }
   444 
   445 unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   446   unsigned char * load, * t, * data, * d;
   447   Uint32 reallen;
   448   int i, size, count, j, length;
   449   unsigned char val;
   450 
   451   t = load = (char *) malloc (len);
   452   reallen = SDL_RWread (src, t, 1, len);
   453 
   454   data = (char *) malloc (x*y*bpp);
   455   for (i = 0; i < bpp; i++) {
   456     d    = data + i;
   457     size = x*y;
   458     count = 0;
   459  
   460     while (size > 0) {
   461       val = *t++;
   462 
   463       length = val;
   464       if (length >= 128) {
   465 	length = 255 - (length - 1);
   466 	if (length == 128) {
   467 	  length = (*t << 8) + t[1];
   468 	  t += 2;
   469 	}
   470 
   471 	count += length;
   472 	size -= length;
   473 
   474 	while (length-- > 0) {
   475 	  *d = *t++;
   476 	  d += bpp;
   477 	}
   478       }
   479       else {
   480 	length += 1;
   481 	if (length == 128) {
   482 	  length = (*t << 8) + t[1];
   483 	  t += 2;
   484 	}
   485 
   486 	count += length;
   487 	size -= length;
   488 
   489 	val = *t++;
   490 
   491 	for (j = 0; j < length; j++) {
   492 	  *d = val;
   493 	  d += bpp;
   494 	}
   495       }
   496     }
   497   }
   498 
   499   free (load);
   500   return (data);
   501 }
   502 
   503 static Uint32 rgb2grey (Uint32 a) {
   504   Uint8 l;
   505   l = 0.2990 * ((a && 0x00FF0000) >> 16)
   506     + 0.5870 * ((a && 0x0000FF00) >>  8)
   507     + 0.1140 * ((a && 0x000000FF));
   508 
   509   return (l << 16) | (l << 8) | l;
   510 }
   511 
   512 void create_channel_surface (SDL_Surface * surf, xcf_image_type itype, Uint32 color, Uint32 opacity) {
   513   Uint32 c;
   514 
   515   switch (itype) {
   516   case IMAGE_RGB:
   517   case IMAGE_INDEXED:
   518     c = opacity | color;
   519     break;
   520   case IMAGE_GREYSCALE:
   521     c = opacity | rgb2grey (color);
   522     break;
   523   }
   524   SDL_FillRect (surf, NULL, c);
   525 }
   526 
   527 int do_layer_surface (SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_layer * layer, load_tile_type load_tile) {
   528   xcf_hierarchy * hierarchy;
   529   xcf_level     * level;
   530   unsigned char * tile;
   531   Uint8  * p8;
   532   Uint16 * p16;
   533   Uint32 * p;
   534   int x, y, tx, ty, ox, oy, width, height, i, j;
   535   Uint32 *row;
   536 
   537   SDL_RWseek (src, layer->hierarchy_file_offset, SEEK_SET);
   538   hierarchy = read_xcf_hierarchy (src);
   539 
   540   level = NULL;
   541   for (i = 0; hierarchy->level_file_offsets [i]; i++) {
   542     SDL_RWseek (src, hierarchy->level_file_offsets [i], SEEK_SET);
   543     level = read_xcf_level (src);
   544 
   545     ty = tx = 0;
   546     for (j = 0; level->tile_file_offsets [j]; j++) {
   547       SDL_RWseek (src, level->tile_file_offsets [j], SEEK_SET);
   548       ox = tx+64 > level->width ? level->width % 64 : 64;
   549       oy = ty+64 > level->height ? level->height % 64 : 64;
   550 
   551       if (level->tile_file_offsets [j+1]) {
   552 	tile = load_tile
   553 	  (src,
   554 	   level->tile_file_offsets [j+1] - level->tile_file_offsets [j],
   555 	   hierarchy->bpp,
   556 	   ox, oy);
   557       }
   558       else {
   559 	tile = load_tile
   560 	  (src,
   561 	   ox*oy*6,
   562 	   hierarchy->bpp,
   563 	   ox, oy);
   564       }
   565 
   566       p8  = tile;
   567       p16 = (Uint16 *) p8;
   568       p   = (Uint32 *) p8;
   569       for (y=ty; y < ty+oy; y++) {
   570 	row = (Uint32 *)((Uint8 *)surface->pixels + y*surface->pitch + tx*4);
   571 	switch (hierarchy->bpp) {
   572 	case 4:
   573 	  for (x=tx; x < tx+ox; x++)
   574 	    *row++ = Swap32 (*p++);
   575 	  break;
   576 	case 3:
   577 	  for (x=tx; x < tx+ox; x++) {
   578 	    *row = 0xFF000000;
   579 	    *row |= ((Uint32) *(p8++) << 16);
   580 	    *row |= ((Uint32) *(p8++) << 8);
   581 	    *row |= ((Uint32) *(p8++) << 0);
   582 	    row++;
   583 	  }
   584 	  break;
   585 	case 2: // Indexed/Greyscale + Alpha
   586 	  switch (head->image_type) {
   587 	  case IMAGE_INDEXED:
   588 	    for (x=tx; x < tx+ox; x++) {
   589 	      *row =  ((Uint32) (head->cm_map [*p8*3])     << 16);
   590 	      *row |= ((Uint32) (head->cm_map [*p8*3+1])   << 8);
   591 	      *row |= ((Uint32) (head->cm_map [*p8++*3+2]) << 0);
   592 	      *row |= ((Uint32) *p8++ << 24);;
   593 	      row++;
   594 	    }
   595 	    break;
   596 	  case IMAGE_GREYSCALE:
   597 	    for (x=tx; x < tx+ox; x++) {
   598 	      *row = ((Uint32) *p8 << 16);
   599 	      *row |= ((Uint32) *p8 << 8);
   600 	      *row |= ((Uint32) *p8++ << 0);
   601 	      *row |= ((Uint32) *p8++ << 24);;
   602 	      row++;
   603 	    }
   604 	    break;	    
   605 	  default:
   606 	    fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
   607 	    return 1;
   608 	  }
   609 	  break;
   610 	case 1: // Indexed/Greyscale
   611 	  switch (head->image_type) {
   612 	  case IMAGE_INDEXED:
   613 	    for (x = tx; x < tx+ox; x++) {
   614 	      *row++ = 0xFF000000
   615 		| ((Uint32) (head->cm_map [*p8*3]) << 16)
   616 		| ((Uint32) (head->cm_map [*p8*3+1]) << 8)
   617 		| ((Uint32) (head->cm_map [*p8*3+2]) << 0);
   618 	      p8++;
   619 	    }
   620 	    break;
   621 	  case IMAGE_GREYSCALE:
   622 	    for (x=tx; x < tx+ox; x++) {
   623 	      *row++ = 0xFF000000
   624 		| (((Uint32) (*p8)) << 16)
   625 		| (((Uint32) (*p8)) << 8)
   626 		| (((Uint32) (*p8++)) << 0);
   627 	    }
   628 	    break;	    
   629 	  default:
   630 	    fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
   631 	    return 1;
   632 	  }
   633 	  break;
   634 	}
   635       }
   636       tx += 64;
   637       if (tx >= level->width) {
   638 	tx = 0;
   639 	ty += 64;
   640       }
   641       if (ty >= level->height) {
   642 	break;
   643       }
   644 
   645       free_xcf_tile (tile);
   646     }
   647     free_xcf_level (level);
   648   }
   649 
   650   free_xcf_hierarchy (hierarchy);
   651 }
   652 
   653 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src) {
   654   SDL_Surface *surface, *lays;
   655   xcf_header * head;
   656   xcf_layer  * layer;
   657   xcf_channel ** channel;
   658   int read_error, chnls, i, offsets;
   659   Uint32 offset, fp;
   660 
   661   unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int);
   662 
   663   /* Initialize the data we will clean up when we're done */
   664   surface = NULL;
   665   read_error = 0;
   666 
   667   /* Check to make sure we have something to do */
   668   if ( ! src ) {
   669     goto done;
   670   }
   671 
   672   head = read_xcf_header (src);
   673 
   674   switch (head->compr) {
   675   case COMPR_NONE:
   676     load_tile = load_xcf_tile_none;
   677     break;
   678   case COMPR_RLE:
   679     load_tile = load_xcf_tile_rle;
   680     break;
   681   default:
   682     fprintf (stderr, "Unsupported Compression.\n");
   683     free_xcf_header (head);
   684     return NULL;
   685   }
   686 
   687   /* Create the surface of the appropriate type */
   688   surface = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
   689 			     0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   690 
   691   if ( surface == NULL ) {
   692     IMG_SetError("Out of memory");
   693     goto done;
   694   }
   695 
   696   head->layer_file_offsets = NULL;
   697   offsets = 0;
   698 
   699   while (offset = SDL_ReadBE32 (src)) {
   700     head->layer_file_offsets = (Uint32 *) realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1));
   701     head->layer_file_offsets [offsets] = offset;
   702     offsets++;
   703   }
   704   fp = SDL_RWtell (src);
   705  
   706   lays = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
   707 			  0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   708 
   709   if ( lays == NULL ) {
   710     IMG_SetError("Out of memory");
   711     goto done;
   712   }
   713 
   714   // Blit layers backwards, because Gimp saves them highest first
   715   for (i = offsets; i > 0; i--) {
   716     SDL_Rect rs, rd;
   717     SDL_RWseek (src, head->layer_file_offsets [i-1], SEEK_SET);
   718 
   719     layer = read_xcf_layer (src);
   720     do_layer_surface (lays, src, head, layer, load_tile);
   721     rs.x = 0;
   722     rs.y = 0;
   723     rs.w = layer->width;
   724     rs.h = layer->height;
   725     rd.x = layer->offset_x;
   726     rd.y = layer->offset_y;
   727     rd.w = layer->width;
   728     rd.h = layer->height;
   729     free_xcf_layer (layer);
   730 
   731     SDL_BlitSurface (lays, &rs, surface, &rd);
   732   }
   733 
   734   SDL_FreeSurface (lays);
   735 
   736   SDL_RWseek (src, fp, SEEK_SET);
   737 
   738   // read channels
   739   channel = NULL;
   740   chnls   = 0;
   741   while (offset = SDL_ReadBE32 (src)) {
   742     channel = (xcf_channel **) realloc (channel, sizeof (xcf_channel *) * (chnls+1));
   743     fp = SDL_RWtell (src);
   744     SDL_RWseek (src, offset, SEEK_SET);
   745     channel [chnls++] = (read_xcf_channel (src));
   746     SDL_RWseek (src, fp, SEEK_SET);    
   747   }
   748 
   749   if (chnls) {
   750     SDL_Surface * chs;
   751 
   752     chs = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
   753 			   0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   754 
   755     if (chs == NULL) {
   756       IMG_SetError("Out of memory");
   757       goto done;
   758     }
   759     for (i = 0; i < chnls; i++) {
   760       //      printf ("CNLBLT %i\n", i);
   761       if (!channel [i]->selection) {
   762 	create_channel_surface (chs, head->image_type, channel [i]->color, channel [i]->opacity);
   763 	SDL_BlitSurface (chs, NULL, surface, NULL);
   764       }
   765       free_xcf_channel (channel [i]);
   766     }
   767 
   768     SDL_FreeSurface (chs);
   769   }
   770 
   771  done:
   772   free_xcf_header (head);
   773   if ( read_error ) {
   774     SDL_FreeSurface(surface);
   775     IMG_SetError("Error reading XCF data");
   776     surface = NULL;
   777   }
   778 
   779   return(surface);
   780 }
   781 
   782 #else
   783 
   784 /* See if an image is contained in a data source */
   785 int IMG_isXCF(SDL_RWops *src)
   786 {
   787   return(0);
   788 }
   789 
   790 /* Load a XCF type image from an SDL datasource */
   791 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   792 {
   793   return(NULL);
   794 }
   795 
   796 #endif /* LOAD_XCF */