IMG_xcf.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 04 Feb 2006 22:26:04 +0000
changeset 118 c5e736a47ad2
parent 117 e613cf987897
child 121 1bf9c0c87374
permissions -rw-r--r--
If there's an error loading an image, seek back to the start of the image.
     1 /*
     2     SDL_image:  An example image loading library for use with SDL
     3     Copyright (C) 1999-2004 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     slouken@libsdl.org
    21 */
    22 
    23 /* $Id$ */
    24 
    25 /* This is a XCF image file loading framework */
    26 
    27 #include <stdio.h>
    28 #include <ctype.h>
    29 #include <string.h>
    30 #include <stdlib.h>
    31 
    32 #include "SDL_endian.h"
    33 #include "SDL_image.h"
    34 
    35 #ifdef LOAD_XCF
    36 
    37 #if DEBUG
    38 static char prop_names [][30] = {
    39   "end",
    40   "colormap",
    41   "active_layer",
    42   "active_channel",
    43   "selection",
    44   "floating_selection",
    45   "opacity",
    46   "mode",
    47   "visible",
    48   "linked",
    49   "preserve_transparency",
    50   "apply_mask",
    51   "edit_mask",
    52   "show_mask",
    53   "show_masked",
    54   "offsets",
    55   "color",
    56   "compression",
    57   "guides",
    58   "resolution",
    59   "tattoo",
    60   "parasites",
    61   "unit",
    62   "paths",
    63   "user_unit"
    64 };
    65 #endif
    66 
    67 
    68 typedef enum
    69 {
    70   PROP_END = 0,
    71   PROP_COLORMAP = 1,
    72   PROP_ACTIVE_LAYER = 2,
    73   PROP_ACTIVE_CHANNEL = 3,
    74   PROP_SELECTION = 4,
    75   PROP_FLOATING_SELECTION = 5,
    76   PROP_OPACITY = 6,
    77   PROP_MODE = 7,
    78   PROP_VISIBLE = 8,
    79   PROP_LINKED = 9,
    80   PROP_PRESERVE_TRANSPARENCY = 10,
    81   PROP_APPLY_MASK = 11,
    82   PROP_EDIT_MASK = 12,
    83   PROP_SHOW_MASK = 13,
    84   PROP_SHOW_MASKED = 14,
    85   PROP_OFFSETS = 15,
    86   PROP_COLOR = 16,
    87   PROP_COMPRESSION = 17,
    88   PROP_GUIDES = 18,
    89   PROP_RESOLUTION = 19,
    90   PROP_TATTOO = 20,
    91   PROP_PARASITES = 21,
    92   PROP_UNIT = 22,
    93   PROP_PATHS = 23,
    94   PROP_USER_UNIT = 24
    95 } xcf_prop_type;
    96 
    97 typedef enum {
    98   COMPR_NONE    = 0,
    99   COMPR_RLE     = 1,
   100   COMPR_ZLIB    = 2,
   101   COMPR_FRACTAL = 3
   102 } xcf_compr_type;
   103 
   104 typedef enum {
   105   IMAGE_RGB       = 0,
   106   IMAGE_GREYSCALE = 1,
   107   IMAGE_INDEXED   = 2
   108 } xcf_image_type;
   109 
   110 typedef struct {
   111   Uint32 id;
   112   Uint32 length;
   113   union {
   114     struct {
   115       Uint32 num;
   116       char * cmap;
   117     } colormap; // 1
   118     struct {
   119       Uint32 drawable_offset;
   120     } floating_selection; // 5
   121     Sint32 opacity;
   122     Sint32 mode;
   123     int    visible;
   124     int    linked;
   125     int    preserve_transparency;
   126     int    apply_mask;
   127     int    show_mask;
   128     struct {
   129       Sint32 x;
   130       Sint32 y;
   131     } offset;
   132     unsigned char color [3];
   133     Uint8 compression;
   134     struct {
   135       Sint32 x;
   136       Sint32 y;
   137     } resolution;
   138     struct {
   139       char * name;
   140       Uint32 flags;
   141       Uint32 size;
   142       char * data;
   143     } parasite;
   144   } data;
   145 } xcf_prop;
   146 
   147 typedef struct {
   148   char   sign [14];
   149   Uint32 width;
   150   Uint32 height;
   151   Sint32 image_type;
   152   xcf_prop * properties;
   153 
   154   Uint32 * layer_file_offsets;
   155   Uint32 * channel_file_offsets;
   156 
   157   xcf_compr_type compr;
   158   Uint32         cm_num;
   159   unsigned char * cm_map;
   160 } xcf_header;
   161 
   162 typedef struct {
   163   Uint32 width;
   164   Uint32 height;
   165   Sint32 layer_type;
   166   char * name;
   167   xcf_prop * properties;
   168 
   169   Uint32 hierarchy_file_offset;
   170   Uint32 layer_mask_offset;
   171 
   172   Uint32 offset_x;
   173   Uint32 offset_y;
   174   int visible;
   175 } xcf_layer;
   176 
   177 typedef struct {
   178   Uint32 width;
   179   Uint32 height;
   180   char * name;
   181   xcf_prop * properties;
   182 
   183   Uint32 hierarchy_file_offset;
   184 
   185   Uint32 color;
   186   Uint32 opacity;
   187   int selection;
   188   int visible;
   189 } xcf_channel;
   190 
   191 typedef struct {
   192   Uint32 width;
   193   Uint32 height;
   194   Uint32 bpp;
   195 
   196   Uint32 * level_file_offsets;
   197 } xcf_hierarchy;
   198 
   199 typedef struct {
   200   Uint32 width;
   201   Uint32 height;
   202 
   203   Uint32 * tile_file_offsets;
   204 } xcf_level;
   205 
   206 typedef unsigned char * xcf_tile;
   207 
   208 typedef unsigned char * (* load_tile_type) (SDL_RWops *, Uint32, int, int, int);
   209 
   210 
   211 /* See if an image is contained in a data source */
   212 int IMG_isXCF(SDL_RWops *src)
   213 {
   214 	int start;
   215 	int is_XCF;
   216 	char magic[14];
   217 
   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, 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 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, SEEK_CUR);
   286   }
   287 }
   288 
   289 void free_xcf_header (xcf_header * h) {
   290   if (h->cm_num)
   291     free (h->cm_map);
   292 
   293   free (h);
   294 }
   295 
   296 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 = (char *) malloc (sizeof (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 void free_xcf_layer (xcf_layer * l) {
   330   free (l->name);
   331   free (l);
   332 }
   333 
   334 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 void free_xcf_channel (xcf_channel * c) {
   362   free (c->name);
   363   free (c);
   364 }
   365 
   366 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 void free_xcf_hierarchy (xcf_hierarchy * h) {
   405   free (h->level_file_offsets);
   406   free (h);
   407 }
   408 
   409 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 void free_xcf_level (xcf_level * l) {
   429   free (l->tile_file_offsets);
   430   free (l);
   431 }
   432 
   433 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 void free_xcf_tile (unsigned char * t) {
   452   free (t);
   453 }
   454 
   455 unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   456   unsigned char * load;
   457 
   458   load = (char *) malloc (len); // expect this is okay
   459   SDL_RWread (src, load, len, 1);
   460 
   461   return load;
   462 }
   463 
   464 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 = (char *) malloc (len);
   471   reallen = SDL_RWread (src, t, 1, len);
   472 
   473   data = (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 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 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, 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], 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], 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 	    }
   647 	    break;	    
   648 	  default:
   649 	    fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
   650 	    return 1;
   651 	  }
   652 	  break;
   653 	}
   654       }
   655       tx += 64;
   656       if (tx >= level->width) {
   657 	tx = 0;
   658 	ty += 64;
   659       }
   660       if (ty >= level->height) {
   661 	break;
   662       }
   663 
   664       free_xcf_tile (tile);
   665     }
   666     free_xcf_level (level);
   667   }
   668 
   669   free_xcf_hierarchy (hierarchy);
   670   
   671   return 0;
   672 }
   673 
   674 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   675 {
   676   int start;
   677   const char *error = NULL;
   678   SDL_Surface *surface, *lays;
   679   xcf_header * head;
   680   xcf_layer  * layer;
   681   xcf_channel ** channel;
   682   int chnls, i, offsets;
   683   Uint32 offset, fp;
   684 
   685   unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int);
   686 
   687   if ( !src ) {
   688     /* The error message has been set in SDL_RWFromFile */
   689     return NULL;
   690   }
   691   start = SDL_RWtell(src);
   692 
   693   /* Initialize the data we will clean up when we're done */
   694   surface = NULL;
   695 
   696   head = read_xcf_header (src);
   697 
   698   switch (head->compr) {
   699   case COMPR_NONE:
   700     load_tile = load_xcf_tile_none;
   701     break;
   702   case COMPR_RLE:
   703     load_tile = load_xcf_tile_rle;
   704     break;
   705   default:
   706     fprintf (stderr, "Unsupported Compression.\n");
   707     free_xcf_header (head);
   708     return NULL;
   709   }
   710 
   711   /* Create the surface of the appropriate type */
   712   surface = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
   713 			     0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   714 
   715   if ( surface == NULL ) {
   716     error = "Out of memory";
   717     goto done;
   718   }
   719 
   720   head->layer_file_offsets = NULL;
   721   offsets = 0;
   722 
   723   while ((offset = SDL_ReadBE32 (src))) {
   724     head->layer_file_offsets = (Uint32 *) realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1));
   725     head->layer_file_offsets [offsets] = offset;
   726     offsets++;
   727   }
   728   fp = SDL_RWtell (src);
   729  
   730   lays = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
   731 			  0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   732 
   733   if ( lays == NULL ) {
   734     error = "Out of memory";
   735     goto done;
   736   }
   737 
   738   // Blit layers backwards, because Gimp saves them highest first
   739   for (i = offsets; i > 0; i--) {
   740     SDL_Rect rs, rd;
   741     SDL_RWseek (src, head->layer_file_offsets [i-1], SEEK_SET);
   742 
   743     layer = read_xcf_layer (src);
   744     do_layer_surface (lays, src, head, layer, load_tile);
   745     rs.x = 0;
   746     rs.y = 0;
   747     rs.w = layer->width;
   748     rs.h = layer->height;
   749     rd.x = layer->offset_x;
   750     rd.y = layer->offset_y;
   751     rd.w = layer->width;
   752     rd.h = layer->height;
   753 
   754     if (layer->visible)
   755       SDL_BlitSurface (lays, &rs, surface, &rd);
   756     free_xcf_layer (layer);
   757   }
   758 
   759   SDL_FreeSurface (lays);
   760 
   761   SDL_RWseek (src, fp, SEEK_SET);
   762 
   763   // read channels
   764   channel = NULL;
   765   chnls   = 0;
   766   while ((offset = SDL_ReadBE32 (src))) {
   767     channel = (xcf_channel **) realloc (channel, sizeof (xcf_channel *) * (chnls+1));
   768     fp = SDL_RWtell (src);
   769     SDL_RWseek (src, offset, SEEK_SET);
   770     channel [chnls++] = (read_xcf_channel (src));
   771     SDL_RWseek (src, fp, SEEK_SET);    
   772   }
   773 
   774   if (chnls) {
   775     SDL_Surface * chs;
   776 
   777     chs = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
   778 			   0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   779 
   780     if (chs == NULL) {
   781       error = "Out of memory";
   782       goto done;
   783     }
   784     for (i = 0; i < chnls; i++) {
   785       //      printf ("CNLBLT %i\n", i);
   786       if (!channel [i]->selection && channel [i]->visible) {
   787 	create_channel_surface (chs, head->image_type, channel [i]->color, channel [i]->opacity);
   788 	SDL_BlitSurface (chs, NULL, surface, NULL);
   789       }
   790       free_xcf_channel (channel [i]);
   791     }
   792 
   793     SDL_FreeSurface (chs);
   794   }
   795 
   796 done:
   797   free_xcf_header (head);
   798   if ( error ) {
   799     SDL_RWseek(src, start, SEEK_SET);
   800     if ( surface ) {
   801       SDL_FreeSurface(surface);
   802       surface = NULL;
   803     }
   804     IMG_SetError(error);
   805   }
   806 
   807   return(surface);
   808 }
   809 
   810 #else
   811 
   812 /* See if an image is contained in a data source */
   813 int IMG_isXCF(SDL_RWops *src)
   814 {
   815   return(0);
   816 }
   817 
   818 /* Load a XCF type image from an SDL datasource */
   819 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   820 {
   821   return(NULL);
   822 }
   823 
   824 #endif /* LOAD_XCF */