2 SDL_image: An example image loading library for use with SDL
3 Copyright (C) 1997-2009 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 /* This is a XCF image file loading framework */
30 #include "SDL_endian.h"
31 #include "SDL_image.h"
36 static char prop_names [][30] = {
47 "preserve_transparency",
70 PROP_ACTIVE_LAYER = 2,
71 PROP_ACTIVE_CHANNEL = 3,
73 PROP_FLOATING_SELECTION = 5,
78 PROP_PRESERVE_TRANSPARENCY = 10,
82 PROP_SHOW_MASKED = 14,
85 PROP_COMPRESSION = 17,
117 Uint32 drawable_offset;
118 } floating_selection; // 5
123 int preserve_transparency;
130 unsigned char color [3];
150 xcf_prop * properties;
152 Uint32 * layer_file_offsets;
153 Uint32 * channel_file_offsets;
155 xcf_compr_type compr;
157 unsigned char * cm_map;
165 xcf_prop * properties;
167 Uint32 hierarchy_file_offset;
168 Uint32 layer_mask_offset;
179 xcf_prop * properties;
181 Uint32 hierarchy_file_offset;
194 Uint32 * level_file_offsets;
201 Uint32 * tile_file_offsets;
204 typedef unsigned char * xcf_tile;
206 typedef unsigned char * (* load_tile_type) (SDL_RWops *, Uint32, int, int, int);
209 /* See if an image is contained in a data source */
210 int IMG_isXCF(SDL_RWops *src)
218 start = SDL_RWtell(src);
220 if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
221 if (strncmp(magic, "gimp xcf ", 9) == 0) {
225 SDL_RWseek(src, start, SEEK_SET);
229 static char * read_string (SDL_RWops * src) {
233 tmp = SDL_ReadBE32 (src);
235 data = (char *) malloc (sizeof (char) * tmp);
236 SDL_RWread (src, data, tmp, 1);
246 static Uint32 Swap32 (Uint32 v) {
248 ((v & 0x000000FF) << 16)
250 | ((v & 0x00FF0000) >> 16)
251 | ((v & 0xFF000000));
254 static void xcf_read_property (SDL_RWops * src, xcf_prop * prop) {
255 prop->id = SDL_ReadBE32 (src);
256 prop->length = SDL_ReadBE32 (src);
259 printf ("%.8X: %s: %d\n", SDL_RWtell (src), prop->id < 25 ? prop_names [prop->id] : "unknown", prop->length);
264 prop->data.colormap.num = SDL_ReadBE32 (src);
265 prop->data.colormap.cmap = (char *) malloc (sizeof (char) * prop->data.colormap.num * 3);
266 SDL_RWread (src, prop->data.colormap.cmap, prop->data.colormap.num*3, 1);
270 prop->data.offset.x = SDL_ReadBE32 (src);
271 prop->data.offset.y = SDL_ReadBE32 (src);
274 prop->data.opacity = SDL_ReadBE32 (src);
276 case PROP_COMPRESSION:
278 SDL_RWread (src, &prop->data, prop->length, 1);
281 prop->data.visible = SDL_ReadBE32 (src);
284 // SDL_RWread (src, &prop->data, prop->length, 1);
285 SDL_RWseek (src, prop->length, SEEK_CUR);
289 static void free_xcf_header (xcf_header * h) {
296 static xcf_header * read_xcf_header (SDL_RWops * src) {
300 h = (xcf_header *) malloc (sizeof (xcf_header));
301 SDL_RWread (src, h->sign, 14, 1);
302 h->width = SDL_ReadBE32 (src);
303 h->height = SDL_ReadBE32 (src);
304 h->image_type = SDL_ReadBE32 (src);
306 h->properties = NULL;
307 h->compr = COMPR_NONE;
311 // Just read, don't save
313 xcf_read_property (src, &prop);
314 if (prop.id == PROP_COMPRESSION)
315 h->compr = prop.data.compression;
316 else if (prop.id == PROP_COLORMAP) {
317 // unused var: int i;
319 h->cm_num = prop.data.colormap.num;
320 h->cm_map = (unsigned char *) malloc (sizeof (unsigned char) * 3 * h->cm_num);
321 memcpy (h->cm_map, prop.data.colormap.cmap, 3*sizeof (char)*h->cm_num);
322 free (prop.data.colormap.cmap);
324 } while (prop.id != PROP_END);
329 static void free_xcf_layer (xcf_layer * l) {
334 static xcf_layer * read_xcf_layer (SDL_RWops * src) {
338 l = (xcf_layer *) malloc (sizeof (xcf_layer));
339 l->width = SDL_ReadBE32 (src);
340 l->height = SDL_ReadBE32 (src);
341 l->layer_type = SDL_ReadBE32 (src);
343 l->name = read_string (src);
346 xcf_read_property (src, &prop);
347 if (prop.id == PROP_OFFSETS) {
348 l->offset_x = prop.data.offset.x;
349 l->offset_y = prop.data.offset.y;
350 } else if (prop.id == PROP_VISIBLE) {
351 l->visible = prop.data.visible ? 1 : 0;
353 } while (prop.id != PROP_END);
355 l->hierarchy_file_offset = SDL_ReadBE32 (src);
356 l->layer_mask_offset = SDL_ReadBE32 (src);
361 static void free_xcf_channel (xcf_channel * c) {
366 static xcf_channel * read_xcf_channel (SDL_RWops * src) {
370 l = (xcf_channel *) malloc (sizeof (xcf_channel));
371 l->width = SDL_ReadBE32 (src);
372 l->height = SDL_ReadBE32 (src);
374 l->name = read_string (src);
378 xcf_read_property (src, &prop);
381 l->opacity = prop.data.opacity << 24;
384 l->color = ((Uint32) prop.data.color[0] << 16)
385 | ((Uint32) prop.data.color[1] << 8)
386 | ((Uint32) prop.data.color[2]);
392 l->visible = prop.data.visible ? 1 : 0;
397 } while (prop.id != PROP_END);
399 l->hierarchy_file_offset = SDL_ReadBE32 (src);
404 static void free_xcf_hierarchy (xcf_hierarchy * h) {
405 free (h->level_file_offsets);
409 static xcf_hierarchy * read_xcf_hierarchy (SDL_RWops * src) {
413 h = (xcf_hierarchy *) malloc (sizeof (xcf_hierarchy));
414 h->width = SDL_ReadBE32 (src);
415 h->height = SDL_ReadBE32 (src);
416 h->bpp = SDL_ReadBE32 (src);
418 h->level_file_offsets = NULL;
421 h->level_file_offsets = (Uint32 *) realloc (h->level_file_offsets, sizeof (Uint32) * (i+1));
422 h->level_file_offsets [i] = SDL_ReadBE32 (src);
423 } while (h->level_file_offsets [i++]);
428 static void free_xcf_level (xcf_level * l) {
429 free (l->tile_file_offsets);
433 static xcf_level * read_xcf_level (SDL_RWops * src) {
437 l = (xcf_level *) malloc (sizeof (xcf_level));
438 l->width = SDL_ReadBE32 (src);
439 l->height = SDL_ReadBE32 (src);
441 l->tile_file_offsets = NULL;
444 l->tile_file_offsets = (Uint32 *) realloc (l->tile_file_offsets, sizeof (Uint32) * (i+1));
445 l->tile_file_offsets [i] = SDL_ReadBE32 (src);
446 } while (l->tile_file_offsets [i++]);
451 static void free_xcf_tile (unsigned char * t) {
455 static unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
456 unsigned char * load;
458 load = (unsigned char *) malloc (len); // expect this is okay
459 SDL_RWread (src, load, len, 1);
464 static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
465 unsigned char * load, * t, * data, * d;
467 int i, size, count, j, length;
470 t = load = (unsigned char *) malloc (len);
471 reallen = SDL_RWread (src, t, 1, len);
473 data = (unsigned char *) malloc (x*y*bpp);
474 for (i = 0; i < bpp; i++) {
484 length = 255 - (length - 1);
486 length = (*t << 8) + t[1];
493 while (length-- > 0) {
501 length = (*t << 8) + t[1];
510 for (j = 0; j < length; j++) {
522 static Uint32 rgb2grey (Uint32 a) {
524 l = 0.2990 * ((a && 0x00FF0000) >> 16)
525 + 0.5870 * ((a && 0x0000FF00) >> 8)
526 + 0.1140 * ((a && 0x000000FF));
528 return (l << 16) | (l << 8) | l;
531 static void create_channel_surface (SDL_Surface * surf, xcf_image_type itype, Uint32 color, Uint32 opacity) {
539 case IMAGE_GREYSCALE:
540 c = opacity | rgb2grey (color);
543 SDL_FillRect (surf, NULL, c);
546 static int do_layer_surface (SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_layer * layer, load_tile_type load_tile) {
547 xcf_hierarchy * hierarchy;
549 unsigned char * tile;
553 int x, y, tx, ty, ox, oy, i, j;
556 SDL_RWseek (src, layer->hierarchy_file_offset, SEEK_SET);
557 hierarchy = read_xcf_hierarchy (src);
560 for (i = 0; hierarchy->level_file_offsets [i]; i++) {
561 SDL_RWseek (src, hierarchy->level_file_offsets [i], SEEK_SET);
562 level = read_xcf_level (src);
565 for (j = 0; level->tile_file_offsets [j]; j++) {
566 SDL_RWseek (src, level->tile_file_offsets [j], SEEK_SET);
567 ox = tx+64 > level->width ? level->width % 64 : 64;
568 oy = ty+64 > level->height ? level->height % 64 : 64;
570 if (level->tile_file_offsets [j+1]) {
573 level->tile_file_offsets [j+1] - level->tile_file_offsets [j],
588 for (y=ty; y < ty+oy; y++) {
589 row = (Uint32 *)((Uint8 *)surface->pixels + y*surface->pitch + tx*4);
590 switch (hierarchy->bpp) {
592 for (x=tx; x < tx+ox; x++)
593 *row++ = Swap32 (*p++);
596 for (x=tx; x < tx+ox; x++) {
598 *row |= ((Uint32) *(p8++) << 16);
599 *row |= ((Uint32) *(p8++) << 8);
600 *row |= ((Uint32) *(p8++) << 0);
604 case 2: // Indexed/Greyscale + Alpha
605 switch (head->image_type) {
607 for (x=tx; x < tx+ox; x++) {
608 *row = ((Uint32) (head->cm_map [*p8*3]) << 16);
609 *row |= ((Uint32) (head->cm_map [*p8*3+1]) << 8);
610 *row |= ((Uint32) (head->cm_map [*p8++*3+2]) << 0);
611 *row |= ((Uint32) *p8++ << 24);;
615 case IMAGE_GREYSCALE:
616 for (x=tx; x < tx+ox; x++) {
617 *row = ((Uint32) *p8 << 16);
618 *row |= ((Uint32) *p8 << 8);
619 *row |= ((Uint32) *p8++ << 0);
620 *row |= ((Uint32) *p8++ << 24);;
625 fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
629 case 1: // Indexed/Greyscale
630 switch (head->image_type) {
632 for (x = tx; x < tx+ox; x++) {
634 | ((Uint32) (head->cm_map [*p8*3]) << 16)
635 | ((Uint32) (head->cm_map [*p8*3+1]) << 8)
636 | ((Uint32) (head->cm_map [*p8*3+2]) << 0);
640 case IMAGE_GREYSCALE:
641 for (x=tx; x < tx+ox; x++) {
643 | (((Uint32) (*p8)) << 16)
644 | (((Uint32) (*p8)) << 8)
645 | (((Uint32) (*p8)) << 0);
650 fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
657 if (tx >= level->width) {
661 if (ty >= level->height) {
665 free_xcf_tile (tile);
667 free_xcf_level (level);
670 free_xcf_hierarchy (hierarchy);
675 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
678 const char *error = NULL;
679 SDL_Surface *surface, *lays;
682 xcf_channel ** channel;
683 int chnls, i, offsets;
686 unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int);
689 /* The error message has been set in SDL_RWFromFile */
692 start = SDL_RWtell(src);
694 /* Initialize the data we will clean up when we're done */
697 head = read_xcf_header (src);
699 switch (head->compr) {
701 load_tile = load_xcf_tile_none;
704 load_tile = load_xcf_tile_rle;
707 fprintf (stderr, "Unsupported Compression.\n");
708 free_xcf_header (head);
712 /* Create the surface of the appropriate type */
713 surface = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
714 0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
716 if ( surface == NULL ) {
717 error = "Out of memory";
721 head->layer_file_offsets = NULL;
724 while ((offset = SDL_ReadBE32 (src))) {
725 head->layer_file_offsets = (Uint32 *) realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1));
726 head->layer_file_offsets [offsets] = offset;
729 fp = SDL_RWtell (src);
731 lays = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
732 0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
734 if ( lays == NULL ) {
735 error = "Out of memory";
739 // Blit layers backwards, because Gimp saves them highest first
740 for (i = offsets; i > 0; i--) {
742 SDL_RWseek (src, head->layer_file_offsets [i-1], SEEK_SET);
744 layer = read_xcf_layer (src);
745 do_layer_surface (lays, src, head, layer, load_tile);
749 rs.h = layer->height;
750 rd.x = layer->offset_x;
751 rd.y = layer->offset_y;
753 rd.h = layer->height;
756 SDL_BlitSurface (lays, &rs, surface, &rd);
757 free_xcf_layer (layer);
760 SDL_FreeSurface (lays);
762 SDL_RWseek (src, fp, SEEK_SET);
767 while ((offset = SDL_ReadBE32 (src))) {
768 channel = (xcf_channel **) realloc (channel, sizeof (xcf_channel *) * (chnls+1));
769 fp = SDL_RWtell (src);
770 SDL_RWseek (src, offset, SEEK_SET);
771 channel [chnls++] = (read_xcf_channel (src));
772 SDL_RWseek (src, fp, SEEK_SET);
778 chs = SDL_AllocSurface(SDL_SWSURFACE, head->width, head->height, 32,
779 0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
782 error = "Out of memory";
785 for (i = 0; i < chnls; i++) {
786 // printf ("CNLBLT %i\n", i);
787 if (!channel [i]->selection && channel [i]->visible) {
788 create_channel_surface (chs, head->image_type, channel [i]->color, channel [i]->opacity);
789 SDL_BlitSurface (chs, NULL, surface, NULL);
791 free_xcf_channel (channel [i]);
794 SDL_FreeSurface (chs);
798 free_xcf_header (head);
800 SDL_RWseek(src, start, SEEK_SET);
802 SDL_FreeSurface(surface);
813 /* See if an image is contained in a data source */
814 int IMG_isXCF(SDL_RWops *src)
819 /* Load a XCF type image from an SDL datasource */
820 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
825 #endif /* LOAD_XCF */