2 SDL_image: An example image loading library for use with SDL
3 Copyright (C) 1999, 2000, 2001 Sam Lantinga
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.
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.
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
23 /* $Id: IMG_gif.c,v 1.1.1.1 2003/01/04 11:37:22 leo Exp $ */
25 /* This is a GIF image file loading framework */
30 #include "SDL_image.h"
36 /* See if an image is contained in a data source */
37 int IMG_isGIF(SDL_RWops
*src
)
43 if ( SDL_RWread(src
, magic
, 6, 1) ) {
44 if ( (strncmp(magic
, "GIF", 3) == 0) &&
45 ((memcmp(magic
+ 3, "87a", 3) == 0) ||
46 (memcmp(magic
+ 3, "89a", 3) == 0)) ) {
53 /* Code from here to end of file has been adapted from XPaint: */
54 /* +-------------------------------------------------------------------+ */
55 /* | Copyright 1990, 1991, 1993 David Koblas. | */
56 /* | Copyright 1996 Torsten Martinsen. | */
57 /* | Permission to use, copy, modify, and distribute this software | */
58 /* | and its documentation for any purpose and without fee is hereby | */
59 /* | granted, provided that the above copyright notice appear in all | */
60 /* | copies and that both that copyright notice and this permission | */
61 /* | notice appear in supporting documentation. This software is | */
62 /* | provided "as is" without express or implied warranty. | */
63 /* +-------------------------------------------------------------------+ */
65 /* Adapted for use in SDL by Sam Lantinga -- 7/20/98 */
72 /* Changes to work with SDL:
74 Include SDL header file
75 Use SDL_Surface rather than xpaint Image structure
76 Define SDL versions of RWSetMsg(), ImageNewCmap() and ImageSetCmap()
80 #define Image SDL_Surface
81 #define RWSetMsg IMG_SetError
82 #define ImageNewCmap(w, h, s) SDL_AllocSurface(SDL_SWSURFACE,w,h,8,0,0,0,0)
83 #define ImageSetCmap(s, i, R, G, B) do { \
84 s->format->palette->colors[i].r = R; \
85 s->format->palette->colors[i].g = G; \
86 s->format->palette->colors[i].b = B; \
92 /* Original XPaint sources */
97 #define SDL_RWops FILE
98 #define SDL_RWclose fclose
100 #endif /* USED_BY_SDL */
103 #define MAXCOLORMAPSIZE 256
112 #define MAX_LWZ_BITS 12
114 #define INTERLACE 0x40
115 #define LOCALCOLORMAP 0x80
116 #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
118 #define ReadOK(file,buffer,len) SDL_RWread(file, buffer, len, 1)
120 #define LM_to_uint(a,b) (((b)<<8)|(a))
125 unsigned char ColorMap
[3][MAXCOLORMAPSIZE
];
126 unsigned int BitPixel
;
127 unsigned int ColorResolution
;
128 unsigned int Background
;
129 unsigned int AspectRatio
;
140 static int ReadColorMap(SDL_RWops
* src
, int number
,
141 unsigned char buffer
[3][MAXCOLORMAPSIZE
], int *flag
);
142 static int DoExtension(SDL_RWops
* src
, int label
);
143 static int GetDataBlock(SDL_RWops
* src
, unsigned char *buf
);
144 static int GetCode(SDL_RWops
* src
, int code_size
, int flag
);
145 static int LWZReadByte(SDL_RWops
* src
, int flag
, int input_code_size
);
146 static Image
*ReadImage(SDL_RWops
* src
, int len
, int height
, int,
147 unsigned char cmap
[3][MAXCOLORMAPSIZE
],
148 int gray
, int interlace
, int ignore
);
151 IMG_LoadGIF_RW(SDL_RWops
*src
)
153 unsigned char buf
[16];
155 unsigned char localColorMap
[3][MAXCOLORMAPSIZE
];
157 int useGlobalColormap
;
167 if (!ReadOK(src
, buf
, 6)) {
168 RWSetMsg("error reading magic number");
171 if (strncmp((char *) buf
, "GIF", 3) != 0) {
172 RWSetMsg("not a GIF file");
175 strncpy(version
, (char *) buf
+ 3, 3);
178 if ((strcmp(version
, "87a") != 0) && (strcmp(version
, "89a") != 0)) {
179 RWSetMsg("bad version number, not '87a' or '89a'");
182 Gif89
.transparent
= -1;
183 Gif89
.delayTime
= -1;
184 Gif89
.inputFlag
= -1;
187 if (!ReadOK(src
, buf
, 7)) {
188 RWSetMsg("failed to read screen descriptor");
191 GifScreen
.Width
= LM_to_uint(buf
[0], buf
[1]);
192 GifScreen
.Height
= LM_to_uint(buf
[2], buf
[3]);
193 GifScreen
.BitPixel
= 2 << (buf
[4] & 0x07);
194 GifScreen
.ColorResolution
= (((buf
[4] & 0x70) >> 3) + 1);
195 GifScreen
.Background
= buf
[5];
196 GifScreen
.AspectRatio
= buf
[6];
198 if (BitSet(buf
[4], LOCALCOLORMAP
)) { /* Global Colormap */
199 if (ReadColorMap(src
, GifScreen
.BitPixel
, GifScreen
.ColorMap
,
200 &GifScreen
.GrayScale
)) {
201 RWSetMsg("error reading global colormap");
206 if (!ReadOK(src
, &c
, 1)) {
207 RWSetMsg("EOF / read error on image data");
210 if (c
== ';') { /* GIF terminator */
211 if (imageCount
< imageNumber
) {
212 RWSetMsg("only %d image%s found in file",
213 imageCount
, imageCount
> 1 ? "s" : "");
217 if (c
== '!') { /* Extension */
218 if (!ReadOK(src
, &c
, 1)) {
219 RWSetMsg("EOF / read error on extention function code");
225 if (c
!= ',') { /* Not a valid start character */
230 if (!ReadOK(src
, buf
, 9)) {
231 RWSetMsg("couldn't read left/top/width/height");
234 useGlobalColormap
= !BitSet(buf
[8], LOCALCOLORMAP
);
236 bitPixel
= 1 << ((buf
[8] & 0x07) + 1);
238 if (!useGlobalColormap
) {
239 if (ReadColorMap(src
, bitPixel
, localColorMap
, &grayScale
)) {
240 RWSetMsg("error reading local colormap");
243 image
= ReadImage(src
, LM_to_uint(buf
[4], buf
[5]),
244 LM_to_uint(buf
[6], buf
[7]),
245 bitPixel
, localColorMap
, grayScale
,
246 BitSet(buf
[8], INTERLACE
),
247 imageCount
!= imageNumber
);
249 image
= ReadImage(src
, LM_to_uint(buf
[4], buf
[5]),
250 LM_to_uint(buf
[6], buf
[7]),
251 GifScreen
.BitPixel
, GifScreen
.ColorMap
,
252 GifScreen
.GrayScale
, BitSet(buf
[8], INTERLACE
),
253 imageCount
!= imageNumber
);
255 } while (image
== NULL
);
258 if ( Gif89
.transparent
>= 0 ) {
259 SDL_SetColorKey(image
, SDL_SRCCOLORKEY
, Gif89
.transparent
);
268 ReadColorMap(SDL_RWops
*src
, int number
,
269 unsigned char buffer
[3][MAXCOLORMAPSIZE
], int *gray
)
272 unsigned char rgb
[3];
277 for (i
= 0; i
< number
; ++i
) {
278 if (!ReadOK(src
, rgb
, sizeof(rgb
))) {
279 RWSetMsg("bad colormap");
282 buffer
[CM_RED
][i
] = rgb
[0];
283 buffer
[CM_GREEN
][i
] = rgb
[1];
284 buffer
[CM_BLUE
][i
] = rgb
[2];
285 flag
&= (rgb
[0] == rgb
[1] && rgb
[1] == rgb
[2]);
290 *gray
= (number
== 2) ? PBM_TYPE
: PGM_TYPE
;
301 DoExtension(SDL_RWops
*src
, int label
)
303 static unsigned char buf
[256];
307 case 0x01: /* Plain Text Extension */
308 str
= "Plain Text Extension";
310 case 0xff: /* Application Extension */
311 str
= "Application Extension";
313 case 0xfe: /* Comment Extension */
314 str
= "Comment Extension";
315 while (GetDataBlock(src
, (unsigned char *) buf
) != 0);
317 case 0xf9: /* Graphic Control Extension */
318 str
= "Graphic Control Extension";
319 (void) GetDataBlock(src
, (unsigned char *) buf
);
320 Gif89
.disposal
= (buf
[0] >> 2) & 0x7;
321 Gif89
.inputFlag
= (buf
[0] >> 1) & 0x1;
322 Gif89
.delayTime
= LM_to_uint(buf
[1], buf
[2]);
323 if ((buf
[0] & 0x1) != 0)
324 Gif89
.transparent
= buf
[3];
326 while (GetDataBlock(src
, (unsigned char *) buf
) != 0);
330 sprintf(str
, "UNKNOWN (0x%02x)", label
);
334 while (GetDataBlock(src
, (unsigned char *) buf
) != 0);
339 static int ZeroDataBlock
= FALSE
;
342 GetDataBlock(SDL_RWops
*src
, unsigned char *buf
)
346 if (!ReadOK(src
, &count
, 1)) {
347 /* pm_message("error in getting DataBlock size" ); */
350 ZeroDataBlock
= count
== 0;
352 if ((count
!= 0) && (!ReadOK(src
, buf
, count
))) {
353 /* pm_message("error in reading DataBlock" ); */
360 GetCode(SDL_RWops
*src
, int code_size
, int flag
)
362 static unsigned char buf
[280];
363 static int curbit
, lastbit
, done
, last_byte
;
373 if ((curbit
+ code_size
) >= lastbit
) {
375 if (curbit
>= lastbit
)
376 RWSetMsg("ran off the end of my bits");
379 buf
[0] = buf
[last_byte
- 2];
380 buf
[1] = buf
[last_byte
- 1];
382 if ((count
= GetDataBlock(src
, &buf
[2])) == 0)
385 last_byte
= 2 + count
;
386 curbit
= (curbit
- lastbit
) + 16;
387 lastbit
= (2 + count
) * 8;
390 for (i
= curbit
, j
= 0; j
< code_size
; ++i
, ++j
)
391 ret
|= ((buf
[i
/ 8] & (1 << (i
% 8))) != 0) << j
;
399 LWZReadByte(SDL_RWops
*src
, int flag
, int input_code_size
)
401 static int fresh
= FALSE
;
403 static int code_size
, set_code_size
;
404 static int max_code
, max_code_size
;
405 static int firstcode
, oldcode
;
406 static int clear_code
, end_code
;
407 static int table
[2][(1 << MAX_LWZ_BITS
)];
408 static int stack
[(1 << (MAX_LWZ_BITS
)) * 2], *sp
;
412 set_code_size
= input_code_size
;
413 code_size
= set_code_size
+ 1;
414 clear_code
= 1 << set_code_size
;
415 end_code
= clear_code
+ 1;
416 max_code_size
= 2 * clear_code
;
417 max_code
= clear_code
+ 2;
419 GetCode(src
, 0, TRUE
);
423 for (i
= 0; i
< clear_code
; ++i
) {
427 for (; i
< (1 << MAX_LWZ_BITS
); ++i
)
428 table
[0][i
] = table
[1][0] = 0;
436 firstcode
= oldcode
= GetCode(src
, code_size
, FALSE
);
437 } while (firstcode
== clear_code
);
443 while ((code
= GetCode(src
, code_size
, FALSE
)) >= 0) {
444 if (code
== clear_code
) {
445 for (i
= 0; i
< clear_code
; ++i
) {
449 for (; i
< (1 << MAX_LWZ_BITS
); ++i
)
450 table
[0][i
] = table
[1][i
] = 0;
451 code_size
= set_code_size
+ 1;
452 max_code_size
= 2 * clear_code
;
453 max_code
= clear_code
+ 2;
455 firstcode
= oldcode
= GetCode(src
, code_size
, FALSE
);
457 } else if (code
== end_code
) {
459 unsigned char buf
[260];
464 while ((count
= GetDataBlock(src
, buf
)) > 0);
468 * pm_message("missing EOD in data stream (common occurence)");
475 if (code
>= max_code
) {
479 while (code
>= clear_code
) {
480 *sp
++ = table
[1][code
];
481 if (code
== table
[0][code
])
482 RWSetMsg("circular table entry BIG ERROR");
483 code
= table
[0][code
];
486 *sp
++ = firstcode
= table
[1][code
];
488 if ((code
= max_code
) < (1 << MAX_LWZ_BITS
)) {
489 table
[0][code
] = oldcode
;
490 table
[1][code
] = firstcode
;
492 if ((max_code
>= max_code_size
) &&
493 (max_code_size
< (1 << MAX_LWZ_BITS
))) {
507 ReadImage(SDL_RWops
* src
, int len
, int height
, int cmapSize
,
508 unsigned char cmap
[3][MAXCOLORMAPSIZE
],
509 int gray
, int interlace
, int ignore
)
514 int xpos
= 0, ypos
= 0, pass
= 0;
517 ** Initialize the compression routines
519 if (!ReadOK(src
, &c
, 1)) {
520 RWSetMsg("EOF / read error on image data");
523 if (LWZReadByte(src
, TRUE
, c
) < 0) {
524 RWSetMsg("error reading image");
528 ** If this is an "uninteresting picture" ignore it.
531 while (LWZReadByte(src
, FALSE
, c
) >= 0);
534 image
= ImageNewCmap(len
, height
, cmapSize
);
536 for (i
= 0; i
< cmapSize
; i
++)
537 ImageSetCmap(image
, i
, cmap
[CM_RED
][i
],
538 cmap
[CM_GREEN
][i
], cmap
[CM_BLUE
][i
]);
540 while ((v
= LWZReadByte(src
, FALSE
, c
)) >= 0) {
542 ((Uint8
*)image
->pixels
)[xpos
+ ypos
* image
->pitch
] = v
;
544 image
->data
[xpos
+ ypos
* len
] = v
;
563 if (ypos
>= height
) {
594 /* See if an image is contained in a data source */
595 int IMG_isGIF(SDL_RWops
*src
)
600 /* Load a GIF type image from an SDL datasource */
601 SDL_Surface
*IMG_LoadGIF_RW(SDL_RWops
*src
)
606 #endif /* LOAD_GIF */