Guest User

PluginBMPRL.cpp

a guest
Feb 22nd, 2018
332
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==========================================================
  2. // BMPRL Loader and Writer
  3. //
  4. // Design and implementation by
  5. // - Djeman
  6. //
  7. // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
  8. // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
  9. // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
  10. // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
  11. // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
  12. // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
  13. // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
  14. // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
  15. // THIS DISCLAIMER.
  16. //
  17. // Use at your own risk!
  18. // ==========================================================
  19.  
  20. #include "FreeImage.h"
  21. #include "Utilities.h"
  22. #include "Quantizers.h"
  23.  
  24. // ----------------------------------------------------------
  25. //   Constants + headers
  26. // ----------------------------------------------------------
  27.  
  28. #define MAX_PALETTE_COUNT       261
  29. #define MAX_PALETTE_SIZE        251
  30. #define MAX_PALETTE_TOTAL_SIZE  (MAX_PALETTE_COUNT * MAX_PALETTE_SIZE)
  31.  
  32. static const BYTE RLE_PALETTE       = 0xFD;
  33. static const BYTE RLE_COMMAND       = 0xFE;
  34. static const BYTE RLE_DELTA         = 0xFF;
  35. static const BYTE RLE_EMPTY         = 0;
  36.  
  37. static const WORD HAVE_ALPHA_MASK   = 0x0001;
  38. static const WORD HAVE_PALETTE_16   = 0x0002;
  39.  
  40. // ----------------------------------------------------------
  41.  
  42. #ifdef _WIN32
  43. #pragma pack(push, 1)
  44. #else
  45. #pragma pack(1)
  46. #endif
  47.  
  48. typedef struct tagBITMAPRLHEADER {
  49.   WORD    bType;        //! The file type
  50.   WORD    bOptions;     //! Image format options
  51.   WORD    bWidth;
  52.   WORD    bHeight;
  53.   WORD    bClrUsed;     //! Colors used
  54.   WORD    bRLRowsUsed;  //! RL Rows used
  55. } BITMAPRLHEADER, *PBITMAPRLHEADER;
  56.  
  57. #ifdef _WIN32
  58. #pragma pack(pop)
  59. #else
  60. #pragma pack()
  61. #endif
  62.  
  63. // ==========================================================
  64. // Plugin Interface
  65. // ==========================================================
  66.  
  67. static int s_format_id;
  68.  
  69. // ==========================================================
  70. // Internal functions
  71. // ==========================================================
  72.  
  73. #ifdef FREEIMAGE_BIGENDIAN
  74. static void
  75. SwapFileHeader(BITMAPRLHEADER *header) {
  76.     SwapShort(&header->bType);
  77.     SwapShort(&header->bReserved1);
  78.     SwapShort(&header->bWidth);
  79.     SwapShort(&header->bHeight);
  80.     SwapShort(&header->bClrUsed);
  81.     SwapShort(&header->bRLRowsUsed);
  82. }
  83. #endif
  84.  
  85. // --------------------------------------------------------------------------
  86.  
  87. /**
  88. Load image pixels for RL compressed dib
  89. @param io FreeImage IO
  90. @param handle FreeImage IO handle
  91. @param width Image width
  92. @param height Image height
  93. @param dib Image to be loaded
  94. @return Returns TRUE if successful, returns FALSE otherwise
  95. */
  96. static BOOL
  97. LoadPixelData(FreeImageIO *io, fi_handle handle, int width, int height, FIBITMAP *dib, BYTE *pal, int bpp) {
  98.     BYTE status_byte = 0;
  99.     BYTE second_byte = 0;
  100.     WORD pal_pos = 0;
  101.     int scanline = height-1;
  102.     int bits = 0;
  103.  
  104.     WORD *pal16 = (WORD*)pal;
  105.     DWORD *pal32 = (DWORD*)pal;
  106.  
  107.     for (;;) {
  108.         if (io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
  109.             return FALSE;
  110.         }
  111.  
  112.         switch (status_byte) {
  113.             case RLE_COMMAND:
  114.             {
  115.                 if (io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
  116.                     return FALSE;
  117.                 }
  118.  
  119.                 if (io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
  120.                     return FALSE;
  121.                 }
  122.  
  123.                 int count = MIN((int)second_byte, width - bits);
  124.  
  125.                 BYTE *sline = FreeImage_GetScanLine(dib, scanline);
  126.  
  127.                 for (int m = 0; m < count; m++) {
  128.                     if (bpp == 32)
  129.                         *(DWORD*)(sline + (bits * sizeof(DWORD))) = pal32[pal_pos + status_byte];
  130.                     else
  131.                         *(WORD*)(sline + (bits * sizeof(WORD))) = pal16[pal_pos + status_byte];
  132.                     bits++;
  133.                 }
  134.  
  135.                 break;
  136.             }
  137.  
  138.             case RLE_DELTA:
  139.             {
  140.                 // read the delta value
  141.                 if (io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
  142.                     return FALSE;
  143.                 }
  144.  
  145.                 int count = MIN((int)second_byte, width - bits);
  146.  
  147.                 bits += count;
  148.  
  149.                 break;
  150.             }
  151.  
  152.             case RLE_PALETTE:
  153.             {
  154.                 // read new palette position
  155.                 if (io->read_proc(&pal_pos, sizeof(WORD), 1, handle) != 1) {
  156.                     return FALSE;
  157.                 }
  158.  
  159.     #ifdef FREEIMAGE_BIGENDIAN
  160.                 SwapShort(&pal_pos);
  161.     #endif
  162.                 break;
  163.             }
  164.  
  165.             case RLE_EMPTY:
  166.             {
  167.                 bits++;
  168.  
  169.                 break;
  170.             }
  171.  
  172.             default:
  173.             {
  174.                 BYTE *sline = FreeImage_GetScanLine(dib, scanline);
  175.                 if (bpp == 32)
  176.                     *(DWORD*)(sline + (bits * sizeof(DWORD))) = pal32[pal_pos + status_byte];
  177.                 else
  178.                     *(WORD*)(sline + (bits * sizeof(WORD))) = pal16[pal_pos + status_byte];
  179.  
  180.                 bits++;
  181.  
  182.                 break;
  183.             }
  184.         }
  185.  
  186.         if (bits == width) {
  187.             pal_pos = 0;
  188.             bits = 0;
  189.             scanline--;
  190.  
  191.             if (scanline < 0) return TRUE;
  192.         }
  193.     }
  194.  
  195.     return TRUE;
  196. }
  197.  
  198. // ==========================================================
  199. // Plugin Implementation
  200. // ==========================================================
  201.  
  202. static const char * DLL_CALLCONV
  203. Format() {
  204.     return "BMPRL";
  205. }
  206.  
  207. static const char * DLL_CALLCONV
  208. Description() {
  209.     return "NNG Bitmap";
  210. }
  211.  
  212. static const char * DLL_CALLCONV
  213. Extension() {
  214.     return "bmp";
  215. }
  216.  
  217. static const char * DLL_CALLCONV
  218. RegExpr() {
  219.     return "^RL";
  220. }
  221.  
  222. static const char * DLL_CALLCONV
  223. MimeType() {
  224.     return "image/bmprl";
  225. }
  226.  
  227. static BOOL DLL_CALLCONV
  228. Validate(FreeImageIO *io, fi_handle handle) {
  229.     BYTE bmprl_signature[] = { 0x52, 0x4C };
  230.     BYTE signature[2] = { 0, 0 };
  231.  
  232.     io->read_proc(signature, 1, sizeof(bmprl_signature), handle);
  233.  
  234.     if (memcmp(bmprl_signature, signature, sizeof(bmprl_signature)) == 0)
  235.         return TRUE;
  236.  
  237.     return FALSE;
  238. }
  239.  
  240. static BOOL DLL_CALLCONV
  241. SupportsExportDepth(int depth) {
  242.     return (
  243.             (depth == 16) ||
  244.             (depth == 24) ||
  245.             (depth == 32)
  246.         );
  247. }
  248.  
  249. static BOOL DLL_CALLCONV
  250. SupportsExportType(FREE_IMAGE_TYPE type) {
  251.     return (type == FIT_BITMAP) ? TRUE : FALSE;
  252. }
  253.  
  254. static BOOL DLL_CALLCONV
  255. SupportsNoPixels() {
  256.     return TRUE;
  257. }
  258.  
  259. // ----------------------------------------------------------
  260.  
  261. static FIBITMAP * DLL_CALLCONV
  262. Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
  263.     if (handle == NULL)
  264.         return NULL;
  265.    
  266.     BITMAPRLHEADER bitmaprlheader;
  267.  
  268.     // read the fileheader
  269.     io->read_proc(&bitmaprlheader, sizeof(BITMAPRLHEADER), 1, handle);
  270. #ifdef FREEIMAGE_BIGENDIAN
  271.     SwapFileHeader(&bitmapfileheader);
  272. #endif
  273.  
  274.     // check the signature
  275.     if ((bitmaprlheader.bType != 0x4C52)) {
  276.         FreeImage_OutputMessageProc(s_format_id, FI_MSG_ERROR_MAGIC_NUMBER);
  277.         return NULL;
  278.     }
  279.  
  280.     // load the BMP RL
  281.     int bpp = 0;
  282.     FIBITMAP *dib = NULL;
  283.     BYTE *pal = NULL;
  284.  
  285.     try {
  286.         BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
  287.  
  288.         // allocate enough memory to hold the bitmap
  289.         if (bitmaprlheader.bOptions & HAVE_ALPHA_MASK) {
  290.             bpp = 32;
  291.             dib = FreeImage_AllocateHeader(header_only, bitmaprlheader.bWidth, bitmaprlheader.bHeight, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  292.         }
  293.         else {
  294.             bpp = 16;
  295.             dib = FreeImage_AllocateHeader(header_only, bitmaprlheader.bWidth, bitmaprlheader.bHeight, 16, FI16_565_RED_MASK, FI16_565_GREEN_MASK, FI16_565_BLUE_MASK);
  296.         }
  297.        
  298.         if (dib == NULL) {
  299.             throw FI_MSG_ERROR_DIB_MEMORY;
  300.         }
  301.  
  302.         if (header_only) {
  303.             // header only mode
  304.             return dib;
  305.         }
  306.  
  307.         // load the 16 bits color palette
  308.         pal = (BYTE*)malloc(bitmaprlheader.bClrUsed * sizeof(WORD));
  309.         io->read_proc(pal, bitmaprlheader.bClrUsed * sizeof(WORD), 1, handle);
  310.  
  311. #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
  312.         for (int i = 0; i < bitmaprlheader.bClrUsed; i++) {
  313.             SwapShort(&pal);
  314.         }
  315. #endif
  316.  
  317.         if (bitmaprlheader.bOptions & HAVE_ALPHA_MASK) {
  318.             // load the alpha layer
  319.             BYTE *layerAlpha = (BYTE*)malloc(bitmaprlheader.bClrUsed);
  320.             io->read_proc(layerAlpha, bitmaprlheader.bClrUsed, 1, handle);
  321.  
  322.             // convert color palette to 32 bits RGBA
  323.             BYTE *oldpal = pal;
  324.             pal = (BYTE*)malloc(bitmaprlheader.bClrUsed * sizeof(DWORD));
  325.             WORD *bits = (WORD *)oldpal;
  326.             BYTE *newpal = pal;
  327.  
  328.             for (int i = 0; i < bitmaprlheader.bClrUsed; i++) {
  329.                 newpal[FI_RGBA_RED] = (BYTE)((((bits[i] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
  330.                 newpal[FI_RGBA_GREEN] = (BYTE)((((bits[i] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
  331.                 newpal[FI_RGBA_BLUE] = (BYTE)((((bits[i] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
  332.                 newpal[FI_RGBA_ALPHA] = (layerAlpha[i] >= 32) ? 0xFF : (layerAlpha[i] * 8);
  333.                 newpal += 4;
  334.             }
  335.  
  336.             free(oldpal);
  337.             free(layerAlpha);
  338.  
  339.             // check if the bitmap contains transparency, if so enable it in the header
  340.             FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));
  341.         }
  342.        
  343.         // ignore array rows length
  344.         WORD rowLen = 0;
  345.         for (int i = 0; i < bitmaprlheader.bRLRowsUsed; i++){
  346.             io->read_proc(&rowLen, sizeof(BYTE), 1, handle);
  347.             if ((rowLen & 0xff) == 0xff) {
  348.                 io->read_proc(&rowLen, sizeof(WORD), 1, handle);
  349.             }
  350.         }
  351.  
  352.         if (!LoadPixelData(io, handle, bitmaprlheader.bWidth, bitmaprlheader.bHeight, dib, pal, bpp)) {
  353.             throw "Error encountered while decoding RL BMP data";
  354.         }
  355.  
  356.         if (pal)
  357.             free(pal);
  358.  
  359.         return dib;
  360.     }
  361.     catch (const char *message) {
  362.         if (pal)
  363.             free(pal);
  364.         if (dib)
  365.             FreeImage_Unload(dib);
  366.  
  367.         FreeImage_OutputMessageProc(s_format_id, message);
  368.     }
  369.  
  370.     return NULL;
  371. }
  372.  
  373. // ----------------------------------------------------------
  374.  
  375. static int
  376. GetPaletteIndexRGBA(WORD color, BYTE alpha, WORD *colorpal, BYTE *alphapal, int palSize) {
  377.     for (int i = 0; i < palSize; i++) {
  378.         if (color == colorpal[i] && alpha == alphapal[i])
  379.             return i;
  380.     }
  381.  
  382.     return -1;
  383. }
  384.  
  385. static int
  386. GetPaletteIndexRGB(WORD color, WORD *colorpal, int palSize) {
  387.     for (int i = 0; i < palSize; i++) {
  388.         if (color == colorpal[i])
  389.             return i;
  390.     }
  391.  
  392.     return -1;
  393. }
  394.  
  395. static BOOL DLL_CALLCONV
  396. Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
  397.     if ((dib != NULL) && (handle != NULL)) {
  398.         int width, height, bpp, npitch;
  399.         width = FreeImage_GetWidth(dib);
  400.         height = FreeImage_GetHeight(dib);
  401.         bpp = FreeImage_GetBPP(dib);
  402.        
  403.         int palDefSize = 65536; // 16-bit
  404.  
  405.         // Allocate pixels array
  406.         WORD* pixels = (WORD*)malloc(height * width * sizeof(WORD));
  407.  
  408.         // Convert to 16-bit
  409.         FIBITMAP *tmp = FreeImage_ConvertTo16Bits565(dib);
  410.         npitch = FreeImage_GetPitch(tmp);
  411.         BYTE *fbits, *fpixs;
  412.         for (int y = 0; y < height; y++) {
  413.             fbits = FreeImage_GetBits(tmp) + (y * npitch);
  414.             fpixs = (BYTE*)pixels + (y * width * sizeof(WORD));
  415.             memcpy(fpixs, fbits, width * sizeof(WORD));
  416.         }
  417.         FreeImage_Unload(tmp);
  418.  
  419.         // Allocate palette
  420.         BYTE *newalphapal = NULL;
  421.         WORD *newpal = (WORD*)malloc(palDefSize * sizeof(WORD));
  422.         BYTE *bits = (BYTE*)malloc(height * width * sizeof(BYTE));
  423.         WORD *palIndex = (WORD*)malloc(height * sizeof(WORD));
  424.  
  425.         memset(palIndex, 0, height * sizeof(WORD));
  426.         newpal[0] = 0xF81F;
  427. #ifdef FREEIMAGE_BIGENDIAN
  428.         SwapShort(newpal[0]);
  429. #endif
  430.  
  431.         BYTE *palSize = (BYTE*)malloc(MAX_PALETTE_COUNT * sizeof(BYTE));
  432.         memset(palSize, 1, MAX_PALETTE_COUNT * sizeof(BYTE));
  433.  
  434.         int palTotalSize = 1;
  435.  
  436.         BOOL isAlpha = FALSE;
  437.  
  438.         if (bpp == 32) {        // RGBA
  439.             BYTE *layerAlpha = (BYTE*)malloc(width*height);
  440.  
  441.             newalphapal = (BYTE*)malloc(palDefSize * sizeof(BYTE));
  442.             newalphapal[0] = 0;
  443.  
  444.             npitch = FreeImage_GetPitch(dib);
  445.  
  446.             /////////////////////////////////////////////////////////////////////
  447.             // Generate all palettes
  448.  
  449.             for (int y = 0, yinv = (height - 1); y < height; y++, yinv--) {
  450.                 BYTE* oribits = FreeImage_GetBits(dib) + (yinv * npitch);
  451.                 BYTE rowPalSize = palSize[palIndex[y]];
  452.                 int x = 0;
  453.                 for (; x < width; x++) {
  454.                     if (palTotalSize == MAX_PALETTE_TOTAL_SIZE) {
  455.                         WuQuantizer16 Q(dib);
  456.                         if (palDefSize == 0 || !Q.Quantize(pixels, palDefSize, 0, NULL)) {
  457.                             free(newalphapal);
  458.                             free(newpal);
  459.                             free(bits);
  460.                             free(palIndex);
  461.                             free(palSize);
  462.                             free(pixels);
  463.                             return FALSE;
  464.                         }
  465.                         if (palDefSize > 8192)
  466.                             palDefSize -= 4096;
  467.                         else
  468.                             palDefSize -= (palDefSize >> 2);
  469.                         memset(palIndex, 0, height * sizeof(WORD));
  470.                         y = -1;
  471.                         yinv = height;
  472.                         palTotalSize = 1;
  473.                         memset(palSize, 1, MAX_PALETTE_COUNT * sizeof(BYTE));
  474.                         break;
  475.                     }
  476.  
  477.                     if (oribits[FI_RGBA_ALPHA] < 7) {
  478.                         pixels[yinv * width + x] = 0xF81F;
  479. #ifdef FREEIMAGE_BIGENDIAN
  480.                         SwapShort(pixels[yinv * width + x]);
  481. #endif
  482.                         layerAlpha[yinv * width + x] = 0;
  483.                         isAlpha = TRUE;
  484.                     } else {
  485.                         layerAlpha[yinv * width + x] = (oribits[FI_RGBA_ALPHA] + 1) / 8;
  486.                         if (layerAlpha[yinv * width + x] < 32) isAlpha = TRUE;
  487.                     }
  488.                     int jo = palTotalSize - (palIndex[y] * MAX_PALETTE_SIZE);
  489.                     int rc = GetPaletteIndexRGBA(pixels[yinv * width + x], layerAlpha[yinv * width + x],
  490.                         &newpal[palIndex[y] * MAX_PALETTE_SIZE], &newalphapal[palIndex[y] * MAX_PALETTE_SIZE], rowPalSize);
  491.                     if (rc == -1) {
  492.                         if (palSize[palIndex[y]] == 0 && rowPalSize == MAX_PALETTE_SIZE) {
  493.                             palTotalSize = MAX_PALETTE_TOTAL_SIZE;
  494.                         } else if (rowPalSize == MAX_PALETTE_SIZE && jo == MAX_PALETTE_SIZE) {
  495.                             palIndex[y]++;
  496.                             newpal[palTotalSize] = 0xF81F;
  497. #ifdef FREEIMAGE_BIGENDIAN
  498.                             SwapShort(newpal[newpalSize]);
  499. #endif
  500.                             newalphapal[palTotalSize] = 0;
  501.                             palTotalSize++;
  502.                             y--;
  503.                             yinv++;
  504.                             break;
  505.                         } else if (jo < MAX_PALETTE_SIZE) {
  506.                             newpal[palTotalSize] = pixels[yinv * width + x];
  507. #ifdef FREEIMAGE_BIGENDIAN
  508.                             SwapShort(newpal[newpalSize]);
  509. #endif
  510.                             newalphapal[palTotalSize] = layerAlpha[yinv * width + x];
  511.                             bits[y * width + x] = jo;
  512.                             palTotalSize++;
  513.                             rowPalSize++;
  514.                         } else if (rowPalSize < MAX_PALETTE_SIZE) {
  515.                             newpal[palIndex[y] * MAX_PALETTE_SIZE + rowPalSize] = pixels[yinv * width + x];
  516. #ifdef FREEIMAGE_BIGENDIAN
  517.                             SwapShort(newpal[palIndex[y] * MAX_PALETTE_SIZE + rowPalSize]);
  518. #endif
  519.                             newalphapal[palIndex[y] * MAX_PALETTE_SIZE + rowPalSize] = layerAlpha[yinv * width + x];
  520.                             bits[y * width + x] = rowPalSize;
  521.                             rowPalSize++;
  522.                         } else {
  523.                             palIndex[y]++;
  524.                             y--;
  525.                             yinv++;
  526.                             break;
  527.                         }
  528.                     } else {
  529.                         bits[y * width + x] = rc;
  530.                     }
  531.  
  532.                     oribits += 4;
  533.                 }
  534.  
  535.                 if (x == width)
  536.                     palSize[palIndex[y]] = rowPalSize;
  537.             }
  538.  
  539.             free(layerAlpha);
  540.             if (!isAlpha) free(newalphapal);
  541.         } else {        // RGB
  542.  
  543.             /////////////////////////////////////////////////////////////////////
  544.             // Generate all palettes
  545.  
  546.             for (int y = 0, yinv = (height - 1); y < height; y++, yinv--) {
  547.                 BYTE rowPalSize = palSize[palIndex[y]];
  548.                 int x = 0;
  549.                 for (; x < width; x++) {
  550.                     if (palTotalSize == MAX_PALETTE_TOTAL_SIZE) {
  551.                         WuQuantizer16 Q(dib);
  552.                         if (palDefSize == 0 || !Q.Quantize(pixels, palDefSize, 0, NULL)) {
  553.                             free(newpal);
  554.                             free(bits);
  555.                             free(palIndex);
  556.                             free(palSize);
  557.                             free(pixels);
  558.                             return FALSE;
  559.                         }
  560.                         if (palDefSize > 8192)
  561.                             palDefSize -= 4096;
  562.                         else
  563.                             palDefSize -= (palDefSize >> 2);
  564.                         memset(palIndex, 0, height * sizeof(WORD));
  565.                         y = -1;
  566.                         yinv = height;
  567.                         palTotalSize = 1;
  568.                         memset(palSize, 1, MAX_PALETTE_COUNT * sizeof(BYTE));
  569.                         break;
  570.                     }
  571.  
  572.                     int jo = palTotalSize - (palIndex[y] * MAX_PALETTE_SIZE);
  573.                     int rc = GetPaletteIndexRGB(pixels[yinv * width + x],
  574.                         &newpal[palIndex[y] * MAX_PALETTE_SIZE], rowPalSize);
  575.                     if (rc == -1) {
  576.                         if (palSize[palIndex[y]] == 0 && rowPalSize == MAX_PALETTE_SIZE) {
  577.                             palTotalSize = MAX_PALETTE_TOTAL_SIZE;
  578.                         } else if (rowPalSize == MAX_PALETTE_SIZE && jo == MAX_PALETTE_SIZE) {
  579.                             palIndex[y]++;
  580.                             newpal[palTotalSize] = 0xF81F;
  581. #ifdef FREEIMAGE_BIGENDIAN
  582.                             SwapShort(newpal[newpalSize]);
  583. #endif
  584.                             palTotalSize++;
  585.                             y--;
  586.                             yinv++;
  587.                             break;
  588.                         } else if (jo < MAX_PALETTE_SIZE) {
  589.                             newpal[palTotalSize] = pixels[yinv * width + x];
  590. #ifdef FREEIMAGE_BIGENDIAN
  591.                             SwapShort(newpal[newpalSize]);
  592. #endif
  593.                             bits[y * width + x] = jo;
  594.                             palTotalSize++;
  595.                             rowPalSize++;
  596.                         } else if (rowPalSize < MAX_PALETTE_SIZE) {
  597.                             newpal[palIndex[y] * MAX_PALETTE_SIZE + rowPalSize] = pixels[yinv * width + x];
  598. #ifdef FREEIMAGE_BIGENDIAN
  599.                             SwapShort(newpal[palIndex[y] * MAX_PALETTE_SIZE + rowPalSize]);
  600. #endif
  601.                             bits[y * width + x] = rowPalSize;
  602.                             rowPalSize++;
  603.                         } else {
  604.                             palIndex[y]++;
  605.                             y--;
  606.                             yinv++;
  607.                             break;
  608.                         }
  609.                     } else {
  610.                         bits[y * width + x] = rc;
  611.                     }
  612.                 }
  613.  
  614.                 if (x == width)
  615.                     palSize[palIndex[y]] = rowPalSize;
  616.             }
  617.         }
  618.  
  619.         free(palSize);
  620.         free(pixels);
  621.  
  622.         // write the file header
  623.         BITMAPRLHEADER bitmaprlheader;
  624.         bitmaprlheader.bType = 0x4C52;
  625.         bitmaprlheader.bOptions = (((palTotalSize > 250) ? 1 : 0) << 1) | ((isAlpha) ? 1 : 0);
  626.         bitmaprlheader.bWidth = width;
  627.         bitmaprlheader.bHeight = height;
  628.         bitmaprlheader.bClrUsed = palTotalSize;
  629.         bitmaprlheader.bRLRowsUsed = height;
  630.  
  631. #ifdef FREEIMAGE_BIGENDIAN
  632.         SwapFileHeader(&bitmaprlheader);
  633. #endif
  634.         if (io->write_proc(&bitmaprlheader, sizeof(BITMAPRLHEADER), 1, handle) != 1) {
  635.             free(newpal);
  636.             if (isAlpha) free(newalphapal);
  637.             free(bits);
  638.             free(palIndex);
  639.             return FALSE;
  640.         }
  641.  
  642.         // write the RGB palette
  643.         if (io->write_proc(newpal, palTotalSize * sizeof(WORD), 1, handle) != 1) {
  644.             free(newpal);
  645.             if (isAlpha) free(newalphapal);
  646.             free(bits);
  647.             free(palIndex);
  648.             return FALSE;
  649.         }
  650.  
  651.         free(newpal);
  652.  
  653.         // write the alpha palette
  654.         if (isAlpha) {
  655.             if (io->write_proc(newalphapal, palTotalSize * sizeof(BYTE), 1, handle) != 1) {
  656.                 free(newalphapal);
  657.                 free(bits);
  658.                 free(palIndex);
  659.                 return FALSE;
  660.             }
  661.  
  662.             free(newalphapal);
  663.         }
  664.  
  665.         // RLE compression
  666.         WORD *rowspitch = (WORD*)malloc(height * sizeof(WORD));
  667.         BYTE *newbits = (BYTE*)malloc(height * width * sizeof(BYTE) + (height * 3));
  668.  
  669.         memset(rowspitch, 0, height * sizeof(WORD));
  670.         int newbitsIndex = 0;
  671.         int newbitsLen = 0;
  672.  
  673.         for (int y = 0; y < height; y++) {
  674.             if (palIndex[y] > 0) {
  675.                 newbits[newbitsIndex++] = RLE_PALETTE;
  676.                 WORD val = (palIndex[y] * MAX_PALETTE_SIZE);
  677. #ifdef FREEIMAGE_BIGENDIAN
  678.                 SwapShort(&val);
  679. #endif
  680.                 *(WORD*)(newbits + newbitsIndex) = val;
  681.                 newbitsIndex += 2;
  682.  
  683.                 rowspitch[y] += 3;
  684.             }
  685.  
  686.             for (int x = 0; x < width; x++) {
  687.                 if ((x < width - 1) && (bits[y * width + x] == bits[y * width + x + 1])) {
  688.                     // find a solid block of same bytes
  689.  
  690.                     int j = x + 1;
  691.                     int jmax = 254 + x;
  692.  
  693.                     while ((j < width - 1) && (j < jmax) && (bits[y * width + j] == bits[y * width + j + 1]))
  694.                         ++j;
  695.  
  696.                     // if the block is larger than 3 bytes, use it
  697.                     // else put the data into the larger pool
  698.  
  699.                     if (((j - x) + 1) > 3) {
  700.                         // write the continuous data
  701.                         if (bits[y * width + x] == 0) {
  702.                             newbits[newbitsIndex++] = RLE_DELTA;
  703.                             newbits[newbitsIndex++] = (BYTE)((j - x) + 1);
  704.                             rowspitch[y] += 2;
  705.                         } else {
  706.                             newbits[newbitsIndex++] = RLE_COMMAND;
  707.                             newbits[newbitsIndex++] = bits[y * width + x];
  708.                             newbits[newbitsIndex++] = (BYTE)((j - x) + 1);
  709.                             rowspitch[y] += 3;
  710.                         }
  711.                     } else {
  712.                         for (int k = 0; k < (j - x) + 1; ++k) {
  713.                             newbits[newbitsIndex++] = bits[y * width + x + k];
  714.                             rowspitch[y]++;
  715.                         }
  716.                     }
  717.  
  718.                     x = j;
  719.                 } else {
  720.                     newbits[newbitsIndex++] = bits[y * width + x];
  721.                     rowspitch[y]++;
  722.                 }
  723.             }
  724.         }
  725.  
  726.         free(bits);
  727.         free(palIndex);
  728.  
  729.         // Write the row pitch array
  730.         for (int y = 0; y < height; y++) {
  731.             if (rowspitch[y] > 0xFD) {
  732.                 BYTE bob = 0xFF;
  733.                 if (io->write_proc(&bob, sizeof(BYTE), 1, handle) != 1) {
  734.                     free(rowspitch);
  735.                     free(newbits);
  736.                     return FALSE;
  737.                 }
  738.  
  739.                 WORD val = rowspitch[y];
  740. #ifndef FREEIMAGE_BIGENDIAN
  741.                 SwapShort(&val);
  742. #endif
  743.                 if (io->write_proc(&val, sizeof(WORD), 1, handle) != 1) {
  744.                     free(rowspitch);
  745.                     free(newbits);
  746.                     return FALSE;
  747.                 }
  748.             } else {
  749.                 if (io->write_proc(&rowspitch[y], sizeof(BYTE), 1, handle) != 1) {
  750.                     free(rowspitch);
  751.                     free(newbits);
  752.                     return FALSE;
  753.                 }
  754.             }
  755.         }
  756.  
  757.         // Write bitmap bits
  758.         unsigned ii = 0;
  759.         for (int y = 0; y < height; y++) {
  760.             if (io->write_proc(&newbits[ii], rowspitch[y] * sizeof(BYTE), 1, handle) != 1) {
  761.                 free(rowspitch);
  762.                 free(newbits);
  763.                 return FALSE;
  764.             }
  765.             ii += rowspitch[y];
  766.         }
  767.  
  768.         free(rowspitch);
  769.         free(newbits);
  770.         return TRUE;
  771.     } else {
  772.         return FALSE;
  773.     }
  774. }
  775.  
  776. // ==========================================================
  777. //   Init
  778. // ==========================================================
  779.  
  780. void DLL_CALLCONV
  781. InitBMPRL(Plugin *plugin, int format_id) {
  782.     s_format_id = format_id;
  783.  
  784.     plugin->format_proc = Format;
  785.     plugin->description_proc = Description;
  786.     plugin->extension_proc = Extension;
  787.     plugin->regexpr_proc = RegExpr;
  788.     plugin->open_proc = NULL;
  789.     plugin->close_proc = NULL;
  790.     plugin->pagecount_proc = NULL;
  791.     plugin->pagecapability_proc = NULL;
  792.     plugin->load_proc = Load;
  793.     plugin->save_proc = Save;
  794.     plugin->validate_proc = Validate;
  795.     plugin->mime_proc = MimeType;
  796.     plugin->supports_export_bpp_proc = SupportsExportDepth;
  797.     plugin->supports_export_type_proc = SupportsExportType;
  798.     plugin->supports_icc_profiles_proc = NULL;  // not implemented yet;
  799.     plugin->supports_no_pixels_proc = SupportsNoPixels;
  800. }
RAW Paste Data