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