IMG_xcf.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 15 Feb 2013 14:47:06 -0800
changeset 347 ad5034cad524
parent 343 5bf0f0d6a74e
child 365 ce8091caddf3
permissions -rw-r--r--
Updated copyright year
     1 /*
     2   SDL_image:  An example image loading library for use with SDL
     3   Copyright (C) 1997-2013 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 	Sint64 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 (SDL_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 = (xcf_compr_type)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 *) SDL_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 *) SDL_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 *) SDL_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 *) SDL_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 *) SDL_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 *) SDL_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   SDL_free (load);
   518   return (data);
   519 }
   520 
   521 static Uint32 rgb2grey (Uint32 a) {
   522   Uint8 l;
   523   l = (Uint8)(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 i, j;
   553   Uint32 x, y, tx, ty, ox, oy;
   554   Uint32 *row;
   555 
   556   SDL_RWseek (src, layer->hierarchy_file_offset, RW_SEEK_SET);
   557   hierarchy = read_xcf_hierarchy (src);
   558 
   559   level = NULL;
   560   for (i = 0; hierarchy->level_file_offsets [i]; i++) {
   561     SDL_RWseek (src, hierarchy->level_file_offsets [i], RW_SEEK_SET);
   562     level = read_xcf_level (src);
   563 
   564     ty = tx = 0;
   565     for (j = 0; level->tile_file_offsets [j]; j++) {
   566       SDL_RWseek (src, level->tile_file_offsets [j], RW_SEEK_SET);
   567       ox = tx+64 > level->width ? level->width % 64 : 64;
   568       oy = ty+64 > level->height ? level->height % 64 : 64;
   569 
   570       if (level->tile_file_offsets [j+1]) {
   571 	tile = load_tile
   572 	  (src,
   573 	   level->tile_file_offsets [j+1] - level->tile_file_offsets [j],
   574 	   hierarchy->bpp,
   575 	   ox, oy);
   576       }
   577       else {
   578 	tile = load_tile
   579 	  (src,
   580 	   ox*oy*6,
   581 	   hierarchy->bpp,
   582 	   ox, oy);
   583       }
   584 
   585       p8  = tile;
   586       p16 = (Uint16 *) p8;
   587       p   = (Uint32 *) p8;
   588       for (y=ty; y < ty+oy; y++) {
   589 	row = (Uint32 *)((Uint8 *)surface->pixels + y*surface->pitch + tx*4);
   590 	switch (hierarchy->bpp) {
   591 	case 4:
   592 	  for (x=tx; x < tx+ox; x++)
   593 	    *row++ = Swap32 (*p++);
   594 	  break;
   595 	case 3:
   596 	  for (x=tx; x < tx+ox; x++) {
   597 	    *row = 0xFF000000;
   598 	    *row |= ((Uint32) *(p8++) << 16);
   599 	    *row |= ((Uint32) *(p8++) << 8);
   600 	    *row |= ((Uint32) *(p8++) << 0);
   601 	    row++;
   602 	  }
   603 	  break;
   604 	case 2: // Indexed/Greyscale + Alpha
   605 	  switch (head->image_type) {
   606 	  case IMAGE_INDEXED:
   607 	    for (x=tx; x < tx+ox; x++) {
   608 	      *row =  ((Uint32) (head->cm_map [*p8*3])     << 16);
   609 	      *row |= ((Uint32) (head->cm_map [*p8*3+1])   << 8);
   610 	      *row |= ((Uint32) (head->cm_map [*p8++*3+2]) << 0);
   611 	      *row |= ((Uint32) *p8++ << 24);;
   612 	      row++;
   613 	    }
   614 	    break;
   615 	  case IMAGE_GREYSCALE:
   616 	    for (x=tx; x < tx+ox; x++) {
   617 	      *row = ((Uint32) *p8 << 16);
   618 	      *row |= ((Uint32) *p8 << 8);
   619 	      *row |= ((Uint32) *p8++ << 0);
   620 	      *row |= ((Uint32) *p8++ << 24);;
   621 	      row++;
   622 	    }
   623 	    break;	    
   624 	  default:
   625 	    fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
   626 	    return 1;
   627 	  }
   628 	  break;
   629 	case 1: // Indexed/Greyscale
   630 	  switch (head->image_type) {
   631 	  case IMAGE_INDEXED:
   632 	    for (x = tx; x < tx+ox; x++) {
   633 	      *row++ = 0xFF000000
   634 		| ((Uint32) (head->cm_map [*p8*3]) << 16)
   635 		| ((Uint32) (head->cm_map [*p8*3+1]) << 8)
   636 		| ((Uint32) (head->cm_map [*p8*3+2]) << 0);
   637 	      p8++;
   638 	    }
   639 	    break;
   640 	  case IMAGE_GREYSCALE:
   641 	    for (x=tx; x < tx+ox; x++) {
   642 	      *row++ = 0xFF000000
   643 		| (((Uint32) (*p8)) << 16)
   644 		| (((Uint32) (*p8)) << 8)
   645 		| (((Uint32) (*p8)) << 0);
   646 			++p8;
   647 	    }
   648 	    break;	    
   649 	  default:
   650 	    fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
   651 	    return 1;
   652 	  }
   653 	  break;
   654 	}
   655       }
   656       tx += 64;
   657       if (tx >= level->width) {
   658 	tx = 0;
   659 	ty += 64;
   660       }
   661       if (ty >= level->height) {
   662 	break;
   663       }
   664 
   665       free_xcf_tile (tile);
   666     }
   667     free_xcf_level (level);
   668   }
   669 
   670   free_xcf_hierarchy (hierarchy);
   671   
   672   return 0;
   673 }
   674 
   675 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   676 {
   677   Sint64 start;
   678   const char *error = NULL;
   679   SDL_Surface *surface, *lays;
   680   xcf_header * head;
   681   xcf_layer  * layer;
   682   xcf_channel ** channel;
   683   int chnls, i, offsets;
   684   Sint64 offset, fp;
   685 
   686   unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int);
   687 
   688   if ( !src ) {
   689     /* The error message has been set in SDL_RWFromFile */
   690     return NULL;
   691   }
   692   start = SDL_RWtell(src);
   693 
   694   /* Initialize the data we will clean up when we're done */
   695   surface = NULL;
   696 
   697   head = read_xcf_header (src);
   698 
   699   switch (head->compr) {
   700   case COMPR_NONE:
   701     load_tile = load_xcf_tile_none;
   702     break;
   703   case COMPR_RLE:
   704     load_tile = load_xcf_tile_rle;
   705     break;
   706   default:
   707     fprintf (stderr, "Unsupported Compression.\n");
   708     free_xcf_header (head);
   709     return NULL;
   710   }
   711 
   712   /* Create the surface of the appropriate type */
   713   surface = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
   714 			     0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   715 
   716   if ( surface == NULL ) {
   717     error = "Out of memory";
   718     goto done;
   719   }
   720 
   721   head->layer_file_offsets = NULL;
   722   offsets = 0;
   723 
   724   while ((offset = SDL_ReadBE32 (src))) {
   725     head->layer_file_offsets = (Uint32 *) realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1));
   726     head->layer_file_offsets [offsets] = (Uint32)offset;
   727     offsets++;
   728   }
   729   fp = SDL_RWtell (src);
   730  
   731   lays = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
   732 			  0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   733 
   734   if ( lays == NULL ) {
   735     error = "Out of memory";
   736     goto done;
   737   }
   738 
   739   // Blit layers backwards, because Gimp saves them highest first
   740   for (i = offsets; i > 0; i--) {
   741     SDL_Rect rs, rd;
   742     SDL_RWseek (src, head->layer_file_offsets [i-1], RW_SEEK_SET);
   743 
   744     layer = read_xcf_layer (src);
   745     do_layer_surface (lays, src, head, layer, load_tile);
   746     rs.x = 0;
   747     rs.y = 0;
   748     rs.w = layer->width;
   749     rs.h = layer->height;
   750     rd.x = layer->offset_x;
   751     rd.y = layer->offset_y;
   752     rd.w = layer->width;
   753     rd.h = layer->height;
   754 
   755     if (layer->visible)
   756       SDL_BlitSurface (lays, &rs, surface, &rd);
   757     free_xcf_layer (layer);
   758   }
   759 
   760   SDL_FreeSurface (lays);
   761 
   762   SDL_RWseek (src, fp, RW_SEEK_SET);
   763 
   764   // read channels
   765   channel = NULL;
   766   chnls   = 0;
   767   while ((offset = SDL_ReadBE32 (src))) {
   768     channel = (xcf_channel **) SDL_realloc (channel, sizeof (xcf_channel *) * (chnls+1));
   769     fp = SDL_RWtell (src);
   770     SDL_RWseek (src, offset, RW_SEEK_SET);
   771     channel [chnls++] = (read_xcf_channel (src));
   772     SDL_RWseek (src, fp, RW_SEEK_SET);    
   773   }
   774 
   775   if (chnls) {
   776     SDL_Surface * chs;
   777 
   778     chs = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
   779 			   0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   780 
   781     if (chs == NULL) {
   782       error = "Out of memory";
   783       goto done;
   784     }
   785     for (i = 0; i < chnls; i++) {
   786       //      printf ("CNLBLT %i\n", i);
   787       if (!channel [i]->selection && channel [i]->visible) {
   788 	create_channel_surface (chs, (xcf_image_type)head->image_type, channel [i]->color, channel [i]->opacity);
   789 	SDL_BlitSurface (chs, NULL, surface, NULL);
   790       }
   791       free_xcf_channel (channel [i]);
   792     }
   793 
   794     SDL_FreeSurface (chs);
   795   }
   796 
   797 done:
   798   free_xcf_header (head);
   799   if ( error ) {
   800     SDL_RWseek(src, start, RW_SEEK_SET);
   801     if ( surface ) {
   802       SDL_FreeSurface(surface);
   803       surface = NULL;
   804     }
   805     IMG_SetError(error);
   806   }
   807 
   808   return(surface);
   809 }
   810 
   811 #else
   812 
   813 /* See if an image is contained in a data source */
   814 int IMG_isXCF(SDL_RWops *src)
   815 {
   816   return(0);
   817 }
   818 
   819 /* Load a XCF type image from an SDL datasource */
   820 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   821 {
   822   return(NULL);
   823 }
   824 
   825 #endif /* LOAD_XCF */