/decoders/image/bmp.d

http://github.com/wilkie/djehuty · D · 1846 lines · 940 code · 385 blank · 521 comment · 264 complexity · 98d58d2825126fe70afc3836bd996343 MD5 · raw file

  1. module decoders.image.bmp;
  2. import graphics.bitmap;
  3. import core.stream;
  4. import core.string;
  5. import core.definitions;
  6. import decoders.image.decoder;
  7. import decoders.decoder;
  8. // Section: Codecs/Image
  9. private {
  10. align(2) struct _djehuty_image_bitmap_file_header {
  11. ushort bfType;
  12. uint bfSize;
  13. ushort bfReserved1;
  14. ushort bfReserved2;
  15. uint bfOffBits;
  16. }
  17. align(2) struct _djehuty_image_bitmap_info_header {
  18. uint biWidth;
  19. int biHeight;
  20. ushort biPlanes;
  21. ushort biBitCount;
  22. uint biCompression;
  23. uint biSizeImage;
  24. int biXPelsPerMeter;
  25. int biYPelsPerMeter;
  26. uint biClrUsed;
  27. uint biClrImportant;
  28. }
  29. align(2) struct _djehuty_image_os2_1_bitmap_info_header {
  30. ushort biWidth;
  31. ushort biHeight;
  32. ushort biPlanes;
  33. ushort biBitCount;
  34. }
  35. align(2) struct _djehuty_image_os2_2_bitmap_info_header {
  36. uint biWidth;
  37. uint biHeight;
  38. ushort biPlanes;
  39. ushort biBitCount;
  40. uint biCompression;
  41. uint biSizeImage;
  42. uint biXPelsPerMeter;
  43. uint biYPelsPerMeter;
  44. uint biClrUsed;
  45. uint biClrImportant;
  46. /* extended os2 2.x stuff */
  47. ushort usUnits;
  48. ushort usReserved;
  49. ushort usRecording;
  50. ushort usRendering;
  51. uint cSize1;
  52. uint cSize2;
  53. uint ulColorEncoding;
  54. uint ulIdentifier;
  55. }
  56. }
  57. // Description: The BMP Codec
  58. class BMPDecoder : ImageDecoder {
  59. override string name() {
  60. return "Bitmap";
  61. }
  62. StreamData decode(Stream stream, ref Bitmap view) {
  63. ImageFrameDescription imageDesc;
  64. bool hasMultipleFrames;
  65. uint* ptr;
  66. uint* ptr_max_line;
  67. uint* ptr_max;
  68. ulong ptr_len;
  69. for (;;) {
  70. switch (decoderState) {
  71. case BMP_STATE_INIT:
  72. //initial stuff
  73. hasMultipleFrames = 0;
  74. decoderState = BMP_STATE_READ_HEADERS;
  75. case BMP_STATE_READ_HEADERS:
  76. //reading the header
  77. if (!stream.read(&bf, 14)) { return StreamData.Required; }
  78. // Check for 'BM' signature
  79. if (bf.bfType != 0x4D42) {
  80. // Header is corrupt
  81. return StreamData.Invalid;
  82. }
  83. decoderState = BMP_STATE_READ_BITMAP_SIZE;
  84. continue;
  85. case BMP_STATE_READ_BITMAP_SIZE:
  86. //reading the bitmap size
  87. if (!stream.read(&biSize, 4)) { return StreamData.Required; }
  88. switch (biSize) {
  89. case 0x0C: // osx 1.0
  90. decoderState = BMP_STATE_READ_OSX_1;
  91. continue;
  92. case 0xF0: // osx 2.0
  93. decoderState = BMP_STATE_READ_OSX_2;
  94. continue;
  95. case 0x28: // windows
  96. decoderState = BMP_STATE_READ_WIN;
  97. continue;
  98. default:
  99. // Bitmap Version not supported
  100. return StreamData.Invalid;
  101. }
  102. case BMP_STATE_READ_OSX_1:
  103. return StreamData.Complete;
  104. case BMP_STATE_READ_OSX_2:
  105. return StreamData.Complete;
  106. // WINDOWS BITMAP DECODING //
  107. case BMP_STATE_READ_WIN:
  108. //get the bitmap info header
  109. if (!stream.read(&bi, 36)) { return StreamData.Required; }
  110. //get the windows color table
  111. switch(bi.biBitCount) {
  112. case 1:
  113. decoderState = BMP_STATE_READ_WIN_PALETTE;
  114. decoderNextState = BMP_STATE_DECODE_WIN_1BPP;
  115. paletteNumColors = 2;
  116. break;
  117. case 2:
  118. decoderState = BMP_STATE_READ_WIN_PALETTE;
  119. decoderNextState = BMP_STATE_DECODE_WIN_2BPP;
  120. paletteNumColors = 4;
  121. break;
  122. case 4:
  123. decoderState = BMP_STATE_READ_WIN_PALETTE;
  124. decoderNextState = BMP_STATE_DECODE_WIN_4BPP;
  125. paletteNumColors = 16;
  126. break;
  127. case 8:
  128. decoderState = BMP_STATE_READ_WIN_PALETTE;
  129. decoderNextState = BMP_STATE_DECODE_WIN_8BPP;
  130. paletteNumColors = 256;
  131. break;
  132. case 16:
  133. decoderState = BMP_STATE_DECODE_WIN_16BPP;
  134. paletteNumColors = 0;
  135. break;
  136. case 24:
  137. decoderState = BMP_STATE_DECODE_WIN_24BPP;
  138. paletteNumColors = 0;
  139. break;
  140. case 32:
  141. decoderState = BMP_STATE_DECODE_WIN_32BPP;
  142. paletteNumColors = 0;
  143. break;
  144. default:
  145. // invalid format
  146. return StreamData.Invalid;
  147. }
  148. continue;
  149. case BMP_STATE_READ_WIN_PALETTE:
  150. // get the amount we need
  151. //read from the file the palette information
  152. if (bi.biClrUsed == 0) {
  153. bi.biClrUsed = paletteNumColors;
  154. }
  155. //read from the file the palette information
  156. if(!stream.read(&palette, (bi.biClrUsed * 4))) { return StreamData.Required; }
  157. for (uint i=0; i<paletteNumColors; i++) {
  158. palette[i] |= 0xFF000000;
  159. }
  160. decoderState = decoderNextState;
  161. continue;
  162. // WINDOWS 1BPP BITMAPS //
  163. case BMP_STATE_DECODE_WIN_1BPP:
  164. //////OutputDebugStringA("bmp - windows - 1 bpp - 2 colors\n");
  165. //skip further padding, skip to image data, according to header
  166. if (bf.bfOffBits - (54 + (bi.biClrUsed * 4)) > 0) {
  167. if(!stream.skip(bf.bfOffBits - (54 + (bi.biClrUsed * 4)) ) ) { return StreamData.Required; }
  168. }
  169. //Calculate the bytes each row will take
  170. //within the file's bitmap data
  171. bytesPerRow = cast(uint)((cast(float)bi.biWidth / 8) + 0.5);
  172. bytesForPadding = 0;
  173. if (bytesPerRow & 0x3) {
  174. //pad bytes per row
  175. bytesForPadding = (4 - (bytesPerRow & 0x3));
  176. bytesPerRow += bytesForPadding;
  177. }
  178. if (bi.biCompression == 0) { // rgb
  179. //calculate the getLength of the bitmap data
  180. bitmapDataLen = bytesPerRow * bi.biHeight;
  181. }
  182. else {
  183. ////OutputDebugStringA("bmp - invalid compression format\n");
  184. return StreamData.Invalid;
  185. }
  186. //create the bitmap's buffer
  187. view.create(bi.biWidth, bi.biHeight);
  188. ptrLine = 0;
  189. ptrPos = 0;
  190. fileDataToSkip = 0;
  191. decoderState = BMP_STATE_RENDER_WIN_1BPP;
  192. case BMP_STATE_RENDER_WIN_1BPP:
  193. //////OutputDebugStringA("bmp - rendering stream input - 1bpp\n");
  194. // TAKE ALL BYTES FROM STREAM
  195. // IF WE FINISH, WE CAN return StreamData.Complete
  196. view.lockBuffer(cast(void**)&ptr_max, ptr_len);
  197. ptr = ptr_max + (ptr_len / 4);
  198. ptr -= (bi.biWidth * (ptrLine + 1));
  199. ptr_max_line = ptr + bi.biWidth;
  200. ptr_max += bi.biWidth;
  201. ptr += ptrPos;
  202. // LOAD FILEDATA WITH PART OF THE STREAM
  203. // CHUNKS AT A TIME
  204. for (;;) {
  205. if (stream.remaining == 0) {
  206. view.unlockBuffer();
  207. return StreamData.Required;
  208. }
  209. fileData = new ubyte[cast(uint)stream.remaining];
  210. fileDataCurPtr = fileDataPtr = fileData.ptr;
  211. fileDataEndPtr = fileDataCurPtr + stream.readAny(fileData.ptr, cast(uint)stream.remaining);
  212. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  213. //////OutputDebugStringA("bmp - rendering error - not enough information\n");
  214. //////OutputDebugStringA("bmp - skipping data across page\n");
  215. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  216. view.unlockBuffer();
  217. delete fileData;
  218. return StreamData.Complete;
  219. }
  220. else if (fileDataToSkip > 0) {
  221. fileDataCurPtr += fileDataToSkip;
  222. fileDataToSkip = 0;
  223. }
  224. // we start from the bottom of the bitmap and work our way up
  225. // ptr_max == ORIGINAL POINTER GIVEN BY LOCK BUFFER
  226. // ptr == WORKS ITS WAY FROM END OF BITMAP TO FRONT
  227. // GO THROUGH AND RENDER TO THE BITMAP
  228. // AS MUCH AS POSSIBLE
  229. for (;fileDataCurPtr < fileDataEndPtr;) {
  230. for (;;) {
  231. // FIRST PIXEL
  232. ptr[0] = palette[fileDataCurPtr[0] >> 7];
  233. ptr++;
  234. ptrPos++;
  235. if (ptr == ptr_max_line) { break; }
  236. // SECOND PIXEL
  237. ptr[0] = palette[(fileDataCurPtr[0] >> 6) & 0x1];
  238. ptr++;
  239. ptrPos++;
  240. if (ptr == ptr_max_line) { break; }
  241. // THIRD PIXEL
  242. ptr[0] = palette[(fileDataCurPtr[0] >> 5) & 0x1];
  243. ptr++;
  244. ptrPos++;
  245. if (ptr == ptr_max_line) { break; }
  246. // FOURTH PIXEL
  247. ptr[0] = palette[(fileDataCurPtr[0] >> 4) & 0x1];
  248. ptr++;
  249. ptrPos++;
  250. if (ptr == ptr_max_line) { break; }
  251. // FIFTH PIXEL
  252. ptr[0] = palette[(fileDataCurPtr[0] >> 3) & 0x1];
  253. ptr++;
  254. ptrPos++;
  255. if (ptr == ptr_max_line) { break; }
  256. // SIXTH PIXEL
  257. ptr[0] = palette[(fileDataCurPtr[0] >> 2) & 0x1];
  258. ptr++;
  259. ptrPos++;
  260. if (ptr == ptr_max_line) { break; }
  261. // SEVENTH PIXEL
  262. ptr[0] = palette[(fileDataCurPtr[0] >> 1) & 0x1];
  263. ptr++;
  264. ptrPos++;
  265. if (ptr == ptr_max_line) { break; }
  266. // EIGHTH PIXEL
  267. ptr[0] = palette[fileDataCurPtr[0] & 0x1];
  268. ptr++;
  269. ptrPos++;
  270. if (ptr == ptr_max_line) { break; }
  271. // MOVE BUFFER POINTER
  272. fileDataCurPtr++;
  273. if (fileDataCurPtr == fileDataEndPtr) {
  274. break;
  275. }
  276. }
  277. if (ptr == ptr_max_line) {
  278. if (ptr == ptr_max) {
  279. view.unlockBuffer();
  280. delete fileData;
  281. return StreamData.Complete;
  282. }
  283. ptrLine++;
  284. ptrPos = 0;
  285. ptr -= (bi.biWidth * 2);
  286. ptr_max_line -= (bi.biWidth);
  287. fileDataCurPtr++;
  288. fileDataToSkip = bytesForPadding;
  289. if (fileDataCurPtr == fileDataEndPtr) {
  290. break;
  291. }
  292. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  293. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  294. break;
  295. }
  296. else {
  297. fileDataCurPtr += fileDataToSkip;
  298. fileDataToSkip = 0;
  299. }
  300. }
  301. if (fileDataCurPtr == fileDataEndPtr) {
  302. break;
  303. }
  304. }
  305. }
  306. // WINDOWS 2BPP BITMAPS //
  307. case BMP_STATE_DECODE_WIN_2BPP:
  308. ////OutputDebugStringA("bmp - windows - 2 bpp - 4 colors\n");
  309. //skip further padding, skip to image data, according to header
  310. if (bf.bfOffBits - (54 + (bi.biClrUsed * 4)) > 0) {
  311. if(!stream.skip(bf.bfOffBits - (54 + (bi.biClrUsed * 4)) ) ) { return StreamData.Required; }
  312. }
  313. //Calculate the bytes each row will take
  314. //within the file's bitmap data
  315. bytesPerRow = cast(uint)((cast(float)bi.biWidth / 4) + 0.5);
  316. bytesForPadding = 0;
  317. if (bytesPerRow & 0x3) {
  318. //pad bytes per row
  319. bytesForPadding = (4 - (bytesPerRow & 0x3));
  320. bytesPerRow += bytesForPadding;
  321. }
  322. if (bi.biCompression == 0) { // rgb
  323. //calculate the getLength of the bitmap data
  324. bitmapDataLen = bytesPerRow * bi.biHeight;
  325. }
  326. else {
  327. ////OutputDebugStringA("bmp - invalid compression format\n");
  328. return StreamData.Invalid;
  329. }
  330. //create the bitmap's buffer
  331. view.create(bi.biWidth, bi.biHeight);
  332. ptrLine = 0;
  333. ptrPos = 0;
  334. fileDataToSkip = 0;
  335. decoderState = BMP_STATE_RENDER_WIN_2BPP;
  336. case BMP_STATE_RENDER_WIN_2BPP:
  337. ////OutputDebugStringA("bmp - rendering stream input - 2bpp\n");
  338. // TAKE ALL BYTES FROM STREAM
  339. // IF WE FINISH, WE CAN return StreamData.Complete
  340. view.lockBuffer(cast(void**)&ptr_max, ptr_len);
  341. ptr = ptr_max + (ptr_len / 4);
  342. ptr -= (bi.biWidth * (ptrLine + 1));
  343. ptr_max_line = ptr + bi.biWidth;
  344. ptr_max += bi.biWidth;
  345. ptr += ptrPos;
  346. // LOAD FILEDATA WITH PART OF THE STREAM
  347. // CHUNKS AT A TIME
  348. for (;;) {
  349. if (stream.remaining() == 0) {
  350. view.unlockBuffer();
  351. return StreamData.Required;
  352. }
  353. fileData = new ubyte[cast(uint)stream.remaining];
  354. fileDataCurPtr = fileDataPtr = fileData.ptr;
  355. fileDataEndPtr = fileDataCurPtr + stream.readAny(fileData.ptr, cast(uint)stream.remaining);
  356. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  357. //////OutputDebugStringA("bmp - rendering error - not enough information\n");
  358. //////OutputDebugStringA("bmp - skipping data across page\n");
  359. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  360. view.unlockBuffer();
  361. delete fileData;
  362. return StreamData.Complete;
  363. }
  364. else if (fileDataToSkip > 0) {
  365. fileDataCurPtr += fileDataToSkip;
  366. fileDataToSkip = 0;
  367. }
  368. // we start from the bottom of the bitmap and work our way up
  369. // ptr_max == ORIGINAL POINTER GIVEN BY LOCK BUFFER
  370. // ptr == WORKS ITS WAY FROM END OF BITMAP TO FRONT
  371. // GO THROUGH AND RENDER TO THE BITMAP
  372. // AS MUCH AS POSSIBLE
  373. for (;fileDataCurPtr < fileDataEndPtr;) {
  374. for (;;) {
  375. // FIRST PIXEL
  376. ptr[0] = palette[fileDataCurPtr[0] >> 6];
  377. ptr++;
  378. ptrPos++;
  379. if (ptr == ptr_max_line) { break; }
  380. // SECOND PIXEL
  381. ptr[0] = palette[(fileDataCurPtr[0] >> 4) & 0x7];
  382. ptr++;
  383. ptrPos++;
  384. if (ptr == ptr_max_line) { break; }
  385. // THIRD PIXEL
  386. ptr[0] = palette[(fileDataCurPtr[0] >> 2) & 0x7];
  387. ptr++;
  388. ptrPos++;
  389. if (ptr == ptr_max_line) { break; }
  390. // FOURTH PIXEL
  391. ptr[0] = palette[fileDataCurPtr[0] & 0x7];
  392. ptr++;
  393. ptrPos++;
  394. if (ptr == ptr_max_line) { break; }
  395. // MOVE BUFFER POINTER
  396. fileDataCurPtr++;
  397. if (fileDataCurPtr == fileDataEndPtr) {
  398. break;
  399. }
  400. }
  401. if (ptr == ptr_max_line) {
  402. //////OutputDebugStringA("bmp - rendered line\n");
  403. if (ptr == ptr_max) {
  404. //////OutputDebugStringA("bmp - rendering complete\n");
  405. view.unlockBuffer();
  406. delete fileData;
  407. return StreamData.Complete;
  408. }
  409. ptrLine++;
  410. ptrPos = 0;
  411. ptr -= (bi.biWidth * 2);
  412. ptr_max_line -= (bi.biWidth);
  413. fileDataCurPtr++;
  414. fileDataToSkip = bytesForPadding;
  415. if (fileDataCurPtr == fileDataEndPtr) {
  416. break;
  417. }
  418. //////OutputDebugString(String(fileDataToSkip) + S("\n"));
  419. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  420. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  421. break;
  422. }
  423. else {
  424. fileDataCurPtr += fileDataToSkip;
  425. fileDataToSkip = 0;
  426. }
  427. }
  428. if (fileDataCurPtr == fileDataEndPtr) {
  429. break;
  430. }
  431. }
  432. }
  433. // WINDOWS 4BPP BITMAPS, RGB AND RLE COMPRESSED //
  434. case BMP_STATE_DECODE_WIN_4BPP:
  435. ////OutputDebugStringA("bmp - windows - 4 bpp - 16 colors\n");
  436. //skip further padding, skip to image data, according to header
  437. if (bf.bfOffBits - (54 + (bi.biClrUsed * 4)) > 0) {
  438. if(!stream.skip(bf.bfOffBits - (54 + (bi.biClrUsed * 4)) ) ) { return StreamData.Required; }
  439. }
  440. //Calculate the bytes each row will take
  441. //within the file's bitmap data
  442. bytesPerRow = cast(uint)((cast(float)bi.biWidth / 2) + 0.5);
  443. bytesForPadding = 0;
  444. if (bytesPerRow & 0x3) {
  445. //pad bytes per row
  446. bytesForPadding = (4 - (bytesPerRow & 0x3));
  447. bytesPerRow += bytesForPadding;
  448. }
  449. if (bi.biCompression == 2) { // rle-4
  450. //calculate the getLength of the bitmap data
  451. bitmapDataLen = bi.biSizeImage;
  452. decoderSubState = 0;
  453. }
  454. else if (bi.biCompression == 0) { // rgb
  455. //calculate the getLength of the bitmap data
  456. bitmapDataLen = bytesPerRow * bi.biHeight;
  457. }
  458. else {
  459. ////OutputDebugStringA("bmp - invalid compression format\n");
  460. }
  461. //create the bitmap's buffer
  462. view.create(bi.biWidth, bi.biHeight);
  463. ptrLine = 0;
  464. ptrPos = 0;
  465. fileDataToSkip = 0;
  466. decoderState = BMP_STATE_RENDER_WIN_4BPP;
  467. case BMP_STATE_RENDER_WIN_4BPP:
  468. //////OutputDebugStringA("bmp - rendering stream input - 4bpp\n");
  469. // TAKE ALL BYTES FROM STREAM
  470. // IF WE FINISH, WE CAN return StreamData.Complete
  471. view.lockBuffer(cast(void**)&ptr_max, ptr_len);
  472. ptr = ptr_max + (ptr_len / 4);
  473. ptr -= (bi.biWidth * (ptrLine + 1));
  474. ptr_max_line = ptr + bi.biWidth;
  475. ptr_max += bi.biWidth;
  476. ptr += ptrPos;
  477. // LOAD FILEDATA WITH PART OF THE STREAM
  478. // CHUNKS AT A TIME
  479. for (;;) {
  480. if (stream.remaining == 0) {
  481. view.unlockBuffer();
  482. return StreamData.Required;
  483. }
  484. fileData = new ubyte[cast(uint)stream.remaining];
  485. fileDataCurPtr = fileDataPtr = fileData.ptr;
  486. fileDataEndPtr = fileDataCurPtr + stream.readAny(fileData.ptr, cast(uint)stream.remaining);
  487. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  488. //////OutputDebugStringA("bmp - rendering error - not enough information\n");
  489. //////OutputDebugStringA("bmp - skipping data across page\n");
  490. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  491. view.unlockBuffer();
  492. delete fileData;
  493. return StreamData.Complete;
  494. }
  495. else if (fileDataToSkip > 0) {
  496. fileDataCurPtr += fileDataToSkip;
  497. fileDataToSkip = 0;
  498. }
  499. // we start from the bottom of the bitmap and work our way up
  500. // ptr_max == ORIGINAL POINTER GIVEN BY LOCK BUFFER
  501. // ptr == WORKS ITS WAY FROM END OF BITMAP TO FRONT
  502. if (bi.biCompression == 0) {
  503. // GO THROUGH AND RENDER TO THE BITMAP
  504. // AS MUCH AS POSSIBLE
  505. for (;fileDataCurPtr < fileDataEndPtr;) {
  506. for (;;) {
  507. // FIRST PIXEL
  508. ptr[0] = palette[fileDataCurPtr[0] >> 4];
  509. ptr++;
  510. ptrPos++;
  511. if (ptr == ptr_max_line) { break; }
  512. // SECOND PIXEL
  513. ptr[0] = palette[fileDataCurPtr[0] & 0xF];
  514. ptr++;
  515. ptrPos++;
  516. if (ptr == ptr_max_line) { break; }
  517. // MOVE BUFFER POINTER
  518. fileDataCurPtr++;
  519. if (fileDataCurPtr == fileDataEndPtr) {
  520. break;
  521. }
  522. }
  523. if (ptr == ptr_max_line) {
  524. //////OutputDebugStringA("bmp - rendered line\n");
  525. if (ptr == ptr_max) {
  526. //////OutputDebugStringA("bmp - rendering complete\n");
  527. view.unlockBuffer();
  528. delete fileData;
  529. return StreamData.Complete;
  530. }
  531. ptrLine++;
  532. ptrPos = 0;
  533. ptr -= (bi.biWidth * 2);
  534. ptr_max_line -= (bi.biWidth);
  535. fileDataCurPtr++;
  536. fileDataToSkip = bytesForPadding;
  537. if (fileDataCurPtr == fileDataEndPtr) {
  538. break;
  539. }
  540. //////OutputDebugString(String(fileDataToSkip) + S("\n"));
  541. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  542. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  543. break;
  544. }
  545. else {
  546. fileDataCurPtr += fileDataToSkip;
  547. fileDataToSkip = 0;
  548. }
  549. }
  550. if (fileDataCurPtr == fileDataEndPtr) {
  551. break;
  552. }
  553. }
  554. }
  555. else // rle - 4
  556. {
  557. //calculate pointers
  558. // LOOP
  559. // {
  560. // STATE 0:
  561. // GET FIRST CODE
  562. // STATE 1: RLE NORMAL
  563. // GET CODE
  564. // RENDER
  565. // STATE 2: ESCAPE
  566. // GET CODE
  567. // FILL IN LINE (EOL)
  568. // FILL IN IMAGE (EOB)
  569. // SWITCH TO DELTA
  570. // SWITCH TO ABSOLUTE
  571. // STATE 3: DELTA
  572. // GET CODES
  573. // REPOSITION
  574. // STATE 4: ABSOLUTE
  575. // RENDER
  576. // }
  577. }
  578. }
  579. //view.unlockBuffer();
  580. //if (bi.biCompression == 0)
  581. //{
  582. //Bitmaps store data from bottom to top...
  583. //The bitmap buffer, however, stores from
  584. //top to bottom...take that into
  585. //consideration when Reading this code
  586. //for (; ((ptr + bi.biWidth) <= ptrmax); )
  587. //{
  588. // for (;;)
  589. // {
  590. // if (i >= width) { break; }
  591. // ptr[i] = palette[fileDataCurPtr[a] >> 4];
  592. // i++;
  593. // if (i >= width) { break; }
  594. // ptr[i] = palette[fileDataCurPtr[a] & 0xF];
  595. // i++;
  596. // a++;
  597. // }
  598. //progress a line
  599. // ptr += width;
  600. //digress a line
  601. // fileDataEndPtr -= bytesPerRow;
  602. // fileDataCurPtr = fileDataEndPtr;
  603. //}
  604. //}
  605. //find expected minimum file size - bitmapDataLen + headers + color tables
  606. //fileSize = bitmapDataLen;
  607. //if (stream.getLength() < fileSize)
  608. //{
  609. //do not continue
  610. // ////OutputDebugStringA("bmp - unexpected size\n");
  611. //return StreamData.Invalid;
  612. //}
  613. //if there is a corrupt header, do not continue
  614. //if (bf.bfOffBits <= 54)
  615. //{
  616. // ////OutputDebugStringA("bmp - corrupt header\n");
  617. // return StreamData.Invalid;
  618. //}
  619. //skip further padding
  620. //if (stream.getLength() - (bitmapDataLen + 54 + (bi.biClrUsed * 4)) > 0)
  621. //{
  622. // stream.skip(stream.getLength() - (bitmapDataLen + 54 + (bi.biClrUsed * 4)));
  623. //}
  624. //allocate the bitmap data
  625. //fileDataPtr = new UInt8[bitmapDataLen];
  626. //read from the file the bitmap data
  627. //stream.read(fileDataPtr, bitmapDataLen);
  628. //calculate pointers
  629. /*fileDataEndPtr = fileDataPtr + bitmapDataLen - bytesPerRow;
  630. fileDataCurPtr = fileDataEndPtr;
  631. //retrieve a pointer to a bitmap buffer
  632. view.lockBuffer((void**)&ptr, ptrlen);
  633. //calculate the buffer's bound
  634. ptrmax = (ptr + (ptrlen/4));
  635. //This loop will paint to the buffer
  636. //using information from the file
  637. if (bi.biCompression == 2) //BI_RLE4
  638. {
  639. //calculate pointers
  640. fileDataEndPtr = fileDataPtr + bitmapDataLen;
  641. fileDataCurPtr = fileDataPtr;
  642. ptrmax -= width;
  643. UInt32* ptr_cur = ptrmax;
  644. for (; ptr_cur >= ptr; )
  645. {
  646. UInt8 lenByte;
  647. //goes through a row
  648. for (i=0; i < width; )
  649. {
  650. //get getLength byte
  651. lenByte = fileDataCurPtr[0];
  652. fileDataCurPtr++;
  653. if (fileDataCurPtr == fileDataEndPtr) { break; }
  654. if (lenByte == 0)
  655. {
  656. //escape sequence or absolute mode
  657. lenByte = fileDataCurPtr[0];
  658. fileDataCurPtr++;
  659. if (fileDataCurPtr == fileDataEndPtr) { break; }
  660. if (lenByte < 3)
  661. {
  662. //encoded mode
  663. if (lenByte == 0)
  664. {
  665. //end of line
  666. //paint black pixels
  667. //to the rest of the line and continue
  668. if (i!=0)
  669. {
  670. for ( ; i < width; i++)
  671. {
  672. ptr_cur[i] = 0;
  673. }
  674. break;
  675. }
  676. }
  677. else if (lenByte == 1)
  678. {
  679. //end of bitmap
  680. //paint black pixels
  681. //to the rest of the bitmap and exit
  682. for (; ptr_cur >= ptr; )
  683. {
  684. for ( ; i < width; i++)
  685. {
  686. ptr_cur[i] = 0;
  687. }
  688. //digress a line
  689. ptrmax-=width;
  690. ptr_cur=ptrmax;
  691. i = 0;
  692. }
  693. break;
  694. }
  695. else
  696. {
  697. //delta
  698. //next two bytes are horiz and vert offsets to new pixel
  699. lenByte = fileDataCurPtr[0];
  700. fileDataCurPtr++;
  701. if (fileDataCurPtr == fileDataEndPtr) { break; }
  702. a = fileDataCurPtr[0];
  703. fileDataCurPtr++;
  704. if (fileDataCurPtr == fileDataEndPtr) { break; }
  705. //lenByte is the horizontal offset
  706. //a is the vertical offset
  707. //for vertical offsets, we decrease or increase
  708. //the ptr_cur;
  709. ptr_cur += (width * (UInt8)(a));
  710. ptr_cur += (lenByte);
  711. }
  712. }
  713. else
  714. {
  715. //absolute mode
  716. //lenByte is the number of colors that follow is normal format
  717. //this must be padded to multiple of four
  718. a = lenByte;
  719. //decode
  720. for ( ; ; )
  721. {
  722. ptr_cur[i] = palette[fileDataCurPtr[0] >> 4];
  723. i++;
  724. if (i>=width) { break; }
  725. a--;
  726. if (a <= 0) { break; }
  727. ptr_cur[i] = palette[fileDataCurPtr[0] & 0xF];
  728. i++;
  729. if (i>=width) { break; }
  730. a--;
  731. if (a <= 0) { break; }
  732. fileDataCurPtr++;
  733. if (fileDataCurPtr >= fileDataEndPtr) { break; }
  734. }
  735. fileDataCurPtr++;
  736. if (fileDataCurPtr >= fileDataEndPtr) { break; }
  737. //realign to a word boundary
  738. if ((lenByte/2) & 0x01)
  739. {
  740. fileDataCurPtr++ ;
  741. if (fileDataCurPtr >= fileDataEndPtr) { break; }
  742. }
  743. }
  744. }
  745. else
  746. {
  747. //run the getLength of lenByte, and paint the pixel
  748. //of the index that many times onto the buffer
  749. for ( ; ; )
  750. {
  751. ptr_cur[i] = palette[fileDataCurPtr[0] >> 4];
  752. i++;
  753. if (i>=width) { break; }
  754. lenByte--;
  755. if (lenByte <= 0) { break; }
  756. ptr_cur[i] = palette[fileDataCurPtr[0] & 0xF];
  757. i++;
  758. if (i>=width) { break; }
  759. lenByte--;
  760. if (lenByte <= 0) { break; }
  761. }
  762. fileDataCurPtr++;
  763. if (fileDataCurPtr >= fileDataEndPtr) { break; }
  764. }
  765. }
  766. //digress a line
  767. ptrmax-=width;
  768. ptr_cur=ptrmax;
  769. }
  770. }
  771. else
  772. {
  773. //Bitmaps store data from bottom to top...
  774. //The bitmap buffer, however, stores from
  775. //top to bottom...take that into
  776. //consideration when Reading this code
  777. for (; ((ptr + width) <= ptrmax); )
  778. {
  779. //goes through a row
  780. i = 0;
  781. a = 0;
  782. for (;;)
  783. {
  784. if (i >= width) { break; }
  785. ptr[i] = palette[fileDataCurPtr[a] >> 4];
  786. i++;
  787. if (i >= width) { break; }
  788. ptr[i] = palette[fileDataCurPtr[a] & 0xF];
  789. i++;
  790. a++;
  791. }
  792. //progress a line
  793. ptr += width;
  794. //digress a line
  795. fileDataEndPtr -= bytesPerRow;
  796. fileDataCurPtr = fileDataEndPtr;
  797. }
  798. }
  799. //unlock the buffer, so the view can refresh
  800. view.unlockBuffer();
  801. */
  802. // return StreamData.Complete;
  803. // WINDOWS 8BPP BITMAPS, RGB AND RLE COMPRESSED //
  804. case BMP_STATE_DECODE_WIN_8BPP:
  805. ////OutputDebugStringA("bmp - windows - 8 bpp - 256 colors\n");
  806. //skip further padding, skip to image data, according to header
  807. if (bf.bfOffBits - (54 + (bi.biClrUsed * 4)) > 0) {
  808. if(!stream.skip(bf.bfOffBits - (54 + (bi.biClrUsed * 4)) ) ) { return StreamData.Required; }
  809. }
  810. //Calculate the bytes each row will take
  811. //within the file's bitmap data
  812. bytesPerRow = bi.biWidth;
  813. if (bytesPerRow & 0x3) {
  814. //pad bytes per row
  815. bytesPerRow += (4 - (bytesPerRow & 0x3));
  816. }
  817. if (bi.biCompression == 1) { // rle-8
  818. //calculate the getLength of the bitmap data
  819. bitmapDataLen = bi.biSizeImage;
  820. decoderSubState = 0;
  821. }
  822. else if (bi.biCompression == 0) { // rgb
  823. //calculate the getLength of the bitmap data
  824. bitmapDataLen = bytesPerRow * bi.biHeight;
  825. }
  826. else {
  827. ////OutputDebugStringA("bmp - invalid compression format\n");
  828. }
  829. //create the bitmap's buffer
  830. view.create(bi.biWidth, bi.biHeight);
  831. ptrLine = 0;
  832. ptrPos = 0;
  833. fileDataToSkip = 0;
  834. decoderState = BMP_STATE_RENDER_WIN_8BPP;
  835. case BMP_STATE_RENDER_WIN_8BPP:
  836. //////OutputDebugStringA("bmp - rendering stream input - 8bpp\n");
  837. // TAKE ALL BYTES FROM STREAM
  838. // IF WE FINISH, WE CAN return StreamData.Complete
  839. // GET THE BITMAP DATA AND GO TO THE NEXT POSITION
  840. // TO RENDER TO
  841. view.lockBuffer(cast(void**)&ptr_max, ptr_len);
  842. ptr = ptr_max + (ptr_len / 4);
  843. ptr -= (bi.biWidth * (ptrLine + 1));
  844. ptr_max_line = ptr + bi.biWidth;
  845. ptr_max += bi.biWidth;
  846. ptr += ptrPos;
  847. // LOAD FILEDATA WITH PART OF THE STREAM
  848. // CHUNKS AT A TIME
  849. for (;;) {
  850. if (stream.remaining == 0) {
  851. view.unlockBuffer();
  852. return StreamData.Required;
  853. }
  854. fileData = new ubyte[cast(uint)stream.remaining];
  855. fileDataCurPtr = fileDataPtr = fileData.ptr;
  856. fileDataEndPtr = fileDataCurPtr + stream.readAny(fileData.ptr, cast(uint)stream.remaining);
  857. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  858. //////OutputDebugStringA("bmp - rendering error - not enough information\n");
  859. //////OutputDebugStringA("bmp - skipping data across page\n");
  860. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  861. view.unlockBuffer();
  862. delete fileData;
  863. return StreamData.Complete;
  864. }
  865. else if (fileDataToSkip > 0) {
  866. fileDataCurPtr += fileDataToSkip;
  867. fileDataToSkip = 0;
  868. }
  869. // we start from the bottom of the bitmap and work our way up
  870. // ptr_max == ORIGINAL POINTER GIVEN BY LOCK BUFFER
  871. // ptr == WORKS ITS WAY FROM END OF BITMAP TO FRONT
  872. if (bi.biCompression == 0) {
  873. // GO THROUGH AND RENDER TO THE BITMAP
  874. // AS MUCH AS POSSIBLE
  875. for (;;) {
  876. ptr[0] = palette[fileDataCurPtr[0]];
  877. ptr++;
  878. ptrPos++;
  879. fileDataCurPtr++;
  880. if (ptr == ptr_max_line) {
  881. //////OutputDebugStringA("bmp - rendered line\n");
  882. if (ptr == ptr_max) {
  883. ////OutputDebugStringA("bmp - rendering complete\n");
  884. view.unlockBuffer();
  885. delete fileData;
  886. return StreamData.Complete;
  887. }
  888. ptrLine++;
  889. ptrPos = 0;
  890. ptr -= (bi.biWidth * 2);
  891. ptr_max_line -= (bi.biWidth);
  892. fileDataToSkip = bytesPerRow - bi.biWidth;
  893. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  894. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  895. break;
  896. }
  897. else {
  898. fileDataCurPtr += fileDataToSkip;
  899. fileDataToSkip = 0;
  900. }
  901. }
  902. if (fileDataCurPtr == fileDataEndPtr) {
  903. break;
  904. }
  905. }
  906. }
  907. else { // rle - 8
  908. //calculate pointers
  909. // LOOP
  910. // {
  911. // STATE 0:
  912. // GET FIRST CODE
  913. // STATE 1: RLE NORMAL
  914. // GET CODE
  915. // RENDER
  916. // STATE 2: ESCAPE
  917. // GET CODE
  918. // FILL IN LINE (EOL)
  919. // FILL IN IMAGE (EOB)
  920. // SWITCH TO DELTA
  921. // SWITCH TO ABSOLUTE
  922. // STATE 3: DELTA
  923. // GET CODES
  924. // REPOSITION
  925. // STATE 4: ABSOLUTE
  926. // RENDER
  927. // }
  928. for (;fileDataCurPtr < fileDataEndPtr;) {
  929. switch(decoderSubState) {
  930. case 0:
  931. // GET CODE
  932. byteData = fileDataCurPtr[0];
  933. if (byteData == 0) {
  934. // ESCAPE SEQUENCE
  935. decoderSubState = 2;
  936. }
  937. else {
  938. // JUST RENDER DATA OUT
  939. decoderSubState = 1;
  940. }
  941. fileDataCurPtr++;
  942. if (fileDataCurPtr == fileDataEndPtr) { break; }
  943. break;
  944. case 1:
  945. //////OutputDebugStringA("bmp - rle - state: RENDER\n");
  946. // RENDER RLE DATA
  947. //run the getLength of lenByte, and paint the pixel
  948. //of the index that many times onto the buffer
  949. for ( ; (byteData > 0); ) {
  950. ptr[0] = palette[fileDataCurPtr[0]];
  951. ptr++;
  952. ptrPos++;
  953. byteData--;
  954. if (ptr == ptr_max_line) {
  955. if (ptr == ptr_max) {
  956. ////OutputDebugStringA("bmp - from render - rendering complete\n");
  957. view.unlockBuffer();
  958. delete fileData;
  959. return StreamData.Complete;
  960. }
  961. ptrLine++;
  962. ptrPos = 0;
  963. ptr -= (bi.biWidth * 2);
  964. ptr_max_line -= (bi.biWidth);
  965. }
  966. }
  967. // GO BACK TO RETRIEVAL OF CODE
  968. decoderSubState = 0;
  969. fileDataCurPtr++;
  970. if (fileDataCurPtr >= fileDataEndPtr) { break; }
  971. break;
  972. case 2:
  973. // HANDLE ESCAPE SEQUENCES
  974. byteData = fileDataCurPtr[0];
  975. if (byteData < 3) {
  976. if (byteData == 0) {
  977. // END OF LINE ENCODING
  978. if (ptrPos!=0) {
  979. for ( ; ; ) {
  980. ptr[0] = 0;
  981. ptr++;
  982. ptrPos++;
  983. if (ptr == ptr_max_line) {
  984. //////OutputDebugStringA("bmp - rendered line\n");
  985. if (ptr == ptr_max) {
  986. ////OutputDebugStringA("bmp - rendering complete\n");
  987. view.unlockBuffer();
  988. delete fileData;
  989. return StreamData.Complete;
  990. }
  991. ptrLine++;
  992. ptrPos = 0;
  993. ptr -= (bi.biWidth * 2);
  994. ptr_max_line -= (bi.biWidth);
  995. break;
  996. }
  997. }
  998. }
  999. // BACK TO GETTING A CODE
  1000. decoderSubState = 0;
  1001. }
  1002. else if (byteData == 1) {
  1003. // END OF BITMAP ENCODING
  1004. //end of bitmap
  1005. //paint black pixels
  1006. //to the rest of the bitmap and exit
  1007. for (;;) {
  1008. for ( ; ; ) {
  1009. ptr[0] = 0;
  1010. ptr++;
  1011. ptrPos++;
  1012. if (ptr == ptr_max_line) {
  1013. //////OutputDebugStringA("bmp - rendered line\n");
  1014. if (ptr == ptr_max) {
  1015. ////OutputDebugStringA("bmp - rendering complete\n");
  1016. view.unlockBuffer();
  1017. delete fileData;
  1018. return StreamData.Complete;
  1019. }
  1020. ptrLine++;
  1021. ptrPos = 0;
  1022. ptr -= (bi.biWidth * 2);
  1023. ptr_max_line -= (bi.biWidth);
  1024. }
  1025. }
  1026. }
  1027. // BACK TO GETTING A CODE
  1028. //decoderSubState = 0;
  1029. }
  1030. else { //if (byteData == 2)
  1031. // DELTA ENCODING
  1032. decoderSubState = 7;
  1033. }
  1034. }
  1035. else {
  1036. //ABSOLUTE MODE
  1037. byteCounter = byteData;
  1038. decoderSubState = 3;
  1039. }
  1040. fileDataCurPtr++;
  1041. if (fileDataCurPtr >= fileDataEndPtr) { break; }
  1042. break;
  1043. case 3:
  1044. // ABSOLUTE MODE
  1045. // BYTE DATA IS THE AMOUNT OF BYTES TO READ
  1046. //decode
  1047. for ( ; (byteCounter>0) && (ptr < ptr_max_line); ) {
  1048. ptr[0] = palette[fileDataCurPtr[0]];
  1049. ptrPos++;
  1050. ptr++;
  1051. byteCounter--;
  1052. if (ptr == ptr_max_line) {
  1053. //////OutputDebugStringA("bmp - rendered line\n");
  1054. if (ptr == ptr_max) {
  1055. view.unlockBuffer();
  1056. return StreamData.Complete;
  1057. }
  1058. ptrLine++;
  1059. ptrPos = 0;
  1060. ptr -= (bi.biWidth * 2);
  1061. ptr_max_line -= (bi.biWidth);
  1062. }
  1063. fileDataCurPtr++;
  1064. if (fileDataCurPtr >= fileDataEndPtr) { break; }
  1065. }
  1066. if (byteCounter == 0) {
  1067. // BACK TO GETTING A CODE
  1068. decoderSubState = 0;
  1069. //realign to a word boundary
  1070. fileDataToSkip = (byteData & 0x01);
  1071. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  1072. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  1073. //ensure we drop out of loop
  1074. fileDataCurPtr = fileDataEndPtr;
  1075. break;
  1076. }
  1077. else {
  1078. fileDataCurPtr += fileDataToSkip;
  1079. fileDataToSkip = 0;
  1080. }
  1081. }
  1082. break;
  1083. case 7:
  1084. ////OutputDebugStringA("bmp - rle - state: DELTA\n");
  1085. // DELTA MODE
  1086. // BACK TO GETTING A CODE
  1087. decoderSubState = 0;
  1088. break;
  1089. case 5:
  1090. break;
  1091. case 6:
  1092. break;
  1093. default: break;
  1094. }
  1095. }
  1096. }
  1097. }
  1098. //view.unlockBuffer();
  1099. //break;
  1100. // WINDOWS 16BPP BITMAPS, 5-6-5 AND 5-5-5 AND others //
  1101. case BMP_STATE_DECODE_WIN_16BPP:
  1102. ////OutputDebugStringA("bmp - windows - 16 bpp\n");
  1103. return StreamData.Complete;
  1104. // WINDOWS 24BPP BITMAPS //
  1105. case BMP_STATE_DECODE_WIN_24BPP:
  1106. ////OutputDebugStringA("bmp - windows - 24 bpp - true color\n");
  1107. //skip further padding, skip to image data, according to header
  1108. if (bf.bfOffBits - (54) > 0) {
  1109. if(!stream.skip(bf.bfOffBits - (54) ) ) { return StreamData.Required; }
  1110. }
  1111. //Calculate the bytes each row will take
  1112. //within the file's bitmap data
  1113. bytesForPadding=0;
  1114. bytesPerRow = bi.biWidth*3;
  1115. if (bytesPerRow & 0x3) {
  1116. //pad bytes per row
  1117. bytesForPadding = (4 - (bytesPerRow & 0x3));
  1118. bytesPerRow += bytesForPadding;
  1119. }
  1120. if (bi.biCompression == 0) { // rgb
  1121. //calculate the getLength of the bitmap data
  1122. bitmapDataLen = bytesPerRow * bi.biHeight;
  1123. }
  1124. else {
  1125. ////OutputDebugStringA("bmp - invalid compression format\n");
  1126. return StreamData.Invalid;
  1127. }
  1128. //create the bitmap's buffer
  1129. view.create(bi.biWidth, bi.biHeight);
  1130. ptrLine = 0;
  1131. ptrPos = 0;
  1132. fileDataToSkip = 0;
  1133. byteCounter = 0;
  1134. decoderState = BMP_STATE_RENDER_WIN_24BPP;
  1135. case BMP_STATE_RENDER_WIN_24BPP:
  1136. //////OutputDebugStringA("bmp - rendering stream input - 24bpp\n");
  1137. // TAKE ALL BYTES FROM STREAM
  1138. // IF WE FINISH, WE CAN return StreamData.Complete
  1139. // GET THE BITMAP DATA AND GO TO THE NEXT POSITION
  1140. // TO RENDER TO
  1141. view.lockBuffer(cast(void**)&ptr_max, ptr_len);
  1142. ptr = ptr_max + (ptr_len / 4);
  1143. ptr -= (bi.biWidth * (ptrLine + 1));
  1144. ptr_max_line = ptr + bi.biWidth;
  1145. ptr_max += bi.biWidth;
  1146. ptr += ptrPos;
  1147. // LOAD FILEDATA WITH PART OF THE STREAM
  1148. // CHUNKS AT A TIME
  1149. for (;;) {
  1150. if (stream.remaining == 0) {
  1151. view.unlockBuffer();
  1152. return StreamData.Required;
  1153. }
  1154. fileData = new ubyte[cast(uint)bitmapDataLen];
  1155. fileDataCurPtr = fileDataPtr = fileData.ptr;
  1156. fileDataEndPtr = fileDataCurPtr + stream.readAny(fileData.ptr, cast(uint)bitmapDataLen);
  1157. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  1158. //////OutputDebugStringA("bmp - rendering error - not enough information\n");
  1159. //////OutputDebugStringA("bmp - skipping data across page\n");
  1160. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  1161. view.unlockBuffer();
  1162. delete fileData;
  1163. return StreamData.Complete;
  1164. }
  1165. else if (fileDataToSkip > 0) {
  1166. fileDataCurPtr += fileDataToSkip;
  1167. fileDataToSkip = 0;
  1168. }
  1169. // we start from the bottom of the bitmap and work our way up
  1170. // ptr_max == ORIGINAL POINTER GIVEN BY LOCK BUFFER
  1171. // ptr == WORKS ITS WAY FROM END OF BITMAP TO FRONT
  1172. // GO THROUGH AND RENDER TO THE BITMAP
  1173. // AS MUCH AS POSSIBLE
  1174. for (;fileDataCurPtr < fileDataEndPtr;) {
  1175. if (((fileDataEndPtr - fileDataCurPtr) > 3) && byteCounter == 0) {
  1176. ptr[0] = 0xFF000000 | ((cast(uint*)fileDataCurPtr)[0] & 0xFFFFFF);// | (fileDataCurPtr[1] << 8) | (fileDataCurPtr[2] << 16);
  1177. fileDataCurPtr+=3;
  1178. ptr++;
  1179. ptrPos++;
  1180. if (ptr == ptr_max_line) {
  1181. if (ptr == ptr_max) {
  1182. ////OutputDebugStringA("bmp - rendering complete\n");
  1183. view.unlockBuffer();
  1184. delete fileData;
  1185. return StreamData.Complete;
  1186. }
  1187. ptrLine++;
  1188. ptrPos = 0;
  1189. ptr -= (bi.biWidth * 2);
  1190. ptr_max_line -= (bi.biWidth);
  1191. fileDataToSkip = bytesForPadding;
  1192. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  1193. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  1194. break;
  1195. }
  1196. else {
  1197. fileDataCurPtr += fileDataToSkip;
  1198. fileDataToSkip = 0;
  1199. }
  1200. }
  1201. }
  1202. else if (byteCounter == 0) {
  1203. ptr[0] = 0xFF000000 | (fileDataCurPtr[0]);
  1204. byteCounter++;
  1205. fileDataCurPtr++;
  1206. }
  1207. else if (byteCounter == 1) {
  1208. ptr[0] |= (fileDataCurPtr[0] << 8);
  1209. byteCounter++;
  1210. fileDataCurPtr++;
  1211. }
  1212. else {
  1213. ptr[0] |= (fileDataCurPtr[0] << 16) ;
  1214. byteCounter = 0;
  1215. ptr++;
  1216. ptrPos++;
  1217. fileDataCurPtr++;
  1218. if (ptr == ptr_max_line) {
  1219. if (ptr == ptr_max) {
  1220. ////OutputDebugStringA("bmp - rendering complete\n");
  1221. view.unlockBuffer();
  1222. delete fileData;
  1223. return StreamData.Complete;
  1224. }
  1225. ptrLine++;
  1226. ptrPos = 0;
  1227. ptr -= (bi.biWidth * 2);
  1228. ptr_max_line -= (bi.biWidth);
  1229. fileDataToSkip = bytesForPadding;
  1230. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  1231. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  1232. break;
  1233. }
  1234. else {
  1235. fileDataCurPtr += fileDataToSkip;
  1236. fileDataToSkip = 0;
  1237. }
  1238. }
  1239. }
  1240. }
  1241. }
  1242. // WINDOWS 32BPP BITMAPS //
  1243. case BMP_STATE_DECODE_WIN_32BPP:
  1244. ////OutputDebugStringA("bmp - windows - 32 bpp - true color\n");
  1245. //skip further padding, skip to image data, according to header
  1246. if (bf.bfOffBits - (54) > 0) {
  1247. if(!stream.skip(bf.bfOffBits - (54) ) ) { return StreamData.Required; }
  1248. }
  1249. //Calculate the bytes each row will take
  1250. //within the file's bitmap data
  1251. bytesPerRow = bi.biWidth*4;
  1252. bytesForPadding = 0;
  1253. if (bi.biCompression == 0 || bi.biCompression == 3) { // rgb
  1254. //calculate the getLength of the bitmap data
  1255. bitmapDataLen = bytesPerRow * bi.biHeight;
  1256. }
  1257. else {
  1258. ////OutputDebugStringA("bmp - invalid compression format\n");
  1259. return StreamData.Invalid;
  1260. }
  1261. //create the bitmap's buffer
  1262. view.create(bi.biWidth, bi.biHeight);
  1263. ptrLine = 0;
  1264. ptrPos = 0;
  1265. fileDataToSkip = 0;
  1266. byteCounter = 0;
  1267. decoderState = BMP_STATE_RENDER_WIN_32BPP;
  1268. case BMP_STATE_RENDER_WIN_32BPP:
  1269. //////OutputDebugStringA("bmp - rendering stream input - 32bpp\n");
  1270. // TAKE ALL BYTES FROM STREAM
  1271. // IF WE FINISH, WE CAN return StreamData.Complete
  1272. // GET THE BITMAP DATA AND GO TO THE NEXT POSITION
  1273. // TO RENDER TO
  1274. view.lockBuffer(cast(void**)&ptr_max, ptr_len);
  1275. ptr = ptr_max + (ptr_len / 4);
  1276. ptr -= (bi.biWidth * (ptrLine + 1));
  1277. ptr_max_line = ptr + bi.biWidth;
  1278. ptr_max += bi.biWidth;
  1279. ptr += ptrPos;
  1280. // LOAD FILEDATA WITH PART OF THE STREAM
  1281. // CHUNKS AT A TIME
  1282. for (;;) {
  1283. if (stream.remaining == 0) {
  1284. view.unlockBuffer();
  1285. return StreamData.Required;
  1286. }
  1287. fileData = new ubyte[cast(uint)stream.remaining];
  1288. fileDataCurPtr = fileDataPtr = fileData.ptr;
  1289. fileDataEndPtr = fileDataCurPtr + stream.readAny(fileData.ptr, cast(uint)stream.remaining);
  1290. // we start from the bottom of the bitmap and work our way up
  1291. // ptr_max == ORIGINAL POINTER GIVEN BY LOCK BUFFER
  1292. // ptr == WORKS ITS WAY FROM END OF BITMAP TO FRONT
  1293. // GO THROUGH AND RENDER TO THE BITMAP
  1294. // AS MUCH AS POSSIBLE
  1295. for (;fileDataCurPtr < fileDataEndPtr;) {
  1296. if (((fileDataEndPtr - fileDataCurPtr) > 3) && byteCounter == 0) {
  1297. ptr[0] = 0xFF000000 | ((cast(uint*)fileDataCurPtr)[0] & 0xFFFFFF);// | (fileDataCurPtr[1] << 8) | (fileDataCurPtr[2] << 16);
  1298. fileDataCurPtr+=4;
  1299. ptr++;
  1300. ptrPos++;
  1301. if (ptr == ptr_max_line) {
  1302. if (ptr == ptr_max) {
  1303. ////OutputDebugStringA("bmp - rendering complete\n");
  1304. view.unlockBuffer();
  1305. delete fileData;
  1306. return StreamData.Complete;
  1307. }
  1308. ptrLine++;
  1309. ptrPos = 0;
  1310. ptr -= (bi.biWidth * 2);
  1311. ptr_max_line -= (bi.biWidth);
  1312. fileDataToSkip = bytesForPadding;
  1313. if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
  1314. fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
  1315. break;
  1316. }
  1317. else {
  1318. fileDataCurPtr += fileDataToSkip;
  1319. fileDataToSkip = 0;
  1320. }
  1321. }
  1322. }
  1323. else if (byteCounter == 0) {
  1324. ptr[0] = 0xFF000000 | (fileDataCurPtr[0]);
  1325. byteCounter++;
  1326. fileDataCurPtr++;
  1327. }
  1328. else if (byteCounter == 1) {
  1329. ptr[0] |= (fileDataCurPtr[0] << 8);
  1330. byteCounter++;
  1331. fileDataCurPtr++;
  1332. }
  1333. else if (byteCounter == 2) {
  1334. ptr[0] |= (fileDataCurPtr[0] << 16);
  1335. byteCounter++;
  1336. fileDataCurPtr++;
  1337. }
  1338. else {
  1339. //ptr[0] |= (fileDataCurPtr[0] << 16) ;
  1340. byteCounter = 0;
  1341. ptr++;
  1342. ptrPos++;
  1343. fileDataCurPtr++;
  1344. if (ptr == ptr_max_line) {
  1345. //////OutputDebugStringA("bmp - rendered line\n");
  1346. if (ptr == ptr_max) {
  1347. ////OutputDebugStringA("bmp - rendering complete\n");
  1348. view.unlockBuffer();
  1349. delete fileData;
  1350. return StreamData.Complete;
  1351. }
  1352. ptrLine++;
  1353. ptrPos = 0;
  1354. ptr -= (bi.biWidth * 2);
  1355. ptr_max_line -= (bi.biWidth);
  1356. }
  1357. }
  1358. }
  1359. }
  1360. default:
  1361. break;
  1362. }
  1363. break;
  1364. }
  1365. return StreamData.Invalid;
  1366. }
  1367. private:
  1368. static const auto BMP_STATE_INIT = 0;
  1369. static const auto BMP_STATE_READ_HEADERS = 1;
  1370. static const auto BMP_STATE_READ_BITMAP_SIZE = 2;
  1371. static const auto BMP_STATE_READ_OSX_1 = 3;
  1372. static const auto BMP_STATE_READ_OSX_2 = 4;
  1373. static const auto BMP_STATE_READ_WIN = 5;
  1374. static const auto BMP_STATE_READ_WIN_PALETTE = 6;
  1375. static const auto BMP_STATE_READ_OSX_1_PALETTE = 7;
  1376. static const auto BMP_STATE_READ_OSX_2_PALETTE = 8;
  1377. static const auto BMP_STATE_DECODE_WIN_1BPP = 9;
  1378. static const auto BMP_STATE_DECODE_WIN_2BPP = 10;
  1379. static const auto BMP_STATE_DECODE_WIN_4BPP = 11;
  1380. static const auto BMP_STATE_DECODE_WIN_8BPP = 12;
  1381. static const auto BMP_STATE_DECODE_WIN_16BPP = 13;
  1382. static const auto BMP_STATE_DECODE_WIN_24BPP = 14;
  1383. static const auto BMP_STATE_DECODE_WIN_32BPP = 15;
  1384. static const auto BMP_STATE_RENDER_WIN_1BPP = 16;
  1385. static const auto BMP_STATE_RENDER_WIN_2BPP = 17;
  1386. static const auto BMP_STATE_RENDER_WIN_4BPP = 18;
  1387. static const auto BMP_STATE_RENDER_WIN_8BPP = 19;
  1388. static const auto BMP_STATE_RENDER_WIN_16BPP = 20;
  1389. static const auto BMP_STATE_RENDER_WIN_24BPP = 21;
  1390. static const auto BMP_STATE_RENDER_WIN_32BPP = 22;
  1391. static const auto BMP_STATE_DECODE_OS2_1_1BPP = 40;
  1392. static const auto BMP_STATE_DECODE_OS2_2_1BPP = 80;
  1393. static const ubyte _djehuty_convert_16_of_6_to_32[64] = (0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61,
  1394. 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125,
  1395. 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186,
  1396. 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255);
  1397. static const ubyte _djehuty_convert_16_of_5_to_32[32] = (0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123,
  1398. 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255);
  1399. protected:
  1400. _djehuty_image_bitmap_file_header bf;
  1401. _djehuty_image_bitmap_info_header bi;
  1402. _djehuty_image_os2_1_bitmap_info_header os2_1_bi;
  1403. _djehuty_image_os2_2_bitmap_info_header os2_2_bi;
  1404. uint biSize;
  1405. uint paletteNumColors;
  1406. uint palette[256];
  1407. int bytesPerRow;
  1408. int bytesForPadding;
  1409. ubyte fileData[];
  1410. ubyte* fileDataPtr;
  1411. ubyte* fileDataEndPtr;
  1412. ubyte* fileDataCurPtr;
  1413. int fileDataToSkip;
  1414. uint ptrLine; //the current scan line of the image (y)
  1415. uint ptrPos; //the current pixel of the line (x)
  1416. uint byteData;
  1417. uint byteCounter;
  1418. ulong bitmapDataLen;
  1419. ulong fileSize;
  1420. }