IMG_gif.c 14 KB

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