IMG_xcf.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 02 Jan 2016 10:42:34 -0800
changeset 486 7bb8af91e887
parent 451 48116d511e5d
child 496 6332f9425dcc
permissions -rw-r--r--
Updated copyright to 2016
     1 /*
     2   SDL_image:  An example image loading library for use with SDL
     3   Copyright (C) 1997-2016 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 *) SDL_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 *) SDL_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     SDL_free (h->cm_map);
   291   if (h->layer_file_offsets)
   292     SDL_free (h->layer_file_offsets);
   293   SDL_free (h);
   294 }
   295 
   296 static xcf_header * read_xcf_header (SDL_RWops * src) {
   297   xcf_header * h;
   298   xcf_prop prop;
   299 
   300   h = (xcf_header *) SDL_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->layer_file_offsets = NULL;
   308   h->compr      = COMPR_NONE;
   309   h->cm_num = 0;
   310   h->cm_map = NULL;
   311 
   312   // Just read, don't save
   313   do {
   314     xcf_read_property (src, &prop);
   315     if (prop.id == PROP_COMPRESSION)
   316       h->compr = (xcf_compr_type)prop.data.compression;
   317     else if (prop.id == PROP_COLORMAP) {
   318       // unused var: int i;
   319 
   320       h->cm_num = prop.data.colormap.num;
   321       h->cm_map = (unsigned char *) SDL_malloc (sizeof (unsigned char) * 3 * h->cm_num);
   322       SDL_memcpy (h->cm_map, prop.data.colormap.cmap, 3*sizeof (char)*h->cm_num);
   323       SDL_free (prop.data.colormap.cmap);
   324     }
   325   } while (prop.id != PROP_END);
   326 
   327   return h;
   328 }
   329 
   330 static void free_xcf_layer (xcf_layer * l) {
   331   SDL_free (l->name);
   332   SDL_free (l);
   333 }
   334 
   335 static xcf_layer * read_xcf_layer (SDL_RWops * src) {
   336   xcf_layer * l;
   337   xcf_prop    prop;
   338 
   339   l = (xcf_layer *) SDL_malloc (sizeof (xcf_layer));
   340   l->width  = SDL_ReadBE32 (src);
   341   l->height = SDL_ReadBE32 (src);
   342   l->layer_type = SDL_ReadBE32 (src);
   343 
   344   l->name = read_string (src);
   345 
   346   do {
   347     xcf_read_property (src, &prop);
   348     if (prop.id == PROP_OFFSETS) {
   349       l->offset_x = prop.data.offset.x;
   350       l->offset_y = prop.data.offset.y;
   351     } else if (prop.id == PROP_VISIBLE) {
   352       l->visible = prop.data.visible ? 1 : 0;
   353     }
   354   } while (prop.id != PROP_END);
   355 
   356   l->hierarchy_file_offset = SDL_ReadBE32 (src);
   357   l->layer_mask_offset     = SDL_ReadBE32 (src);
   358 
   359   return l;
   360 }
   361 
   362 static void free_xcf_channel (xcf_channel * c) {
   363   SDL_free (c->name);
   364   SDL_free (c);
   365 }
   366 
   367 static xcf_channel * read_xcf_channel (SDL_RWops * src) {
   368   xcf_channel * l;
   369   xcf_prop    prop;
   370 
   371   l = (xcf_channel *) SDL_malloc (sizeof (xcf_channel));
   372   l->width  = SDL_ReadBE32 (src);
   373   l->height = SDL_ReadBE32 (src);
   374 
   375   l->name = read_string (src);
   376 
   377   l->selection = 0;
   378   do {
   379     xcf_read_property (src, &prop);
   380     switch (prop.id) {
   381     case PROP_OPACITY:
   382       l->opacity = prop.data.opacity << 24;
   383       break;
   384     case PROP_COLOR:
   385       l->color = ((Uint32) prop.data.color[0] << 16)
   386     | ((Uint32) prop.data.color[1] << 8)
   387     | ((Uint32) prop.data.color[2]);
   388       break;
   389     case PROP_SELECTION:
   390       l->selection = 1;
   391       break;
   392     case PROP_VISIBLE:
   393       l->visible = prop.data.visible ? 1 : 0;
   394       break;
   395     default:
   396         ;
   397     }
   398   } while (prop.id != PROP_END);
   399 
   400   l->hierarchy_file_offset = SDL_ReadBE32 (src);
   401 
   402   return l;
   403 }
   404 
   405 static void free_xcf_hierarchy (xcf_hierarchy * h) {
   406   SDL_free (h->level_file_offsets);
   407   SDL_free (h);
   408 }
   409 
   410 static xcf_hierarchy * read_xcf_hierarchy (SDL_RWops * src) {
   411   xcf_hierarchy * h;
   412   int i;
   413 
   414   h = (xcf_hierarchy *) SDL_malloc (sizeof (xcf_hierarchy));
   415   h->width  = SDL_ReadBE32 (src);
   416   h->height = SDL_ReadBE32 (src);
   417   h->bpp    = SDL_ReadBE32 (src);
   418 
   419   h->level_file_offsets = NULL;
   420   i = 0;
   421   do {
   422     h->level_file_offsets = (Uint32 *) SDL_realloc (h->level_file_offsets, sizeof (Uint32) * (i+1));
   423     h->level_file_offsets [i] = SDL_ReadBE32 (src);
   424   } while (h->level_file_offsets [i++]);
   425 
   426   return h;
   427 }
   428 
   429 static void free_xcf_level (xcf_level * l) {
   430   SDL_free (l->tile_file_offsets);
   431   SDL_free (l);
   432 }
   433 
   434 static xcf_level * read_xcf_level (SDL_RWops * src) {
   435   xcf_level * l;
   436   int i;
   437 
   438   l = (xcf_level *) SDL_malloc (sizeof (xcf_level));
   439   l->width  = SDL_ReadBE32 (src);
   440   l->height = SDL_ReadBE32 (src);
   441 
   442   l->tile_file_offsets = NULL;
   443   i = 0;
   444   do {
   445     l->tile_file_offsets = (Uint32 *) SDL_realloc (l->tile_file_offsets, sizeof (Uint32) * (i+1));
   446     l->tile_file_offsets [i] = SDL_ReadBE32 (src);
   447   } while (l->tile_file_offsets [i++]);
   448 
   449   return l;
   450 }
   451 
   452 static void free_xcf_tile (unsigned char * t) {
   453   SDL_free (t);
   454 }
   455 
   456 static unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   457   unsigned char * load;
   458 
   459   load = (unsigned char *) SDL_malloc (len); // expect this is okay
   460   SDL_RWread (src, load, len, 1);
   461 
   462   return load;
   463 }
   464 
   465 static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   466   unsigned char * load, * t, * data, * d;
   467   Uint32 reallen;
   468   int i, size, count, j, length;
   469   unsigned char val;
   470 
   471   t = load = (unsigned char *) SDL_malloc (len);
   472   reallen = SDL_RWread (src, t, 1, len);
   473 
   474   data = (unsigned char *) SDL_malloc (x*y*bpp);
   475   for (i = 0; i < bpp; i++) {
   476     d    = data + i;
   477     size = x*y;
   478     count = 0;
   479 
   480     while (size > 0) {
   481       val = *t++;
   482 
   483       length = val;
   484       if (length >= 128) {
   485     length = 255 - (length - 1);
   486     if (length == 128) {
   487       length = (*t << 8) + t[1];
   488       t += 2;
   489     }
   490 
   491     count += length;
   492     size -= length;
   493 
   494     while (length-- > 0) {
   495       *d = *t++;
   496       d += bpp;
   497     }
   498       }
   499       else {
   500     length += 1;
   501     if (length == 128) {
   502       length = (*t << 8) + t[1];
   503       t += 2;
   504     }
   505 
   506     count += length;
   507     size -= length;
   508 
   509     val = *t++;
   510 
   511     for (j = 0; j < length; j++) {
   512       *d = val;
   513       d += bpp;
   514     }
   515       }
   516     }
   517   }
   518 
   519   SDL_free (load);
   520   return (data);
   521 }
   522 
   523 static Uint32 rgb2grey (Uint32 a) {
   524   Uint8 l;
   525   l = (Uint8)(0.2990 * ((a & 0x00FF0000) >> 16)
   526     + 0.5870 * ((a & 0x0000FF00) >>  8)
   527     + 0.1140 * ((a & 0x000000FF)));
   528 
   529   return (l << 16) | (l << 8) | l;
   530 }
   531 
   532 static void create_channel_surface (SDL_Surface * surf, xcf_image_type itype, Uint32 color, Uint32 opacity) {
   533   Uint32 c = 0;
   534 
   535   switch (itype) {
   536   case IMAGE_RGB:
   537   case IMAGE_INDEXED:
   538     c = opacity | color;
   539     break;
   540   case IMAGE_GREYSCALE:
   541     c = opacity | rgb2grey (color);
   542     break;
   543   }
   544   SDL_FillRect (surf, NULL, c);
   545 }
   546 
   547 static int do_layer_surface (SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_layer * layer, load_tile_type load_tile) {
   548   xcf_hierarchy * hierarchy;
   549   xcf_level     * level;
   550   unsigned char * tile;
   551   Uint8  * p8;
   552   Uint16 * p16;
   553   Uint32 * p;
   554   int i, j;
   555   Uint32 x, y, tx, ty, ox, oy;
   556   Uint32 *row;
   557 
   558   SDL_RWseek (src, layer->hierarchy_file_offset, RW_SEEK_SET);
   559   hierarchy = read_xcf_hierarchy (src);
   560 
   561   level = NULL;
   562   for (i = 0; hierarchy->level_file_offsets [i]; i++) {
   563     SDL_RWseek (src, hierarchy->level_file_offsets [i], RW_SEEK_SET);
   564     level = read_xcf_level (src);
   565 
   566     ty = tx = 0;
   567     for (j = 0; level->tile_file_offsets [j]; j++) {
   568       SDL_RWseek (src, level->tile_file_offsets [j], RW_SEEK_SET);
   569       ox = tx+64 > level->width ? level->width % 64 : 64;
   570       oy = ty+64 > level->height ? level->height % 64 : 64;
   571 
   572       if (level->tile_file_offsets [j+1]) {
   573     tile = load_tile
   574       (src,
   575        level->tile_file_offsets [j+1] - level->tile_file_offsets [j],
   576        hierarchy->bpp,
   577        ox, oy);
   578       }
   579       else {
   580     tile = load_tile
   581       (src,
   582        ox*oy*6,
   583        hierarchy->bpp,
   584        ox, oy);
   585       }
   586 
   587       p8  = tile;
   588       p16 = (Uint16 *) p8;
   589       p   = (Uint32 *) p8;
   590       for (y=ty; y < ty+oy; y++) {
   591     row = (Uint32 *)((Uint8 *)surface->pixels + y*surface->pitch + tx*4);
   592     switch (hierarchy->bpp) {
   593     case 4:
   594       for (x=tx; x < tx+ox; x++)
   595         *row++ = Swap32 (*p++);
   596       break;
   597     case 3:
   598       for (x=tx; x < tx+ox; x++) {
   599         *row = 0xFF000000;
   600         *row |= ((Uint32) *(p8++) << 16);
   601         *row |= ((Uint32) *(p8++) << 8);
   602         *row |= ((Uint32) *(p8++) << 0);
   603         row++;
   604       }
   605       break;
   606     case 2: // Indexed/Greyscale + Alpha
   607       switch (head->image_type) {
   608       case IMAGE_INDEXED:
   609         for (x=tx; x < tx+ox; x++) {
   610           *row =  ((Uint32) (head->cm_map [*p8*3])     << 16);
   611           *row |= ((Uint32) (head->cm_map [*p8*3+1])   << 8);
   612           *row |= ((Uint32) (head->cm_map [*p8++*3+2]) << 0);
   613           *row |= ((Uint32) *p8++ << 24);;
   614           row++;
   615         }
   616         break;
   617       case IMAGE_GREYSCALE:
   618         for (x=tx; x < tx+ox; x++) {
   619           *row = ((Uint32) *p8 << 16);
   620           *row |= ((Uint32) *p8 << 8);
   621           *row |= ((Uint32) *p8++ << 0);
   622           *row |= ((Uint32) *p8++ << 24);;
   623           row++;
   624         }
   625         break;
   626       default:
   627         fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
   628         if (hierarchy)
   629         {
   630           if (hierarchy->level_file_offsets)
   631             SDL_free(hierarchy->level_file_offsets);
   632          
   633           free_xcf_hierarchy(hierarchy);
   634         }
   635         if (level)     
   636           free_xcf_level (level);
   637         return 1;
   638       }
   639       break;
   640     case 1: // Indexed/Greyscale
   641       switch (head->image_type) {
   642       case IMAGE_INDEXED:
   643         for (x = tx; x < tx+ox; x++) {
   644           *row++ = 0xFF000000
   645         | ((Uint32) (head->cm_map [*p8*3]) << 16)
   646         | ((Uint32) (head->cm_map [*p8*3+1]) << 8)
   647         | ((Uint32) (head->cm_map [*p8*3+2]) << 0);
   648           p8++;
   649         }
   650         break;
   651       case IMAGE_GREYSCALE:
   652         for (x=tx; x < tx+ox; x++) {
   653           *row++ = 0xFF000000
   654         | (((Uint32) (*p8)) << 16)
   655         | (((Uint32) (*p8)) << 8)
   656         | (((Uint32) (*p8)) << 0);
   657             ++p8;
   658         }
   659         break;
   660       default:
   661         fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
   662         if (tile)
   663           free_xcf_tile (tile);
   664         if (level)
   665           free_xcf_level (level);
   666         if (hierarchy)
   667           free_xcf_hierarchy (hierarchy);
   668         return 1;
   669       }
   670       break;
   671     }
   672       }
   673       tx += 64;
   674       if (tx >= level->width) {
   675     tx = 0;
   676     ty += 64;
   677       }
   678       if (ty >= level->height) {
   679     break;
   680       }
   681 
   682       free_xcf_tile (tile);
   683     }
   684     free_xcf_level (level);
   685   }
   686 
   687   free_xcf_hierarchy (hierarchy);
   688 
   689   return 0;
   690 }
   691 
   692 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   693 {
   694   Sint64 start;
   695   const char *error = NULL;
   696   SDL_Surface *surface, *lays;
   697   xcf_header * head;
   698   xcf_layer  * layer;
   699   xcf_channel ** channel;
   700   int chnls, i, offsets;
   701   Sint64 offset, fp;
   702 
   703   unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int);
   704 
   705   if ( !src ) {
   706     /* The error message has been set in SDL_RWFromFile */
   707     return NULL;
   708   }
   709   start = SDL_RWtell(src);
   710 
   711   /* Initialize the data we will clean up when we're done */
   712   surface = NULL;
   713 
   714   head = read_xcf_header (src);
   715 
   716   switch (head->compr) {
   717   case COMPR_NONE:
   718     load_tile = load_xcf_tile_none;
   719     break;
   720   case COMPR_RLE:
   721     load_tile = load_xcf_tile_rle;
   722     break;
   723   default:
   724     fprintf (stderr, "Unsupported Compression.\n");
   725     free_xcf_header (head);
   726     return NULL;
   727   }
   728 
   729   /* Create the surface of the appropriate type */
   730   surface = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
   731                  0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   732 
   733   if ( surface == NULL ) {
   734     error = "Out of memory";
   735     goto done;
   736   }
   737 
   738   offsets = 0;
   739 
   740   while ((offset = SDL_ReadBE32 (src))) {
   741     head->layer_file_offsets = (Uint32 *) SDL_realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1));
   742     head->layer_file_offsets [offsets] = (Uint32)offset;
   743     offsets++;
   744   }
   745   fp = SDL_RWtell (src);
   746 
   747   lays = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
   748               0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   749 
   750   if ( lays == NULL ) {
   751     error = "Out of memory";
   752     goto done;
   753   }
   754 
   755   // Blit layers backwards, because Gimp saves them highest first
   756   for (i = offsets; i > 0; i--) {
   757     SDL_Rect rs, rd;
   758     SDL_RWseek (src, head->layer_file_offsets [i-1], RW_SEEK_SET);
   759 
   760     layer = read_xcf_layer (src);
   761     do_layer_surface (lays, src, head, layer, load_tile);
   762     rs.x = 0;
   763     rs.y = 0;
   764     rs.w = layer->width;
   765     rs.h = layer->height;
   766     rd.x = layer->offset_x;
   767     rd.y = layer->offset_y;
   768     rd.w = layer->width;
   769     rd.h = layer->height;
   770 
   771     if (layer->visible)
   772       SDL_BlitSurface (lays, &rs, surface, &rd);
   773     free_xcf_layer (layer);
   774   }
   775 
   776   SDL_FreeSurface (lays);
   777 
   778   SDL_RWseek (src, fp, RW_SEEK_SET);
   779 
   780   // read channels
   781   channel = NULL;
   782   chnls   = 0;
   783   while ((offset = SDL_ReadBE32 (src))) {
   784     channel = (xcf_channel **) SDL_realloc (channel, sizeof (xcf_channel *) * (chnls+1));
   785     fp = SDL_RWtell (src);
   786     SDL_RWseek (src, offset, RW_SEEK_SET);
   787     channel [chnls++] = (read_xcf_channel (src));
   788     SDL_RWseek (src, fp, RW_SEEK_SET);
   789   }
   790 
   791   if (chnls) {
   792     SDL_Surface * chs;
   793 
   794     chs = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
   795                0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   796 
   797     if (chs == NULL) {
   798       error = "Out of memory";
   799       goto done;
   800     }
   801     for (i = 0; i < chnls; i++) {
   802       //      printf ("CNLBLT %i\n", i);
   803       if (!channel [i]->selection && channel [i]->visible) {
   804     create_channel_surface (chs, (xcf_image_type)head->image_type, channel [i]->color, channel [i]->opacity);
   805     SDL_BlitSurface (chs, NULL, surface, NULL);
   806       }
   807       free_xcf_channel (channel [i]);
   808     }
   809 
   810     SDL_FreeSurface (chs);
   811   }
   812 
   813 done:
   814   free_xcf_header (head);
   815   if ( error ) {
   816     SDL_RWseek(src, start, RW_SEEK_SET);
   817     if ( surface ) {
   818       SDL_FreeSurface(surface);
   819       surface = NULL;
   820     }
   821     IMG_SetError("%s", error);
   822   }
   823 
   824   return(surface);
   825 }
   826 
   827 #else
   828 
   829 /* See if an image is contained in a data source */
   830 int IMG_isXCF(SDL_RWops *src)
   831 {
   832   return(0);
   833 }
   834 
   835 /* Load a XCF type image from an SDL datasource */
   836 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   837 {
   838   return(NULL);
   839 }
   840 
   841 #endif /* LOAD_XCF */