IMG_xcf.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 22 Jan 2012 21:52:00 -0500
changeset 320 aa5d55b11751
parent 280 ec4ae96c100c
child 343 5bf0f0d6a74e
permissions -rw-r--r--
Updated for SDL 2.0
     1 /*
     2   SDL_image:  An example image loading library for use with SDL
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 /* This is a XCF image file loading framework */
    23 
    24 #include <stdio.h>
    25 #include <ctype.h>
    26 #include <string.h>
    27 #include <stdlib.h>
    28 
    29 #include "SDL_endian.h"
    30 #include "SDL_image.h"
    31 
    32 #ifdef LOAD_XCF
    33 
    34 #if DEBUG
    35 static char prop_names [][30] = {
    36   "end",
    37   "colormap",
    38   "active_layer",
    39   "active_channel",
    40   "selection",
    41   "floating_selection",
    42   "opacity",
    43   "mode",
    44   "visible",
    45   "linked",
    46   "preserve_transparency",
    47   "apply_mask",
    48   "edit_mask",
    49   "show_mask",
    50   "show_masked",
    51   "offsets",
    52   "color",
    53   "compression",
    54   "guides",
    55   "resolution",
    56   "tattoo",
    57   "parasites",
    58   "unit",
    59   "paths",
    60   "user_unit"
    61 };
    62 #endif
    63 
    64 
    65 typedef enum
    66 {
    67   PROP_END = 0,
    68   PROP_COLORMAP = 1,
    69   PROP_ACTIVE_LAYER = 2,
    70   PROP_ACTIVE_CHANNEL = 3,
    71   PROP_SELECTION = 4,
    72   PROP_FLOATING_SELECTION = 5,
    73   PROP_OPACITY = 6,
    74   PROP_MODE = 7,
    75   PROP_VISIBLE = 8,
    76   PROP_LINKED = 9,
    77   PROP_PRESERVE_TRANSPARENCY = 10,
    78   PROP_APPLY_MASK = 11,
    79   PROP_EDIT_MASK = 12,
    80   PROP_SHOW_MASK = 13,
    81   PROP_SHOW_MASKED = 14,
    82   PROP_OFFSETS = 15,
    83   PROP_COLOR = 16,
    84   PROP_COMPRESSION = 17,
    85   PROP_GUIDES = 18,
    86   PROP_RESOLUTION = 19,
    87   PROP_TATTOO = 20,
    88   PROP_PARASITES = 21,
    89   PROP_UNIT = 22,
    90   PROP_PATHS = 23,
    91   PROP_USER_UNIT = 24
    92 } xcf_prop_type;
    93 
    94 typedef enum {
    95   COMPR_NONE    = 0,
    96   COMPR_RLE     = 1,
    97   COMPR_ZLIB    = 2,
    98   COMPR_FRACTAL = 3
    99 } xcf_compr_type;
   100 
   101 typedef enum {
   102   IMAGE_RGB       = 0,
   103   IMAGE_GREYSCALE = 1,
   104   IMAGE_INDEXED   = 2
   105 } xcf_image_type;
   106 
   107 typedef struct {
   108   Uint32 id;
   109   Uint32 length;
   110   union {
   111     struct {
   112       Uint32 num;
   113       char * cmap;
   114     } colormap; // 1
   115     struct {
   116       Uint32 drawable_offset;
   117     } floating_selection; // 5
   118     Sint32 opacity;
   119     Sint32 mode;
   120     int    visible;
   121     int    linked;
   122     int    preserve_transparency;
   123     int    apply_mask;
   124     int    show_mask;
   125     struct {
   126       Sint32 x;
   127       Sint32 y;
   128     } offset;
   129     unsigned char color [3];
   130     Uint8 compression;
   131     struct {
   132       Sint32 x;
   133       Sint32 y;
   134     } resolution;
   135     struct {
   136       char * name;
   137       Uint32 flags;
   138       Uint32 size;
   139       char * data;
   140     } parasite;
   141   } data;
   142 } xcf_prop;
   143 
   144 typedef struct {
   145   char   sign [14];
   146   Uint32 width;
   147   Uint32 height;
   148   Sint32 image_type;
   149   xcf_prop * properties;
   150 
   151   Uint32 * layer_file_offsets;
   152   Uint32 * channel_file_offsets;
   153 
   154   xcf_compr_type compr;
   155   Uint32         cm_num;
   156   unsigned char * cm_map;
   157 } xcf_header;
   158 
   159 typedef struct {
   160   Uint32 width;
   161   Uint32 height;
   162   Sint32 layer_type;
   163   char * name;
   164   xcf_prop * properties;
   165 
   166   Uint32 hierarchy_file_offset;
   167   Uint32 layer_mask_offset;
   168 
   169   Uint32 offset_x;
   170   Uint32 offset_y;
   171   int visible;
   172 } xcf_layer;
   173 
   174 typedef struct {
   175   Uint32 width;
   176   Uint32 height;
   177   char * name;
   178   xcf_prop * properties;
   179 
   180   Uint32 hierarchy_file_offset;
   181 
   182   Uint32 color;
   183   Uint32 opacity;
   184   int selection;
   185   int visible;
   186 } xcf_channel;
   187 
   188 typedef struct {
   189   Uint32 width;
   190   Uint32 height;
   191   Uint32 bpp;
   192 
   193   Uint32 * level_file_offsets;
   194 } xcf_hierarchy;
   195 
   196 typedef struct {
   197   Uint32 width;
   198   Uint32 height;
   199 
   200   Uint32 * tile_file_offsets;
   201 } xcf_level;
   202 
   203 typedef unsigned char * xcf_tile;
   204 
   205 typedef unsigned char * (* load_tile_type) (SDL_RWops *, Uint32, int, int, int);
   206 
   207 
   208 /* See if an image is contained in a data source */
   209 int IMG_isXCF(SDL_RWops *src)
   210 {
   211 	int start;
   212 	int is_XCF;
   213 	char magic[14];
   214 
   215 	if ( !src )
   216 		return 0;
   217 	start = SDL_RWtell(src);
   218 	is_XCF = 0;
   219 	if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
   220 		if (strncmp(magic, "gimp xcf ", 9) == 0) {
   221 			is_XCF = 1;
   222 		}
   223 	}
   224 	SDL_RWseek(src, start, RW_SEEK_SET);
   225 	return(is_XCF);
   226 }
   227 
   228 static char * read_string (SDL_RWops * src) {
   229   Uint32 tmp;
   230   char * data;
   231 
   232   tmp = SDL_ReadBE32 (src);
   233   if (tmp > 0) {
   234     data = (char *) malloc (sizeof (char) * tmp);
   235     SDL_RWread (src, data, tmp, 1);
   236   }
   237   else {
   238     data = NULL;
   239   }
   240 
   241   return data;
   242 }
   243 
   244 
   245 static Uint32 Swap32 (Uint32 v) {
   246   return
   247     ((v & 0x000000FF) << 16)
   248     |  ((v & 0x0000FF00))
   249     |  ((v & 0x00FF0000) >> 16)
   250     |  ((v & 0xFF000000));
   251 }
   252 
   253 static void xcf_read_property (SDL_RWops * src, xcf_prop * prop) {
   254   prop->id = SDL_ReadBE32 (src);
   255   prop->length = SDL_ReadBE32 (src);
   256 
   257 #if DEBUG
   258   printf ("%.8X: %s: %d\n", SDL_RWtell (src), prop->id < 25 ? prop_names [prop->id] : "unknown", prop->length);
   259 #endif
   260 
   261   switch (prop->id) {
   262   case PROP_COLORMAP:
   263     prop->data.colormap.num = SDL_ReadBE32 (src);
   264     prop->data.colormap.cmap = (char *) malloc (sizeof (char) * prop->data.colormap.num * 3);
   265     SDL_RWread (src, prop->data.colormap.cmap, prop->data.colormap.num*3, 1);
   266     break;
   267 
   268   case PROP_OFFSETS:
   269     prop->data.offset.x = SDL_ReadBE32 (src);
   270     prop->data.offset.y = SDL_ReadBE32 (src);
   271     break;
   272   case PROP_OPACITY:
   273     prop->data.opacity = SDL_ReadBE32 (src);
   274     break;
   275   case PROP_COMPRESSION:
   276   case PROP_COLOR:
   277     SDL_RWread (src, &prop->data, prop->length, 1);
   278     break;
   279   case PROP_VISIBLE:
   280     prop->data.visible = SDL_ReadBE32 (src);
   281     break;
   282   default:
   283     //    SDL_RWread (src, &prop->data, prop->length, 1);
   284     SDL_RWseek (src, prop->length, RW_SEEK_CUR);
   285   }
   286 }
   287 
   288 static void free_xcf_header (xcf_header * h) {
   289   if (h->cm_num)
   290     free (h->cm_map);
   291 
   292   free (h);
   293 }
   294 
   295 static xcf_header * read_xcf_header (SDL_RWops * src) {
   296   xcf_header * h;
   297   xcf_prop prop;
   298 
   299   h = (xcf_header *) malloc (sizeof (xcf_header));
   300   SDL_RWread (src, h->sign, 14, 1);
   301   h->width       = SDL_ReadBE32 (src);
   302   h->height      = SDL_ReadBE32 (src);
   303   h->image_type  = SDL_ReadBE32 (src);
   304 
   305   h->properties = NULL;
   306   h->compr      = COMPR_NONE;
   307   h->cm_num = 0;
   308   h->cm_map = NULL;
   309 
   310   // Just read, don't save
   311   do {
   312     xcf_read_property (src, &prop);
   313     if (prop.id == PROP_COMPRESSION)
   314       h->compr = prop.data.compression;
   315     else if (prop.id == PROP_COLORMAP) {
   316       // unused var: int i;
   317 
   318       h->cm_num = prop.data.colormap.num;
   319       h->cm_map = (unsigned char *) malloc (sizeof (unsigned char) * 3 * h->cm_num);
   320       memcpy (h->cm_map, prop.data.colormap.cmap, 3*sizeof (char)*h->cm_num);
   321       free (prop.data.colormap.cmap);
   322     }
   323   } while (prop.id != PROP_END);
   324 
   325   return h;
   326 }
   327 
   328 static void free_xcf_layer (xcf_layer * l) {
   329   free (l->name);
   330   free (l);
   331 }
   332 
   333 static xcf_layer * read_xcf_layer (SDL_RWops * src) {
   334   xcf_layer * l;
   335   xcf_prop    prop;
   336 
   337   l = (xcf_layer *) malloc (sizeof (xcf_layer));
   338   l->width  = SDL_ReadBE32 (src);
   339   l->height = SDL_ReadBE32 (src);
   340   l->layer_type = SDL_ReadBE32 (src);
   341 
   342   l->name = read_string (src);
   343 
   344   do {
   345     xcf_read_property (src, &prop);
   346     if (prop.id == PROP_OFFSETS) {
   347       l->offset_x = prop.data.offset.x;
   348       l->offset_y = prop.data.offset.y;
   349     } else if (prop.id == PROP_VISIBLE) {
   350       l->visible = prop.data.visible ? 1 : 0;
   351     }
   352   } while (prop.id != PROP_END);
   353 
   354   l->hierarchy_file_offset = SDL_ReadBE32 (src);
   355   l->layer_mask_offset     = SDL_ReadBE32 (src);
   356 
   357   return l;
   358 }
   359 
   360 static void free_xcf_channel (xcf_channel * c) {
   361   free (c->name);
   362   free (c);
   363 }
   364 
   365 static xcf_channel * read_xcf_channel (SDL_RWops * src) {
   366   xcf_channel * l;
   367   xcf_prop    prop;
   368 
   369   l = (xcf_channel *) malloc (sizeof (xcf_channel));
   370   l->width  = SDL_ReadBE32 (src);
   371   l->height = SDL_ReadBE32 (src);
   372 
   373   l->name = read_string (src);
   374 
   375   l->selection = 0;
   376   do {
   377     xcf_read_property (src, &prop);
   378     switch (prop.id) {
   379     case PROP_OPACITY:
   380       l->opacity = prop.data.opacity << 24;
   381       break;
   382     case PROP_COLOR:
   383       l->color = ((Uint32) prop.data.color[0] << 16)
   384 	| ((Uint32) prop.data.color[1] << 8)
   385 	| ((Uint32) prop.data.color[2]);
   386       break;
   387     case PROP_SELECTION:
   388       l->selection = 1;
   389       break;
   390     case PROP_VISIBLE:
   391       l->visible = prop.data.visible ? 1 : 0;
   392       break;
   393     default:
   394         ;
   395     }
   396   } while (prop.id != PROP_END);
   397 
   398   l->hierarchy_file_offset = SDL_ReadBE32 (src);
   399 
   400   return l;
   401 }
   402 
   403 static void free_xcf_hierarchy (xcf_hierarchy * h) {
   404   free (h->level_file_offsets);
   405   free (h);
   406 }
   407 
   408 static xcf_hierarchy * read_xcf_hierarchy (SDL_RWops * src) {
   409   xcf_hierarchy * h;
   410   int i;
   411 
   412   h = (xcf_hierarchy *) malloc (sizeof (xcf_hierarchy));
   413   h->width  = SDL_ReadBE32 (src);
   414   h->height = SDL_ReadBE32 (src);
   415   h->bpp    = SDL_ReadBE32 (src);
   416 
   417   h->level_file_offsets = NULL;
   418   i = 0;
   419   do {
   420     h->level_file_offsets = (Uint32 *) realloc (h->level_file_offsets, sizeof (Uint32) * (i+1));
   421     h->level_file_offsets [i] = SDL_ReadBE32 (src);
   422   } while (h->level_file_offsets [i++]);
   423 
   424   return h;
   425 }
   426 
   427 static void free_xcf_level (xcf_level * l) {
   428   free (l->tile_file_offsets);
   429   free (l);
   430 }
   431 
   432 static xcf_level * read_xcf_level (SDL_RWops * src) {
   433   xcf_level * l;
   434   int i;
   435 
   436   l = (xcf_level *) malloc (sizeof (xcf_level));
   437   l->width  = SDL_ReadBE32 (src);
   438   l->height = SDL_ReadBE32 (src);
   439 
   440   l->tile_file_offsets = NULL;
   441   i = 0;
   442   do {
   443     l->tile_file_offsets = (Uint32 *) realloc (l->tile_file_offsets, sizeof (Uint32) * (i+1));
   444     l->tile_file_offsets [i] = SDL_ReadBE32 (src);
   445   } while (l->tile_file_offsets [i++]);
   446 
   447   return l;
   448 }
   449 
   450 static void free_xcf_tile (unsigned char * t) {
   451   free (t);
   452 }
   453 
   454 static unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   455   unsigned char * load;
   456 
   457   load = (unsigned char *) malloc (len); // expect this is okay
   458   SDL_RWread (src, load, len, 1);
   459 
   460   return load;
   461 }
   462 
   463 static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   464   unsigned char * load, * t, * data, * d;
   465   Uint32 reallen;
   466   int i, size, count, j, length;
   467   unsigned char val;
   468 
   469   t = load = (unsigned char *) malloc (len);
   470   reallen = SDL_RWread (src, t, 1, len);
   471 
   472   data = (unsigned char *) malloc (x*y*bpp);
   473   for (i = 0; i < bpp; i++) {
   474     d    = data + i;
   475     size = x*y;
   476     count = 0;
   477  
   478     while (size > 0) {
   479       val = *t++;
   480 
   481       length = val;
   482       if (length >= 128) {
   483 	length = 255 - (length - 1);
   484 	if (length == 128) {
   485 	  length = (*t << 8) + t[1];
   486 	  t += 2;
   487 	}
   488 
   489 	count += length;
   490 	size -= length;
   491 
   492 	while (length-- > 0) {
   493 	  *d = *t++;
   494 	  d += bpp;
   495 	}
   496       }
   497       else {
   498 	length += 1;
   499 	if (length == 128) {
   500 	  length = (*t << 8) + t[1];
   501 	  t += 2;
   502 	}
   503 
   504 	count += length;
   505 	size -= length;
   506 
   507 	val = *t++;
   508 
   509 	for (j = 0; j < length; j++) {
   510 	  *d = val;
   511 	  d += bpp;
   512 	}
   513       }
   514     }
   515   }
   516 
   517   free (load);
   518   return (data);
   519 }
   520 
   521 static Uint32 rgb2grey (Uint32 a) {
   522   Uint8 l;
   523   l = 0.2990 * ((a && 0x00FF0000) >> 16)
   524     + 0.5870 * ((a && 0x0000FF00) >>  8)
   525     + 0.1140 * ((a && 0x000000FF));
   526 
   527   return (l << 16) | (l << 8) | l;
   528 }
   529 
   530 static void create_channel_surface (SDL_Surface * surf, xcf_image_type itype, Uint32 color, Uint32 opacity) {
   531   Uint32 c = 0;
   532 
   533   switch (itype) {
   534   case IMAGE_RGB:
   535   case IMAGE_INDEXED:
   536     c = opacity | color;
   537     break;
   538   case IMAGE_GREYSCALE:
   539     c = opacity | rgb2grey (color);
   540     break;
   541   }
   542   SDL_FillRect (surf, NULL, c);
   543 }
   544 
   545 static int do_layer_surface (SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_layer * layer, load_tile_type load_tile) {
   546   xcf_hierarchy * hierarchy;
   547   xcf_level     * level;
   548   unsigned char * tile;
   549   Uint8  * p8;
   550   Uint16 * p16;
   551   Uint32 * p;
   552   int x, y, tx, ty, ox, oy, i, j;
   553   Uint32 *row;
   554 
   555   SDL_RWseek (src, layer->hierarchy_file_offset, RW_SEEK_SET);
   556   hierarchy = read_xcf_hierarchy (src);
   557 
   558   level = NULL;
   559   for (i = 0; hierarchy->level_file_offsets [i]; i++) {
   560     SDL_RWseek (src, hierarchy->level_file_offsets [i], RW_SEEK_SET);
   561     level = read_xcf_level (src);
   562 
   563     ty = tx = 0;
   564     for (j = 0; level->tile_file_offsets [j]; j++) {
   565       SDL_RWseek (src, level->tile_file_offsets [j], RW_SEEK_SET);
   566       ox = tx+64 > level->width ? level->width % 64 : 64;
   567       oy = ty+64 > level->height ? level->height % 64 : 64;
   568 
   569       if (level->tile_file_offsets [j+1]) {
   570 	tile = load_tile
   571 	  (src,
   572 	   level->tile_file_offsets [j+1] - level->tile_file_offsets [j],
   573 	   hierarchy->bpp,
   574 	   ox, oy);
   575       }
   576       else {
   577 	tile = load_tile
   578 	  (src,
   579 	   ox*oy*6,
   580 	   hierarchy->bpp,
   581 	   ox, oy);
   582       }
   583 
   584       p8  = tile;
   585       p16 = (Uint16 *) p8;
   586       p   = (Uint32 *) p8;
   587       for (y=ty; y < ty+oy; y++) {
   588 	row = (Uint32 *)((Uint8 *)surface->pixels + y*surface->pitch + tx*4);
   589 	switch (hierarchy->bpp) {
   590 	case 4:
   591 	  for (x=tx; x < tx+ox; x++)
   592 	    *row++ = Swap32 (*p++);
   593 	  break;
   594 	case 3:
   595 	  for (x=tx; x < tx+ox; x++) {
   596 	    *row = 0xFF000000;
   597 	    *row |= ((Uint32) *(p8++) << 16);
   598 	    *row |= ((Uint32) *(p8++) << 8);
   599 	    *row |= ((Uint32) *(p8++) << 0);
   600 	    row++;
   601 	  }
   602 	  break;
   603 	case 2: // Indexed/Greyscale + Alpha
   604 	  switch (head->image_type) {
   605 	  case IMAGE_INDEXED:
   606 	    for (x=tx; x < tx+ox; x++) {
   607 	      *row =  ((Uint32) (head->cm_map [*p8*3])     << 16);
   608 	      *row |= ((Uint32) (head->cm_map [*p8*3+1])   << 8);
   609 	      *row |= ((Uint32) (head->cm_map [*p8++*3+2]) << 0);
   610 	      *row |= ((Uint32) *p8++ << 24);;
   611 	      row++;
   612 	    }
   613 	    break;
   614 	  case IMAGE_GREYSCALE:
   615 	    for (x=tx; x < tx+ox; x++) {
   616 	      *row = ((Uint32) *p8 << 16);
   617 	      *row |= ((Uint32) *p8 << 8);
   618 	      *row |= ((Uint32) *p8++ << 0);
   619 	      *row |= ((Uint32) *p8++ << 24);;
   620 	      row++;
   621 	    }
   622 	    break;	    
   623 	  default:
   624 	    fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
   625 	    return 1;
   626 	  }
   627 	  break;
   628 	case 1: // Indexed/Greyscale
   629 	  switch (head->image_type) {
   630 	  case IMAGE_INDEXED:
   631 	    for (x = tx; x < tx+ox; x++) {
   632 	      *row++ = 0xFF000000
   633 		| ((Uint32) (head->cm_map [*p8*3]) << 16)
   634 		| ((Uint32) (head->cm_map [*p8*3+1]) << 8)
   635 		| ((Uint32) (head->cm_map [*p8*3+2]) << 0);
   636 	      p8++;
   637 	    }
   638 	    break;
   639 	  case IMAGE_GREYSCALE:
   640 	    for (x=tx; x < tx+ox; x++) {
   641 	      *row++ = 0xFF000000
   642 		| (((Uint32) (*p8)) << 16)
   643 		| (((Uint32) (*p8)) << 8)
   644 		| (((Uint32) (*p8)) << 0);
   645 			++p8;
   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_CreateRGBSurface(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_CreateRGBSurface(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], RW_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, RW_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, RW_SEEK_SET);
   770     channel [chnls++] = (read_xcf_channel (src));
   771     SDL_RWseek (src, fp, RW_SEEK_SET);    
   772   }
   773 
   774   if (chnls) {
   775     SDL_Surface * chs;
   776 
   777     chs = SDL_CreateRGBSurface(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, RW_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 */