/decoders/image/gif.d

http://github.com/wilkie/djehuty · D · 1346 lines · 834 code · 341 blank · 171 comment · 164 complexity · 87c6705490f11b01e4bead89781e08fb MD5 · raw file

  1. /*
  2. * gif.d
  3. *
  4. * This module implements the GIF 89a standard.
  5. *
  6. * Author: Dave Wilkinson
  7. *
  8. */
  9. module decoders.image.gif;
  10. import graphics.bitmap;
  11. import core.string;
  12. import core.stream;
  13. import core.color;
  14. import core.definitions;
  15. import decoders.image.decoder;
  16. import decoders.decoder;
  17. // For debugging
  18. import io.console;
  19. // The structures define structures found in the standard and utilized
  20. // when reading the file or stream.
  21. private {
  22. align(1) struct _djehuty_image_gif_header {
  23. ubyte gifSignature[3];
  24. ubyte gifVersion[3];
  25. }
  26. align(1) struct _djehuty_image_gif_logical_screen {
  27. ushort gifLogicalScreenWidth;
  28. ushort gifLogicalScreenHeight;
  29. ubyte gifPackedFields;
  30. ubyte gifBackgroundColorIndex;
  31. ubyte gifPixelAspectRatio;
  32. }
  33. align(1) struct _djehuty_image_gif_color {
  34. ubyte red;
  35. ubyte green;
  36. ubyte blue;
  37. }
  38. align(1) struct _djehuty_image_gif_image_descriptor {
  39. ushort gifImageLeftPos;
  40. ushort gifImageTopPos;
  41. ushort gifImageWidth;
  42. ushort gifImageHeight;
  43. ubyte gifPackedFields;
  44. }
  45. align(1) struct _djehuty_image_gif_graphics_extension {
  46. ubyte gifBlockSize;
  47. ubyte gifPackedFields;
  48. ushort gifDelayTime;
  49. ubyte gifTransparentColorIndex;
  50. ubyte gifBlockTerminator;
  51. }
  52. struct _djehuty_image_gif_lzw_dictionary_entry {
  53. short code;
  54. short hops;
  55. short output;
  56. }
  57. const ubyte gifMasks[] =
  58. [
  59. /* STARTBYTE, INTERMEDIATE BYTE, LAST BYTE */
  60. /* 8 STEPS PER BIT COUNT */
  61. /* 2 masks */
  62. 0x3, 0x0, 0x0, 0x6, 0x0, 0x0, 0xC, 0x0, 0x0, 0x18, 0x0, 0x0, 0x30, 0x0, 0x0, 0x60, 0x0, 0x0, 0xC0, 0x0, 0x0, 0x80, 0x1, 0x0,
  63. /* 3 masks */
  64. 0x7, 0x0, 0x0, 0xE, 0x0, 0x0, 0x1C, 0x0, 0x0, 0x38, 0x0, 0x0, 0x70, 0x0, 0x0, 0xE0, 0x0, 0x0, 0xC0, 0x1, 0x0, 0x80, 0x3, 0x0,
  65. /* 4 masks */
  66. 0xF, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x3C, 0x0, 0x0, 0x78, 0x0, 0x0, 0xF0, 0x0, 0x0, 0xE0, 0x1, 0x0, 0xC0, 0x3, 0x0, 0x80, 0x7, 0x0,
  67. /* 5 masks */
  68. 0x1F, 0x0, 0x0, 0x3E, 0x0, 0x0, 0x7C, 0x0, 0x0, 0xF8, 0x0, 0x0, 0xF0, 0x1, 0x0, 0xE0, 0x3, 0x0, 0xC0, 0x7, 0x0, 0x80, 0xF, 0x0,
  69. /* 6 masks */
  70. 0x3F, 0x0, 0x0, 0x7E, 0x0, 0x0, 0xFC, 0x0, 0x0, 0xF8, 0x1, 0x0, 0xF0, 0x3, 0x0, 0xE0, 0x7, 0x0, 0xC0, 0xF, 0x0, 0x80, 0x1F, 0x0,
  71. /* 7 masks */
  72. 0x7F, 0x0, 0x0, 0xFE, 0x0, 0x0, 0xFC, 0x1, 0x0, 0xF8, 0x3, 0x0, 0xF0, 0x7, 0x0, 0xE0, 0xF, 0x0, 0xC0, 0x1F, 0x0, 0x80, 0x3F, 0x0,
  73. /* 8 masks */
  74. 0xFF, 0x0, 0x0, 0xFE, 0x1, 0x0, 0xFC, 0x3, 0x0, 0xF8, 0x7, 0x0, 0xF0, 0xF, 0x0, 0xE0, 0x1F, 0x0, 0xC0, 0x3F, 0x0, 0x80, 0x7F, 0x0,
  75. /* 9 masks */
  76. 0xFF, 0x1, 0x0, 0xFE, 0x3, 0x0, 0xFC, 0x7, 0x0, 0xF8, 0xF, 0x0, 0xF0, 0x1F, 0x0, 0xE0, 0x3F, 0x0, 0xC0, 0x7F, 0x0, 0x80, 0xFF, 0x0,
  77. /* 10 masks */
  78. 0xFF, 0x3, 0x0, 0xFE, 0x7, 0x0, 0xFC, 0xF, 0x0, 0xF8, 0x1F, 0x0, 0xF0, 0x3F, 0x0, 0xE0, 0x7F, 0x0, 0xC0, 0xFF, 0x0, 0x80, 0xFF, 0x1,
  79. /* 11 masks */
  80. 0xFF, 0x7, 0x0, 0xFE, 0xF, 0x0, 0xFC, 0x1F, 0x0, 0xF8, 0x3F, 0x0, 0xF0, 0x7F, 0x0, 0xE0, 0xFF, 0x0, 0xC0, 0xFF, 0x1, 0x80, 0xFF, 0x3,
  81. /* 12 masks */
  82. 0xFF, 0xF, 0x0, 0xFE, 0x1F, 0x0, 0xFC, 0x3F, 0x0, 0xF8, 0x7F, 0x0, 0xF0, 0xFF, 0x0, 0xE0, 0xFF, 0x1, 0xC0, 0xFF, 0x3, 0x80, 0xFF, 0x7
  83. ];
  84. //global constants
  85. const int _djehuty_image_gif_size_of_global_color_table_ref[] = [2,4,8,16,32,64,128,256];
  86. // _decoder States
  87. const auto GIF_STATE_INIT = 0;
  88. const auto GIF_STATE_READ_HEADERS = 1;
  89. const auto GIF_STATE_READ_GRAPHIC_CONTROL = 2;
  90. const auto GIF_STATE_DECODE_IMAGE = 3;
  91. const auto GIF_STATE_READ_LOCAL_COLOR_TABLE = 4;
  92. const auto GIF_STATE_INIT_DECODER = 5;
  93. const auto GIF_STATE_READ_LZW_CODESIZE = 6;
  94. const auto GIF_STATE_DECODE = 7;
  95. }
  96. // Description: The GIF Codec
  97. class GIFDecoder : ImageDecoder {
  98. override string name() {
  99. return "Graphics Interchange Format";
  100. }
  101. override StreamData decode(Stream stream, ref Bitmap view) {
  102. ImageFrameDescription imageDesc;
  103. // will read headers and such
  104. StreamData ret = StreamData.Accepted;
  105. ret = _decoder(stream, view, imageDesc);
  106. if (ret == StreamData.Accepted) {
  107. // the image frame will be next
  108. // stop, since we got what we needed
  109. // which is the first frame
  110. // but this signals that we have more than one frame
  111. return StreamData.Accepted;
  112. }
  113. return ret;
  114. }
  115. override StreamData decodeFrame(Stream stream, ref Bitmap view, ref ImageFrameDescription imageDesc) {
  116. // will read headers and such
  117. StreamData ret = _decoder(stream, view, imageDesc);
  118. if (ret == StreamData.Complete) {
  119. // we are done
  120. imageDesc.clearFirst = gifFirstClear;
  121. imageDesc.clearColor = gifFirstClearColor;
  122. imageDesc.time = gifFirstTime;
  123. return StreamData.Complete;
  124. }
  125. return ret;
  126. }
  127. protected:
  128. StreamData _decoder(ref Stream stream, ref Bitmap view, ref ImageFrameDescription imageDesc) {
  129. uint q;
  130. ushort gifCode;
  131. ushort gifCodeTemp;
  132. ulong ptr_len;
  133. for (;;) {
  134. // READ HEADERS
  135. switch(decoderState) {
  136. // READ HEADERS //
  137. case GIF_STATE_INIT:
  138. gifGraphicControl.gifBlockSize = 0;
  139. gifIsFirst = 1;
  140. decoderSubState = 0;
  141. decoderState = GIF_STATE_READ_HEADERS;
  142. case GIF_STATE_READ_HEADERS:
  143. // READ FILE HEADER
  144. switch(decoderSubState) {
  145. // READ GIF HEADER
  146. case 0:
  147. if (!stream.read(&gifHeader, _djehuty_image_gif_header.sizeof)) {
  148. return StreamData.Required;
  149. }
  150. if (!(gifHeader.gifSignature[0] == 'G' &&
  151. gifHeader.gifSignature[1] == 'I' &&
  152. gifHeader.gifSignature[2] == 'F')) {
  153. return StreamData.Invalid;
  154. }
  155. if (!(gifHeader.gifVersion[0] == '8' &&
  156. gifHeader.gifVersion[1] == '9' &&
  157. gifHeader.gifVersion[2] == 'a')) {
  158. return StreamData.Invalid;
  159. }
  160. gifVersion = 1; // 89a
  161. decoderSubState = 1;
  162. // READ LOGICAL SCREEN DESCRIPTOR
  163. case 1:
  164. if(!(stream.read(&gifScreen, _djehuty_image_gif_logical_screen.sizeof))) {
  165. return StreamData.Required;
  166. }
  167. // DETERMINE WHETHER OR NOT WE GET A GLOBAL COLOR TABLE
  168. if (gifScreen.gifPackedFields & 128) {
  169. // global color table present
  170. gifGlobalColorTableSize = _djehuty_image_gif_size_of_global_color_table_ref[ gifScreen.gifPackedFields & 0x7 ];
  171. decoderSubState = 2;
  172. }
  173. else {
  174. // global color table not present
  175. gifGlobalColorTableSize = 0;
  176. decoderSubState = 0;
  177. gifGraphicControl.gifBlockSize = 0;
  178. decoderState = GIF_STATE_READ_GRAPHIC_CONTROL;
  179. break;
  180. }
  181. // READ IN GLOBAL COLOR TABLE WHEN PRESENT
  182. case 2:
  183. //Global Color Table is present; load it
  184. if(!(stream.read(gifGlobalColorTable.ptr, 3 * gifGlobalColorTableSize))) {
  185. return StreamData.Required;
  186. }
  187. // Compute a 32bit argb color
  188. for (q=0; q<gifGlobalColorTableSize; q++) {
  189. gifGlobalColorTableComputed[q] = 0xFF000000 | (gifGlobalColorTable[q].red << 16) | ((gifGlobalColorTable[q].green << 8) | (gifGlobalColorTable[q].blue));
  190. }
  191. gifGlobalColorTableSize = 0;
  192. decoderSubState = 0;
  193. gifGraphicControl.gifBlockSize = 0;
  194. decoderState = GIF_STATE_READ_GRAPHIC_CONTROL;
  195. break;
  196. default: break;
  197. }
  198. continue;
  199. // READS IN ALL EXTENSIONS
  200. case GIF_STATE_READ_GRAPHIC_CONTROL:
  201. switch(decoderSubState) {
  202. //READ EXTENSION INTRODUCER
  203. case 0:
  204. if(!(stream.read(&gifExtensionIntroducer, 1))) {
  205. return StreamData.Required;
  206. }
  207. if (gifExtensionIntroducer == 0x3B) {
  208. // no more blocks
  209. return StreamData.Complete;
  210. }
  211. else if (gifExtensionIntroducer == 0x21) {
  212. //this is an extension
  213. decoderSubState = 1;
  214. }
  215. else if (gifExtensionIntroducer == 0x2C) {
  216. // the image is next
  217. decoderState = GIF_STATE_DECODE_IMAGE;
  218. if (gifGraphicControl.gifBlockSize == 4) {
  219. if (gifIsFirst) {
  220. gifFirstTime = (gifGraphicControl.gifDelayTime * 10);
  221. if ((gifGraphicControl.gifPackedFields & 0x1C) == 0x08) {
  222. gifFirstClear = 1;
  223. }
  224. else {
  225. gifFirstClear = 0;
  226. }
  227. if (gifScreen.gifBackgroundColorIndex >= gifGlobalColorTableSize) {
  228. gifFirstClearColor = Color.Black;
  229. }
  230. else {
  231. // if TRANSPARENT is set, clear color is transparent
  232. if ((gifGraphicControl.gifBlockSize == 4) && (gifGraphicControl.gifPackedFields & 1) ) {
  233. gifFirstClearColor = Color.Black;
  234. }
  235. else {
  236. gifFirstClearColor.red =
  237. cast(double)gifGlobalColorTable[gifScreen.gifBackgroundColorIndex].red / 255.0;
  238. gifFirstClearColor.green =
  239. cast(double)gifGlobalColorTable[gifScreen.gifBackgroundColorIndex].green / 255.0;
  240. gifFirstClearColor.blue =
  241. cast(double)gifGlobalColorTable[gifScreen.gifBackgroundColorIndex].blue / 255.0;
  242. }
  243. }
  244. }
  245. else {
  246. imageDesc.time = (gifGraphicControl.gifDelayTime * 10);
  247. if ((gifGraphicControl.gifPackedFields & 0x1C) == 0x08) {
  248. imageDesc.clearFirst = 1;
  249. }
  250. else {
  251. imageDesc.clearFirst = 0;
  252. }
  253. if (gifScreen.gifBackgroundColorIndex >= gifGlobalColorTableSize) {
  254. imageDesc.clearColor = Color.Black;
  255. }
  256. else {
  257. // iF TRANSPARENT is set, clear color is transparent
  258. if ((gifGraphicControl.gifBlockSize == 4) && (gifGraphicControl.gifPackedFields & 1) ) {
  259. imageDesc.clearColor = Color.Black;
  260. }
  261. else {
  262. imageDesc.clearColor.red =
  263. cast(double)gifGlobalColorTable[gifScreen.gifBackgroundColorIndex].red / 255.0;
  264. imageDesc.clearColor.green =
  265. cast(double)gifGlobalColorTable[gifScreen.gifBackgroundColorIndex].green / 255.0;
  266. imageDesc.clearColor.blue =
  267. cast(double)gifGlobalColorTable[gifScreen.gifBackgroundColorIndex].blue / 255.0;
  268. }
  269. }
  270. }
  271. }
  272. else {
  273. if (gifIsFirst) {
  274. gifFirstClear = 0;
  275. }
  276. else {
  277. imageDesc.clearFirst = 0;
  278. }
  279. }
  280. // image data is next, there is another frame
  281. return StreamData.Accepted; // indicate frame is next
  282. }
  283. break;
  284. //READ EXTENSION LABEL
  285. case 1:
  286. //otherwise, it is the table's lzw minimum code size
  287. if(!(stream.read(&gifExtensionLabel, 1))) {
  288. return StreamData.Required;
  289. }
  290. if (gifExtensionLabel == 0xF9) {
  291. // IS A GRAPHIC CONTROL EXTENSION
  292. decoderSubState = 2;
  293. }
  294. else {
  295. // READ THE BLOCK SIZE
  296. // SKIP THAT MANY BYTES
  297. decoderSubState = 3;
  298. }
  299. break;
  300. //READ IN GRAPHIC CONTROL EXTENSION
  301. case 2:
  302. if(!(stream.read(&gifGraphicControl, _djehuty_image_gif_graphics_extension.sizeof))) {
  303. return StreamData.Required;
  304. }
  305. // IT SHOULD BE 4, BUT WE WILL SET IT AS SUCH ANYWAY
  306. // THIS WILL BE OUR CHECK FOR WHEN THE STRUCTURE IS FILLED
  307. gifGraphicControl.gifBlockSize = 4;
  308. decoderSubState = 0;
  309. break;
  310. //SKIP IRREVALVENT EXTENSION DATA
  311. //FIND EXTENSION SIZE
  312. case 3:
  313. if (!(stream.read(&gifExtensionLabel, 1))) {
  314. return StreamData.Required;
  315. }
  316. decoderSubState = 4;
  317. //SKIP EXTENSION LABEL
  318. case 4:
  319. if(!(stream.skip(gifExtensionLabel))) {
  320. return StreamData.Required;
  321. }
  322. decoderSubState = 5;
  323. //SKIP EXTENSION DATA BLOCKS
  324. //READ IN SIZE OF DATA BLOCK
  325. case 5:
  326. // NOW READ IN ALL SUB-DATA BLOCKS
  327. // AND SKIP THEM
  328. if (!(stream.read(&gifExtensionLabel, 1))) {
  329. return StreamData.Required;
  330. }
  331. decoderSubState = 6;
  332. case 6:
  333. if (gifExtensionLabel > 0) {
  334. stream.skip(gifExtensionLabel);
  335. decoderSubState = 5;
  336. }
  337. else {
  338. decoderSubState = 0;
  339. }
  340. default: break;
  341. }
  342. continue;
  343. // READ IN IMAGE DESCRIPTOR
  344. case GIF_STATE_DECODE_IMAGE:
  345. //DecodeImage(stream, view, imageDesc, idp);
  346. //return StreamData.Required;
  347. // READ IN IMAGE DESCRIPTOR
  348. if(!(stream.read(&gifImage, _djehuty_image_gif_image_descriptor.sizeof))) {
  349. return StreamData.Required;
  350. }
  351. if (gifImage.gifPackedFields & 128) {
  352. // local color table present
  353. gifLocalColorTableSize = _djehuty_image_gif_size_of_global_color_table_ref[ gifImage.gifPackedFields & 0x7 ];
  354. decoderState = GIF_STATE_READ_LOCAL_COLOR_TABLE;
  355. // ... note we will drop through ... //
  356. }
  357. else {
  358. decoderState = GIF_STATE_INIT_DECODER;
  359. // local color table is not present
  360. gifLocalColorTableSize = 0;
  361. gifCurColorTable = gifGlobalColorTableComputed.ptr;
  362. continue;
  363. }
  364. // ... drop through WHEN there is a local color table ... //
  365. // READ IN LOCAL COLOR TABLE WHEN PRESENT
  366. case GIF_STATE_READ_LOCAL_COLOR_TABLE:
  367. //local Color Table is present
  368. if(!(stream.read(gifLocalColorTable.ptr, 3 * gifLocalColorTableSize))) {
  369. return StreamData.Required;
  370. }
  371. //compute values
  372. uint i;
  373. for (i=0; i<gifLocalColorTableSize; i++) {
  374. gifLocalColorTableComputed[i] = 0xFF000000 | (gifLocalColorTable[i].red << 16) | ((gifLocalColorTable[i].green << 8) | (gifLocalColorTable[i].blue));
  375. }
  376. gifCurColorTable = gifLocalColorTableComputed.ptr;
  377. decoderState = GIF_STATE_INIT_DECODER;
  378. case GIF_STATE_INIT_DECODER:
  379. // UPDATE Transparent Color INDEX IN THE COLOR TABLE (if present)
  380. if ((gifGraphicControl.gifBlockSize == 4) && (gifGraphicControl.gifPackedFields & 1)) {
  381. gifCurColorTable[gifGraphicControl.gifTransparentColorIndex] = 0;
  382. }
  383. // UPDATE FRAME DESCRIPTION
  384. imageDesc.xoffset = gifImage.gifImageLeftPos;
  385. imageDesc.yoffset = gifImage.gifImageTopPos;
  386. // CHECK TO SEE IF IMAGE IS INTERLACED
  387. gifIsInterlaced = (gifImage.gifPackedFields & 64);
  388. decoderState = GIF_STATE_READ_LZW_CODESIZE;
  389. case GIF_STATE_READ_LZW_CODESIZE:
  390. // READ IN THE LZW MINIMUM CODE SIZE
  391. if (!(stream.read(&gifExtensionIntroducer, 1))) {
  392. return StreamData.Required;
  393. }
  394. if (gifExtensionIntroducer < 2)
  395. {
  396. // incorrect lzw min size
  397. return StreamData.Invalid;
  398. }
  399. // we start from code size + 1 when reading in data
  400. // so we increment the code size
  401. gifExtensionIntroducer++;
  402. // set the default dictionary size
  403. gifDictionarySize = _djehuty_image_gif_size_of_global_color_table_ref[gifExtensionIntroducer-2];
  404. // BUILD INITIAL LZW DICTIONARY
  405. //i will iterate through the dictionary
  406. for (short i=0; i<gifDictionarySize+2; i++) {
  407. gifDictionary[i].code = 0;
  408. gifDictionary[i].hops = 0;
  409. gifDictionary[i].output = i;
  410. }
  411. gifClearCode = cast(ushort)gifDictionarySize;
  412. gifEOICode = cast(ushort)(gifDictionarySize + 1);
  413. // N WILL BE THE NEXT CODE
  414. lzw_nextEntry = cast(ushort)(gifClearCode + 2);
  415. // bound the next entry to gifDictionarySize * 2
  416. gifDictionarySize *= 2;
  417. gifCodeSize = gifExtensionIntroducer;
  418. gifStartCodeSize = gifCodeSize;
  419. // ESTABLISH MASKS
  420. gifCurMaskArray = cast(ubyte*)&gifMasks[(gifCodeSize - 2) * 24];
  421. gifCurMaskIndex = 0;
  422. gifCurMaskIndexComp = 0;
  423. gifMaskStart = gifCurMaskArray[0];
  424. gifMaskIntermediate = gifCurMaskArray[1];
  425. gifMaskEnd = gifCurMaskArray[2];
  426. lzw_isFirstEntry = 0;
  427. gifInterlaceState = 0; //the state of the interlacing
  428. ptrPos = 0;
  429. ptrLine = 0;
  430. gifBlockSize = 0;
  431. gifBlockCounter = 0;
  432. view.create(gifImage.gifImageWidth, gifImage.gifImageHeight);
  433. decoderState = GIF_STATE_DECODE;
  434. decoderSubState = 0;
  435. // ... drop through ... //
  436. case GIF_STATE_DECODE:
  437. // start decoding
  438. view.lockBuffer(cast(void**)&ptr_start, ptr_len);
  439. ptr = ptr_start;
  440. ptr += (gifImage.gifImageWidth * ptrLine);
  441. ptr_max_line = ptr + gifImage.gifImageWidth;
  442. ptr_max_page = ptr_start + (ptr_len / 4);
  443. ptr += ptrPos;
  444. while(decoderState == GIF_STATE_DECODE) {
  445. switch(decoderSubState) {
  446. //READ IN BLOCK SIZE
  447. case 0:
  448. gifLastBlockSize = gifBlockSize;
  449. gifBlockSize=0;
  450. decoderSubState = 1;
  451. case 1:
  452. if (!(stream.read(&gifBlockSize, 1))) {
  453. view.unlockBuffer();
  454. return StreamData.Required;
  455. }
  456. if (gifBlockSize == 0) {
  457. // block terminator found (end of blocks)
  458. // PERHAPS THERE WILL BE ANOTHER FRAME
  459. decoderState = GIF_STATE_READ_GRAPHIC_CONTROL;
  460. decoderSubState = 0;
  461. view.unlockBuffer();
  462. break;
  463. }
  464. else {
  465. decoderSubState = 2;
  466. // ... drop through ... //
  467. }
  468. // READ IN IMAGE DATA BLOCK
  469. // APPEND, IF NEEDED, TO OLD BLOCK
  470. case 2:
  471. // decode this image block
  472. if ((gifBlockCounter==gifLastBlockSize-1)) {
  473. gifImageData[0] = gifImageData[gifBlockCounter];
  474. if(!(stream.read(&gifImageData[1], gifBlockSize))) {
  475. view.unlockBuffer();
  476. return StreamData.Required;
  477. }
  478. gifBlockSize++;
  479. }
  480. else if ((gifBlockCounter==gifLastBlockSize-2)) {
  481. gifImageData[0] = gifImageData[gifBlockCounter];
  482. gifImageData[1] = gifImageData[gifBlockCounter+1];
  483. if (!(stream.read(&gifImageData[2], gifBlockSize))) {
  484. view.unlockBuffer();
  485. return StreamData.Required;
  486. }
  487. gifBlockSize+=2;
  488. }
  489. else {
  490. if (!(stream.read(gifImageData.ptr, gifBlockSize))) {
  491. view.unlockBuffer();
  492. return StreamData.Required;
  493. }
  494. }
  495. gifBlockCounter = 0;
  496. gifCode = 0;
  497. gifCodeTemp = 0;
  498. //get a code
  499. decoderSubState = 3;
  500. if (gifIsInterlaced) {
  501. decoderNextSubState = 5;
  502. }
  503. else {
  504. //DECODER FOR NON INTERLACED IMAGES
  505. decoderNextSubState = 4;
  506. }
  507. // READ IN CODE
  508. case 3:
  509. // get next code
  510. uint old_blockcounter = gifBlockCounter;
  511. gifCode = cast(ushort)(gifImageData[gifBlockCounter] & gifMaskStart);
  512. // reading in a code
  513. if (gifCurMaskIndex) {
  514. gifCode >>= gifCurMaskIndex;
  515. }
  516. if (gifMaskIntermediate) {
  517. // go to next byte
  518. gifBlockCounter++;
  519. if (gifBlockCounter>=gifBlockSize) {
  520. gifBlockCounter = old_blockcounter;
  521. decoderSubState = 0;
  522. break;
  523. }
  524. gifCodeTemp = cast(ushort)(gifImageData[gifBlockCounter] & gifMaskIntermediate);
  525. if (8 - gifCurMaskIndex) {
  526. gifCodeTemp <<= (8 - gifCurMaskIndex);
  527. }
  528. gifCode |= gifCodeTemp;
  529. }
  530. else {
  531. //goto next byte when gifMaskStart's first bit is 1
  532. if (gifMaskStart & 128) {
  533. //goto next byte
  534. gifBlockCounter++;
  535. if (gifBlockCounter>=gifBlockSize) {
  536. gifBlockCounter=old_blockcounter;
  537. decoderSubState = 0;
  538. break;
  539. }
  540. }
  541. }
  542. if (gifMaskEnd) {
  543. // go to ultimate byte
  544. gifBlockCounter++;
  545. if (gifBlockCounter>=gifBlockSize) {
  546. gifBlockCounter=old_blockcounter;
  547. decoderSubState = 0;
  548. break;
  549. }
  550. gifCodeTemp = cast(ushort)(gifImageData[gifBlockCounter] & gifMaskEnd);
  551. if (8-gifCurMaskIndex) {
  552. gifCodeTemp <<= (8-gifCurMaskIndex);
  553. }
  554. gifCodeTemp <<= 8;
  555. gifCode |= gifCodeTemp;
  556. }
  557. else {
  558. //goto next byte when gifMaskIntermediate's first bit is 1
  559. if (gifMaskIntermediate & 128) {
  560. //goto next byte
  561. gifBlockCounter++;
  562. if (gifBlockCounter>=gifBlockSize) {
  563. gifBlockCounter=old_blockcounter;
  564. decoderSubState = 0;
  565. break;
  566. }
  567. }
  568. }
  569. // set next mask index
  570. gifCurMaskIndex = (gifCurMaskIndex + gifCodeSize) % 8;
  571. gifCurMaskIndexComp = gifCurMaskIndex * 3;
  572. gifMaskStart = gifCurMaskArray[gifCurMaskIndexComp];
  573. gifMaskIntermediate = gifCurMaskArray[gifCurMaskIndexComp+1];
  574. gifMaskEnd = gifCurMaskArray[gifCurMaskIndexComp+2];
  575. // GOTO LZW DECODER
  576. decoderSubState = decoderNextSubState;
  577. break;
  578. // DECODER (non-interlaced)
  579. case 4:
  580. decoderSubState = 3;
  581. // THIS IS THE LZW DECOMPRESSOR FOR UNINTERLACED IMAGES
  582. // INTERPRET gifCode
  583. if (gifCode == gifEOICode) {
  584. // stop decoding (End Of Image)
  585. decoderNextState = 0;
  586. break;
  587. }
  588. if (lzw_isFirstEntry==0) {
  589. //init LZW decompressor (first entry)
  590. lzw_isFirstEntry=1;
  591. lzw_curEntry = gifCode;
  592. // INTERPRET CODE AS PIXEL
  593. if (gifCode < gifClearCode) {
  594. ptr[0] = gifCurColorTable[gifCode];
  595. ptr++;
  596. ptrPos++;
  597. // READ CODE
  598. break;
  599. }
  600. }
  601. if (gifCode == gifClearCode) {
  602. //CLEAR CODE (reset dictionary)
  603. lzw_nextEntry = cast(ushort)(gifClearCode + 2);
  604. gifDictionarySize = gifClearCode * 2;
  605. gifCodeSize = gifStartCodeSize;
  606. //update mask array
  607. gifCurMaskArray = cast(ubyte*)&gifMasks[(gifCodeSize - 2) * 24];
  608. gifMaskStart = gifCurMaskArray[gifCurMaskIndexComp];
  609. gifMaskIntermediate = gifCurMaskArray[gifCurMaskIndexComp+1];
  610. gifMaskEnd = gifCurMaskArray[gifCurMaskIndexComp+2];
  611. lzw_isFirstEntry = 0;
  612. // READ CODE
  613. break;
  614. }
  615. if (gifCode >= lzw_nextEntry) {
  616. // PRINT OUT LAST CODE FROM DICTIONARY
  617. gifCodeTemp = lzw_curEntry;
  618. q = gifDictionary[gifCodeTemp].hops;
  619. for (;;) {
  620. ptr[q] = gifCurColorTable[gifDictionary[gifCodeTemp].output];
  621. if (gifCodeTemp < gifClearCode) { break; }
  622. gifCodeTemp = cast(ushort)gifDictionary[gifCodeTemp].code;
  623. q--;
  624. }
  625. ptr += gifDictionary[lzw_curEntry].hops + 1;
  626. ptr[0] = gifCurColorTable[gifDictionary[gifCodeTemp].output];
  627. ptr++;
  628. ptrPos += gifDictionary[lzw_curEntry].hops + 2;
  629. }
  630. else {
  631. // print code from dictionary
  632. gifCodeTemp = gifCode;
  633. q = gifDictionary[gifCodeTemp].hops;
  634. for (;;) {
  635. ptr[q] = gifCurColorTable[gifDictionary[gifCodeTemp].output];
  636. if (gifCodeTemp < gifClearCode) { break; }
  637. gifCodeTemp = cast(ushort)gifDictionary[gifCodeTemp].code;
  638. q--;
  639. }
  640. ptr += gifDictionary[gifCode].hops+1;
  641. ptrPos += gifDictionary[gifCode].hops+1;
  642. }
  643. if (lzw_nextEntry < 4096) {
  644. // add this entry to the dictionary
  645. gifDictionary[lzw_nextEntry].code = cast(short)lzw_curEntry;
  646. gifDictionary[lzw_nextEntry].output = cast(short)gifDictionary[gifCodeTemp].output;
  647. gifDictionary[lzw_nextEntry].hops = cast(short)(gifDictionary[lzw_curEntry].hops + 1);
  648. lzw_nextEntry++;
  649. lzw_curEntry = gifCode;
  650. if (lzw_nextEntry != 4096) {
  651. if (lzw_nextEntry >= gifDictionarySize) {
  652. gifDictionarySize *= 2;
  653. gifCodeSize++;
  654. //update mask array
  655. gifCurMaskArray = cast(ubyte*)&gifMasks[(gifCodeSize - 2) * 24];
  656. gifMaskStart = gifCurMaskArray[gifCurMaskIndexComp];
  657. gifMaskIntermediate = gifCurMaskArray[gifCurMaskIndexComp+1];
  658. gifMaskEnd = gifCurMaskArray[gifCurMaskIndexComp+2];
  659. }
  660. }
  661. }
  662. // READ CODE
  663. break;
  664. // DECODER (interlaced)
  665. case 5:
  666. decoderSubState = 3;
  667. // THIS IS THE LZW DECOMPRESSOR FOR UNINTERLACED IMAGES
  668. // INTERPRET gifCode
  669. if (gifCode == gifEOICode) {
  670. // stop decoding (End Of Image)
  671. decoderNextState = 0;
  672. break;
  673. }
  674. if (lzw_isFirstEntry==0) {
  675. //init LZW decompressor (first entry)
  676. lzw_isFirstEntry=1;
  677. lzw_curEntry = gifCode;
  678. // INTERPRET CODE AS PIXEL
  679. if (gifCode < gifClearCode) {
  680. ptr[0] = gifCurColorTable[gifCode];
  681. // draw surrounding pixels?
  682. if (gifInterlaceState < 3) {
  683. uint* ptrInterlaced = ptr + gifImage.gifImageWidth;
  684. uint* ptrLast = void;
  685. switch (gifInterlaceState) {
  686. case 0:
  687. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 7);
  688. break;
  689. case 1:
  690. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 3);
  691. break;
  692. case 2:
  693. default:
  694. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 1);
  695. break;
  696. }
  697. if (ptr_max_page < ptrLast) { ptrLast = ptr_max_page; }
  698. for ( ; ptrInterlaced < ptrLast ; ptrInterlaced += gifImage.gifImageWidth) {
  699. ptrInterlaced[0] = gifCurColorTable[gifDictionary[gifCodeTemp].output];
  700. }
  701. }
  702. ptr++;
  703. ptrPos++;
  704. if (ptr == ptr_max_line) {
  705. //change the line
  706. ptrPos=0;
  707. ptrLine++;
  708. _interlaceIncrement();
  709. }
  710. // READ CODE
  711. break;
  712. }
  713. }
  714. if (gifCode == gifClearCode) {
  715. //CLEAR CODE
  716. lzw_nextEntry = cast(ushort)(gifClearCode + 2);
  717. gifDictionarySize = gifClearCode * 2;
  718. gifCodeSize = gifStartCodeSize;
  719. //update mask array
  720. gifCurMaskArray = cast(ubyte*)&gifMasks[(gifCodeSize - 2) * 24];
  721. gifMaskStart = gifCurMaskArray[gifCurMaskIndexComp];
  722. gifMaskIntermediate = gifCurMaskArray[gifCurMaskIndexComp+1];
  723. gifMaskEnd = gifCurMaskArray[gifCurMaskIndexComp+2];
  724. lzw_isFirstEntry = 0;
  725. // READ CODE
  726. break;
  727. }
  728. if (gifCode >= lzw_nextEntry) {
  729. // PRINT OUT LAST CODE FROM DICTIONARY
  730. gifCodeTemp = lzw_curEntry;
  731. q = gifDictionary[gifCodeTemp].hops;
  732. for (;;) {
  733. gifUncompressed[q] = gifCurColorTable[gifDictionary[gifCodeTemp].output];
  734. if (gifCodeTemp < gifClearCode) { break; }
  735. gifCodeTemp = cast(ushort)gifDictionary[gifCodeTemp].code;
  736. q--;
  737. }
  738. ptr[0] = gifCurColorTable[gifDictionary[gifCodeTemp].output];
  739. // draw surrounding pixels?
  740. if (gifInterlaceState < 3) {
  741. uint* ptrInterlaced = ptr + gifImage.gifImageWidth;
  742. uint* ptrLast = void;
  743. switch (gifInterlaceState) {
  744. case 0:
  745. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 7);
  746. break;
  747. case 1:
  748. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 3);
  749. break;
  750. case 2:
  751. default:
  752. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 1);
  753. break;
  754. }
  755. if (ptr_max_page < ptrLast) { ptrLast = ptr_max_page; }
  756. for ( ; ptrInterlaced < ptrLast ; ptrInterlaced += gifImage.gifImageWidth) {
  757. ptrInterlaced[0] = gifCurColorTable[gifDictionary[gifCodeTemp].output];
  758. }
  759. }
  760. ptr++;
  761. ptrPos++;
  762. if (ptr == ptr_max_line) {
  763. //change the line
  764. ptrPos=0;
  765. // draw surrounding pixels?
  766. if (gifInterlaceState < 3) {
  767. uint* ptrInterlaced = ptr + gifImage.gifImageWidth;
  768. uint* ptrLast = void;
  769. switch (gifInterlaceState) {
  770. case 0:
  771. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 7);
  772. break;
  773. case 1:
  774. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 3);
  775. break;
  776. case 2:
  777. default:
  778. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 1);
  779. break;
  780. }
  781. if (ptr_max_page < ptrLast) { ptrLast = ptr_max_page; }
  782. for ( ; ptrInterlaced < ptrLast ; ptrInterlaced += gifImage.gifImageWidth) {
  783. ptrInterlaced[0] = gifCurColorTable[gifDictionary[gifCodeTemp].output];
  784. }
  785. }
  786. ptrLine++;
  787. _interlaceIncrement();
  788. }
  789. for (q=0; q<=gifDictionary[lzw_curEntry].hops; q++) {
  790. ptr[0] = gifUncompressed[q];
  791. // draw surrounding pixels?
  792. if (gifInterlaceState < 3) {
  793. uint* ptrInterlaced = ptr + gifImage.gifImageWidth;
  794. uint* ptrLast = void;
  795. switch (gifInterlaceState) {
  796. case 0:
  797. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 7);
  798. break;
  799. case 1:
  800. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 3);
  801. break;
  802. case 2:
  803. default:
  804. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 1);
  805. break;
  806. }
  807. if (ptr_max_page < ptrLast) { ptrLast = ptr_max_page; }
  808. for ( ; ptrInterlaced < ptrLast ; ptrInterlaced += gifImage.gifImageWidth) {
  809. ptrInterlaced[0] = gifCurColorTable[gifDictionary[gifCodeTemp].output];
  810. }
  811. }
  812. ptr++;
  813. ptrPos++;
  814. if (ptr == ptr_max_line) {
  815. //change the line
  816. ptrPos=0;
  817. ptrLine++;
  818. _interlaceIncrement();
  819. }
  820. }
  821. }
  822. else
  823. {
  824. // PRINT OUT CODE FROM DICTIONARY
  825. gifCodeTemp = gifCode;
  826. q = gifDictionary[gifCodeTemp].hops;
  827. for (;;) {
  828. gifUncompressed[q] = gifCurColorTable[gifDictionary[gifCodeTemp].output];
  829. if (gifCodeTemp < gifClearCode) { break; }
  830. gifCodeTemp = cast(ushort)gifDictionary[gifCodeTemp].code;
  831. q--;
  832. }
  833. for (q=0; q<=gifDictionary[gifCode].hops; q++) {
  834. ptr[0] = gifUncompressed[q];
  835. // draw surrounding pixels?
  836. if (gifInterlaceState < 3) {
  837. uint* ptrInterlaced = ptr + gifImage.gifImageWidth;
  838. uint* ptrLast = void;
  839. switch (gifInterlaceState) {
  840. case 0:
  841. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 7);
  842. break;
  843. case 1:
  844. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 3);
  845. break;
  846. case 2:
  847. default:
  848. ptrLast = ptrInterlaced + (gifImage.gifImageWidth * 1);
  849. break;
  850. }
  851. if (ptr_max_page < ptrLast) { ptrLast = ptr_max_page; }
  852. for ( ; ptrInterlaced < ptrLast ; ptrInterlaced += gifImage.gifImageWidth) {
  853. ptrInterlaced[0] = gifCurColorTable[gifDictionary[gifCodeTemp].output];
  854. }
  855. }
  856. ptr++;
  857. ptrPos++;
  858. if (ptr == ptr_max_line) {
  859. //change the line
  860. ptrPos = 0;
  861. ptrLine++;
  862. _interlaceIncrement();
  863. }
  864. }
  865. }
  866. if (lzw_nextEntry < 4096) {
  867. // add this entry to the dictionary
  868. gifDictionary[lzw_nextEntry].code = cast(short)lzw_curEntry;
  869. gifDictionary[lzw_nextEntry].output = gifDictionary[gifCodeTemp].output;
  870. gifDictionary[lzw_nextEntry].hops = cast(short)(gifDictionary[lzw_curEntry].hops + 1);
  871. lzw_nextEntry++;
  872. lzw_curEntry = gifCode;
  873. if (lzw_nextEntry != 4096) {
  874. if (lzw_nextEntry >= gifDictionarySize) {
  875. gifDictionarySize *= 2;
  876. gifCodeSize++;
  877. //update mask array
  878. gifCurMaskArray = cast(ubyte*)&gifMasks[(gifCodeSize - 2) * 24];
  879. gifMaskStart = gifCurMaskArray[gifCurMaskIndexComp];
  880. gifMaskIntermediate = gifCurMaskArray[gifCurMaskIndexComp+1];
  881. gifMaskEnd = gifCurMaskArray[gifCurMaskIndexComp+2];
  882. }
  883. }
  884. }
  885. // READ CODE
  886. break;
  887. default: break;
  888. }
  889. }
  890. continue;
  891. default:
  892. break;
  893. }
  894. break;
  895. }
  896. return StreamData.Invalid;
  897. }
  898. void _interlaceIncrement() {
  899. //ptr will be at the end of the current row
  900. //essentially in the beginning of the next row
  901. //if it had gone through row 0, it will now be
  902. //in row 1, and as such, will only have to
  903. //increment n-1 rows, where n is the number of
  904. //rows that the current state is interlaced
  905. switch (gifInterlaceState) {
  906. case 0:
  907. case 1:
  908. //increase 8 lines
  909. ptrLine += 7;
  910. ptr += (7 * gifImage.gifImageWidth);
  911. break;
  912. case 2:
  913. //increase 4 lines
  914. ptrLine += 3;
  915. ptr += (3 * gifImage.gifImageWidth);
  916. break;
  917. case 3:
  918. //increase 2 lines
  919. ptrLine ++;
  920. ptr += (gifImage.gifImageWidth);
  921. break;
  922. default:
  923. //eh?
  924. break;
  925. }
  926. if (ptr >= ptr_max_page) {
  927. //we start over again
  928. gifInterlaceState++;
  929. switch(gifInterlaceState) {
  930. case 1:
  931. //start at row 4
  932. ptrLine = 4;
  933. ptr = ptr_start + (gifImage.gifImageWidth * 4);
  934. break;
  935. case 2:
  936. //start at row 2
  937. ptrLine = 2;
  938. ptr = ptr_start + (gifImage.gifImageWidth * 2);
  939. break;
  940. case 3:
  941. //start at row 1
  942. ptrLine = 1;
  943. ptr = ptr_start + (gifImage.gifImageWidth);
  944. break;
  945. default:
  946. //eh?
  947. break;
  948. }
  949. }
  950. ptr_max_line = ptr + gifImage.gifImageWidth;
  951. }
  952. uint gifIsFirst;
  953. uint gifFirstTime;
  954. uint gifFirstClear;
  955. Color gifFirstClearColor;
  956. uint gifHeadersLoaded;
  957. ubyte gifMaskStart;
  958. ubyte gifMaskIntermediate;
  959. ubyte gifMaskEnd;
  960. // starting index into the array
  961. ubyte* gifCurMaskArray;
  962. // current index within subsection
  963. uint gifCurMaskIndex;
  964. uint gifCurMaskIndexComp;
  965. //the pointer to the current color table in use
  966. uint* gifCurColorTable;
  967. uint gifUncompressed[4096];
  968. uint gifCodeSize;
  969. uint gifStartCodeSize;
  970. _djehuty_image_gif_header gifHeader;
  971. _djehuty_image_gif_logical_screen gifScreen;
  972. _djehuty_image_gif_image_descriptor gifImage;
  973. _djehuty_image_gif_color gifGlobalColorTable[256];
  974. uint gifGlobalColorTableComputed[256];
  975. uint gifGlobalColorTableSize;
  976. _djehuty_image_gif_color gifLocalColorTable[256];
  977. uint gifLocalColorTableComputed[256];
  978. uint gifLocalColorTableSize;
  979. _djehuty_image_gif_graphics_extension gifGraphicControl;
  980. _djehuty_image_gif_lzw_dictionary_entry gifDictionary[4096];
  981. uint gifDictionarySize;
  982. uint gifVersion;
  983. uint gifIsInterlaced;
  984. uint gifBlockSize;
  985. uint gifLastBlockSize;
  986. uint gifBlockCounter;
  987. ushort gifCurCode;
  988. ushort gifClearCode;
  989. ushort gifEOICode;
  990. ubyte gifImageData[259]; //256 of block, 3 more for extra padding
  991. ubyte gifImageLeftOver;
  992. uint gifBlockCount;
  993. ubyte gifExtensionIntroducer;
  994. ubyte gifExtensionLabel;
  995. int gifInterlaceState;
  996. ushort lzw_nextEntry;
  997. ushort lzw_curEntry;
  998. ushort lzw_isFirstEntry;
  999. uint* ptr_start; //ptr of the first pixel
  1000. uint* ptr; //current ptr in image data
  1001. uint* ptr_max_line; //ptr of the next line
  1002. uint* ptr_max_page; //ptr outside of image bounds
  1003. uint ptrLine; //the current scan line of the image (y)
  1004. uint ptrPos; //the current pixel of the line (x)
  1005. }