IMG_xcf.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 03 May 2002 02:10:44 +0000
changeset 70 ef5fe56a0f07
parent 53 96b084473b47
child 80 e793c7a63324
permissions -rw-r--r--
Date: 02 May 2002 04:11:26 +0200
From: Dag-Erling Smorgrav <des@ofug.org>
Subject: SDL_image XCF patch

The attached patch makes the XCF code ignore invisible layers and
channels, and disables the debugging printouts. This makes the XCF
loader quite usable; I think it should be enabled by default.
     1 /*
     2     SDL_image:  An example image loading library for use with SDL
     3     Copyright (C) 1999, 2000, 2001  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 
    31 #include "SDL_image.h"
    32 
    33 #ifdef LOAD_XCF
    34 
    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 
    63 typedef enum
    64 {
    65   PROP_END = 0,
    66   PROP_COLORMAP = 1,
    67   PROP_ACTIVE_LAYER = 2,
    68   PROP_ACTIVE_CHANNEL = 3,
    69   PROP_SELECTION = 4,
    70   PROP_FLOATING_SELECTION = 5,
    71   PROP_OPACITY = 6,
    72   PROP_MODE = 7,
    73   PROP_VISIBLE = 8,
    74   PROP_LINKED = 9,
    75   PROP_PRESERVE_TRANSPARENCY = 10,
    76   PROP_APPLY_MASK = 11,
    77   PROP_EDIT_MASK = 12,
    78   PROP_SHOW_MASK = 13,
    79   PROP_SHOW_MASKED = 14,
    80   PROP_OFFSETS = 15,
    81   PROP_COLOR = 16,
    82   PROP_COMPRESSION = 17,
    83   PROP_GUIDES = 18,
    84   PROP_RESOLUTION = 19,
    85   PROP_TATTOO = 20,
    86   PROP_PARASITES = 21,
    87   PROP_UNIT = 22,
    88   PROP_PATHS = 23,
    89   PROP_USER_UNIT = 24
    90 } xcf_prop_type;
    91 
    92 typedef enum {
    93   COMPR_NONE    = 0,
    94   COMPR_RLE     = 1,
    95   COMPR_ZLIB    = 2,
    96   COMPR_FRACTAL = 3
    97 } xcf_compr_type;
    98 
    99 typedef enum {
   100   IMAGE_RGB       = 0,
   101   IMAGE_GREYSCALE = 1,
   102   IMAGE_INDEXED   = 2
   103 } xcf_image_type;
   104 
   105 typedef struct {
   106   Uint32 id;
   107   Uint32 length;
   108   union {
   109     struct {
   110       Uint32 num;
   111       char * cmap;
   112     } colormap; // 1
   113     struct {
   114       Uint32 drawable_offset;
   115     } floating_selection; // 5
   116     Sint32 opacity;
   117     Sint32 mode;
   118     int    visible;
   119     int    linked;
   120     int    preserve_transparency;
   121     int    apply_mask;
   122     int    show_mask;
   123     struct {
   124       Sint32 x;
   125       Sint32 y;
   126     } offset;
   127     unsigned char color [3];
   128     Uint8 compression;
   129     struct {
   130       Sint32 x;
   131       Sint32 y;
   132     } resolution;
   133     struct {
   134       char * name;
   135       Uint32 flags;
   136       Uint32 size;
   137       char * data;
   138     } parasite;
   139   } data;
   140 } xcf_prop;
   141 
   142 typedef struct {
   143   char   sign [14];
   144   Uint32 width;
   145   Uint32 height;
   146   Sint32 image_type;
   147   xcf_prop * properties;
   148 
   149   Uint32 * layer_file_offsets;
   150   Uint32 * channel_file_offsets;
   151 
   152   xcf_compr_type compr;
   153   Uint32         cm_num;
   154   unsigned char * cm_map;
   155 } xcf_header;
   156 
   157 typedef struct {
   158   Uint32 width;
   159   Uint32 height;
   160   Sint32 layer_type;
   161   char * name;
   162   xcf_prop * properties;
   163 
   164   Uint32 hierarchy_file_offset;
   165   Uint32 layer_mask_offset;
   166 
   167   Uint32 offset_x;
   168   Uint32 offset_y;
   169   int visible;
   170 } xcf_layer;
   171 
   172 typedef struct {
   173   Uint32 width;
   174   Uint32 height;
   175   char * name;
   176   xcf_prop * properties;
   177 
   178   Uint32 hierarchy_file_offset;
   179 
   180   Uint32 color;
   181   Uint32 opacity;
   182   int selection;
   183   int visible;
   184 } xcf_channel;
   185 
   186 typedef struct {
   187   Uint32 width;
   188   Uint32 height;
   189   Uint32 bpp;
   190 
   191   Uint32 * level_file_offsets;
   192 } xcf_hierarchy;
   193 
   194 typedef struct {
   195   Uint32 width;
   196   Uint32 height;
   197 
   198   Uint32 * tile_file_offsets;
   199 } xcf_level;
   200 
   201 typedef unsigned char * xcf_tile;
   202 
   203 typedef unsigned char * (* load_tile_type) (SDL_RWops *, Uint32, int, int, int);
   204 
   205 
   206 /* See if an image is contained in a data source */
   207 int IMG_isXCF(SDL_RWops *src) {
   208   int is_XCF;
   209   char magic[14];
   210 
   211   is_XCF = 0;
   212   if ( SDL_RWread(src, magic, 14, 1) ) {
   213     if (strncmp(magic, "gimp xcf ", 9) == 0) {
   214       is_XCF = 1;
   215     }
   216   }
   217 
   218   return(is_XCF);
   219 }
   220 
   221 static char * read_string (SDL_RWops * src) {
   222   Uint32 tmp;
   223   char * data;
   224 
   225   tmp = SDL_ReadBE32 (src);
   226   if (tmp > 0) {
   227     data = (char *) malloc (sizeof (char) * tmp);
   228     SDL_RWread (src, data, tmp, 1);
   229   }
   230   else {
   231     data = NULL;
   232   }
   233 
   234   return data;
   235 }
   236 
   237 
   238 static Uint32 Swap32 (Uint32 v) {
   239   return
   240     ((v & 0x000000FF) << 16)
   241     |  ((v & 0x0000FF00))
   242     |  ((v & 0x00FF0000) >> 16)
   243     |  ((v & 0xFF000000));
   244 }
   245 
   246 void xcf_read_property (SDL_RWops * src, xcf_prop * prop) {
   247   prop->id = SDL_ReadBE32 (src);
   248   prop->length = SDL_ReadBE32 (src);
   249 
   250 #if 0
   251   printf ("%.8X: %s: %d\n", SDL_RWtell (src), prop->id < 25 ? prop_names [prop->id] : "unknown", prop->length);
   252 #endif
   253 
   254   switch (prop->id) {
   255   case PROP_COLORMAP:
   256     prop->data.colormap.num = SDL_ReadBE32 (src);
   257     prop->data.colormap.cmap = (char *) malloc (sizeof (char) * prop->data.colormap.num * 3);
   258     SDL_RWread (src, prop->data.colormap.cmap, prop->data.colormap.num*3, 1);
   259     break;
   260 
   261   case PROP_OFFSETS:
   262     prop->data.offset.x = SDL_ReadBE32 (src);
   263     prop->data.offset.y = SDL_ReadBE32 (src);
   264     break;
   265   case PROP_OPACITY:
   266     prop->data.opacity = SDL_ReadBE32 (src);
   267     break;
   268   case PROP_COMPRESSION:
   269   case PROP_COLOR:
   270     SDL_RWread (src, &prop->data, prop->length, 1);
   271     break;
   272   case PROP_VISIBLE:
   273     prop->data.visible = SDL_ReadBE32 (src);
   274     break;
   275   default:
   276     //    SDL_RWread (src, &prop->data, prop->length, 1);
   277     SDL_RWseek (src, prop->length, SEEK_CUR);
   278   }
   279 }
   280 
   281 void free_xcf_header (xcf_header * h) {
   282   if (h->cm_num)
   283     free (h->cm_map);
   284 
   285   free (h);
   286 }
   287 
   288 xcf_header * read_xcf_header (SDL_RWops * src) {
   289   xcf_header * h;
   290   xcf_prop prop;
   291 
   292   h = (xcf_header *) malloc (sizeof (xcf_header));
   293   SDL_RWread (src, h->sign, 14, 1);
   294   h->width       = SDL_ReadBE32 (src);
   295   h->height      = SDL_ReadBE32 (src);
   296   h->image_type  = SDL_ReadBE32 (src);
   297 
   298   h->properties = NULL;
   299   h->compr      = COMPR_NONE;
   300   h->cm_num = 0;
   301   h->cm_map = NULL;
   302 
   303   // Just read, don't save
   304   do {
   305     xcf_read_property (src, &prop);
   306     if (prop.id == PROP_COMPRESSION)
   307       h->compr = prop.data.compression;
   308     else if (prop.id == PROP_COLORMAP) {
   309       int i;
   310 
   311       h->cm_num = prop.data.colormap.num;
   312       h->cm_map = (char *) malloc (sizeof (char) * 3 * h->cm_num);
   313       memcpy (h->cm_map, prop.data.colormap.cmap, 3*sizeof (char)*h->cm_num);
   314       free (prop.data.colormap.cmap);
   315     }
   316   } while (prop.id != PROP_END);
   317 
   318   return h;
   319 }
   320 
   321 void free_xcf_layer (xcf_layer * l) {
   322   free (l->name);
   323   free (l);
   324 }
   325 
   326 xcf_layer * read_xcf_layer (SDL_RWops * src) {
   327   xcf_layer * l;
   328   xcf_prop    prop;
   329 
   330   l = (xcf_layer *) malloc (sizeof (xcf_layer));
   331   l->width  = SDL_ReadBE32 (src);
   332   l->height = SDL_ReadBE32 (src);
   333   l->layer_type = SDL_ReadBE32 (src);
   334 
   335   l->name = read_string (src);
   336 
   337   do {
   338     xcf_read_property (src, &prop);
   339     if (prop.id == PROP_OFFSETS) {
   340       l->offset_x = prop.data.offset.x;
   341       l->offset_y = prop.data.offset.y;
   342     } else if (prop.id == PROP_VISIBLE) {
   343       l->visible = prop.data.visible ? 1 : 0;
   344     }
   345   } while (prop.id != PROP_END);
   346 
   347   l->hierarchy_file_offset = SDL_ReadBE32 (src);
   348   l->layer_mask_offset     = SDL_ReadBE32 (src);
   349 
   350   return l;
   351 }
   352 
   353 void free_xcf_channel (xcf_channel * c) {
   354   free (c->name);
   355   free (c);
   356 }
   357 
   358 xcf_channel * read_xcf_channel (SDL_RWops * src) {
   359   xcf_channel * l;
   360   xcf_prop    prop;
   361 
   362   l = (xcf_channel *) malloc (sizeof (xcf_channel));
   363   l->width  = SDL_ReadBE32 (src);
   364   l->height = SDL_ReadBE32 (src);
   365 
   366   l->name = read_string (src);
   367 
   368   l->selection = 0;
   369   do {
   370     xcf_read_property (src, &prop);
   371     switch (prop.id) {
   372     case PROP_OPACITY:
   373       l->opacity = prop.data.opacity << 24;
   374       break;
   375     case PROP_COLOR:
   376       l->color = ((Uint32) prop.data.color[0] << 16)
   377 	| ((Uint32) prop.data.color[1] << 8)
   378 	| ((Uint32) prop.data.color[2]);
   379       break;
   380     case PROP_SELECTION:
   381       l->selection = 1;
   382       break;
   383     case PROP_VISIBLE:
   384       l->visible = prop.data.visible ? 1 : 0;
   385       break;
   386     default:
   387     }
   388   } while (prop.id != PROP_END);
   389 
   390   l->hierarchy_file_offset = SDL_ReadBE32 (src);
   391 
   392   return l;
   393 }
   394 
   395 void free_xcf_hierarchy (xcf_hierarchy * h) {
   396   free (h->level_file_offsets);
   397   free (h);
   398 }
   399 
   400 xcf_hierarchy * read_xcf_hierarchy (SDL_RWops * src) {
   401   xcf_hierarchy * h;
   402   int i;
   403 
   404   h = (xcf_hierarchy *) malloc (sizeof (xcf_hierarchy));
   405   h->width  = SDL_ReadBE32 (src);
   406   h->height = SDL_ReadBE32 (src);
   407   h->bpp    = SDL_ReadBE32 (src);
   408 
   409   h->level_file_offsets = NULL;
   410   i = 0;
   411   do {
   412     h->level_file_offsets = (Uint32 *) realloc (h->level_file_offsets, sizeof (Uint32) * (i+1));
   413     h->level_file_offsets [i] = SDL_ReadBE32 (src);
   414   } while (h->level_file_offsets [i++]);
   415 
   416   return h;
   417 }
   418 
   419 void free_xcf_level (xcf_level * l) {
   420   free (l->tile_file_offsets);
   421   free (l);
   422 }
   423 
   424 xcf_level * read_xcf_level (SDL_RWops * src) {
   425   xcf_level * l;
   426   int i;
   427 
   428   l = (xcf_level *) malloc (sizeof (xcf_level));
   429   l->width  = SDL_ReadBE32 (src);
   430   l->height = SDL_ReadBE32 (src);
   431 
   432   l->tile_file_offsets = NULL;
   433   i = 0;
   434   do {
   435     l->tile_file_offsets = (Uint32 *) realloc (l->tile_file_offsets, sizeof (Uint32) * (i+1));
   436     l->tile_file_offsets [i] = SDL_ReadBE32 (src);
   437   } while (l->tile_file_offsets [i++]);
   438 
   439   return l;
   440 }
   441 
   442 void free_xcf_tile (unsigned char * t) {
   443   free (t);
   444 }
   445 
   446 unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   447   unsigned char * load;
   448 
   449   load = (char *) malloc (len); // expect this is okay
   450   SDL_RWread (src, load, len, 1);
   451 
   452   return load;
   453 }
   454 
   455 unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   456   unsigned char * load, * t, * data, * d;
   457   Uint32 reallen;
   458   int i, size, count, j, length;
   459   unsigned char val;
   460 
   461   t = load = (char *) malloc (len);
   462   reallen = SDL_RWread (src, t, 1, len);
   463 
   464   data = (char *) malloc (x*y*bpp);
   465   for (i = 0; i < bpp; i++) {
   466     d    = data + i;
   467     size = x*y;
   468     count = 0;
   469  
   470     while (size > 0) {
   471       val = *t++;
   472 
   473       length = val;
   474       if (length >= 128) {
   475 	length = 255 - (length - 1);
   476 	if (length == 128) {
   477 	  length = (*t << 8) + t[1];
   478 	  t += 2;
   479 	}
   480 
   481 	count += length;
   482 	size -= length;
   483 
   484 	while (length-- > 0) {
   485 	  *d = *t++;
   486 	  d += bpp;
   487 	}
   488       }
   489       else {
   490 	length += 1;
   491 	if (length == 128) {
   492 	  length = (*t << 8) + t[1];
   493 	  t += 2;
   494 	}
   495 
   496 	count += length;
   497 	size -= length;
   498 
   499 	val = *t++;
   500 
   501 	for (j = 0; j < length; j++) {
   502 	  *d = val;
   503 	  d += bpp;
   504 	}
   505       }
   506     }
   507   }
   508 
   509   free (load);
   510   return (data);
   511 }
   512 
   513 static Uint32 rgb2grey (Uint32 a) {
   514   Uint8 l;
   515   l = 0.2990 * ((a && 0x00FF0000) >> 16)
   516     + 0.5870 * ((a && 0x0000FF00) >>  8)
   517     + 0.1140 * ((a && 0x000000FF));
   518 
   519   return (l << 16) | (l << 8) | l;
   520 }
   521 
   522 void create_channel_surface (SDL_Surface * surf, xcf_image_type itype, Uint32 color, Uint32 opacity) {
   523   Uint32 c;
   524 
   525   switch (itype) {
   526   case IMAGE_RGB:
   527   case IMAGE_INDEXED:
   528     c = opacity | color;
   529     break;
   530   case IMAGE_GREYSCALE:
   531     c = opacity | rgb2grey (color);
   532     break;
   533   }
   534   SDL_FillRect (surf, NULL, c);
   535 }
   536 
   537 int do_layer_surface (SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_layer * layer, load_tile_type load_tile) {
   538   xcf_hierarchy * hierarchy;
   539   xcf_level     * level;
   540   unsigned char * tile;
   541   Uint8  * p8;
   542   Uint16 * p16;
   543   Uint32 * p;
   544   int x, y, tx, ty, ox, oy, width, height, i, j;
   545   Uint32 *row;
   546 
   547   SDL_RWseek (src, layer->hierarchy_file_offset, SEEK_SET);
   548   hierarchy = read_xcf_hierarchy (src);
   549 
   550   level = NULL;
   551   for (i = 0; hierarchy->level_file_offsets [i]; i++) {
   552     SDL_RWseek (src, hierarchy->level_file_offsets [i], SEEK_SET);
   553     level = read_xcf_level (src);
   554 
   555     ty = tx = 0;
   556     for (j = 0; level->tile_file_offsets [j]; j++) {
   557       SDL_RWseek (src, level->tile_file_offsets [j], SEEK_SET);
   558       ox = tx+64 > level->width ? level->width % 64 : 64;
   559       oy = ty+64 > level->height ? level->height % 64 : 64;
   560 
   561       if (level->tile_file_offsets [j+1]) {
   562 	tile = load_tile
   563 	  (src,
   564 	   level->tile_file_offsets [j+1] - level->tile_file_offsets [j],
   565 	   hierarchy->bpp,
   566 	   ox, oy);
   567       }
   568       else {
   569 	tile = load_tile
   570 	  (src,
   571 	   ox*oy*6,
   572 	   hierarchy->bpp,
   573 	   ox, oy);
   574       }
   575 
   576       p8  = tile;
   577       p16 = (Uint16 *) p8;
   578       p   = (Uint32 *) p8;
   579       for (y=ty; y < ty+oy; y++) {
   580 	row = (Uint32 *)((Uint8 *)surface->pixels + y*surface->pitch + tx*4);
   581 	switch (hierarchy->bpp) {
   582 	case 4:
   583 	  for (x=tx; x < tx+ox; x++)
   584 	    *row++ = Swap32 (*p++);
   585 	  break;
   586 	case 3:
   587 	  for (x=tx; x < tx+ox; x++) {
   588 	    *row = 0xFF000000;
   589 	    *row |= ((Uint32) *(p8++) << 16);
   590 	    *row |= ((Uint32) *(p8++) << 8);
   591 	    *row |= ((Uint32) *(p8++) << 0);
   592 	    row++;
   593 	  }
   594 	  break;
   595 	case 2: // Indexed/Greyscale + Alpha
   596 	  switch (head->image_type) {
   597 	  case IMAGE_INDEXED:
   598 	    for (x=tx; x < tx+ox; x++) {
   599 	      *row =  ((Uint32) (head->cm_map [*p8*3])     << 16);
   600 	      *row |= ((Uint32) (head->cm_map [*p8*3+1])   << 8);
   601 	      *row |= ((Uint32) (head->cm_map [*p8++*3+2]) << 0);
   602 	      *row |= ((Uint32) *p8++ << 24);;
   603 	      row++;
   604 	    }
   605 	    break;
   606 	  case IMAGE_GREYSCALE:
   607 	    for (x=tx; x < tx+ox; x++) {
   608 	      *row = ((Uint32) *p8 << 16);
   609 	      *row |= ((Uint32) *p8 << 8);
   610 	      *row |= ((Uint32) *p8++ << 0);
   611 	      *row |= ((Uint32) *p8++ << 24);;
   612 	      row++;
   613 	    }
   614 	    break;	    
   615 	  default:
   616 	    fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
   617 	    return 1;
   618 	  }
   619 	  break;
   620 	case 1: // Indexed/Greyscale
   621 	  switch (head->image_type) {
   622 	  case IMAGE_INDEXED:
   623 	    for (x = tx; x < tx+ox; x++) {
   624 	      *row++ = 0xFF000000
   625 		| ((Uint32) (head->cm_map [*p8*3]) << 16)
   626 		| ((Uint32) (head->cm_map [*p8*3+1]) << 8)
   627 		| ((Uint32) (head->cm_map [*p8*3+2]) << 0);
   628 	      p8++;
   629 	    }
   630 	    break;
   631 	  case IMAGE_GREYSCALE:
   632 	    for (x=tx; x < tx+ox; x++) {
   633 	      *row++ = 0xFF000000
   634 		| (((Uint32) (*p8)) << 16)
   635 		| (((Uint32) (*p8)) << 8)
   636 		| (((Uint32) (*p8++)) << 0);
   637 	    }
   638 	    break;	    
   639 	  default:
   640 	    fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
   641 	    return 1;
   642 	  }
   643 	  break;
   644 	}
   645       }
   646       tx += 64;
   647       if (tx >= level->width) {
   648 	tx = 0;
   649 	ty += 64;
   650       }
   651       if (ty >= level->height) {
   652 	break;
   653       }
   654 
   655       free_xcf_tile (tile);
   656     }
   657     free_xcf_level (level);
   658   }
   659 
   660   free_xcf_hierarchy (hierarchy);
   661 }
   662 
   663 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src) {
   664   SDL_Surface *surface, *lays;
   665   xcf_header * head;
   666   xcf_layer  * layer;
   667   xcf_channel ** channel;
   668   int read_error, chnls, i, offsets;
   669   Uint32 offset, fp;
   670 
   671   unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int);
   672 
   673   /* Initialize the data we will clean up when we're done */
   674   surface = NULL;
   675   read_error = 0;
   676 
   677   /* Check to make sure we have something to do */
   678   if ( ! src ) {
   679     goto done;
   680   }
   681 
   682   head = read_xcf_header (src);
   683 
   684   switch (head->compr) {
   685   case COMPR_NONE:
   686     load_tile = load_xcf_tile_none;
   687     break;
   688   case COMPR_RLE:
   689     load_tile = load_xcf_tile_rle;
   690     break;
   691   default:
   692     fprintf (stderr, "Unsupported Compression.\n");
   693     free_xcf_header (head);
   694     return NULL;
   695   }
   696 
   697   /* Create the surface of the appropriate type */
   698   surface = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
   699 			     0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   700 
   701   if ( surface == NULL ) {
   702     IMG_SetError("Out of memory");
   703     goto done;
   704   }
   705 
   706   head->layer_file_offsets = NULL;
   707   offsets = 0;
   708 
   709   while (offset = SDL_ReadBE32 (src)) {
   710     head->layer_file_offsets = (Uint32 *) realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1));
   711     head->layer_file_offsets [offsets] = offset;
   712     offsets++;
   713   }
   714   fp = SDL_RWtell (src);
   715  
   716   lays = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
   717 			  0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   718 
   719   if ( lays == NULL ) {
   720     IMG_SetError("Out of memory");
   721     goto done;
   722   }
   723 
   724   // Blit layers backwards, because Gimp saves them highest first
   725   for (i = offsets; i > 0; i--) {
   726     SDL_Rect rs, rd;
   727     SDL_RWseek (src, head->layer_file_offsets [i-1], SEEK_SET);
   728 
   729     layer = read_xcf_layer (src);
   730     do_layer_surface (lays, src, head, layer, load_tile);
   731     rs.x = 0;
   732     rs.y = 0;
   733     rs.w = layer->width;
   734     rs.h = layer->height;
   735     rd.x = layer->offset_x;
   736     rd.y = layer->offset_y;
   737     rd.w = layer->width;
   738     rd.h = layer->height;
   739 
   740     if (layer->visible)
   741       SDL_BlitSurface (lays, &rs, surface, &rd);
   742     free_xcf_layer (layer);
   743   }
   744 
   745   SDL_FreeSurface (lays);
   746 
   747   SDL_RWseek (src, fp, SEEK_SET);
   748 
   749   // read channels
   750   channel = NULL;
   751   chnls   = 0;
   752   while (offset = SDL_ReadBE32 (src)) {
   753     channel = (xcf_channel **) realloc (channel, sizeof (xcf_channel *) * (chnls+1));
   754     fp = SDL_RWtell (src);
   755     SDL_RWseek (src, offset, SEEK_SET);
   756     channel [chnls++] = (read_xcf_channel (src));
   757     SDL_RWseek (src, fp, SEEK_SET);    
   758   }
   759 
   760   if (chnls) {
   761     SDL_Surface * chs;
   762 
   763     chs = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
   764 			   0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   765 
   766     if (chs == NULL) {
   767       IMG_SetError("Out of memory");
   768       goto done;
   769     }
   770     for (i = 0; i < chnls; i++) {
   771       //      printf ("CNLBLT %i\n", i);
   772       if (!channel [i]->selection && channel [i]->visible) {
   773 	create_channel_surface (chs, head->image_type, channel [i]->color, channel [i]->opacity);
   774 	SDL_BlitSurface (chs, NULL, surface, NULL);
   775       }
   776       free_xcf_channel (channel [i]);
   777     }
   778 
   779     SDL_FreeSurface (chs);
   780   }
   781 
   782  done:
   783   free_xcf_header (head);
   784   if ( read_error ) {
   785     SDL_FreeSurface(surface);
   786     IMG_SetError("Error reading XCF data");
   787     surface = NULL;
   788   }
   789 
   790   return(surface);
   791 }
   792 
   793 #else
   794 
   795 /* See if an image is contained in a data source */
   796 int IMG_isXCF(SDL_RWops *src)
   797 {
   798   return(0);
   799 }
   800 
   801 /* Load a XCF type image from an SDL datasource */
   802 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   803 {
   804   return(NULL);
   805 }
   806 
   807 #endif /* LOAD_XCF */