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