Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 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
 
25
/* This is a GIF image file loading framework */
26
 
27
#include 
28
#include 
29
 
30
#include "SDL_image.h"
31
 
32
#ifdef LOAD_GIF
33
 
34
/* See if an image is contained in a data source */
35
int IMG_isGIF(SDL_RWops *src)
36
{
37
	int is_GIF;
38
	char magic[6];
39
 
40
	is_GIF = 0;
41
	if ( SDL_RWread(src, magic, 6, 1) ) {
42
		if ( (strncmp(magic, "GIF", 3) == 0) &&
43
		     ((memcmp(magic + 3, "87a", 3) == 0) ||
44
		      (memcmp(magic + 3, "89a", 3) == 0)) ) {
45
			is_GIF = 1;
46
		}
47
	}
48
	return(is_GIF);
49
}
50
 
51
/* Code from here to end of file has been adapted from XPaint:           */
52
/* +-------------------------------------------------------------------+ */
53
/* | Copyright 1990, 1991, 1993 David Koblas.			       | */
54
/* | Copyright 1996 Torsten Martinsen.				       | */
55
/* |   Permission to use, copy, modify, and distribute this software   | */
56
/* |   and its documentation for any purpose and without fee is hereby | */
57
/* |   granted, provided that the above copyright notice appear in all | */
58
/* |   copies and that both that copyright notice and this permission  | */
59
/* |   notice appear in supporting documentation.  This software is    | */
60
/* |   provided "as is" without express or implied warranty.	       | */
61
/* +-------------------------------------------------------------------+ */
62
 
63
/* Adapted for use in SDL by Sam Lantinga -- 7/20/98 */
64
#define USED_BY_SDL
65
 
66
#include 
67
#include 
68
 
69
#ifdef USED_BY_SDL
70
/* Changes to work with SDL:
71
 
72
   Include SDL header file
73
   Use SDL_Surface rather than xpaint Image structure
74
   Define SDL versions of RWSetMsg(), ImageNewCmap() and ImageSetCmap()
75
*/
76
#include "SDL.h"
77
 
78
#define Image			SDL_Surface
79
#define RWSetMsg		IMG_SetError
80
#define ImageNewCmap(w, h, s)	SDL_AllocSurface(SDL_SWSURFACE,w,h,8,0,0,0,0)
81
#define ImageSetCmap(s, i, R, G, B) do { \
82
				s->format->palette->colors[i].r = R; \
83
				s->format->palette->colors[i].g = G; \
84
				s->format->palette->colors[i].b = B; \
85
			} while (0)
86
/* * * * * */
87
 
88
#else
89
 
90
/* Original XPaint sources */
91
 
92
#include "image.h"
93
#include "rwTable.h"
94
 
95
#define SDL_RWops	FILE
96
#define SDL_RWclose	fclose
97
 
98
#endif /* USED_BY_SDL */
99
 
100
 
101
#define	MAXCOLORMAPSIZE		256
102
 
103
#define	TRUE	1
104
#define	FALSE	0
105
 
106
#define CM_RED		0
107
#define CM_GREEN	1
108
#define CM_BLUE		2
109
 
110
#define	MAX_LWZ_BITS		12
111
 
112
#define INTERLACE		0x40
113
#define LOCALCOLORMAP	0x80
114
#define BitSet(byte, bit)	(((byte) & (bit)) == (bit))
115
 
116
#define	ReadOK(file,buffer,len)	SDL_RWread(file, buffer, len, 1)
117
 
118
#define LM_to_uint(a,b)			(((b)<<8)|(a))
119
 
120
static struct {
121
    unsigned int Width;
122
    unsigned int Height;
123
    unsigned char ColorMap[3][MAXCOLORMAPSIZE];
124
    unsigned int BitPixel;
125
    unsigned int ColorResolution;
126
    unsigned int Background;
127
    unsigned int AspectRatio;
128
    int GrayScale;
129
} GifScreen;
130
 
131
static struct {
132
    int transparent;
133
    int delayTime;
134
    int inputFlag;
135
    int disposal;
136
} Gif89;
137
 
138
static int ReadColorMap(SDL_RWops * src, int number,
139
			unsigned char buffer[3][MAXCOLORMAPSIZE], int *flag);
140
static int DoExtension(SDL_RWops * src, int label);
141
static int GetDataBlock(SDL_RWops * src, unsigned char *buf);
142
static int GetCode(SDL_RWops * src, int code_size, int flag);
143
static int LWZReadByte(SDL_RWops * src, int flag, int input_code_size);
144
static Image *ReadImage(SDL_RWops * src, int len, int height, int,
145
			unsigned char cmap[3][MAXCOLORMAPSIZE],
146
			int gray, int interlace, int ignore);
147
 
148
Image *
149
IMG_LoadGIF_RW(SDL_RWops *src)
150
{
151
    unsigned char buf[16];
152
    unsigned char c;
153
    unsigned char localColorMap[3][MAXCOLORMAPSIZE];
154
    int grayScale;
155
    int useGlobalColormap;
156
    int bitPixel;
157
    int imageCount = 0;
158
    char version[4];
159
    int imageNumber = 1;
160
    Image *image = NULL;
161
 
162
    if ( src == NULL ) {
163
        goto done;
164
    }
165
    if (!ReadOK(src, buf, 6)) {
166
	RWSetMsg("error reading magic number");
167
        goto done;
168
    }
169
    if (strncmp((char *) buf, "GIF", 3) != 0) {
170
	RWSetMsg("not a GIF file");
171
        goto done;
172
    }
173
    strncpy(version, (char *) buf + 3, 3);
174
    version[3] = '\0';
175
 
176
    if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
177
	RWSetMsg("bad version number, not '87a' or '89a'");
178
        goto done;
179
    }
180
    Gif89.transparent = -1;
181
    Gif89.delayTime = -1;
182
    Gif89.inputFlag = -1;
183
    Gif89.disposal = 0;
184
 
185
    if (!ReadOK(src, buf, 7)) {
186
	RWSetMsg("failed to read screen descriptor");
187
        goto done;
188
    }
189
    GifScreen.Width = LM_to_uint(buf[0], buf[1]);
190
    GifScreen.Height = LM_to_uint(buf[2], buf[3]);
191
    GifScreen.BitPixel = 2 << (buf[4] & 0x07);
192
    GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
193
    GifScreen.Background = buf[5];
194
    GifScreen.AspectRatio = buf[6];
195
 
196
    if (BitSet(buf[4], LOCALCOLORMAP)) {	/* Global Colormap */
197
	if (ReadColorMap(src, GifScreen.BitPixel, GifScreen.ColorMap,
198
			 &GifScreen.GrayScale)) {
199
	    RWSetMsg("error reading global colormap");
200
            goto done;
201
	}
202
    }
203
    do {
204
	if (!ReadOK(src, &c, 1)) {
205
	    RWSetMsg("EOF / read error on image data");
206
            goto done;
207
	}
208
	if (c == ';') {		/* GIF terminator */
209
	    if (imageCount < imageNumber) {
210
		RWSetMsg("only %d image%s found in file",
211
			 imageCount, imageCount > 1 ? "s" : "");
212
                goto done;
213
	    }
214
	}
215
	if (c == '!') {		/* Extension */
216
	    if (!ReadOK(src, &c, 1)) {
217
		RWSetMsg("EOF / read error on extention function code");
218
                goto done;
219
	    }
220
	    DoExtension(src, c);
221
	    continue;
222
	}
223
	if (c != ',') {		/* Not a valid start character */
224
	    continue;
225
	}
226
	++imageCount;
227
 
228
	if (!ReadOK(src, buf, 9)) {
229
	    RWSetMsg("couldn't read left/top/width/height");
230
            goto done;
231
	}
232
	useGlobalColormap = !BitSet(buf[8], LOCALCOLORMAP);
233
 
234
	bitPixel = 1 << ((buf[8] & 0x07) + 1);
235
 
236
	if (!useGlobalColormap) {
237
	    if (ReadColorMap(src, bitPixel, localColorMap, &grayScale)) {
238
		RWSetMsg("error reading local colormap");
239
                goto done;
240
	    }
241
	    image = ReadImage(src, LM_to_uint(buf[4], buf[5]),
242
			      LM_to_uint(buf[6], buf[7]),
243
			      bitPixel, localColorMap, grayScale,
244
			      BitSet(buf[8], INTERLACE),
245
			      imageCount != imageNumber);
246
	} else {
247
	    image = ReadImage(src, LM_to_uint(buf[4], buf[5]),
248
			      LM_to_uint(buf[6], buf[7]),
249
			      GifScreen.BitPixel, GifScreen.ColorMap,
250
			      GifScreen.GrayScale, BitSet(buf[8], INTERLACE),
251
			      imageCount != imageNumber);
252
	}
253
    } while (image == NULL);
254
 
255
#ifdef USED_BY_SDL
256
    if ( Gif89.transparent > 0 ) {
257
        SDL_SetColorKey(image, SDL_SRCCOLORKEY, Gif89.transparent);
258
    }
259
#endif
260
 
261
done:
262
    return image;
263
}
264
 
265
static int
266
ReadColorMap(SDL_RWops *src, int number,
267
             unsigned char buffer[3][MAXCOLORMAPSIZE], int *gray)
268
{
269
    int i;
270
    unsigned char rgb[3];
271
    int flag;
272
 
273
    flag = TRUE;
274
 
275
    for (i = 0; i < number; ++i) {
276
	if (!ReadOK(src, rgb, sizeof(rgb))) {
277
	    RWSetMsg("bad colormap");
278
	    return 1;
279
	}
280
	buffer[CM_RED][i] = rgb[0];
281
	buffer[CM_GREEN][i] = rgb[1];
282
	buffer[CM_BLUE][i] = rgb[2];
283
	flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
284
    }
285
 
286
#if 0
287
    if (flag)
288
	*gray = (number == 2) ? PBM_TYPE : PGM_TYPE;
289
    else
290
	*gray = PPM_TYPE;
291
#else
292
    *gray = 0;
293
#endif
294
 
295
    return FALSE;
296
}
297
 
298
static int
299
DoExtension(SDL_RWops *src, int label)
300
{
301
    static unsigned char buf[256];
302
    char *str;
303
 
304
    switch (label) {
305
    case 0x01:			/* Plain Text Extension */
306
	str = "Plain Text Extension";
307
	break;
308
    case 0xff:			/* Application Extension */
309
	str = "Application Extension";
310
	break;
311
    case 0xfe:			/* Comment Extension */
312
	str = "Comment Extension";
313
	while (GetDataBlock(src, (unsigned char *) buf) != 0);
314
	return FALSE;
315
    case 0xf9:			/* Graphic Control Extension */
316
	str = "Graphic Control Extension";
317
	(void) GetDataBlock(src, (unsigned char *) buf);
318
	Gif89.disposal = (buf[0] >> 2) & 0x7;
319
	Gif89.inputFlag = (buf[0] >> 1) & 0x1;
320
	Gif89.delayTime = LM_to_uint(buf[1], buf[2]);
321
	if ((buf[0] & 0x1) != 0)
322
	    Gif89.transparent = buf[3];
323
 
324
	while (GetDataBlock(src, (unsigned char *) buf) != 0);
325
	return FALSE;
326
    default:
327
	str = (char *)buf;
328
	sprintf(str, "UNKNOWN (0x%02x)", label);
329
	break;
330
    }
331
 
332
    while (GetDataBlock(src, (unsigned char *) buf) != 0);
333
 
334
    return FALSE;
335
}
336
 
337
static int ZeroDataBlock = FALSE;
338
 
339
static int
340
GetDataBlock(SDL_RWops *src, unsigned char *buf)
341
{
342
    unsigned char count;
343
 
344
    if (!ReadOK(src, &count, 1)) {
345
	/* pm_message("error in getting DataBlock size" ); */
346
	return -1;
347
    }
348
    ZeroDataBlock = count == 0;
349
 
350
    if ((count != 0) && (!ReadOK(src, buf, count))) {
351
	/* pm_message("error in reading DataBlock" ); */
352
	return -1;
353
    }
354
    return count;
355
}
356
 
357
static int
358
GetCode(SDL_RWops *src, int code_size, int flag)
359
{
360
    static unsigned char buf[280];
361
    static int curbit, lastbit, done, last_byte;
362
    int i, j, ret;
363
    unsigned char count;
364
 
365
    if (flag) {
366
	curbit = 0;
367
	lastbit = 0;
368
	done = FALSE;
369
	return 0;
370
    }
371
    if ((curbit + code_size) >= lastbit) {
372
	if (done) {
373
	    if (curbit >= lastbit)
374
		RWSetMsg("ran off the end of my bits");
375
	    return -1;
376
	}
377
	buf[0] = buf[last_byte - 2];
378
	buf[1] = buf[last_byte - 1];
379
 
380
	if ((count = GetDataBlock(src, &buf[2])) == 0)
381
	    done = TRUE;
382
 
383
	last_byte = 2 + count;
384
	curbit = (curbit - lastbit) + 16;
385
	lastbit = (2 + count) * 8;
386
    }
387
    ret = 0;
388
    for (i = curbit, j = 0; j < code_size; ++i, ++j)
389
	ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j;
390
 
391
    curbit += code_size;
392
 
393
    return ret;
394
}
395
 
396
static int
397
LWZReadByte(SDL_RWops *src, int flag, int input_code_size)
398
{
399
    static int fresh = FALSE;
400
    int code, incode;
401
    static int code_size, set_code_size;
402
    static int max_code, max_code_size;
403
    static int firstcode, oldcode;
404
    static int clear_code, end_code;
405
    static int table[2][(1 << MAX_LWZ_BITS)];
406
    static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
407
    register int i;
408
 
409
    if (flag) {
410
	set_code_size = input_code_size;
411
	code_size = set_code_size + 1;
412
	clear_code = 1 << set_code_size;
413
	end_code = clear_code + 1;
414
	max_code_size = 2 * clear_code;
415
	max_code = clear_code + 2;
416
 
417
	GetCode(src, 0, TRUE);
418
 
419
	fresh = TRUE;
420
 
421
	for (i = 0; i < clear_code; ++i) {
422
	    table[0][i] = 0;
423
	    table[1][i] = i;
424
	}
425
	for (; i < (1 << MAX_LWZ_BITS); ++i)
426
	    table[0][i] = table[1][0] = 0;
427
 
428
	sp = stack;
429
 
430
	return 0;
431
    } else if (fresh) {
432
	fresh = FALSE;
433
	do {
434
	    firstcode = oldcode = GetCode(src, code_size, FALSE);
435
	} while (firstcode == clear_code);
436
	return firstcode;
437
    }
438
    if (sp > stack)
439
	return *--sp;
440
 
441
    while ((code = GetCode(src, code_size, FALSE)) >= 0) {
442
	if (code == clear_code) {
443
	    for (i = 0; i < clear_code; ++i) {
444
		table[0][i] = 0;
445
		table[1][i] = i;
446
	    }
447
	    for (; i < (1 << MAX_LWZ_BITS); ++i)
448
		table[0][i] = table[1][i] = 0;
449
	    code_size = set_code_size + 1;
450
	    max_code_size = 2 * clear_code;
451
	    max_code = clear_code + 2;
452
	    sp = stack;
453
	    firstcode = oldcode = GetCode(src, code_size, FALSE);
454
	    return firstcode;
455
	} else if (code == end_code) {
456
	    int count;
457
	    unsigned char buf[260];
458
 
459
	    if (ZeroDataBlock)
460
		return -2;
461
 
462
	    while ((count = GetDataBlock(src, buf)) > 0);
463
 
464
	    if (count != 0) {
465
		/*
466
		 * pm_message("missing EOD in data stream (common occurence)");
467
		 */
468
	    }
469
	    return -2;
470
	}
471
	incode = code;
472
 
473
	if (code >= max_code) {
474
	    *sp++ = firstcode;
475
	    code = oldcode;
476
	}
477
	while (code >= clear_code) {
478
	    *sp++ = table[1][code];
479
	    if (code == table[0][code])
480
		RWSetMsg("circular table entry BIG ERROR");
481
	    code = table[0][code];
482
	}
483
 
484
	*sp++ = firstcode = table[1][code];
485
 
486
	if ((code = max_code) < (1 << MAX_LWZ_BITS)) {
487
	    table[0][code] = oldcode;
488
	    table[1][code] = firstcode;
489
	    ++max_code;
490
	    if ((max_code >= max_code_size) &&
491
		(max_code_size < (1 << MAX_LWZ_BITS))) {
492
		max_code_size *= 2;
493
		++code_size;
494
	    }
495
	}
496
	oldcode = incode;
497
 
498
	if (sp > stack)
499
	    return *--sp;
500
    }
501
    return code;
502
}
503
 
504
static Image *
505
ReadImage(SDL_RWops * src, int len, int height, int cmapSize,
506
	  unsigned char cmap[3][MAXCOLORMAPSIZE],
507
	  int gray, int interlace, int ignore)
508
{
509
    Image *image;
510
    unsigned char c;
511
    int i, v;
512
    int xpos = 0, ypos = 0, pass = 0;
513
 
514
    /*
515
    **	Initialize the compression routines
516
     */
517
    if (!ReadOK(src, &c, 1)) {
518
	RWSetMsg("EOF / read error on image data");
519
	return NULL;
520
    }
521
    if (LWZReadByte(src, TRUE, c) < 0) {
522
	RWSetMsg("error reading image");
523
	return NULL;
524
    }
525
    /*
526
    **	If this is an "uninteresting picture" ignore it.
527
     */
528
    if (ignore) {
529
	while (LWZReadByte(src, FALSE, c) >= 0);
530
	return NULL;
531
    }
532
    image = ImageNewCmap(len, height, cmapSize);
533
 
534
    for (i = 0; i < cmapSize; i++)
535
	ImageSetCmap(image, i, cmap[CM_RED][i],
536
		     cmap[CM_GREEN][i], cmap[CM_BLUE][i]);
537
 
538
    while ((v = LWZReadByte(src, FALSE, c)) >= 0) {
539
#ifdef USED_BY_SDL
540
	((Uint8 *)image->pixels)[xpos + ypos * image->pitch] = v;
541
#else
542
	image->data[xpos + ypos * len] = v;
543
#endif
544
	++xpos;
545
	if (xpos == len) {
546
	    xpos = 0;
547
	    if (interlace) {
548
		switch (pass) {
549
		case 0:
550
		case 1:
551
		    ypos += 8;
552
		    break;
553
		case 2:
554
		    ypos += 4;
555
		    break;
556
		case 3:
557
		    ypos += 2;
558
		    break;
559
		}
560
 
561
		if (ypos >= height) {
562
		    ++pass;
563
		    switch (pass) {
564
		    case 1:
565
			ypos = 4;
566
			break;
567
		    case 2:
568
			ypos = 2;
569
			break;
570
		    case 3:
571
			ypos = 1;
572
			break;
573
		    default:
574
			goto fini;
575
		    }
576
		}
577
	    } else {
578
		++ypos;
579
	    }
580
	}
581
	if (ypos >= height)
582
	    break;
583
    }
584
 
585
  fini:
586
 
587
    return image;
588
}
589
 
590
#else
591
 
592
/* See if an image is contained in a data source */
593
int IMG_isGIF(SDL_RWops *src)
594
{
595
	return(0);
596
}
597
 
598
/* Load a GIF type image from an SDL datasource */
599
SDL_Surface *IMG_LoadGIF_RW(SDL_RWops *src)
600
{
601
	return(NULL);
602
}
603
 
604
#endif /* LOAD_GIF */