IMG_xcf.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 04 Feb 2006 23:39:03 +0000
changeset 121 1bf9c0c87374
parent 118 c5e736a47ad2
child 128 3ed445f2f4fd
permissions -rw-r--r--
Updated copyright information
     1 /*
     2     SDL_image:  An example image loading library for use with SDL
     3     Copyright (C) 1997-2006 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 	start = SDL_RWtell(src);
   217 	is_XCF = 0;
   218 	if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
   219 		if (strncmp(magic, "gimp xcf ", 9) == 0) {
   220 			is_XCF = 1;
   221 		}
   222 	}
   223 	SDL_RWseek(src, start, SEEK_SET);
   224 	return(is_XCF);
   225 }
   226 
   227 static char * read_string (SDL_RWops * src) {
   228   Uint32 tmp;
   229   char * data;
   230 
   231   tmp = SDL_ReadBE32 (src);
   232   if (tmp > 0) {
   233     data = (char *) malloc (sizeof (char) * tmp);
   234     SDL_RWread (src, data, tmp, 1);
   235   }
   236   else {
   237     data = NULL;
   238   }
   239 
   240   return data;
   241 }
   242 
   243 
   244 static Uint32 Swap32 (Uint32 v) {
   245   return
   246     ((v & 0x000000FF) << 16)
   247     |  ((v & 0x0000FF00))
   248     |  ((v & 0x00FF0000) >> 16)
   249     |  ((v & 0xFF000000));
   250 }
   251 
   252 void xcf_read_property (SDL_RWops * src, xcf_prop * prop) {
   253   prop->id = SDL_ReadBE32 (src);
   254   prop->length = SDL_ReadBE32 (src);
   255 
   256 #if DEBUG
   257   printf ("%.8X: %s: %d\n", SDL_RWtell (src), prop->id < 25 ? prop_names [prop->id] : "unknown", prop->length);
   258 #endif
   259 
   260   switch (prop->id) {
   261   case PROP_COLORMAP:
   262     prop->data.colormap.num = SDL_ReadBE32 (src);
   263     prop->data.colormap.cmap = (char *) malloc (sizeof (char) * prop->data.colormap.num * 3);
   264     SDL_RWread (src, prop->data.colormap.cmap, prop->data.colormap.num*3, 1);
   265     break;
   266 
   267   case PROP_OFFSETS:
   268     prop->data.offset.x = SDL_ReadBE32 (src);
   269     prop->data.offset.y = SDL_ReadBE32 (src);
   270     break;
   271   case PROP_OPACITY:
   272     prop->data.opacity = SDL_ReadBE32 (src);
   273     break;
   274   case PROP_COMPRESSION:
   275   case PROP_COLOR:
   276     SDL_RWread (src, &prop->data, prop->length, 1);
   277     break;
   278   case PROP_VISIBLE:
   279     prop->data.visible = SDL_ReadBE32 (src);
   280     break;
   281   default:
   282     //    SDL_RWread (src, &prop->data, prop->length, 1);
   283     SDL_RWseek (src, prop->length, SEEK_CUR);
   284   }
   285 }
   286 
   287 void free_xcf_header (xcf_header * h) {
   288   if (h->cm_num)
   289     free (h->cm_map);
   290 
   291   free (h);
   292 }
   293 
   294 xcf_header * read_xcf_header (SDL_RWops * src) {
   295   xcf_header * h;
   296   xcf_prop prop;
   297 
   298   h = (xcf_header *) malloc (sizeof (xcf_header));
   299   SDL_RWread (src, h->sign, 14, 1);
   300   h->width       = SDL_ReadBE32 (src);
   301   h->height      = SDL_ReadBE32 (src);
   302   h->image_type  = SDL_ReadBE32 (src);
   303 
   304   h->properties = NULL;
   305   h->compr      = COMPR_NONE;
   306   h->cm_num = 0;
   307   h->cm_map = NULL;
   308 
   309   // Just read, don't save
   310   do {
   311     xcf_read_property (src, &prop);
   312     if (prop.id == PROP_COMPRESSION)
   313       h->compr = prop.data.compression;
   314     else if (prop.id == PROP_COLORMAP) {
   315       // unused var: int i;
   316 
   317       h->cm_num = prop.data.colormap.num;
   318       h->cm_map = (char *) malloc (sizeof (char) * 3 * h->cm_num);
   319       memcpy (h->cm_map, prop.data.colormap.cmap, 3*sizeof (char)*h->cm_num);
   320       free (prop.data.colormap.cmap);
   321     }
   322   } while (prop.id != PROP_END);
   323 
   324   return h;
   325 }
   326 
   327 void free_xcf_layer (xcf_layer * l) {
   328   free (l->name);
   329   free (l);
   330 }
   331 
   332 xcf_layer * read_xcf_layer (SDL_RWops * src) {
   333   xcf_layer * l;
   334   xcf_prop    prop;
   335 
   336   l = (xcf_layer *) malloc (sizeof (xcf_layer));
   337   l->width  = SDL_ReadBE32 (src);
   338   l->height = SDL_ReadBE32 (src);
   339   l->layer_type = SDL_ReadBE32 (src);
   340 
   341   l->name = read_string (src);
   342 
   343   do {
   344     xcf_read_property (src, &prop);
   345     if (prop.id == PROP_OFFSETS) {
   346       l->offset_x = prop.data.offset.x;
   347       l->offset_y = prop.data.offset.y;
   348     } else if (prop.id == PROP_VISIBLE) {
   349       l->visible = prop.data.visible ? 1 : 0;
   350     }
   351   } while (prop.id != PROP_END);
   352 
   353   l->hierarchy_file_offset = SDL_ReadBE32 (src);
   354   l->layer_mask_offset     = SDL_ReadBE32 (src);
   355 
   356   return l;
   357 }
   358 
   359 void free_xcf_channel (xcf_channel * c) {
   360   free (c->name);
   361   free (c);
   362 }
   363 
   364 xcf_channel * read_xcf_channel (SDL_RWops * src) {
   365   xcf_channel * l;
   366   xcf_prop    prop;
   367 
   368   l = (xcf_channel *) malloc (sizeof (xcf_channel));
   369   l->width  = SDL_ReadBE32 (src);
   370   l->height = SDL_ReadBE32 (src);
   371 
   372   l->name = read_string (src);
   373 
   374   l->selection = 0;
   375   do {
   376     xcf_read_property (src, &prop);
   377     switch (prop.id) {
   378     case PROP_OPACITY:
   379       l->opacity = prop.data.opacity << 24;
   380       break;
   381     case PROP_COLOR:
   382       l->color = ((Uint32) prop.data.color[0] << 16)
   383 	| ((Uint32) prop.data.color[1] << 8)
   384 	| ((Uint32) prop.data.color[2]);
   385       break;
   386     case PROP_SELECTION:
   387       l->selection = 1;
   388       break;
   389     case PROP_VISIBLE:
   390       l->visible = prop.data.visible ? 1 : 0;
   391       break;
   392     default:
   393         ;
   394     }
   395   } while (prop.id != PROP_END);
   396 
   397   l->hierarchy_file_offset = SDL_ReadBE32 (src);
   398 
   399   return l;
   400 }
   401 
   402 void free_xcf_hierarchy (xcf_hierarchy * h) {
   403   free (h->level_file_offsets);
   404   free (h);
   405 }
   406 
   407 xcf_hierarchy * read_xcf_hierarchy (SDL_RWops * src) {
   408   xcf_hierarchy * h;
   409   int i;
   410 
   411   h = (xcf_hierarchy *) malloc (sizeof (xcf_hierarchy));
   412   h->width  = SDL_ReadBE32 (src);
   413   h->height = SDL_ReadBE32 (src);
   414   h->bpp    = SDL_ReadBE32 (src);
   415 
   416   h->level_file_offsets = NULL;
   417   i = 0;
   418   do {
   419     h->level_file_offsets = (Uint32 *) realloc (h->level_file_offsets, sizeof (Uint32) * (i+1));
   420     h->level_file_offsets [i] = SDL_ReadBE32 (src);
   421   } while (h->level_file_offsets [i++]);
   422 
   423   return h;
   424 }
   425 
   426 void free_xcf_level (xcf_level * l) {
   427   free (l->tile_file_offsets);
   428   free (l);
   429 }
   430 
   431 xcf_level * read_xcf_level (SDL_RWops * src) {
   432   xcf_level * l;
   433   int i;
   434 
   435   l = (xcf_level *) malloc (sizeof (xcf_level));
   436   l->width  = SDL_ReadBE32 (src);
   437   l->height = SDL_ReadBE32 (src);
   438 
   439   l->tile_file_offsets = NULL;
   440   i = 0;
   441   do {
   442     l->tile_file_offsets = (Uint32 *) realloc (l->tile_file_offsets, sizeof (Uint32) * (i+1));
   443     l->tile_file_offsets [i] = SDL_ReadBE32 (src);
   444   } while (l->tile_file_offsets [i++]);
   445 
   446   return l;
   447 }
   448 
   449 void free_xcf_tile (unsigned char * t) {
   450   free (t);
   451 }
   452 
   453 unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   454   unsigned char * load;
   455 
   456   load = (char *) malloc (len); // expect this is okay
   457   SDL_RWread (src, load, len, 1);
   458 
   459   return load;
   460 }
   461 
   462 unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   463   unsigned char * load, * t, * data, * d;
   464   Uint32 reallen;
   465   int i, size, count, j, length;
   466   unsigned char val;
   467 
   468   t = load = (char *) malloc (len);
   469   reallen = SDL_RWread (src, t, 1, len);
   470 
   471   data = (char *) malloc (x*y*bpp);
   472   for (i = 0; i < bpp; i++) {
   473     d    = data + i;
   474     size = x*y;
   475     count = 0;
   476  
   477     while (size > 0) {
   478       val = *t++;
   479 
   480       length = val;
   481       if (length >= 128) {
   482 	length = 255 - (length - 1);
   483 	if (length == 128) {
   484 	  length = (*t << 8) + t[1];
   485 	  t += 2;
   486 	}
   487 
   488 	count += length;
   489 	size -= length;
   490 
   491 	while (length-- > 0) {
   492 	  *d = *t++;
   493 	  d += bpp;
   494 	}
   495       }
   496       else {
   497 	length += 1;
   498 	if (length == 128) {
   499 	  length = (*t << 8) + t[1];
   500 	  t += 2;
   501 	}
   502 
   503 	count += length;
   504 	size -= length;
   505 
   506 	val = *t++;
   507 
   508 	for (j = 0; j < length; j++) {
   509 	  *d = val;
   510 	  d += bpp;
   511 	}
   512       }
   513     }
   514   }
   515 
   516   free (load);
   517   return (data);
   518 }
   519 
   520 static Uint32 rgb2grey (Uint32 a) {
   521   Uint8 l;
   522   l = 0.2990 * ((a && 0x00FF0000) >> 16)
   523     + 0.5870 * ((a && 0x0000FF00) >>  8)
   524     + 0.1140 * ((a && 0x000000FF));
   525 
   526   return (l << 16) | (l << 8) | l;
   527 }
   528 
   529 void create_channel_surface (SDL_Surface * surf, xcf_image_type itype, Uint32 color, Uint32 opacity) {
   530   Uint32 c = 0;
   531 
   532   switch (itype) {
   533   case IMAGE_RGB:
   534   case IMAGE_INDEXED:
   535     c = opacity | color;
   536     break;
   537   case IMAGE_GREYSCALE:
   538     c = opacity | rgb2grey (color);
   539     break;
   540   }
   541   SDL_FillRect (surf, NULL, c);
   542 }
   543 
   544 int do_layer_surface (SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_layer * layer, load_tile_type load_tile) {
   545   xcf_hierarchy * hierarchy;
   546   xcf_level     * level;
   547   unsigned char * tile;
   548   Uint8  * p8;
   549   Uint16 * p16;
   550   Uint32 * p;
   551   int x, y, tx, ty, ox, oy, i, j;
   552   Uint32 *row;
   553 
   554   SDL_RWseek (src, layer->hierarchy_file_offset, SEEK_SET);
   555   hierarchy = read_xcf_hierarchy (src);
   556 
   557   level = NULL;
   558   for (i = 0; hierarchy->level_file_offsets [i]; i++) {
   559     SDL_RWseek (src, hierarchy->level_file_offsets [i], SEEK_SET);
   560     level = read_xcf_level (src);
   561 
   562     ty = tx = 0;
   563     for (j = 0; level->tile_file_offsets [j]; j++) {
   564       SDL_RWseek (src, level->tile_file_offsets [j], SEEK_SET);
   565       ox = tx+64 > level->width ? level->width % 64 : 64;
   566       oy = ty+64 > level->height ? level->height % 64 : 64;
   567 
   568       if (level->tile_file_offsets [j+1]) {
   569 	tile = load_tile
   570 	  (src,
   571 	   level->tile_file_offsets [j+1] - level->tile_file_offsets [j],
   572 	   hierarchy->bpp,
   573 	   ox, oy);
   574       }
   575       else {
   576 	tile = load_tile
   577 	  (src,
   578 	   ox*oy*6,
   579 	   hierarchy->bpp,
   580 	   ox, oy);
   581       }
   582 
   583       p8  = tile;
   584       p16 = (Uint16 *) p8;
   585       p   = (Uint32 *) p8;
   586       for (y=ty; y < ty+oy; y++) {
   587 	row = (Uint32 *)((Uint8 *)surface->pixels + y*surface->pitch + tx*4);
   588 	switch (hierarchy->bpp) {
   589 	case 4:
   590 	  for (x=tx; x < tx+ox; x++)
   591 	    *row++ = Swap32 (*p++);
   592 	  break;
   593 	case 3:
   594 	  for (x=tx; x < tx+ox; x++) {
   595 	    *row = 0xFF000000;
   596 	    *row |= ((Uint32) *(p8++) << 16);
   597 	    *row |= ((Uint32) *(p8++) << 8);
   598 	    *row |= ((Uint32) *(p8++) << 0);
   599 	    row++;
   600 	  }
   601 	  break;
   602 	case 2: // Indexed/Greyscale + Alpha
   603 	  switch (head->image_type) {
   604 	  case IMAGE_INDEXED:
   605 	    for (x=tx; x < tx+ox; x++) {
   606 	      *row =  ((Uint32) (head->cm_map [*p8*3])     << 16);
   607 	      *row |= ((Uint32) (head->cm_map [*p8*3+1])   << 8);
   608 	      *row |= ((Uint32) (head->cm_map [*p8++*3+2]) << 0);
   609 	      *row |= ((Uint32) *p8++ << 24);;
   610 	      row++;
   611 	    }
   612 	    break;
   613 	  case IMAGE_GREYSCALE:
   614 	    for (x=tx; x < tx+ox; x++) {
   615 	      *row = ((Uint32) *p8 << 16);
   616 	      *row |= ((Uint32) *p8 << 8);
   617 	      *row |= ((Uint32) *p8++ << 0);
   618 	      *row |= ((Uint32) *p8++ << 24);;
   619 	      row++;
   620 	    }
   621 	    break;	    
   622 	  default:
   623 	    fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
   624 	    return 1;
   625 	  }
   626 	  break;
   627 	case 1: // Indexed/Greyscale
   628 	  switch (head->image_type) {
   629 	  case IMAGE_INDEXED:
   630 	    for (x = tx; x < tx+ox; x++) {
   631 	      *row++ = 0xFF000000
   632 		| ((Uint32) (head->cm_map [*p8*3]) << 16)
   633 		| ((Uint32) (head->cm_map [*p8*3+1]) << 8)
   634 		| ((Uint32) (head->cm_map [*p8*3+2]) << 0);
   635 	      p8++;
   636 	    }
   637 	    break;
   638 	  case IMAGE_GREYSCALE:
   639 	    for (x=tx; x < tx+ox; x++) {
   640 	      *row++ = 0xFF000000
   641 		| (((Uint32) (*p8)) << 16)
   642 		| (((Uint32) (*p8)) << 8)
   643 		| (((Uint32) (*p8++)) << 0);
   644 	    }
   645 	    break;	    
   646 	  default:
   647 	    fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
   648 	    return 1;
   649 	  }
   650 	  break;
   651 	}
   652       }
   653       tx += 64;
   654       if (tx >= level->width) {
   655 	tx = 0;
   656 	ty += 64;
   657       }
   658       if (ty >= level->height) {
   659 	break;
   660       }
   661 
   662       free_xcf_tile (tile);
   663     }
   664     free_xcf_level (level);
   665   }
   666 
   667   free_xcf_hierarchy (hierarchy);
   668   
   669   return 0;
   670 }
   671 
   672 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   673 {
   674   int start;
   675   const char *error = NULL;
   676   SDL_Surface *surface, *lays;
   677   xcf_header * head;
   678   xcf_layer  * layer;
   679   xcf_channel ** channel;
   680   int chnls, i, offsets;
   681   Uint32 offset, fp;
   682 
   683   unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int);
   684 
   685   if ( !src ) {
   686     /* The error message has been set in SDL_RWFromFile */
   687     return NULL;
   688   }
   689   start = SDL_RWtell(src);
   690 
   691   /* Initialize the data we will clean up when we're done */
   692   surface = NULL;
   693 
   694   head = read_xcf_header (src);
   695 
   696   switch (head->compr) {
   697   case COMPR_NONE:
   698     load_tile = load_xcf_tile_none;
   699     break;
   700   case COMPR_RLE:
   701     load_tile = load_xcf_tile_rle;
   702     break;
   703   default:
   704     fprintf (stderr, "Unsupported Compression.\n");
   705     free_xcf_header (head);
   706     return NULL;
   707   }
   708 
   709   /* Create the surface of the appropriate type */
   710   surface = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
   711 			     0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   712 
   713   if ( surface == NULL ) {
   714     error = "Out of memory";
   715     goto done;
   716   }
   717 
   718   head->layer_file_offsets = NULL;
   719   offsets = 0;
   720 
   721   while ((offset = SDL_ReadBE32 (src))) {
   722     head->layer_file_offsets = (Uint32 *) realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1));
   723     head->layer_file_offsets [offsets] = offset;
   724     offsets++;
   725   }
   726   fp = SDL_RWtell (src);
   727  
   728   lays = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
   729 			  0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   730 
   731   if ( lays == NULL ) {
   732     error = "Out of memory";
   733     goto done;
   734   }
   735 
   736   // Blit layers backwards, because Gimp saves them highest first
   737   for (i = offsets; i > 0; i--) {
   738     SDL_Rect rs, rd;
   739     SDL_RWseek (src, head->layer_file_offsets [i-1], SEEK_SET);
   740 
   741     layer = read_xcf_layer (src);
   742     do_layer_surface (lays, src, head, layer, load_tile);
   743     rs.x = 0;
   744     rs.y = 0;
   745     rs.w = layer->width;
   746     rs.h = layer->height;
   747     rd.x = layer->offset_x;
   748     rd.y = layer->offset_y;
   749     rd.w = layer->width;
   750     rd.h = layer->height;
   751 
   752     if (layer->visible)
   753       SDL_BlitSurface (lays, &rs, surface, &rd);
   754     free_xcf_layer (layer);
   755   }
   756 
   757   SDL_FreeSurface (lays);
   758 
   759   SDL_RWseek (src, fp, SEEK_SET);
   760 
   761   // read channels
   762   channel = NULL;
   763   chnls   = 0;
   764   while ((offset = SDL_ReadBE32 (src))) {
   765     channel = (xcf_channel **) realloc (channel, sizeof (xcf_channel *) * (chnls+1));
   766     fp = SDL_RWtell (src);
   767     SDL_RWseek (src, offset, SEEK_SET);
   768     channel [chnls++] = (read_xcf_channel (src));
   769     SDL_RWseek (src, fp, SEEK_SET);    
   770   }
   771 
   772   if (chnls) {
   773     SDL_Surface * chs;
   774 
   775     chs = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
   776 			   0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   777 
   778     if (chs == NULL) {
   779       error = "Out of memory";
   780       goto done;
   781     }
   782     for (i = 0; i < chnls; i++) {
   783       //      printf ("CNLBLT %i\n", i);
   784       if (!channel [i]->selection && channel [i]->visible) {
   785 	create_channel_surface (chs, head->image_type, channel [i]->color, channel [i]->opacity);
   786 	SDL_BlitSurface (chs, NULL, surface, NULL);
   787       }
   788       free_xcf_channel (channel [i]);
   789     }
   790 
   791     SDL_FreeSurface (chs);
   792   }
   793 
   794 done:
   795   free_xcf_header (head);
   796   if ( error ) {
   797     SDL_RWseek(src, start, SEEK_SET);
   798     if ( surface ) {
   799       SDL_FreeSurface(surface);
   800       surface = NULL;
   801     }
   802     IMG_SetError(error);
   803   }
   804 
   805   return(surface);
   806 }
   807 
   808 #else
   809 
   810 /* See if an image is contained in a data source */
   811 int IMG_isXCF(SDL_RWops *src)
   812 {
   813   return(0);
   814 }
   815 
   816 /* Load a XCF type image from an SDL datasource */
   817 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   818 {
   819   return(NULL);
   820 }
   821 
   822 #endif /* LOAD_XCF */