PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/fltk/src/Fl_GIF_Image.cxx

http://luafltk.googlecode.com/
C++ | 390 lines | 241 code | 54 blank | 95 comment | 84 complexity | 4378169d41860e51747585389f4db490 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-3.0, 0BSD
  1. //
  2. // "$Id: Fl_GIF_Image.cxx 6616 2009-01-01 21:28:26Z matt $"
  3. //
  4. // Fl_GIF_Image routines.
  5. //
  6. // Copyright 1997-2009 by Bill Spitzak and others.
  7. //
  8. // This library is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU Library General Public
  10. // License as published by the Free Software Foundation; either
  11. // version 2 of the License, or (at your option) any later version.
  12. //
  13. // This library is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. // Library General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Library General Public
  19. // License along with this library; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. // USA.
  22. //
  23. // Please report all bugs and problems on the following page:
  24. //
  25. // http://www.fltk.org/str.php
  26. //
  27. // Contents:
  28. //
  29. //
  30. //
  31. // Include necessary header files...
  32. //
  33. #include <FL/Fl.H>
  34. #include <FL/Fl_GIF_Image.H>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <FL/fl_utf8.h>
  38. #include "flstring.h"
  39. // Read a .gif file and convert it to a "xpm" format (actually my
  40. // modified one with compressed colormaps).
  41. // Extensively modified from original code for gif2ras by
  42. // Patrick J. Naughton of Sun Microsystems. The original
  43. // copyright notice follows:
  44. /* gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
  45. *
  46. * Copyright (c) 1988 by Patrick J. Naughton
  47. *
  48. * Author: Patrick J. Naughton
  49. * naughton@wind.sun.com
  50. *
  51. * Permission to use, copy, modify, and distribute this software and its
  52. * documentation for any purpose and without fee is hereby granted,
  53. * provided that the above copyright notice appear in all copies and that
  54. * both that copyright notice and this permission notice appear in
  55. * supporting documentation.
  56. *
  57. * This file is provided AS IS with no warranties of any kind. The author
  58. * shall have no liability with respect to the infringement of copyrights,
  59. * trade secrets or any patents by this file or any part thereof. In no
  60. * event will the author be liable for any lost revenue or profits or
  61. * other special, indirect and consequential damages.
  62. *
  63. * Comments and additions should be sent to the author:
  64. *
  65. * Patrick J. Naughton
  66. * Sun Microsystems, Inc.
  67. * 2550 Garcia Ave, MS 14-40
  68. * Mountain View, CA 94043
  69. * (415) 336-1080
  70. */
  71. typedef unsigned char uchar;
  72. #define NEXTBYTE (uchar)getc(GifFile)
  73. #define GETSHORT(var) var = NEXTBYTE; var += NEXTBYTE << 8
  74. /**
  75. The constructor loads the named GIF image.
  76. <P>The inherited destructor free all memory and server resources that are used by
  77. the image.
  78. */
  79. Fl_GIF_Image::Fl_GIF_Image(const char *infname) : Fl_Pixmap((char *const*)0) {
  80. FILE *GifFile; // File to read
  81. char **new_data; // Data array
  82. if ((GifFile = fl_fopen(infname, "rb")) == NULL) {
  83. Fl::error("Fl_GIF_Image: Unable to open %s!", infname);
  84. return;
  85. }
  86. {char b[6];
  87. if (fread(b,1,6,GifFile)<6) {
  88. fclose(GifFile);
  89. return; /* quit on eof */
  90. }
  91. if (b[0]!='G' || b[1]!='I' || b[2] != 'F') {
  92. fclose(GifFile);
  93. Fl::error("Fl_GIF_Image: %s is not a GIF file.\n", infname);
  94. return;
  95. }
  96. if (b[3]!='8' || b[4]>'9' || b[5]!= 'a')
  97. Fl::warning("%s is version %c%c%c.",infname,b[3],b[4],b[5]);
  98. }
  99. int Width; GETSHORT(Width);
  100. int Height; GETSHORT(Height);
  101. uchar ch = NEXTBYTE;
  102. char HasColormap = ((ch & 0x80) != 0);
  103. int BitsPerPixel = (ch & 7) + 1;
  104. int ColorMapSize = 1 << BitsPerPixel;
  105. // int OriginalResolution = ((ch>>4)&7)+1;
  106. // int SortedTable = (ch&8)!=0;
  107. ch = NEXTBYTE; // Background Color index
  108. ch = NEXTBYTE; // Aspect ratio is N/64
  109. // Read in global colormap:
  110. uchar transparent_pixel = 0;
  111. char has_transparent = 0;
  112. uchar Red[256], Green[256], Blue[256]; /* color map */
  113. if (HasColormap) {
  114. for (int i=0; i < ColorMapSize; i++) {
  115. Red[i] = NEXTBYTE;
  116. Green[i] = NEXTBYTE;
  117. Blue[i] = NEXTBYTE;
  118. }
  119. } else {
  120. Fl::warning("%s does not have a colormap.", infname);
  121. for (int i = 0; i < ColorMapSize; i++)
  122. Red[i] = Green[i] = Blue[i] = (uchar)(255 * i / (ColorMapSize-1));
  123. }
  124. int CodeSize; /* Code size, init from GIF header, increases... */
  125. char Interlace;
  126. for (;;) {
  127. int i = NEXTBYTE;
  128. if (i<0) {
  129. fclose(GifFile);
  130. Fl::error("Fl_GIF_Image: %s - unexpected EOF",infname);
  131. return;
  132. }
  133. int blocklen;
  134. // if (i == 0x3B) return 0; eof code
  135. if (i == 0x21) { // a "gif extension"
  136. ch = NEXTBYTE;
  137. blocklen = NEXTBYTE;
  138. if (ch==0xF9 && blocklen==4) { // Netscape animation extension
  139. char bits;
  140. bits = NEXTBYTE;
  141. getc(GifFile); getc(GifFile); // GETSHORT(delay);
  142. transparent_pixel = NEXTBYTE;
  143. if (bits & 1) has_transparent = 1;
  144. blocklen = NEXTBYTE;
  145. } else if (ch == 0xFF) { // Netscape repeat count
  146. ;
  147. } else if (ch != 0xFE) { //Gif Comment
  148. Fl::warning("%s: unknown gif extension 0x%02x.", infname, ch);
  149. }
  150. } else if (i == 0x2c) { // an image
  151. ch = NEXTBYTE; ch = NEXTBYTE; // GETSHORT(x_position);
  152. ch = NEXTBYTE; ch = NEXTBYTE; // GETSHORT(y_position);
  153. GETSHORT(Width);
  154. GETSHORT(Height);
  155. ch = NEXTBYTE;
  156. Interlace = ((ch & 0x40) != 0);
  157. if (ch&0x80) {
  158. // read local color map
  159. int n = 2<<(ch&7);
  160. for (i=0; i < n; i++) {
  161. Red[i] = NEXTBYTE;
  162. Green[i] = NEXTBYTE;
  163. Blue[i] = NEXTBYTE;
  164. }
  165. }
  166. CodeSize = NEXTBYTE+1;
  167. break; // okay, this is the image we want
  168. } else {
  169. Fl::warning("%s: unknown gif code 0x%02x", infname, i);
  170. blocklen = 0;
  171. }
  172. // skip the data:
  173. while (blocklen>0) {while (blocklen--) {ch = NEXTBYTE;} blocklen=NEXTBYTE;}
  174. }
  175. if (BitsPerPixel >= CodeSize)
  176. {
  177. // Workaround for broken GIF files...
  178. BitsPerPixel = CodeSize - 1;
  179. ColorMapSize = 1 << BitsPerPixel;
  180. }
  181. uchar *Image = new uchar[Width*Height];
  182. int YC = 0, Pass = 0; /* Used to de-interlace the picture */
  183. uchar *p = Image;
  184. uchar *eol = p+Width;
  185. int InitCodeSize = CodeSize;
  186. int ClearCode = (1 << (CodeSize-1));
  187. int EOFCode = ClearCode + 1;
  188. int FirstFree = ClearCode + 2;
  189. int FinChar = 0;
  190. int ReadMask = (1<<CodeSize) - 1;
  191. int FreeCode = FirstFree;
  192. int OldCode = ClearCode;
  193. // tables used by LZW decompresser:
  194. short int Prefix[4096];
  195. uchar Suffix[4096];
  196. int blocklen = NEXTBYTE;
  197. uchar thisbyte = NEXTBYTE; blocklen--;
  198. int frombit = 0;
  199. for (;;) {
  200. /* Fetch the next code from the raster data stream. The codes can be
  201. * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
  202. * maintain our location as a pointer and a bit offset.
  203. * In addition, gif adds totally useless and annoying block counts
  204. * that must be correctly skipped over. */
  205. int CurCode = thisbyte;
  206. if (frombit+CodeSize > 7) {
  207. if (blocklen <= 0) {
  208. blocklen = NEXTBYTE;
  209. if (blocklen <= 0) break;
  210. }
  211. thisbyte = NEXTBYTE; blocklen--;
  212. CurCode |= thisbyte<<8;
  213. }
  214. if (frombit+CodeSize > 15) {
  215. if (blocklen <= 0) {
  216. blocklen = NEXTBYTE;
  217. if (blocklen <= 0) break;
  218. }
  219. thisbyte = NEXTBYTE; blocklen--;
  220. CurCode |= thisbyte<<16;
  221. }
  222. CurCode = (CurCode>>frombit)&ReadMask;
  223. frombit = (frombit+CodeSize)%8;
  224. if (CurCode == ClearCode) {
  225. CodeSize = InitCodeSize;
  226. ReadMask = (1<<CodeSize) - 1;
  227. FreeCode = FirstFree;
  228. OldCode = ClearCode;
  229. continue;
  230. }
  231. if (CurCode == EOFCode) break;
  232. uchar OutCode[1025]; // temporary array for reversing codes
  233. uchar *tp = OutCode;
  234. int i;
  235. if (CurCode < FreeCode) i = CurCode;
  236. else if (CurCode == FreeCode) {*tp++ = (uchar)FinChar; i = OldCode;}
  237. else {Fl::error("Fl_GIF_Image: %s - LZW Barf!", infname); break;}
  238. while (i >= ColorMapSize) {*tp++ = Suffix[i]; i = Prefix[i];}
  239. *tp++ = FinChar = i;
  240. do {
  241. *p++ = *--tp;
  242. if (p >= eol) {
  243. if (!Interlace) YC++;
  244. else switch (Pass) {
  245. case 0: YC += 8; if (YC >= Height) {Pass++; YC = 4;} break;
  246. case 1: YC += 8; if (YC >= Height) {Pass++; YC = 2;} break;
  247. case 2: YC += 4; if (YC >= Height) {Pass++; YC = 1;} break;
  248. case 3: YC += 2; break;
  249. }
  250. if (YC>=Height) YC=0; /* cheap bug fix when excess data */
  251. p = Image + YC*Width;
  252. eol = p+Width;
  253. }
  254. } while (tp > OutCode);
  255. if (OldCode != ClearCode) {
  256. Prefix[FreeCode] = (short)OldCode;
  257. Suffix[FreeCode] = FinChar;
  258. FreeCode++;
  259. if (FreeCode > ReadMask) {
  260. if (CodeSize < 12) {
  261. CodeSize++;
  262. ReadMask = (1 << CodeSize) - 1;
  263. }
  264. else FreeCode--;
  265. }
  266. }
  267. OldCode = CurCode;
  268. }
  269. // We are done reading the file, now convert to xpm:
  270. // allocate line pointer arrays:
  271. w(Width);
  272. h(Height);
  273. d(1);
  274. new_data = new char*[Height+2];
  275. // transparent pixel must be zero, swap if it isn't:
  276. if (has_transparent && transparent_pixel != 0) {
  277. // swap transparent pixel with zero
  278. p = Image+Width*Height;
  279. while (p-- > Image) {
  280. if (*p==transparent_pixel) *p = 0;
  281. else if (!*p) *p = transparent_pixel;
  282. }
  283. uchar t;
  284. t = Red[0];
  285. Red[0] = Red[transparent_pixel];
  286. Red[transparent_pixel] = t;
  287. t = Green[0];
  288. Green[0] = Green[transparent_pixel];
  289. Green[transparent_pixel] = t;
  290. t = Blue[0];
  291. Blue[0] = Blue[transparent_pixel];
  292. Blue[transparent_pixel] = t;
  293. }
  294. // find out what colors are actually used:
  295. uchar used[256]; uchar remap[256];
  296. int i;
  297. for (i = 0; i < ColorMapSize; i++) used[i] = 0;
  298. p = Image+Width*Height;
  299. while (p-- > Image) used[*p] = 1;
  300. // remap them to start with printing characters:
  301. int base = has_transparent && used[0] ? ' ' : ' '+1;
  302. int numcolors = 0;
  303. for (i = 0; i < ColorMapSize; i++) if (used[i]) {
  304. remap[i] = (uchar)(base++);
  305. numcolors++;
  306. }
  307. // write the first line of xpm data (use suffix as temp array):
  308. int length = sprintf((char*)(Suffix),
  309. "%d %d %d %d",Width,Height,-numcolors,1);
  310. new_data[0] = new char[length+1];
  311. strcpy(new_data[0], (char*)Suffix);
  312. // write the colormap
  313. new_data[1] = (char*)(p = new uchar[4*numcolors]);
  314. for (i = 0; i < ColorMapSize; i++) if (used[i]) {
  315. *p++ = remap[i];
  316. *p++ = Red[i];
  317. *p++ = Green[i];
  318. *p++ = Blue[i];
  319. }
  320. // remap the image data:
  321. p = Image+Width*Height;
  322. while (p-- > Image) *p = remap[*p];
  323. // split the image data into lines:
  324. for (i=0; i<Height; i++) {
  325. new_data[i+2] = new char[Width+1];
  326. memcpy(new_data[i + 2], (char*)(Image + i*Width), Width);
  327. new_data[i + 2][Width] = 0;
  328. }
  329. data((const char **)new_data, Height + 2);
  330. alloc_data = 1;
  331. delete[] Image;
  332. fclose(GifFile);
  333. }
  334. //
  335. // End of "$Id: Fl_GIF_Image.cxx 6616 2009-01-01 21:28:26Z matt $".
  336. //