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