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

/juce/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp

http://juced.googlecode.com/
C++ | 469 lines | 346 code | 98 blank | 25 comment | 94 complexity | 9b250ae082490c1ad2c90ed097220965 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-2.0
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../../../../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "juce_GIFLoader.h"
  21. #include "../../colour/juce_PixelFormats.h"
  22. //==============================================================================
  23. GIFLoader::GIFLoader (InputStream& in)
  24. : image (0),
  25. input (in),
  26. dataBlockIsZero (false),
  27. fresh (false),
  28. finished (false)
  29. {
  30. currentBit = lastBit = lastByteIndex = 0;
  31. maxCode = maxCodeSize = codeSize = setCodeSize = 0;
  32. firstcode = oldcode = 0;
  33. clearCode = end_code = 0;
  34. int imageWidth, imageHeight;
  35. int transparent = -1;
  36. if (! getSizeFromHeader (imageWidth, imageHeight))
  37. return;
  38. if ((imageWidth <= 0) || (imageHeight <= 0))
  39. return;
  40. unsigned char buf [16];
  41. if (in.read (buf, 3) != 3)
  42. return;
  43. int numColours = 2 << (buf[0] & 7);
  44. if ((buf[0] & 0x80) != 0)
  45. readPalette (numColours);
  46. for (;;)
  47. {
  48. if (input.read (buf, 1) != 1)
  49. break;
  50. if (buf[0] == ';')
  51. break;
  52. if (buf[0] == '!')
  53. {
  54. if (input.read (buf, 1) != 1)
  55. break;
  56. if (processExtension (buf[0], transparent) < 0)
  57. break;
  58. continue;
  59. }
  60. if (buf[0] != ',')
  61. continue;
  62. if (input.read (buf, 9) != 9)
  63. break;
  64. imageWidth = makeWord (buf[4], buf[5]);
  65. imageHeight = makeWord (buf[6], buf[7]);
  66. numColours = 2 << (buf[8] & 7);
  67. if ((buf[8] & 0x80) != 0)
  68. if (! readPalette (numColours))
  69. break;
  70. image = Image::createNativeImage ((transparent >= 0) ? Image::ARGB : Image::RGB,
  71. imageWidth, imageHeight, (transparent >= 0));
  72. readImage (imageWidth, imageHeight,
  73. (buf[8] & 0x40) != 0,
  74. transparent);
  75. break;
  76. }
  77. }
  78. GIFLoader::~GIFLoader()
  79. {
  80. }
  81. bool GIFLoader::getSizeFromHeader (int& w, int& h)
  82. {
  83. unsigned char b [8];
  84. if (input.read (b, 6) == 6)
  85. {
  86. if ((strncmp ("GIF87a", (char*) b, 6) == 0)
  87. || (strncmp ("GIF89a", (char*) b, 6) == 0))
  88. {
  89. if (input.read (b, 4) == 4)
  90. {
  91. w = makeWord (b[0], b[1]);
  92. h = makeWord (b[2], b[3]);
  93. return true;
  94. }
  95. }
  96. }
  97. return false;
  98. }
  99. bool GIFLoader::readPalette (const int numCols)
  100. {
  101. unsigned char rgb[4];
  102. for (int i = 0; i < numCols; ++i)
  103. {
  104. input.read (rgb, 3);
  105. palette [i][0] = rgb[0];
  106. palette [i][1] = rgb[1];
  107. palette [i][2] = rgb[2];
  108. palette [i][3] = 0xff;
  109. }
  110. return true;
  111. }
  112. int GIFLoader::readDataBlock (unsigned char* const dest)
  113. {
  114. unsigned char n;
  115. if (input.read (&n, 1) == 1)
  116. {
  117. dataBlockIsZero = (n == 0);
  118. if (dataBlockIsZero || (input.read (dest, n) == n))
  119. return n;
  120. }
  121. return -1;
  122. }
  123. int GIFLoader::processExtension (const int type, int& transparent)
  124. {
  125. unsigned char b [300];
  126. int n = 0;
  127. if (type == 0xf9)
  128. {
  129. n = readDataBlock (b);
  130. if (n < 0)
  131. return 1;
  132. if ((b[0] & 0x1) != 0)
  133. transparent = b[3];
  134. }
  135. do
  136. {
  137. n = readDataBlock (b);
  138. }
  139. while (n > 0);
  140. return n;
  141. }
  142. int GIFLoader::getCode (const int codeSize_, const bool initialise)
  143. {
  144. if (initialise)
  145. {
  146. currentBit = 0;
  147. lastBit = 0;
  148. finished = false;
  149. return 0;
  150. }
  151. if ((currentBit + codeSize_) >= lastBit)
  152. {
  153. if (finished)
  154. return -1;
  155. buffer[0] = buffer [lastByteIndex - 2];
  156. buffer[1] = buffer [lastByteIndex - 1];
  157. const int n = readDataBlock (&buffer[2]);
  158. if (n == 0)
  159. finished = true;
  160. lastByteIndex = 2 + n;
  161. currentBit = (currentBit - lastBit) + 16;
  162. lastBit = (2 + n) * 8 ;
  163. }
  164. int result = 0;
  165. int i = currentBit;
  166. for (int j = 0; j < codeSize_; ++j)
  167. {
  168. result |= ((buffer[i >> 3] & (1 << (i & 7))) != 0) << j;
  169. ++i;
  170. }
  171. currentBit += codeSize_;
  172. return result;
  173. }
  174. int GIFLoader::readLZWByte (const bool initialise, const int inputCodeSize)
  175. {
  176. int code, incode, i;
  177. if (initialise)
  178. {
  179. setCodeSize = inputCodeSize;
  180. codeSize = setCodeSize + 1;
  181. clearCode = 1 << setCodeSize;
  182. end_code = clearCode + 1;
  183. maxCodeSize = 2 * clearCode;
  184. maxCode = clearCode + 2;
  185. getCode (0, true);
  186. fresh = true;
  187. for (i = 0; i < clearCode; ++i)
  188. {
  189. table[0][i] = 0;
  190. table[1][i] = i;
  191. }
  192. for (; i < maxGifCode; ++i)
  193. {
  194. table[0][i] = 0;
  195. table[1][i] = 0;
  196. }
  197. sp = stack;
  198. return 0;
  199. }
  200. else if (fresh)
  201. {
  202. fresh = false;
  203. do
  204. {
  205. firstcode = oldcode
  206. = getCode (codeSize, false);
  207. }
  208. while (firstcode == clearCode);
  209. return firstcode;
  210. }
  211. if (sp > stack)
  212. return *--sp;
  213. while ((code = getCode (codeSize, false)) >= 0)
  214. {
  215. if (code == clearCode)
  216. {
  217. for (i = 0; i < clearCode; ++i)
  218. {
  219. table[0][i] = 0;
  220. table[1][i] = i;
  221. }
  222. for (; i < maxGifCode; ++i)
  223. {
  224. table[0][i] = 0;
  225. table[1][i] = 0;
  226. }
  227. codeSize = setCodeSize + 1;
  228. maxCodeSize = 2 * clearCode;
  229. maxCode = clearCode + 2;
  230. sp = stack;
  231. firstcode = oldcode = getCode (codeSize, false);
  232. return firstcode;
  233. }
  234. else if (code == end_code)
  235. {
  236. if (dataBlockIsZero)
  237. return -2;
  238. unsigned char buf [260];
  239. int n;
  240. while ((n = readDataBlock (buf)) > 0)
  241. {}
  242. if (n != 0)
  243. return -2;
  244. }
  245. incode = code;
  246. if (code >= maxCode)
  247. {
  248. *sp++ = firstcode;
  249. code = oldcode;
  250. }
  251. while (code >= clearCode)
  252. {
  253. *sp++ = table[1][code];
  254. if (code == table[0][code])
  255. return -2;
  256. code = table[0][code];
  257. }
  258. *sp++ = firstcode = table[1][code];
  259. if ((code = maxCode) < maxGifCode)
  260. {
  261. table[0][code] = oldcode;
  262. table[1][code] = firstcode;
  263. ++maxCode;
  264. if ((maxCode >= maxCodeSize)
  265. && (maxCodeSize < maxGifCode))
  266. {
  267. maxCodeSize <<= 1;
  268. ++codeSize;
  269. }
  270. }
  271. oldcode = incode;
  272. if (sp > stack)
  273. return *--sp;
  274. }
  275. return code;
  276. }
  277. bool GIFLoader::readImage (const int width, const int height,
  278. const int interlace, const int transparent)
  279. {
  280. unsigned char c;
  281. if (input.read (&c, 1) != 1
  282. || readLZWByte (true, c) < 0)
  283. return false;
  284. if (transparent >= 0)
  285. {
  286. palette [transparent][0] = 0;
  287. palette [transparent][1] = 0;
  288. palette [transparent][2] = 0;
  289. palette [transparent][3] = 0;
  290. }
  291. int index;
  292. int xpos = 0, ypos = 0, pass = 0;
  293. const Image::BitmapData destData (*image, 0, 0, width, height, true);
  294. uint8* p = destData.data;
  295. const bool hasAlpha = image->hasAlphaChannel();
  296. while ((index = readLZWByte (false, c)) >= 0)
  297. {
  298. const uint8* const paletteEntry = palette [index];
  299. if (hasAlpha)
  300. {
  301. ((PixelARGB*) p)->setARGB (paletteEntry[3],
  302. paletteEntry[0],
  303. paletteEntry[1],
  304. paletteEntry[2]);
  305. ((PixelARGB*) p)->premultiply();
  306. }
  307. else
  308. {
  309. ((PixelRGB*) p)->setARGB (0,
  310. paletteEntry[0],
  311. paletteEntry[1],
  312. paletteEntry[2]);
  313. }
  314. p += destData.pixelStride;
  315. ++xpos;
  316. if (xpos == width)
  317. {
  318. xpos = 0;
  319. if (interlace)
  320. {
  321. switch (pass)
  322. {
  323. case 0:
  324. case 1:
  325. ypos += 8;
  326. break;
  327. case 2:
  328. ypos += 4;
  329. break;
  330. case 3:
  331. ypos += 2;
  332. break;
  333. }
  334. while (ypos >= height)
  335. {
  336. ++pass;
  337. switch (pass)
  338. {
  339. case 1:
  340. ypos = 4;
  341. break;
  342. case 2:
  343. ypos = 2;
  344. break;
  345. case 3:
  346. ypos = 1;
  347. break;
  348. default:
  349. return true;
  350. }
  351. }
  352. }
  353. else
  354. {
  355. ++ypos;
  356. }
  357. p = destData.getPixelPointer (xpos, ypos);
  358. }
  359. if (ypos >= height)
  360. break;
  361. }
  362. return true;
  363. }
  364. END_JUCE_NAMESPACE