/src/FreeImage/Source/FreeImage/PluginBMP.cpp

https://bitbucket.org/cabalistic/ogredeps/ · C++ · 1480 lines · 987 code · 303 blank · 190 comment · 280 complexity · 992db755149e41de68b37e55c8d8b79b MD5 · raw file

  1. // ==========================================================
  2. // BMP Loader and Writer
  3. //
  4. // Design and implementation by
  5. // - Floris van den Berg (flvdberg@wxs.nl)
  6. // - Markus Loibl (markus.loibl@epost.de)
  7. // - Martin Weber (martweb@gmx.net)
  8. // - Hervé Drolon (drolon@infonie.fr)
  9. // - Michal Novotny (michal@etc.cz)
  10. //
  11. // This file is part of FreeImage 3
  12. //
  13. // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
  14. // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
  15. // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
  16. // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
  17. // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
  18. // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
  19. // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
  20. // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
  21. // THIS DISCLAIMER.
  22. //
  23. // Use at your own risk!
  24. // ==========================================================
  25. #include "FreeImage.h"
  26. #include "Utilities.h"
  27. // ----------------------------------------------------------
  28. // Constants + headers
  29. // ----------------------------------------------------------
  30. static const BYTE RLE_COMMAND = 0;
  31. static const BYTE RLE_ENDOFLINE = 0;
  32. static const BYTE RLE_ENDOFBITMAP = 1;
  33. static const BYTE RLE_DELTA = 2;
  34. static const BYTE BI_RGB = 0;
  35. static const BYTE BI_RLE8 = 1;
  36. static const BYTE BI_RLE4 = 2;
  37. static const BYTE BI_BITFIELDS = 3;
  38. // ----------------------------------------------------------
  39. #ifdef _WIN32
  40. #pragma pack(push, 1)
  41. #else
  42. #pragma pack(1)
  43. #endif
  44. typedef struct tagBITMAPCOREHEADER {
  45. DWORD bcSize;
  46. WORD bcWidth;
  47. WORD bcHeight;
  48. WORD bcPlanes;
  49. WORD bcBitCnt;
  50. } BITMAPCOREHEADER, *PBITMAPCOREHEADER;
  51. typedef struct tagBITMAPINFOOS2_1X_HEADER {
  52. DWORD biSize;
  53. WORD biWidth;
  54. WORD biHeight;
  55. WORD biPlanes;
  56. WORD biBitCount;
  57. } BITMAPINFOOS2_1X_HEADER, *PBITMAPINFOOS2_1X_HEADER;
  58. typedef struct tagBITMAPFILEHEADER {
  59. WORD bfType;
  60. DWORD bfSize;
  61. WORD bfReserved1;
  62. WORD bfReserved2;
  63. DWORD bfOffBits;
  64. } BITMAPFILEHEADER, *PBITMAPFILEHEADER;
  65. #ifdef _WIN32
  66. #pragma pack(pop)
  67. #else
  68. #pragma pack()
  69. #endif
  70. // ==========================================================
  71. // Plugin Interface
  72. // ==========================================================
  73. static int s_format_id;
  74. // ==========================================================
  75. // Internal functions
  76. // ==========================================================
  77. #ifdef FREEIMAGE_BIGENDIAN
  78. static void
  79. SwapInfoHeader(BITMAPINFOHEADER *header) {
  80. SwapLong(&header->biSize);
  81. SwapLong((DWORD *)&header->biWidth);
  82. SwapLong((DWORD *)&header->biHeight);
  83. SwapShort(&header->biPlanes);
  84. SwapShort(&header->biBitCount);
  85. SwapLong(&header->biCompression);
  86. SwapLong(&header->biSizeImage);
  87. SwapLong((DWORD *)&header->biXPelsPerMeter);
  88. SwapLong((DWORD *)&header->biYPelsPerMeter);
  89. SwapLong(&header->biClrUsed);
  90. SwapLong(&header->biClrImportant);
  91. }
  92. static void
  93. SwapCoreHeader(BITMAPCOREHEADER *header) {
  94. SwapLong(&header->bcSize);
  95. SwapShort(&header->bcWidth);
  96. SwapShort(&header->bcHeight);
  97. SwapShort(&header->bcPlanes);
  98. SwapShort(&header->bcBitCnt);
  99. }
  100. static void
  101. SwapOS21XHeader(BITMAPINFOOS2_1X_HEADER *header) {
  102. SwapLong(&header->biSize);
  103. SwapShort(&header->biWidth);
  104. SwapShort(&header->biHeight);
  105. SwapShort(&header->biPlanes);
  106. SwapShort(&header->biBitCount);
  107. }
  108. static void
  109. SwapFileHeader(BITMAPFILEHEADER *header) {
  110. SwapShort(&header->bfType);
  111. SwapLong(&header->bfSize);
  112. SwapShort(&header->bfReserved1);
  113. SwapShort(&header->bfReserved2);
  114. SwapLong(&header->bfOffBits);
  115. }
  116. #endif
  117. // --------------------------------------------------------------------------
  118. /**
  119. Load uncompressed image pixels for 1-, 4-, 8-, 16-, 24- and 32-bit dib
  120. @param io FreeImage IO
  121. @param handle FreeImage IO handle
  122. @param dib Image to be loaded
  123. @param height Image height
  124. @param pitch Image pitch
  125. @param bit_count Image bit-depth (1-, 4-, 8-, 16-, 24- or 32-bit)
  126. @return Returns TRUE if successful, returns FALSE otherwise
  127. */
  128. static BOOL
  129. LoadPixelData(FreeImageIO *io, fi_handle handle, FIBITMAP *dib, int height, unsigned pitch, unsigned bit_count) {
  130. unsigned count = 0;
  131. // Load pixel data
  132. // NB: height can be < 0 for BMP data
  133. if (height > 0) {
  134. count = io->read_proc((void *)FreeImage_GetBits(dib), height * pitch, 1, handle);
  135. if(count != 1) {
  136. return FALSE;
  137. }
  138. } else {
  139. int positiveHeight = abs(height);
  140. for (int c = 0; c < positiveHeight; ++c) {
  141. count = io->read_proc((void *)FreeImage_GetScanLine(dib, positiveHeight - c - 1), pitch, 1, handle);
  142. if(count != 1) {
  143. return FALSE;
  144. }
  145. }
  146. }
  147. // swap as needed
  148. #ifdef FREEIMAGE_BIGENDIAN
  149. if (bit_count == 16) {
  150. for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
  151. WORD *pixel = (WORD *)FreeImage_GetScanLine(dib, y);
  152. for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
  153. SwapShort(pixel);
  154. pixel++;
  155. }
  156. }
  157. }
  158. #endif
  159. #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
  160. if (bit_count == 24 || bit_count == 32) {
  161. for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
  162. BYTE *pixel = FreeImage_GetScanLine(dib, y);
  163. for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
  164. INPLACESWAP(pixel[0], pixel[2]);
  165. pixel += (bit_count >> 3);
  166. }
  167. }
  168. }
  169. #endif
  170. return TRUE;
  171. }
  172. /**
  173. Load image pixels for 4-bit RLE compressed dib
  174. @param io FreeImage IO
  175. @param handle FreeImage IO handle
  176. @param width Image width
  177. @param height Image height
  178. @param dib Image to be loaded
  179. @return Returns TRUE if successful, returns FALSE otherwise
  180. */
  181. static BOOL
  182. LoadPixelDataRLE4(FreeImageIO *io, fi_handle handle, int width, int height, FIBITMAP *dib) {
  183. int status_byte = 0;
  184. BYTE second_byte = 0;
  185. int bits = 0;
  186. BYTE *pixels = NULL; // temporary 8-bit buffer
  187. try {
  188. height = abs(height);
  189. pixels = (BYTE*)malloc(width * height * sizeof(BYTE));
  190. if(!pixels) throw(1);
  191. memset(pixels, 0, width * height * sizeof(BYTE));
  192. BYTE *q = pixels;
  193. BYTE *end = pixels + height * width;
  194. for (int scanline = 0; scanline < height; ) {
  195. if (q < pixels || q >= end) {
  196. break;
  197. }
  198. if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
  199. throw(1);
  200. }
  201. if (status_byte != 0) {
  202. status_byte = (int)MIN((size_t)status_byte, (size_t)(end - q));
  203. // Encoded mode
  204. if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
  205. throw(1);
  206. }
  207. for (int i = 0; i < status_byte; i++) {
  208. *q++=(BYTE)((i & 0x01) ? (second_byte & 0x0f) : ((second_byte >> 4) & 0x0f));
  209. }
  210. bits += status_byte;
  211. }
  212. else {
  213. // Escape mode
  214. if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
  215. throw(1);
  216. }
  217. switch (status_byte) {
  218. case RLE_ENDOFLINE:
  219. {
  220. // End of line
  221. bits = 0;
  222. scanline++;
  223. q = pixels + scanline*width;
  224. }
  225. break;
  226. case RLE_ENDOFBITMAP:
  227. // End of bitmap
  228. q = end;
  229. break;
  230. case RLE_DELTA:
  231. {
  232. // read the delta values
  233. BYTE delta_x = 0;
  234. BYTE delta_y = 0;
  235. if(io->read_proc(&delta_x, sizeof(BYTE), 1, handle) != 1) {
  236. throw(1);
  237. }
  238. if(io->read_proc(&delta_y, sizeof(BYTE), 1, handle) != 1) {
  239. throw(1);
  240. }
  241. // apply them
  242. bits += delta_x;
  243. scanline += delta_y;
  244. q = pixels + scanline*width+bits;
  245. }
  246. break;
  247. default:
  248. {
  249. // Absolute mode
  250. status_byte = (int)MIN((size_t)status_byte, (size_t)(end - q));
  251. for (int i = 0; i < status_byte; i++) {
  252. if ((i & 0x01) == 0) {
  253. if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
  254. throw(1);
  255. }
  256. }
  257. *q++=(BYTE)((i & 0x01) ? (second_byte & 0x0f) : ((second_byte >> 4) & 0x0f));
  258. }
  259. bits += status_byte;
  260. // Read pad byte
  261. if (((status_byte & 0x03) == 1) || ((status_byte & 0x03) == 2)) {
  262. BYTE padding = 0;
  263. if(io->read_proc(&padding, sizeof(BYTE), 1, handle) != 1) {
  264. throw(1);
  265. }
  266. }
  267. }
  268. break;
  269. }
  270. }
  271. }
  272. {
  273. // Convert to 4-bit
  274. for(int y = 0; y < height; y++) {
  275. const BYTE *src = (BYTE*)pixels + y * width;
  276. BYTE *dst = FreeImage_GetScanLine(dib, y);
  277. BOOL hinibble = TRUE;
  278. for (int cols = 0; cols < width; cols++){
  279. if (hinibble) {
  280. dst[cols >> 1] = (src[cols] << 4);
  281. } else {
  282. dst[cols >> 1] |= src[cols];
  283. }
  284. hinibble = !hinibble;
  285. }
  286. }
  287. }
  288. free(pixels);
  289. return TRUE;
  290. } catch(int) {
  291. if(pixels) free(pixels);
  292. return FALSE;
  293. }
  294. }
  295. /**
  296. Load image pixels for 8-bit RLE compressed dib
  297. @param io FreeImage IO
  298. @param handle FreeImage IO handle
  299. @param width Image width
  300. @param height Image height
  301. @param dib Image to be loaded
  302. @return Returns TRUE if successful, returns FALSE otherwise
  303. */
  304. static BOOL
  305. LoadPixelDataRLE8(FreeImageIO *io, fi_handle handle, int width, int height, FIBITMAP *dib) {
  306. BYTE status_byte = 0;
  307. BYTE second_byte = 0;
  308. int scanline = 0;
  309. int bits = 0;
  310. for (;;) {
  311. if( io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
  312. return FALSE;
  313. }
  314. switch (status_byte) {
  315. case RLE_COMMAND :
  316. if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
  317. return FALSE;
  318. }
  319. switch (status_byte) {
  320. case RLE_ENDOFLINE :
  321. bits = 0;
  322. scanline++;
  323. break;
  324. case RLE_ENDOFBITMAP :
  325. return TRUE;
  326. case RLE_DELTA :
  327. {
  328. // read the delta values
  329. BYTE delta_x = 0;
  330. BYTE delta_y = 0;
  331. if(io->read_proc(&delta_x, sizeof(BYTE), 1, handle) != 1) {
  332. return FALSE;
  333. }
  334. if(io->read_proc(&delta_y, sizeof(BYTE), 1, handle) != 1) {
  335. return FALSE;
  336. }
  337. // apply them
  338. bits += delta_x;
  339. scanline += delta_y;
  340. break;
  341. }
  342. default :
  343. {
  344. if(scanline >= abs(height)) {
  345. return TRUE;
  346. }
  347. int count = MIN((int)status_byte, width - bits);
  348. BYTE *sline = FreeImage_GetScanLine(dib, scanline);
  349. if(io->read_proc((void *)(sline + bits), sizeof(BYTE) * count, 1, handle) != 1) {
  350. return FALSE;
  351. }
  352. // align run length to even number of bytes
  353. if ((status_byte & 1) == 1) {
  354. if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
  355. return FALSE;
  356. }
  357. }
  358. bits += status_byte;
  359. break;
  360. }
  361. }
  362. break;
  363. default :
  364. {
  365. if(scanline >= abs(height)) {
  366. return TRUE;
  367. }
  368. int count = MIN((int)status_byte, width - bits);
  369. BYTE *sline = FreeImage_GetScanLine(dib, scanline);
  370. if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
  371. return FALSE;
  372. }
  373. for (int i = 0; i < count; i++) {
  374. *(sline + bits) = second_byte;
  375. bits++;
  376. }
  377. break;
  378. }
  379. }
  380. }
  381. }
  382. // --------------------------------------------------------------------------
  383. static FIBITMAP *
  384. LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) {
  385. FIBITMAP *dib = NULL;
  386. try {
  387. BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
  388. // load the info header
  389. BITMAPINFOHEADER bih;
  390. io->read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle);
  391. #ifdef FREEIMAGE_BIGENDIAN
  392. SwapInfoHeader(&bih);
  393. #endif
  394. // keep some general information about the bitmap
  395. unsigned used_colors = bih.biClrUsed;
  396. int width = bih.biWidth;
  397. int height = bih.biHeight; // WARNING: height can be < 0 => check each call using 'height' as a parameter
  398. unsigned bit_count = bih.biBitCount;
  399. unsigned compression = bih.biCompression;
  400. unsigned pitch = CalculatePitch(CalculateLine(width, bit_count));
  401. switch (bit_count) {
  402. case 1 :
  403. case 4 :
  404. case 8 :
  405. {
  406. if ((used_colors == 0) || (used_colors > CalculateUsedPaletteEntries(bit_count)))
  407. used_colors = CalculateUsedPaletteEntries(bit_count);
  408. // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette
  409. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count);
  410. if (dib == NULL) {
  411. throw FI_MSG_ERROR_DIB_MEMORY;
  412. }
  413. // set resolution information
  414. FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
  415. FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
  416. // load the palette
  417. io->read_proc(FreeImage_GetPalette(dib), used_colors * sizeof(RGBQUAD), 1, handle);
  418. #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
  419. RGBQUAD *pal = FreeImage_GetPalette(dib);
  420. for(int i = 0; i < used_colors; i++) {
  421. INPLACESWAP(pal[i].rgbRed, pal[i].rgbBlue);
  422. }
  423. #endif
  424. if(header_only) {
  425. // header only mode
  426. return dib;
  427. }
  428. // seek to the actual pixel data.
  429. // this is needed because sometimes the palette is larger than the entries it contains predicts
  430. if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * sizeof(RGBQUAD))))
  431. io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
  432. // read the pixel data
  433. switch (compression) {
  434. case BI_RGB :
  435. if( LoadPixelData(io, handle, dib, height, pitch, bit_count) ) {
  436. return dib;
  437. } else {
  438. throw "Error encountered while decoding BMP data";
  439. }
  440. break;
  441. case BI_RLE4 :
  442. if( LoadPixelDataRLE4(io, handle, width, height, dib) ) {
  443. return dib;
  444. } else {
  445. throw "Error encountered while decoding RLE4 BMP data";
  446. }
  447. break;
  448. case BI_RLE8 :
  449. if( LoadPixelDataRLE8(io, handle, width, height, dib) ) {
  450. return dib;
  451. } else {
  452. throw "Error encountered while decoding RLE8 BMP data";
  453. }
  454. break;
  455. default :
  456. throw FI_MSG_ERROR_UNSUPPORTED_COMPRESSION;
  457. }
  458. }
  459. break; // 1-, 4-, 8-bit
  460. case 16 :
  461. {
  462. if (bih.biCompression == BI_BITFIELDS) {
  463. DWORD bitfields[3];
  464. io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle);
  465. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
  466. } else {
  467. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
  468. }
  469. if (dib == NULL) {
  470. throw FI_MSG_ERROR_DIB_MEMORY;
  471. }
  472. // set resolution information
  473. FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
  474. FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
  475. if(header_only) {
  476. // header only mode
  477. return dib;
  478. }
  479. // load pixel data and swap as needed if OS is Big Endian
  480. if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))) {
  481. // seek to the actual pixel data
  482. io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
  483. }
  484. LoadPixelData(io, handle, dib, height, pitch, bit_count);
  485. return dib;
  486. }
  487. break; // 16-bit
  488. case 24 :
  489. case 32 :
  490. {
  491. if (bih.biCompression == BI_BITFIELDS) {
  492. DWORD bitfields[3];
  493. io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle);
  494. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
  495. } else {
  496. if( bit_count == 32 ) {
  497. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  498. } else {
  499. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  500. }
  501. }
  502. if (dib == NULL) {
  503. throw FI_MSG_ERROR_DIB_MEMORY;
  504. }
  505. // set resolution information
  506. FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
  507. FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
  508. if(header_only) {
  509. // header only mode
  510. return dib;
  511. }
  512. // Skip over the optional palette
  513. // A 24 or 32 bit DIB may contain a palette for faster color reduction
  514. if (FreeImage_GetColorsUsed(dib) > 0) {
  515. io->seek_proc(handle, FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD), SEEK_CUR);
  516. } else if ((bih.biCompression != BI_BITFIELDS) && (bitmap_bits_offset > sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))) {
  517. io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
  518. }
  519. // read in the bitmap bits
  520. // load pixel data and swap as needed if OS is Big Endian
  521. LoadPixelData(io, handle, dib, height, pitch, bit_count);
  522. // check if the bitmap contains transparency, if so enable it in the header
  523. FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));
  524. return dib;
  525. }
  526. break; // 24-, 32-bit
  527. }
  528. } catch(const char *message) {
  529. if(dib) {
  530. FreeImage_Unload(dib);
  531. }
  532. if(message) {
  533. FreeImage_OutputMessageProc(s_format_id, message);
  534. }
  535. }
  536. return NULL;
  537. }
  538. // --------------------------------------------------------------------------
  539. static FIBITMAP *
  540. LoadOS22XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) {
  541. FIBITMAP *dib = NULL;
  542. try {
  543. BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
  544. // load the info header
  545. BITMAPINFOHEADER bih;
  546. io->read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle);
  547. #ifdef FREEIMAGE_BIGENDIAN
  548. SwapInfoHeader(&bih);
  549. #endif
  550. // keep some general information about the bitmap
  551. unsigned used_colors = bih.biClrUsed;
  552. int width = bih.biWidth;
  553. int height = bih.biHeight; // WARNING: height can be < 0 => check each read_proc using 'height' as a parameter
  554. unsigned bit_count = bih.biBitCount;
  555. unsigned compression = bih.biCompression;
  556. unsigned pitch = CalculatePitch(CalculateLine(width, bit_count));
  557. switch (bit_count) {
  558. case 1 :
  559. case 4 :
  560. case 8 :
  561. {
  562. if ((used_colors == 0) || (used_colors > CalculateUsedPaletteEntries(bit_count)))
  563. used_colors = CalculateUsedPaletteEntries(bit_count);
  564. // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette
  565. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count);
  566. if (dib == NULL) {
  567. throw FI_MSG_ERROR_DIB_MEMORY;
  568. }
  569. // set resolution information
  570. FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
  571. FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
  572. // load the palette
  573. // note that it may contain RGB or RGBA values : we will calculate this
  574. unsigned pal_size = (bitmap_bits_offset - sizeof(BITMAPFILEHEADER) - bih.biSize) / used_colors;
  575. io->seek_proc(handle, sizeof(BITMAPFILEHEADER) + bih.biSize, SEEK_SET);
  576. RGBQUAD *pal = FreeImage_GetPalette(dib);
  577. if(pal_size == 4) {
  578. for (unsigned count = 0; count < used_colors; count++) {
  579. FILE_BGRA bgra;
  580. io->read_proc(&bgra, sizeof(FILE_BGRA), 1, handle);
  581. pal[count].rgbRed = bgra.r;
  582. pal[count].rgbGreen = bgra.g;
  583. pal[count].rgbBlue = bgra.b;
  584. }
  585. } else if(pal_size == 3) {
  586. for (unsigned count = 0; count < used_colors; count++) {
  587. FILE_BGR bgr;
  588. io->read_proc(&bgr, sizeof(FILE_BGR), 1, handle);
  589. pal[count].rgbRed = bgr.r;
  590. pal[count].rgbGreen = bgr.g;
  591. pal[count].rgbBlue = bgr.b;
  592. }
  593. }
  594. if(header_only) {
  595. // header only mode
  596. return dib;
  597. }
  598. // seek to the actual pixel data.
  599. // this is needed because sometimes the palette is larger than the entries it contains predicts
  600. if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3)))
  601. io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
  602. // read the pixel data
  603. switch (compression) {
  604. case BI_RGB :
  605. // load pixel data
  606. LoadPixelData(io, handle, dib, height, pitch, bit_count);
  607. return dib;
  608. case BI_RLE4 :
  609. if( LoadPixelDataRLE4(io, handle, width, height, dib) ) {
  610. return dib;
  611. } else {
  612. throw "Error encountered while decoding RLE4 BMP data";
  613. }
  614. break;
  615. case BI_RLE8 :
  616. if( LoadPixelDataRLE8(io, handle, width, height, dib) ) {
  617. return dib;
  618. } else {
  619. throw "Error encountered while decoding RLE8 BMP data";
  620. }
  621. break;
  622. default :
  623. throw FI_MSG_ERROR_UNSUPPORTED_COMPRESSION;
  624. }
  625. }
  626. case 16 :
  627. {
  628. if (bih.biCompression == 3) {
  629. DWORD bitfields[3];
  630. io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle);
  631. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
  632. } else {
  633. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
  634. }
  635. if (dib == NULL) {
  636. throw FI_MSG_ERROR_DIB_MEMORY;
  637. }
  638. // set resolution information
  639. FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
  640. FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
  641. if(header_only) {
  642. // header only mode
  643. return dib;
  644. }
  645. if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) {
  646. io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
  647. }
  648. // load pixel data and swap as needed if OS is Big Endian
  649. LoadPixelData(io, handle, dib, height, pitch, bit_count);
  650. return dib;
  651. }
  652. case 24 :
  653. case 32 :
  654. {
  655. if( bit_count == 32 ) {
  656. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  657. } else {
  658. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  659. }
  660. if (dib == NULL) {
  661. throw FI_MSG_ERROR_DIB_MEMORY;
  662. }
  663. // set resolution information
  664. FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
  665. FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
  666. if(header_only) {
  667. // header only mode
  668. return dib;
  669. }
  670. // Skip over the optional palette
  671. // A 24 or 32 bit DIB may contain a palette for faster color reduction
  672. if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3)))
  673. io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
  674. // read in the bitmap bits
  675. // load pixel data and swap as needed if OS is Big Endian
  676. LoadPixelData(io, handle, dib, height, pitch, bit_count);
  677. // check if the bitmap contains transparency, if so enable it in the header
  678. FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));
  679. return dib;
  680. }
  681. }
  682. } catch(const char *message) {
  683. if(dib)
  684. FreeImage_Unload(dib);
  685. FreeImage_OutputMessageProc(s_format_id, message);
  686. }
  687. return NULL;
  688. }
  689. // --------------------------------------------------------------------------
  690. static FIBITMAP *
  691. LoadOS21XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) {
  692. FIBITMAP *dib = NULL;
  693. try {
  694. BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
  695. BITMAPINFOOS2_1X_HEADER bios2_1x;
  696. io->read_proc(&bios2_1x, sizeof(BITMAPINFOOS2_1X_HEADER), 1, handle);
  697. #ifdef FREEIMAGE_BIGENDIAN
  698. SwapOS21XHeader(&bios2_1x);
  699. #endif
  700. // keep some general information about the bitmap
  701. unsigned used_colors = 0;
  702. unsigned width = bios2_1x.biWidth;
  703. unsigned height = bios2_1x.biHeight; // WARNING: height can be < 0 => check each read_proc using 'height' as a parameter
  704. unsigned bit_count = bios2_1x.biBitCount;
  705. unsigned pitch = CalculatePitch(CalculateLine(width, bit_count));
  706. switch (bit_count) {
  707. case 1 :
  708. case 4 :
  709. case 8 :
  710. {
  711. used_colors = CalculateUsedPaletteEntries(bit_count);
  712. // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette
  713. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count);
  714. if (dib == NULL) {
  715. throw FI_MSG_ERROR_DIB_MEMORY;
  716. }
  717. // set resolution information to default values (72 dpi in english units)
  718. FreeImage_SetDotsPerMeterX(dib, 2835);
  719. FreeImage_SetDotsPerMeterY(dib, 2835);
  720. // load the palette
  721. RGBQUAD *pal = FreeImage_GetPalette(dib);
  722. for (unsigned count = 0; count < used_colors; count++) {
  723. FILE_BGR bgr;
  724. io->read_proc(&bgr, sizeof(FILE_BGR), 1, handle);
  725. pal[count].rgbRed = bgr.r;
  726. pal[count].rgbGreen = bgr.g;
  727. pal[count].rgbBlue = bgr.b;
  728. }
  729. if(header_only) {
  730. // header only mode
  731. return dib;
  732. }
  733. // Skip over the optional palette
  734. // A 24 or 32 bit DIB may contain a palette for faster color reduction
  735. io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
  736. // read the pixel data
  737. // load pixel data
  738. LoadPixelData(io, handle, dib, height, pitch, bit_count);
  739. return dib;
  740. }
  741. case 16 :
  742. {
  743. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
  744. if (dib == NULL) {
  745. throw FI_MSG_ERROR_DIB_MEMORY;
  746. }
  747. // set resolution information to default values (72 dpi in english units)
  748. FreeImage_SetDotsPerMeterX(dib, 2835);
  749. FreeImage_SetDotsPerMeterY(dib, 2835);
  750. if(header_only) {
  751. // header only mode
  752. return dib;
  753. }
  754. // load pixel data and swap as needed if OS is Big Endian
  755. LoadPixelData(io, handle, dib, height, pitch, bit_count);
  756. return dib;
  757. }
  758. case 24 :
  759. case 32 :
  760. {
  761. if( bit_count == 32 ) {
  762. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  763. } else {
  764. dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  765. }
  766. if (dib == NULL) {
  767. throw FI_MSG_ERROR_DIB_MEMORY;
  768. }
  769. // set resolution information to default values (72 dpi in english units)
  770. FreeImage_SetDotsPerMeterX(dib, 2835);
  771. FreeImage_SetDotsPerMeterY(dib, 2835);
  772. if(header_only) {
  773. // header only mode
  774. return dib;
  775. }
  776. // Skip over the optional palette
  777. // A 24 or 32 bit DIB may contain a palette for faster color reduction
  778. // load pixel data and swap as needed if OS is Big Endian
  779. LoadPixelData(io, handle, dib, height, pitch, bit_count);
  780. // check if the bitmap contains transparency, if so enable it in the header
  781. FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));
  782. return dib;
  783. }
  784. }
  785. } catch(const char *message) {
  786. if(dib)
  787. FreeImage_Unload(dib);
  788. FreeImage_OutputMessageProc(s_format_id, message);
  789. }
  790. return NULL;
  791. }
  792. // ==========================================================
  793. // Plugin Implementation
  794. // ==========================================================
  795. static const char * DLL_CALLCONV
  796. Format() {
  797. return "BMP";
  798. }
  799. static const char * DLL_CALLCONV
  800. Description() {
  801. return "Windows or OS/2 Bitmap";
  802. }
  803. static const char * DLL_CALLCONV
  804. Extension() {
  805. return "bmp";
  806. }
  807. static const char * DLL_CALLCONV
  808. RegExpr() {
  809. return "^BM";
  810. }
  811. static const char * DLL_CALLCONV
  812. MimeType() {
  813. return "image/bmp";
  814. }
  815. static BOOL DLL_CALLCONV
  816. Validate(FreeImageIO *io, fi_handle handle) {
  817. BYTE bmp_signature1[] = { 0x42, 0x4D };
  818. BYTE bmp_signature2[] = { 0x42, 0x41 };
  819. BYTE signature[2] = { 0, 0 };
  820. io->read_proc(signature, 1, sizeof(bmp_signature1), handle);
  821. if (memcmp(bmp_signature1, signature, sizeof(bmp_signature1)) == 0)
  822. return TRUE;
  823. if (memcmp(bmp_signature2, signature, sizeof(bmp_signature2)) == 0)
  824. return TRUE;
  825. return FALSE;
  826. }
  827. static BOOL DLL_CALLCONV
  828. SupportsExportDepth(int depth) {
  829. return (
  830. (depth == 1) ||
  831. (depth == 4) ||
  832. (depth == 8) ||
  833. (depth == 16) ||
  834. (depth == 24) ||
  835. (depth == 32)
  836. );
  837. }
  838. static BOOL DLL_CALLCONV
  839. SupportsExportType(FREE_IMAGE_TYPE type) {
  840. return (type == FIT_BITMAP) ? TRUE : FALSE;
  841. }
  842. static BOOL DLL_CALLCONV
  843. SupportsNoPixels() {
  844. return TRUE;
  845. }
  846. // ----------------------------------------------------------
  847. static FIBITMAP * DLL_CALLCONV
  848. Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
  849. if (handle != NULL) {
  850. BITMAPFILEHEADER bitmapfileheader;
  851. DWORD type = 0;
  852. // we use this offset value to make seemingly absolute seeks relative in the file
  853. long offset_in_file = io->tell_proc(handle);
  854. // read the fileheader
  855. io->read_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle);
  856. #ifdef FREEIMAGE_BIGENDIAN
  857. SwapFileHeader(&bitmapfileheader);
  858. #endif
  859. // check the signature
  860. if((bitmapfileheader.bfType != 0x4D42) && (bitmapfileheader.bfType != 0x4142)) {
  861. FreeImage_OutputMessageProc(s_format_id, FI_MSG_ERROR_MAGIC_NUMBER);
  862. return NULL;
  863. }
  864. // read the first byte of the infoheader
  865. io->read_proc(&type, sizeof(DWORD), 1, handle);
  866. io->seek_proc(handle, 0 - (long)sizeof(DWORD), SEEK_CUR);
  867. #ifdef FREEIMAGE_BIGENDIAN
  868. SwapLong(&type);
  869. #endif
  870. // call the appropriate load function for the found bitmap type
  871. switch(type) {
  872. case 12:
  873. // OS/2 and also all Windows versions since Windows 3.0
  874. return LoadOS21XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits);
  875. case 64:
  876. // OS/2
  877. return LoadOS22XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits);
  878. case 40:
  879. // BITMAPINFOHEADER - all Windows versions since Windows 3.0
  880. return LoadWindowsBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits);
  881. case 52:
  882. // BITMAPV2INFOHEADER (undocumented)
  883. break;
  884. case 56:
  885. // BITMAPV3INFOHEADER (undocumented)
  886. break;
  887. case 108:
  888. // BITMAPV4HEADER - all Windows versions since Windows 95/NT4 (not supported)
  889. break;
  890. case 124:
  891. // BITMAPV5HEADER - Windows 98/2000 and newer (not supported)
  892. break;
  893. default:
  894. break;
  895. }
  896. FreeImage_OutputMessageProc(s_format_id, "unknown bmp subtype with id %d", type);
  897. }
  898. return NULL;
  899. }
  900. // ----------------------------------------------------------
  901. /**
  902. Encode a 8-bit source buffer into a 8-bit target buffer using a RLE compression algorithm.
  903. The size of the target buffer must be equal to the size of the source buffer.
  904. On return, the function will return the real size of the target buffer, which should be less that or equal to the source buffer size.
  905. @param target 8-bit Target buffer
  906. @param source 8-bit Source buffer
  907. @param size Source/Target input buffer size
  908. @return Returns the target buffer size
  909. */
  910. static int
  911. RLEEncodeLine(BYTE *target, BYTE *source, int size) {
  912. BYTE buffer[256];
  913. int buffer_size = 0;
  914. int target_pos = 0;
  915. for (int i = 0; i < size; ++i) {
  916. if ((i < size - 1) && (source[i] == source[i + 1])) {
  917. // find a solid block of same bytes
  918. int j = i + 1;
  919. int jmax = 254 + i;
  920. while ((j < size - 1) && (j < jmax) && (source[j] == source[j + 1]))
  921. ++j;
  922. // if the block is larger than 3 bytes, use it
  923. // else put the data into the larger pool
  924. if (((j - i) + 1) > 3) {
  925. // don't forget to write what we already have in the buffer
  926. switch(buffer_size) {
  927. case 0 :
  928. break;
  929. case RLE_DELTA :
  930. target[target_pos++] = 1;
  931. target[target_pos++] = buffer[0];
  932. target[target_pos++] = 1;
  933. target[target_pos++] = buffer[1];
  934. break;
  935. case RLE_ENDOFBITMAP :
  936. target[target_pos++] = (BYTE)buffer_size;
  937. target[target_pos++] = buffer[0];
  938. break;
  939. default :
  940. target[target_pos++] = RLE_COMMAND;
  941. target[target_pos++] = (BYTE)buffer_size;
  942. memcpy(target + target_pos, buffer, buffer_size);
  943. // prepare for next run
  944. target_pos += buffer_size;
  945. if ((buffer_size & 1) == 1)
  946. target_pos++;
  947. break;
  948. }
  949. // write the continuous data
  950. target[target_pos++] = (BYTE)((j - i) + 1);
  951. target[target_pos++] = source[i];
  952. buffer_size = 0;
  953. } else {
  954. for (int k = 0; k < (j - i) + 1; ++k) {
  955. buffer[buffer_size++] = source[i + k];
  956. if (buffer_size == 254) {
  957. // write what we have
  958. target[target_pos++] = RLE_COMMAND;
  959. target[target_pos++] = (BYTE)buffer_size;
  960. memcpy(target + target_pos, buffer, buffer_size);
  961. // prepare for next run
  962. target_pos += buffer_size;
  963. buffer_size = 0;
  964. }
  965. }
  966. }
  967. i = j;
  968. } else {
  969. buffer[buffer_size++] = source[i];
  970. }
  971. // write the buffer if it's full
  972. if (buffer_size == 254) {
  973. target[target_pos++] = RLE_COMMAND;
  974. target[target_pos++] = (BYTE)buffer_size;
  975. memcpy(target + target_pos, buffer, buffer_size);
  976. // prepare for next run
  977. target_pos += buffer_size;
  978. buffer_size = 0;
  979. }
  980. }
  981. // write the last bytes
  982. switch(buffer_size) {
  983. case 0 :
  984. break;
  985. case RLE_DELTA :
  986. target[target_pos++] = 1;
  987. target[target_pos++] = buffer[0];
  988. target[target_pos++] = 1;
  989. target[target_pos++] = buffer[1];
  990. break;
  991. case RLE_ENDOFBITMAP :
  992. target[target_pos++] = (BYTE)buffer_size;
  993. target[target_pos++] = buffer[0];
  994. break;
  995. default :
  996. target[target_pos++] = RLE_COMMAND;
  997. target[target_pos++] = (BYTE)buffer_size;
  998. memcpy(target + target_pos, buffer, buffer_size);
  999. // prepare for next run
  1000. target_pos += buffer_size;
  1001. if ((buffer_size & 1) == 1)
  1002. target_pos++;
  1003. break;
  1004. }
  1005. // write the END_OF_LINE marker
  1006. target[target_pos++] = RLE_COMMAND;
  1007. target[target_pos++] = RLE_ENDOFLINE;
  1008. // return the written size
  1009. return target_pos;
  1010. }
  1011. static BOOL DLL_CALLCONV
  1012. Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
  1013. if ((dib != NULL) && (handle != NULL)) {
  1014. // write the file header
  1015. BITMAPFILEHEADER bitmapfileheader;
  1016. bitmapfileheader.bfType = 0x4D42;
  1017. bitmapfileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD);
  1018. bitmapfileheader.bfSize = bitmapfileheader.bfOffBits + FreeImage_GetHeight(dib) * FreeImage_GetPitch(dib);
  1019. bitmapfileheader.bfReserved1 = 0;
  1020. bitmapfileheader.bfReserved2 = 0;
  1021. // take care of the bit fields data of any
  1022. bool bit_fields = (FreeImage_GetBPP(dib) == 16);
  1023. if (bit_fields) {
  1024. bitmapfileheader.bfSize += 3 * sizeof(DWORD);
  1025. bitmapfileheader.bfOffBits += 3 * sizeof(DWORD);
  1026. }
  1027. #ifdef FREEIMAGE_BIGENDIAN
  1028. SwapFileHeader(&bitmapfileheader);
  1029. #endif
  1030. if (io->write_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle) != 1)
  1031. return FALSE;
  1032. // update the bitmap info header
  1033. BITMAPINFOHEADER bih;
  1034. memcpy(&bih, FreeImage_GetInfoHeader(dib), sizeof(BITMAPINFOHEADER));
  1035. if (bit_fields)
  1036. bih.biCompression = BI_BITFIELDS;
  1037. else if ((bih.biBitCount == 8) && (flags & BMP_SAVE_RLE))
  1038. bih.biCompression = BI_RLE8;
  1039. else
  1040. bih.biCompression = BI_RGB;
  1041. // write the bitmap info header
  1042. #ifdef FREEIMAGE_BIGENDIAN
  1043. SwapInfoHeader(&bih);
  1044. #endif
  1045. if (io->write_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle) != 1)
  1046. return FALSE;
  1047. // write the bit fields when we are dealing with a 16 bit BMP
  1048. if (bit_fields) {
  1049. DWORD d;
  1050. d = FreeImage_GetRedMask(dib);
  1051. if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1)
  1052. return FALSE;
  1053. d = FreeImage_GetGreenMask(dib);
  1054. if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1)
  1055. return FALSE;
  1056. d = FreeImage_GetBlueMask(dib);
  1057. if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1)
  1058. return FALSE;
  1059. }
  1060. // write the palette
  1061. if (FreeImage_GetPalette(dib) != NULL) {
  1062. RGBQUAD *pal = FreeImage_GetPalette(dib);
  1063. FILE_BGRA bgra;
  1064. for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++ ) {
  1065. bgra.b = pal[i].rgbBlue;
  1066. bgra.g = pal[i].rgbGreen;
  1067. bgra.r = pal[i].rgbRed;
  1068. bgra.a = pal[i].rgbReserved;
  1069. if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1)
  1070. return FALSE;
  1071. }
  1072. }
  1073. // write the bitmap data... if RLE compression is enable, use it
  1074. unsigned bpp = FreeImage_GetBPP(dib);
  1075. if ((bpp == 8) && (flags & BMP_SAVE_RLE)) {
  1076. BYTE *buffer = (BYTE*)malloc(FreeImage_GetPitch(dib) * 2 * sizeof(BYTE));
  1077. for (DWORD i = 0; i < FreeImage_GetHeight(dib); ++i) {
  1078. int size = RLEEncodeLine(buffer, FreeImage_GetScanLine(dib, i), FreeImage_GetLine(dib));
  1079. if (io->write_proc(buffer, size, 1, handle) != 1) {
  1080. free(buffer);
  1081. return FALSE;
  1082. }
  1083. }
  1084. buffer[0] = RLE_COMMAND;
  1085. buffer[1] = RLE_ENDOFBITMAP;
  1086. if (io->write_proc(buffer, 2, 1, handle) != 1) {
  1087. free(buffer);
  1088. return FALSE;
  1089. }
  1090. free(buffer);
  1091. #ifdef FREEIMAGE_BIGENDIAN
  1092. } else if (bpp == 16) {
  1093. int padding = FreeImage_GetPitch(dib) - FreeImage_GetWidth(dib) * sizeof(WORD);
  1094. WORD pad = 0;
  1095. WORD pixel;
  1096. for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
  1097. BYTE *line = FreeImage_GetScanLine(dib, y);
  1098. for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
  1099. pixel = ((WORD *)line)[x];
  1100. SwapShort(&pixel);
  1101. if (io->write_proc(&pixel, sizeof(WORD), 1, handle) != 1)
  1102. return FALSE;
  1103. }
  1104. if(padding != 0) {
  1105. if(io->write_proc(&pad, padding, 1, handle) != 1) {
  1106. return FALSE;
  1107. }
  1108. }
  1109. }
  1110. #endif
  1111. #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
  1112. } else if (bpp == 24) {
  1113. int padding = FreeImage_GetPitch(dib) - FreeImage_GetWidth(dib) * sizeof(FILE_BGR);
  1114. DWORD pad = 0;
  1115. FILE_BGR bgr;
  1116. for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
  1117. BYTE *line = FreeImage_GetScanLine(dib, y);
  1118. for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
  1119. RGBTRIPLE *triple = ((RGBTRIPLE *)line)+x;
  1120. bgr.b = triple->rgbtBlue;
  1121. bgr.g = triple->rgbtGreen;
  1122. bgr.r = triple->rgbtRed;
  1123. if (io->write_proc(&bgr, sizeof(FILE_BGR), 1, handle) != 1)
  1124. return FALSE;
  1125. }
  1126. if(padding != 0) {
  1127. if(io->write_proc(&pad, padding, 1, handle) != 1) {
  1128. return FALSE;
  1129. }
  1130. }
  1131. }
  1132. } else if (bpp == 32) {
  1133. FILE_BGRA bgra;
  1134. for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
  1135. BYTE *line = FreeImage_GetScanLine(dib, y);
  1136. for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
  1137. RGBQUAD *quad = ((RGBQUAD *)line)+x;
  1138. bgra.b = quad->rgbBlue;
  1139. bgra.g = quad->rgbGreen;
  1140. bgra.r = quad->rgbRed;
  1141. bgra.a = quad->rgbReserved;
  1142. if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1)
  1143. return FALSE;
  1144. }
  1145. }
  1146. #endif
  1147. } else if (io->write_proc(FreeImage_GetBits(dib), FreeImage_GetHeight(dib) * FreeImage_GetPitch(dib), 1, handle) != 1) {
  1148. return FALSE;
  1149. }
  1150. return TRUE;
  1151. } else {
  1152. return FALSE;
  1153. }
  1154. }
  1155. // ==========================================================
  1156. // Init
  1157. // ==========================================================
  1158. void DLL_CALLCONV
  1159. InitBMP(Plugin *plugin, int format_id) {
  1160. s_format_id = format_id;
  1161. plugin->format_proc = Format;
  1162. plugin->description_proc = Description;
  1163. plugin->extension_proc = Extension;
  1164. plugin->regexpr_proc = RegExpr;
  1165. plugin->open_proc = NULL;
  1166. plugin->close_proc = NULL;
  1167. plugin->pagecount_proc = NULL;
  1168. plugin->pagecapability_proc = NULL;
  1169. plugin->load_proc = Load;
  1170. plugin->save_proc = Save;
  1171. plugin->validate_proc = Validate;
  1172. plugin->mime_proc = MimeType;
  1173. plugin->supports_export_bpp_proc = SupportsExportDepth;
  1174. plugin->supports_export_type_proc = SupportsExportType;
  1175. plugin->supports_icc_profiles_proc = NULL; // not implemented yet;
  1176. plugin->supports_no_pixels_proc = SupportsNoPixels;
  1177. }