1 /*
2 SDL_image: An example image loading library for use with SDL
3 Copyright (C) 1997-2019 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 file_version;
142 Uint32 width;
143 Uint32 height;
144 Sint32 image_type;
145 Uint32 precision;
146 xcf_prop * properties;
147
148 Uint32 * layer_file_offsets;
149 Uint32 * channel_file_offsets;
150
151 xcf_compr_type compr;
152 Uint32 cm_num;
153 unsigned char * cm_map;
154 } xcf_header;
155
156 typedef struct {
157 Uint32 width;
158 Uint32 height;
159 Sint32 layer_type;
160 char * name;
161 xcf_prop * properties;
162
163 Uint32 hierarchy_file_offset;
164 Uint32 layer_mask_offset;
165
166 Uint32 offset_x;
167 Uint32 offset_y;
168 int visible;
169 } xcf_layer;
170
171 typedef struct {
172 Uint32 width;
173 Uint32 height;
174 char * name;
175 xcf_prop * properties;
176
177 Uint32 hierarchy_file_offset;
178
179 Uint32 color;
180 Uint32 opacity;
181 int selection;
182 int visible;
183 } xcf_channel;
184
185 typedef struct {
186 Uint32 width;
187 Uint32 height;
188 Uint32 bpp;
189
190 Uint32 * level_file_offsets;
191 } xcf_hierarchy;
192
193 typedef struct {
194 Uint32 width;
195 Uint32 height;
196
197 Uint32 * tile_file_offsets;
198 } xcf_level;
199
200 typedef unsigned char * xcf_tile;
201
202 typedef unsigned char * (* load_tile_type) (SDL_RWops *, Uint32, int, int, int);
203
204
205 /* See if an image is contained in a data source */
IMG_isXCF(SDL_RWops * src)206 int IMG_isXCF(SDL_RWops *src)
207 {
208 Sint64 start;
209 int is_XCF;
210 char magic[14];
211
212 if ( !src )
213 return 0;
214 start = SDL_RWtell(src);
215 is_XCF = 0;
216 if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
217 if (SDL_strncmp(magic, "gimp xcf ", 9) == 0) {
218 is_XCF = 1;
219 }
220 }
221 SDL_RWseek(src, start, RW_SEEK_SET);
222 return(is_XCF);
223 }
224
read_string(SDL_RWops * src)225 static char * read_string (SDL_RWops * src) {
226 Sint64 remaining;
227 Uint32 tmp;
228 char * data;
229
230 tmp = SDL_ReadBE32(src);
231 remaining = SDL_RWsize(src) - SDL_RWtell(src);
232 if (tmp > 0 && (Sint32)tmp <= remaining) {
233 data = (char *) SDL_malloc (sizeof (char) * tmp);
234 if (data) {
235 SDL_RWread(src, data, tmp, 1);
236 data[tmp - 1] = '\0';
237 }
238 }
239 else {
240 data = NULL;
241 }
242 return data;
243 }
244
read_offset(SDL_RWops * src,const xcf_header * h)245 static Uint64 read_offset (SDL_RWops * src, const xcf_header * h) {
246 Uint64 offset; // starting with version 11, offsets are 64 bits
247 offset = (h->file_version >= 11) ? (Uint64)SDL_ReadBE32 (src) << 32 : 0;
248 offset |= SDL_ReadBE32 (src);
249 return offset;
250 }
251
252
Swap32(Uint32 v)253 static Uint32 Swap32 (Uint32 v) {
254 return
255 ((v & 0x000000FF) << 16)
256 | ((v & 0x0000FF00))
257 | ((v & 0x00FF0000) >> 16)
258 | ((v & 0xFF000000));
259 }
260
xcf_read_property(SDL_RWops * src,xcf_prop * prop)261 static int xcf_read_property (SDL_RWops * src, xcf_prop * prop) {
262 Uint32 len;
263 prop->id = SDL_ReadBE32 (src);
264 prop->length = SDL_ReadBE32 (src);
265
266 #if DEBUG
267 printf ("%.8X: %s(%u): %u\n", SDL_RWtell (src), prop->id < 25 ? prop_names [prop->id] : "unknown", prop->id, prop->length);
268 #endif
269
270 switch (prop->id) {
271 case PROP_COLORMAP:
272 prop->data.colormap.num = SDL_ReadBE32 (src);
273 prop->data.colormap.cmap = (char *) SDL_malloc (sizeof (char) * prop->data.colormap.num * 3);
274 SDL_RWread (src, prop->data.colormap.cmap, prop->data.colormap.num*3, 1);
275 break;
276
277 case PROP_OFFSETS:
278 prop->data.offset.x = SDL_ReadBE32 (src);
279 prop->data.offset.y = SDL_ReadBE32 (src);
280 break;
281 case PROP_OPACITY:
282 prop->data.opacity = SDL_ReadBE32 (src);
283 break;
284 case PROP_COMPRESSION:
285 case PROP_COLOR:
286 if (prop->length > sizeof(prop->data)) {
287 len = sizeof(prop->data);
288 } else {
289 len = prop->length;
290 }
291 SDL_RWread(src, &prop->data, len, 1);
292 break;
293 case PROP_VISIBLE:
294 prop->data.visible = SDL_ReadBE32 (src);
295 break;
296 default:
297 // SDL_RWread (src, &prop->data, prop->length, 1);
298 if (SDL_RWseek (src, prop->length, RW_SEEK_CUR) < 0)
299 return 0; // ERROR
300 }
301 return 1; // OK
302 }
303
free_xcf_header(xcf_header * h)304 static void free_xcf_header (xcf_header * h) {
305 if (h->cm_num)
306 SDL_free (h->cm_map);
307 if (h->layer_file_offsets)
308 SDL_free (h->layer_file_offsets);
309 SDL_free (h);
310 }
311
read_xcf_header(SDL_RWops * src)312 static xcf_header * read_xcf_header (SDL_RWops * src) {
313 xcf_header * h;
314 xcf_prop prop;
315
316 h = (xcf_header *) SDL_malloc (sizeof (xcf_header));
317 if (!h) {
318 return NULL;
319 }
320 SDL_RWread (src, h->sign, 14, 1);
321 h->width = SDL_ReadBE32 (src);
322 h->height = SDL_ReadBE32 (src);
323 h->image_type = SDL_ReadBE32 (src);
324 h->file_version = (h->sign[10] - '0') * 100 + (h->sign[11] - '0') * 10 + (h->sign[12] - '0');
325 #ifdef DEBUG
326 printf ("XCF signature : %.14s (version %u)\n", h->sign, h->file_version);
327 printf (" (%u,%u) type=%u\n", h->width, h->height, h->image_type);
328 #endif
329 if (h->file_version >= 4)
330 h->precision = SDL_ReadBE32 (src);
331 else
332 h->precision = 150;
333
334 h->properties = NULL;
335 h->layer_file_offsets = NULL;
336 h->compr = COMPR_NONE;
337 h->cm_num = 0;
338 h->cm_map = NULL;
339
340 // Just read, don't save
341 do {
342 if (!xcf_read_property (src, &prop)) {
343 free_xcf_header (h);
344 return NULL;
345 }
346 if (prop.id == PROP_COMPRESSION)
347 h->compr = (xcf_compr_type)prop.data.compression;
348 else if (prop.id == PROP_COLORMAP) {
349 // unused var: int i;
350 Uint32 cm_num;
351 unsigned char *cm_map;
352
353 cm_num = prop.data.colormap.num;
354 cm_map = (unsigned char *) SDL_realloc(h->cm_map, sizeof (unsigned char) * 3 * cm_num);
355 if (cm_map) {
356 h->cm_num = cm_num;
357 h->cm_map = cm_map;
358 SDL_memcpy (h->cm_map, prop.data.colormap.cmap, 3*sizeof (char)*h->cm_num);
359 }
360 SDL_free (prop.data.colormap.cmap);
361
362 if (!cm_map) {
363 free_xcf_header(h);
364 return NULL;
365 }
366 }
367 } while (prop.id != PROP_END);
368
369 return h;
370 }
371
free_xcf_layer(xcf_layer * l)372 static void free_xcf_layer (xcf_layer * l) {
373 SDL_free (l->name);
374 SDL_free (l);
375 }
376
read_xcf_layer(SDL_RWops * src,const xcf_header * h)377 static xcf_layer * read_xcf_layer (SDL_RWops * src, const xcf_header * h) {
378 xcf_layer * l;
379 xcf_prop prop;
380
381 l = (xcf_layer *) SDL_malloc (sizeof (xcf_layer));
382 l->width = SDL_ReadBE32 (src);
383 l->height = SDL_ReadBE32 (src);
384 l->layer_type = SDL_ReadBE32 (src);
385
386 l->name = read_string (src);
387 #ifdef DEBUG
388 printf ("layer (%d,%d) type=%d '%s'\n", l->width, l->height, l->layer_type, l->name);
389 #endif
390
391 do {
392 if (!xcf_read_property (src, &prop)) {
393 free_xcf_layer (l);
394 return NULL;
395 }
396 if (prop.id == PROP_OFFSETS) {
397 l->offset_x = prop.data.offset.x;
398 l->offset_y = prop.data.offset.y;
399 } else if (prop.id == PROP_VISIBLE) {
400 l->visible = prop.data.visible ? 1 : 0;
401 } else if (prop.id == PROP_COLORMAP) {
402 SDL_free (prop.data.colormap.cmap);
403 }
404 } while (prop.id != PROP_END);
405
406 l->hierarchy_file_offset = read_offset (src, h);
407 l->layer_mask_offset = read_offset (src, h);
408
409 return l;
410 }
411
free_xcf_channel(xcf_channel * c)412 static void free_xcf_channel (xcf_channel * c) {
413 SDL_free (c->name);
414 SDL_free (c);
415 }
416
read_xcf_channel(SDL_RWops * src,const xcf_header * h)417 static xcf_channel * read_xcf_channel (SDL_RWops * src, const xcf_header * h) {
418 xcf_channel * l;
419 xcf_prop prop;
420
421 l = (xcf_channel *) SDL_malloc (sizeof (xcf_channel));
422 l->width = SDL_ReadBE32 (src);
423 l->height = SDL_ReadBE32 (src);
424
425 l->name = read_string (src);
426 #ifdef DEBUG
427 printf ("channel (%u,%u) '%s'\n", l->width, l->height, l->name);
428 #endif
429
430 l->selection = 0;
431 do {
432 if (!xcf_read_property (src, &prop)) {
433 free_xcf_channel (l);
434 return NULL;
435 }
436 switch (prop.id) {
437 case PROP_OPACITY:
438 l->opacity = prop.data.opacity << 24;
439 break;
440 case PROP_COLOR:
441 l->color = ((Uint32) prop.data.color[0] << 16)
442 | ((Uint32) prop.data.color[1] << 8)
443 | ((Uint32) prop.data.color[2]);
444 break;
445 case PROP_SELECTION:
446 l->selection = 1;
447 break;
448 case PROP_VISIBLE:
449 l->visible = prop.data.visible ? 1 : 0;
450 break;
451 default:
452 ;
453 }
454 } while (prop.id != PROP_END);
455
456 l->hierarchy_file_offset = read_offset (src, h);
457
458 return l;
459 }
460
free_xcf_hierarchy(xcf_hierarchy * h)461 static void free_xcf_hierarchy (xcf_hierarchy * h) {
462 SDL_free (h->level_file_offsets);
463 SDL_free (h);
464 }
465
read_xcf_hierarchy(SDL_RWops * src,const xcf_header * head)466 static xcf_hierarchy * read_xcf_hierarchy (SDL_RWops * src, const xcf_header * head) {
467 xcf_hierarchy * h;
468 int i;
469
470 h = (xcf_hierarchy *) SDL_malloc (sizeof (xcf_hierarchy));
471 h->width = SDL_ReadBE32 (src);
472 h->height = SDL_ReadBE32 (src);
473 h->bpp = SDL_ReadBE32 (src);
474
475 h->level_file_offsets = NULL;
476 i = 0;
477 do {
478 h->level_file_offsets = (Uint32 *) SDL_realloc (h->level_file_offsets, sizeof (Uint32) * (i+1));
479 h->level_file_offsets [i] = read_offset (src, head);
480 } while (h->level_file_offsets [i++]);
481
482 return h;
483 }
484
free_xcf_level(xcf_level * l)485 static void free_xcf_level (xcf_level * l) {
486 SDL_free (l->tile_file_offsets);
487 SDL_free (l);
488 }
489
read_xcf_level(SDL_RWops * src,const xcf_header * h)490 static xcf_level * read_xcf_level (SDL_RWops * src, const xcf_header * h) {
491 xcf_level * l;
492 int i;
493
494 l = (xcf_level *) SDL_malloc (sizeof (xcf_level));
495 l->width = SDL_ReadBE32 (src);
496 l->height = SDL_ReadBE32 (src);
497
498 l->tile_file_offsets = NULL;
499 i = 0;
500 do {
501 l->tile_file_offsets = (Uint32 *) SDL_realloc (l->tile_file_offsets, sizeof (Uint32) * (i+1));
502 l->tile_file_offsets [i] = read_offset (src, h);
503 } while (l->tile_file_offsets [i++]);
504
505 return l;
506 }
507
free_xcf_tile(unsigned char * t)508 static void free_xcf_tile (unsigned char * t) {
509 SDL_free (t);
510 }
511
load_xcf_tile_none(SDL_RWops * src,Uint32 len,int bpp,int x,int y)512 static unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
513 unsigned char * load;
514
515 load = (unsigned char *) SDL_malloc (len); // expect this is okay
516 if (load != NULL)
517 SDL_RWread (src, load, len, 1);
518
519 return load;
520 }
521
load_xcf_tile_rle(SDL_RWops * src,Uint32 len,int bpp,int x,int y)522 static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
523 unsigned char * load, * t, * data, * d;
524 Uint32 reallen;
525 int i, size, count, j, length;
526 unsigned char val;
527
528 if (len == 0) { /* probably bogus data. */
529 return NULL;
530 }
531
532 t = load = (unsigned char *) SDL_malloc (len);
533 if (load == NULL)
534 return NULL;
535 reallen = SDL_RWread (src, t, 1, len);
536
537 data = (unsigned char *) SDL_calloc (1, x*y*bpp);
538 for (i = 0; i < bpp; i++) {
539 d = data + i;
540 size = x*y;
541 count = 0;
542
543 while (size > 0) {
544 val = *t++;
545
546 length = val;
547 if (length >= 128) {
548 length = 255 - (length - 1);
549 if (length == 128) {
550 length = (*t << 8) + t[1];
551 t += 2;
552 }
553
554 if (((size_t) (t - load) + length) >= len) {
555 break; /* bogus data */
556 } else if (length > size) {
557 break; /* bogus data */
558 }
559
560 count += length;
561 size -= length;
562
563 while (length-- > 0) {
564 *d = *t++;
565 d += bpp;
566 }
567 } else {
568 length += 1;
569 if (length == 128) {
570 length = (*t << 8) + t[1];
571 t += 2;
572 }
573
574 if (((size_t) (t - load)) >= len) {
575 break; /* bogus data */
576 } else if (length > size) {
577 break; /* bogus data */
578 }
579
580 count += length;
581 size -= length;
582
583 val = *t++;
584
585 for (j = 0; j < length; j++) {
586 *d = val;
587 d += bpp;
588 }
589 }
590 }
591
592 if (size > 0) {
593 break; /* just drop out, untouched data initialized to zero. */
594 }
595
596 }
597
598 SDL_free (load);
599 return (data);
600 }
601
rgb2grey(Uint32 a)602 static Uint32 rgb2grey (Uint32 a) {
603 Uint8 l;
604 l = (Uint8)(0.2990 * ((a & 0x00FF0000) >> 16)
605 + 0.5870 * ((a & 0x0000FF00) >> 8)
606 + 0.1140 * ((a & 0x000000FF)));
607
608 return (l << 16) | (l << 8) | l;
609 }
610
create_channel_surface(SDL_Surface * surf,xcf_image_type itype,Uint32 color,Uint32 opacity)611 static void create_channel_surface (SDL_Surface * surf, xcf_image_type itype, Uint32 color, Uint32 opacity) {
612 Uint32 c = 0;
613
614 switch (itype) {
615 case IMAGE_RGB:
616 case IMAGE_INDEXED:
617 c = opacity | color;
618 break;
619 case IMAGE_GREYSCALE:
620 c = opacity | rgb2grey (color);
621 break;
622 }
623 SDL_FillRect (surf, NULL, c);
624 }
625
626 static int
do_layer_surface(SDL_Surface * surface,SDL_RWops * src,xcf_header * head,xcf_layer * layer,load_tile_type load_tile)627 do_layer_surface(SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_layer * layer, load_tile_type load_tile)
628 {
629 xcf_hierarchy *hierarchy;
630 xcf_level *level;
631 unsigned char *tile;
632 Uint8 *p8;
633 Uint16 *p16;
634 Uint32 *p;
635 int i, j;
636 Uint32 x, y, tx, ty, ox, oy;
637 Uint32 *row;
638 Uint32 length;
639
640 SDL_RWseek(src, layer->hierarchy_file_offset, RW_SEEK_SET);
641 hierarchy = read_xcf_hierarchy(src, head);
642
643 if (hierarchy->bpp > 4) { /* unsupported. */
644 SDL_Log("Unknown Gimp image bpp (%u)\n", (unsigned int) hierarchy->bpp);
645 free_xcf_hierarchy(hierarchy);
646 return 1;
647 }
648
649 if ((hierarchy->width > 20000) || (hierarchy->height > 20000)) { /* arbitrary limit to avoid integer overflow. */
650 SDL_Log("Gimp image too large (%ux%u)\n", (unsigned int) hierarchy->width, (unsigned int) hierarchy->height);
651 free_xcf_hierarchy(hierarchy);
652 return 1;
653 }
654
655 level = NULL;
656 for (i = 0; hierarchy->level_file_offsets[i]; i++) {
657 if (SDL_RWseek(src, hierarchy->level_file_offsets[i], RW_SEEK_SET) < 0)
658 break;
659 if (i > 0) // skip level except the 1st one, just like GIMP does
660 continue;
661 level = read_xcf_level(src, head);
662
663 ty = tx = 0;
664 for (j = 0; level->tile_file_offsets[j]; j++) {
665 SDL_RWseek(src, level->tile_file_offsets[j], RW_SEEK_SET);
666 ox = tx + 64 > level->width ? level->width % 64 : 64;
667 oy = ty + 64 > level->height ? level->height % 64 : 64;
668 length = ox*oy*6;
669
670 if (level->tile_file_offsets[j + 1] > level->tile_file_offsets[j]) {
671 length = level->tile_file_offsets[j + 1] - level->tile_file_offsets[j];
672 }
673 tile = load_tile(src, length, hierarchy->bpp, ox, oy);
674
675 if (!tile) {
676 if (hierarchy) {
677 free_xcf_hierarchy(hierarchy);
678 }
679 if (level) {
680 free_xcf_level(level);
681 }
682 return 1;
683 }
684
685 p8 = tile;
686 p16 = (Uint16 *) p8;
687 p = (Uint32 *) p8;
688 for (y = ty; y < ty + oy; y++) {
689 if ((y >= surface->h) || ((tx+ox) > surface->w)) {
690 break;
691 }
692 row = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch + tx * 4);
693 switch (hierarchy->bpp) {
694 case 4:
695 for (x = tx; x < tx + ox; x++)
696 *row++ = Swap32(*p++);
697 break;
698 case 3:
699 for (x = tx; x < tx + ox; x++) {
700 *row = 0xFF000000;
701 *row |= ((Uint32)*p8++ << 16);
702 *row |= ((Uint32)*p8++ << 8);
703 *row |= ((Uint32)*p8++ << 0);
704 row++;
705 }
706 break;
707 case 2:
708 /* Indexed / Greyscale + Alpha */
709 switch (head->image_type) {
710 case IMAGE_INDEXED:
711 for (x = tx; x < tx + ox; x++) {
712 *row = ((Uint32)(head->cm_map[*p8 * 3]) << 16);
713 *row |= ((Uint32)(head->cm_map[*p8 * 3 + 1]) << 8);
714 *row |= ((Uint32)(head->cm_map[*p8++ * 3 + 2]) << 0);
715 *row |= ((Uint32)*p8++ << 24);
716 row++;
717 }
718 break;
719 case IMAGE_GREYSCALE:
720 for (x = tx; x < tx + ox; x++) {
721 *row = ((Uint32)*p8 << 16);
722 *row |= ((Uint32)*p8 << 8);
723 *row |= ((Uint32)*p8++ << 0);
724 *row |= ((Uint32)*p8++ << 24);
725 row++;
726 }
727 break;
728 default:
729 SDL_Log("Unknown Gimp image type (%d)\n", head->image_type);
730 if (hierarchy) {
731 free_xcf_hierarchy(hierarchy);
732 }
733 if (level)
734 free_xcf_level(level);
735 return 1;
736 }
737 break;
738 case 1:
739 /* Indexed / Greyscale */
740 switch (head->image_type) {
741 case IMAGE_INDEXED:
742 for (x = tx; x < tx + ox; x++) {
743 *row++ = 0xFF000000
744 | ((Uint32)(head->cm_map[*p8 * 3]) << 16)
745 | ((Uint32)(head->cm_map[*p8 * 3 + 1]) << 8)
746 | ((Uint32)(head->cm_map[*p8 * 3 + 2]) << 0);
747 p8++;
748 }
749 break;
750 case IMAGE_GREYSCALE:
751 for (x = tx; x < tx + ox; x++) {
752 *row++ = 0xFF000000
753 | (((Uint32)(*p8)) << 16)
754 | (((Uint32)(*p8)) << 8)
755 | (((Uint32)(*p8)) << 0);
756 ++p8;
757 }
758 break;
759 default:
760 SDL_Log("Unknown Gimp image type (%d)\n", head->image_type);
761 if (tile)
762 free_xcf_tile(tile);
763 if (level)
764 free_xcf_level(level);
765 if (hierarchy)
766 free_xcf_hierarchy(hierarchy);
767 return 1;
768 }
769 break;
770 }
771 }
772 free_xcf_tile(tile);
773
774 tx += 64;
775 if (tx >= level->width) {
776 tx = 0;
777 ty += 64;
778 }
779 if (ty >= level->height) {
780 break;
781 }
782 }
783 free_xcf_level(level);
784 }
785
786 free_xcf_hierarchy(hierarchy);
787
788 return 0;
789 }
790
IMG_LoadXCF_RW(SDL_RWops * src)791 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
792 {
793 Sint64 start;
794 const char *error = NULL;
795 SDL_Surface *surface, *lays;
796 xcf_header * head;
797 xcf_layer * layer;
798 xcf_channel ** channel;
799 int chnls, i, offsets;
800 Sint64 offset, fp;
801
802 unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int);
803
804 if (!src) {
805 /* The error message has been set in SDL_RWFromFile */
806 return NULL;
807 }
808 start = SDL_RWtell(src);
809
810 /* Initialize the data we will clean up when we're done */
811 surface = NULL;
812
813 head = read_xcf_header(src);
814 if (!head) {
815 return NULL;
816 }
817
818 switch (head->compr) {
819 case COMPR_NONE:
820 load_tile = load_xcf_tile_none;
821 break;
822 case COMPR_RLE:
823 load_tile = load_xcf_tile_rle;
824 break;
825 default:
826 SDL_Log("Unsupported Compression.\n");
827 free_xcf_header (head);
828 return NULL;
829 }
830
831 /* Create the surface of the appropriate type */
832 surface = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
833 0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
834
835 if ( surface == NULL ) {
836 error = "Out of memory";
837 goto done;
838 }
839
840 offsets = 0;
841
842 while ((offset = read_offset (src, head))) {
843 head->layer_file_offsets = (Uint32 *) SDL_realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1));
844 head->layer_file_offsets [offsets] = (Uint32)offset;
845 offsets++;
846 }
847 fp = SDL_RWtell (src);
848
849 lays = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
850 0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
851
852 if ( lays == NULL ) {
853 error = "Out of memory";
854 goto done;
855 }
856
857 // Blit layers backwards, because Gimp saves them highest first
858 for (i = offsets; i > 0; i--) {
859 SDL_Rect rs, rd;
860 SDL_RWseek (src, head->layer_file_offsets [i-1], RW_SEEK_SET);
861
862 layer = read_xcf_layer (src, head);
863 if (layer != NULL) {
864 do_layer_surface (lays, src, head, layer, load_tile);
865 rs.x = 0;
866 rs.y = 0;
867 rs.w = layer->width;
868 rs.h = layer->height;
869 rd.x = layer->offset_x;
870 rd.y = layer->offset_y;
871 rd.w = layer->width;
872 rd.h = layer->height;
873
874 if (layer->visible)
875 SDL_BlitSurface (lays, &rs, surface, &rd);
876 free_xcf_layer (layer);
877 }
878 }
879
880 SDL_FreeSurface (lays);
881
882 SDL_RWseek (src, fp, RW_SEEK_SET);
883
884 // read channels
885 channel = NULL;
886 chnls = 0;
887 while ((offset = read_offset (src, head))) {
888 channel = (xcf_channel **) SDL_realloc (channel, sizeof (xcf_channel *) * (chnls+1));
889 fp = SDL_RWtell (src);
890 SDL_RWseek (src, offset, RW_SEEK_SET);
891 channel [chnls] = (read_xcf_channel (src, head));
892 if (channel [chnls] != NULL)
893 chnls++;
894 SDL_RWseek (src, fp, RW_SEEK_SET);
895 }
896
897 if (chnls) {
898 SDL_Surface * chs;
899
900 chs = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
901 0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
902
903 if (chs == NULL) {
904 error = "Out of memory";
905 goto done;
906 }
907 for (i = 0; i < chnls; i++) {
908 // printf ("CNLBLT %i\n", i);
909 if (!channel [i]->selection && channel [i]->visible) {
910 create_channel_surface (chs, (xcf_image_type)head->image_type, channel [i]->color, channel [i]->opacity);
911 SDL_BlitSurface (chs, NULL, surface, NULL);
912 }
913 free_xcf_channel (channel [i]);
914 }
915 SDL_free(channel);
916
917 SDL_FreeSurface (chs);
918 }
919
920 done:
921 free_xcf_header (head);
922 if ( error ) {
923 SDL_RWseek(src, start, RW_SEEK_SET);
924 if ( surface ) {
925 SDL_FreeSurface(surface);
926 surface = NULL;
927 }
928 IMG_SetError("%s", error);
929 }
930
931 return(surface);
932 }
933
934 #else
935
936 /* See if an image is contained in a data source */
IMG_isXCF(SDL_RWops * src)937 int IMG_isXCF(SDL_RWops *src)
938 {
939 return(0);
940 }
941
942 /* Load a XCF type image from an SDL datasource */
IMG_LoadXCF_RW(SDL_RWops * src)943 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
944 {
945 return(NULL);
946 }
947
948 #endif /* LOAD_XCF */
949