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