Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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