Advertisement
Guest User

PluginBMPRL.cpp

a guest
Dec 16th, 2017
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 21.20 KB | None | 0 0
  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 "bmprl";
  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 == 1) ||
  244.             (depth == 4) ||
  245.             (depth == 8) ||
  246.             (depth == 16) ||
  247.             (depth == 24) ||
  248.             (depth == 32)
  249.         );
  250. }
  251.  
  252. static BOOL DLL_CALLCONV
  253. SupportsExportType(FREE_IMAGE_TYPE type) {
  254.     return (type == FIT_BITMAP) ? TRUE : FALSE;
  255. }
  256.  
  257. static BOOL DLL_CALLCONV
  258. SupportsNoPixels() {
  259.     return TRUE;
  260. }
  261.  
  262. // ----------------------------------------------------------
  263.  
  264. static FIBITMAP * DLL_CALLCONV
  265. Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
  266.     if (handle == NULL)
  267.         return NULL;
  268.    
  269.     BITMAPRLHEADER bitmaprlheader;
  270.  
  271.     // read the fileheader
  272.     io->read_proc(&bitmaprlheader, sizeof(BITMAPRLHEADER), 1, handle);
  273. #ifdef FREEIMAGE_BIGENDIAN
  274.     SwapFileHeader(&bitmapfileheader);
  275. #endif
  276.  
  277.     // check the signature
  278.     if ((bitmaprlheader.bType != 0x4C52)) {
  279.         FreeImage_OutputMessageProc(s_format_id, FI_MSG_ERROR_MAGIC_NUMBER);
  280.         return NULL;
  281.     }
  282.  
  283.     // load the BMP RL
  284.     int bpp = 0;
  285.     FIBITMAP *dib = NULL;
  286.     BYTE *pal = NULL;
  287.  
  288.     try {
  289.         BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
  290.  
  291.         // allocate enough memory to hold the bitmap
  292.         if (bitmaprlheader.bOptions & HAVE_ALPHA_MASK) {
  293.             bpp = 32;
  294.             dib = FreeImage_AllocateHeader(header_only, bitmaprlheader.bWidth, bitmaprlheader.bHeight, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  295.         }
  296.         else {
  297.             bpp = 16;
  298.             dib = FreeImage_AllocateHeader(header_only, bitmaprlheader.bWidth, bitmaprlheader.bHeight, 16, FI16_565_RED_MASK, FI16_565_GREEN_MASK, FI16_565_BLUE_MASK);
  299.         }
  300.        
  301.         if (dib == NULL) {
  302.             throw FI_MSG_ERROR_DIB_MEMORY;
  303.         }
  304.  
  305.         if (header_only) {
  306.             // header only mode
  307.             return dib;
  308.         }
  309.  
  310.         // load the 16 bits color palette
  311.         pal = (BYTE*)malloc(bitmaprlheader.bClrUsed * sizeof(WORD));
  312.         io->read_proc(pal, bitmaprlheader.bClrUsed * sizeof(WORD), 1, handle);
  313.  
  314. #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
  315.         for (int i = 0; i < bitmaprlheader.bClrUsed; i++) {
  316.             SwapShort(&pal);
  317.         }
  318. #endif
  319.  
  320.         if (bitmaprlheader.bOptions & HAVE_ALPHA_MASK) {
  321.             // load the alpha layer
  322.             BYTE *layerAlpha = (BYTE*)malloc(bitmaprlheader.bClrUsed);
  323.             io->read_proc(layerAlpha, bitmaprlheader.bClrUsed, 1, handle);
  324.  
  325.             // convert color palette to 32 bits RGBA
  326.             BYTE *oldpal = pal;
  327.             pal = (BYTE*)malloc(bitmaprlheader.bClrUsed * sizeof(DWORD));
  328.             WORD *bits = (WORD *)oldpal;
  329.             BYTE *newpal = pal;
  330.  
  331.             for (int i = 0; i < bitmaprlheader.bClrUsed; i++) {
  332.                 newpal[FI_RGBA_RED] = (BYTE)((((bits[i] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
  333.                 newpal[FI_RGBA_GREEN] = (BYTE)((((bits[i] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
  334.                 newpal[FI_RGBA_BLUE] = (BYTE)((((bits[i] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
  335.                 newpal[FI_RGBA_ALPHA] = (layerAlpha[i] >= 32) ? 0xFF : (layerAlpha[i] * 8);
  336.                 newpal += 4;
  337.             }
  338.  
  339.             free(oldpal);
  340.             free(layerAlpha);
  341.  
  342.             // check if the bitmap contains transparency, if so enable it in the header
  343.             FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));
  344.         }
  345.        
  346.         // ignore array rows length
  347.         WORD rowLen = 0;
  348.         for (int i = 0; i < bitmaprlheader.bRLRowsUsed; i++){
  349.             io->read_proc(&rowLen, sizeof(BYTE), 1, handle);
  350.             if ((rowLen & 0xff) == 0xff) {
  351.                 io->read_proc(&rowLen, sizeof(WORD), 1, handle);
  352.             }
  353.         }
  354.  
  355.         if (!LoadPixelData(io, handle, bitmaprlheader.bWidth, bitmaprlheader.bHeight, dib, pal, bpp)) {
  356.             throw "Error encountered while decoding RL BMP data";
  357.         }
  358.  
  359.         if (pal)
  360.             free(pal);
  361.  
  362.         return dib;
  363.     }
  364.     catch (const char *message) {
  365.         if (pal)
  366.             free(pal);
  367.         if (dib)
  368.             FreeImage_Unload(dib);
  369.  
  370.         FreeImage_OutputMessageProc(s_format_id, message);
  371.     }
  372.  
  373.     return NULL;
  374. }
  375.  
  376. // ----------------------------------------------------------
  377.  
  378. static int
  379. GetPaletteIndexRGBA(WORD color, BYTE alpha, WORD *colorpal, BYTE *alphapal, int palSize) {
  380.     for (int i = 0; i < palSize; i++) {
  381.         if (color == colorpal[i] && alpha == alphapal[i])
  382.             return i;
  383.     }
  384.  
  385.     return -1;
  386. }
  387.  
  388. static int
  389. GetPaletteIndexRGB(WORD color, WORD *colorpal, int palSize) {
  390.     for (int i = 0; i < palSize; i++) {
  391.         if (color == colorpal[i])
  392.             return i;
  393.     }
  394.  
  395.     return -1;
  396. }
  397.  
  398. static BOOL DLL_CALLCONV
  399. Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
  400.     if ((dib != NULL) && (handle != NULL)) {
  401.         int width, height, bpp, npitch;
  402.         width = FreeImage_GetWidth(dib);
  403.         height = FreeImage_GetHeight(dib);
  404.         bpp = FreeImage_GetBPP(dib);
  405.        
  406.         int palDefSize = 65536; // 16-bit
  407.  
  408.         // Allocate pixels array
  409.         WORD* pixels = (WORD*)malloc(height * width * sizeof(WORD));
  410.  
  411.         // Convert to 16-bit
  412.         FIBITMAP *tmp = FreeImage_ConvertTo16Bits565(dib);
  413.         npitch = FreeImage_GetPitch(tmp);
  414.         BYTE *fbits, *fpixs;
  415.         for (int y = 0; y < height; y++) {
  416.             fbits = FreeImage_GetBits(tmp) + (y * npitch);
  417.             fpixs = (BYTE*)pixels + (y * width * sizeof(WORD));
  418.             memcpy(fpixs, fbits, width * sizeof(WORD));
  419.         }
  420.         FreeImage_Unload(tmp);
  421.  
  422.         // Allocate palette
  423.         BYTE *newalphapal = NULL;
  424.         WORD *newpal = (WORD*)malloc(palDefSize * sizeof(WORD));
  425.         BYTE *bits = (BYTE*)malloc(height * width * sizeof(BYTE));
  426.         WORD *palIndex = (WORD*)malloc(height * sizeof(WORD));
  427.  
  428.         memset(palIndex, 0, height * sizeof(WORD));
  429.         newpal[0] = 0xF81F;
  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] = 32;
  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.                         palDefSize >>= 1;
  466.                         memset(palIndex, 0, height * sizeof(WORD));
  467.                         y = -1;
  468.                         yinv = height;
  469.                         palTotalSize = 1;
  470.                         memset(palSize, 1, MAX_PALETTE_COUNT * sizeof(BYTE));
  471.                         break;
  472.                     }
  473.  
  474.                     if (oribits[FI_RGBA_ALPHA] < 7) {
  475.                         pixels[yinv * width + x] = 0xF81F;
  476. #ifdef FREEIMAGE_BIGENDIAN
  477.                         SwapShort(pixels[yinv * width + x]);
  478. #endif
  479.                         layerAlpha[yinv * width + x] = 32;
  480.                     } else {
  481.                         layerAlpha[yinv * width + x] = (oribits[FI_RGBA_ALPHA] + 1) / 8;
  482.                         if (layerAlpha[yinv * width + x] < 32) isAlpha = TRUE;
  483.                     }
  484.                     int jo = palTotalSize - (palIndex[y] * MAX_PALETTE_SIZE);
  485.                     int rc = GetPaletteIndexRGBA(pixels[yinv * width + x], layerAlpha[yinv * width + x],
  486.                         &newpal[palIndex[y] * MAX_PALETTE_SIZE], &newalphapal[palIndex[y] * MAX_PALETTE_SIZE], rowPalSize);
  487.                     if (rc == -1) {
  488.                         if (palSize[palIndex[y]] == 0 && rowPalSize == MAX_PALETTE_SIZE) {
  489.                             palTotalSize = MAX_PALETTE_TOTAL_SIZE;
  490.                         } else if (rowPalSize == MAX_PALETTE_SIZE && jo == MAX_PALETTE_SIZE) {
  491.                             palIndex[y]++;
  492.                             newpal[palTotalSize] = 0xF81F;
  493. #ifdef FREEIMAGE_BIGENDIAN
  494.                             SwapShort(newpal[newpalSize]);
  495. #endif
  496.                             newalphapal[palTotalSize] = 32;
  497.                             palTotalSize++;
  498.                             y--;
  499.                             yinv++;
  500.                             break;
  501.                         } else if (jo < MAX_PALETTE_SIZE) {
  502.                             newpal[palTotalSize] = pixels[yinv * width + x];
  503. #ifdef FREEIMAGE_BIGENDIAN
  504.                             SwapShort(newpal[newpalSize]);
  505. #endif
  506.                             newalphapal[palTotalSize] = layerAlpha[yinv * width + x];
  507.                             bits[y * width + x] = jo;
  508.                             palTotalSize++;
  509.                             rowPalSize++;
  510.                         } else if (rowPalSize < MAX_PALETTE_SIZE) {
  511.                             newpal[palIndex[y] * MAX_PALETTE_SIZE + rowPalSize] = pixels[yinv * width + x];
  512. #ifdef FREEIMAGE_BIGENDIAN
  513.                             SwapShort(newpal[palIndex[y] * MAX_PALETTE_SIZE + rowPalSize]);
  514. #endif
  515.                             newalphapal[palIndex[y] * MAX_PALETTE_SIZE + rowPalSize] = layerAlpha[yinv * width + x];
  516.                             bits[y * width + x] = rowPalSize;
  517.                             rowPalSize++;
  518.                         } else {
  519.                             palIndex[y]++;
  520.                             y--;
  521.                             yinv++;
  522.                             break;
  523.                         }
  524.                     } else {
  525.                         bits[y * width + x] = rc;
  526.                     }
  527.  
  528.                     oribits += 4;
  529.                 }
  530.  
  531.                 if (x == width)
  532.                     palSize[palIndex[y]] = rowPalSize;
  533.             }
  534.  
  535.             free(layerAlpha);
  536.             if (!isAlpha) free(newalphapal);
  537.         } else {        // RGB
  538.  
  539.             /////////////////////////////////////////////////////////////////////
  540.             // Generate all palettes
  541.  
  542.             for (int y = 0, yinv = (height - 1); y < height; y++, yinv--) {
  543.                 BYTE rowPalSize = palSize[palIndex[y]];
  544.                 int x = 0;
  545.                 for (; x < width; x++) {
  546.                     if (palTotalSize == MAX_PALETTE_TOTAL_SIZE) {
  547.                         WuQuantizer16 Q(dib);
  548.                         if (palDefSize == 0 || !Q.Quantize(pixels, palDefSize, 0, NULL)) {
  549.                             free(newpal);
  550.                             free(bits);
  551.                             free(palIndex);
  552.                             free(palSize);
  553.                             free(pixels);
  554.                             return FALSE;
  555.                         }
  556.                         palDefSize >>= 1;
  557.                         memset(palIndex, 0, height * sizeof(WORD));
  558.                         y = -1;
  559.                         yinv = height;
  560.                         palTotalSize = 1;
  561.                         memset(palSize, 1, MAX_PALETTE_COUNT * sizeof(BYTE));
  562.                         break;
  563.                     }
  564.  
  565.                     int jo = palTotalSize - (palIndex[y] * MAX_PALETTE_SIZE);
  566.                     int rc = GetPaletteIndexRGB(pixels[yinv * width + x],
  567.                         &newpal[palIndex[y] * MAX_PALETTE_SIZE], rowPalSize);
  568.                     if (rc == -1) {
  569.                         if (palSize[palIndex[y]] == 0 && rowPalSize == MAX_PALETTE_SIZE) {
  570.                             palTotalSize = MAX_PALETTE_TOTAL_SIZE;
  571.                         } else if (rowPalSize == MAX_PALETTE_SIZE && jo == MAX_PALETTE_SIZE) {
  572.                             palIndex[y]++;
  573.                             newpal[palTotalSize] = 0xF81F;
  574. #ifdef FREEIMAGE_BIGENDIAN
  575.                             SwapShort(newpal[newpalSize]);
  576. #endif
  577.                             palTotalSize++;
  578.                             y--;
  579.                             yinv++;
  580.                             break;
  581.                         } else if (jo < MAX_PALETTE_SIZE) {
  582.                             newpal[palTotalSize] = pixels[yinv * width + x];
  583. #ifdef FREEIMAGE_BIGENDIAN
  584.                             SwapShort(newpal[newpalSize]);
  585. #endif
  586.                             bits[y * width + x] = jo;
  587.                             palTotalSize++;
  588.                             rowPalSize++;
  589.                         } else if (rowPalSize < MAX_PALETTE_SIZE) {
  590.                             newpal[palIndex[y] * MAX_PALETTE_SIZE + rowPalSize] = pixels[yinv * width + x];
  591. #ifdef FREEIMAGE_BIGENDIAN
  592.                             SwapShort(newpal[palIndex[y] * MAX_PALETTE_SIZE + rowPalSize]);
  593. #endif
  594.                             bits[y * width + x] = rowPalSize;
  595.                             rowPalSize++;
  596.                         } else {
  597.                             palIndex[y]++;
  598.                             y--;
  599.                             yinv++;
  600.                             break;
  601.                         }
  602.                     } else {
  603.                         bits[y * width + x] = rc;
  604.                     }
  605.                 }
  606.  
  607.                 if (x == width)
  608.                     palSize[palIndex[y]] = rowPalSize;
  609.             }
  610.         }
  611.  
  612.         free(palSize);
  613.         free(pixels);
  614.  
  615.         // write the file header
  616.         BITMAPRLHEADER bitmaprlheader;
  617.         bitmaprlheader.bType = 0x4C52;
  618.         bitmaprlheader.bOptions = (((palTotalSize > 250) ? 1 : 0) << 1) | ((isAlpha) ? 1 : 0);
  619.         bitmaprlheader.bWidth = width;
  620.         bitmaprlheader.bHeight = height;
  621.         bitmaprlheader.bClrUsed = palTotalSize;
  622.         bitmaprlheader.bRLRowsUsed = height;
  623.  
  624. #ifdef FREEIMAGE_BIGENDIAN
  625.         SwapFileHeader(&bitmaprlheader);
  626. #endif
  627.         if (io->write_proc(&bitmaprlheader, sizeof(BITMAPRLHEADER), 1, handle) != 1) {
  628.             free(newpal);
  629.             if (isAlpha) free(newalphapal);
  630.             free(bits);
  631.             free(palIndex);
  632.             return FALSE;
  633.         }
  634.  
  635.         // write the RGB palette
  636.         if (io->write_proc(newpal, palTotalSize * sizeof(WORD), 1, handle) != 1) {
  637.             free(newpal);
  638.             if (isAlpha) free(newalphapal);
  639.             free(bits);
  640.             free(palIndex);
  641.             return FALSE;
  642.         }
  643.  
  644.         free(newpal);
  645.  
  646.         // write the alpha palette
  647.         if (isAlpha) {
  648.             if (io->write_proc(newalphapal, palTotalSize * sizeof(BYTE), 1, handle) != 1) {
  649.                 free(newalphapal);
  650.                 free(bits);
  651.                 free(palIndex);
  652.                 return FALSE;
  653.             }
  654.  
  655.             free(newalphapal);
  656.         }
  657.  
  658.         // RLE compression
  659.         WORD *rowspitch = (WORD*)malloc(height * sizeof(WORD));
  660.         BYTE *newbits = (BYTE*)malloc(height * width * sizeof(BYTE));
  661.  
  662.         memset(rowspitch, 0, height * sizeof(WORD));
  663.         int newbitsIndex = 0;
  664.         int newbitsLen = 0;
  665.  
  666.         for (int y = 0; y < height; y++) {
  667.             if (palIndex[y] > 0) {
  668.                 newbits[newbitsIndex++] = RLE_PALETTE;
  669.                 WORD val = (palIndex[y] * MAX_PALETTE_SIZE);
  670. #ifdef FREEIMAGE_BIGENDIAN
  671.                 SwapShort(&val);
  672. #endif
  673.                 *(WORD*)(newbits + newbitsIndex) = val;
  674.                 newbitsIndex += 2;
  675.  
  676.                 rowspitch[y] += 3;
  677.             }
  678.  
  679.             for (int x = 0; x < width; x++) {
  680.                 if ((x < width - 1) && (bits[y * width + x] == bits[y * width + x + 1])) {
  681.                     // find a solid block of same bytes
  682.  
  683.                     int j = x + 1;
  684.                     int jmax = 254 + x;
  685.  
  686.                     while ((j < width - 1) && (j < jmax) && (bits[y * width + j] == bits[y * width + j + 1]))
  687.                         ++j;
  688.  
  689.                     // if the block is larger than 3 bytes, use it
  690.                     // else put the data into the larger pool
  691.  
  692.                     if (((j - x) + 1) > 3) {
  693.                         // write the continuous data
  694.                         if (bits[y * width + x] == 0) {
  695.                             newbits[newbitsIndex++] = RLE_DELTA;
  696.                             newbits[newbitsIndex++] = (BYTE)((j - x) + 1);
  697.                             rowspitch[y] += 2;
  698.                         } else {
  699.                             newbits[newbitsIndex++] = RLE_COMMAND;
  700.                             newbits[newbitsIndex++] = bits[y * width + x];
  701.                             newbits[newbitsIndex++] = (BYTE)((j - x) + 1);
  702.                             rowspitch[y] += 3;
  703.                         }
  704.                     } else {
  705.                         for (int k = 0; k < (j - x) + 1; ++k) {
  706.                             newbits[newbitsIndex++] = bits[y * width + x + k];
  707.                             rowspitch[y]++;
  708.                         }
  709.                     }
  710.  
  711.                     x = j;
  712.                 } else {
  713.                     newbits[newbitsIndex++] = bits[y * width + x];
  714.                     rowspitch[y]++;
  715.                 }
  716.             }
  717.         }
  718.  
  719.         free(bits);
  720.         free(palIndex);
  721.  
  722.         // Write the row pitch array
  723.         for (int y = 0; y < height; y++) {
  724.             if (rowspitch[y] > 0xFD) {
  725.                 BYTE bob = 0xFF;
  726.                 if (io->write_proc(&bob, sizeof(BYTE), 1, handle) != 1) {
  727.                     free(rowspitch);
  728.                     free(newbits);
  729.                     return FALSE;
  730.                 }
  731.  
  732.                 WORD val = rowspitch[y];
  733. #ifndef FREEIMAGE_BIGENDIAN
  734.                 SwapShort(&val);
  735. #endif
  736.                 if (io->write_proc(&val, sizeof(WORD), 1, handle) != 1) {
  737.                     free(rowspitch);
  738.                     free(newbits);
  739.                     return FALSE;
  740.                 }
  741.             } else {
  742.                 if (io->write_proc(&rowspitch[y], sizeof(BYTE), 1, handle) != 1) {
  743.                     free(rowspitch);
  744.                     free(newbits);
  745.                     return FALSE;
  746.                 }
  747.             }
  748.         }
  749.  
  750.         // Write the bitmap bits
  751.         unsigned ii = 0;
  752.         for (int y = 0; y < height; y++) {
  753.             if (io->write_proc(&newbits[ii], rowspitch[y] * sizeof(BYTE), 1, handle) != 1) {
  754.                 free(rowspitch);
  755.                 free(newbits);
  756.                 return FALSE;
  757.             }
  758.             ii += rowspitch[y];
  759.         }
  760.  
  761.         free(rowspitch);
  762.         free(newbits);
  763.         return TRUE;
  764.     } else {
  765.         return FALSE;
  766.     }
  767. }
  768.  
  769. // ==========================================================
  770. //   Init
  771. // ==========================================================
  772.  
  773. void DLL_CALLCONV
  774. InitBMPRL(Plugin *plugin, int format_id) {
  775.     s_format_id = format_id;
  776.  
  777.     plugin->format_proc = Format;
  778.     plugin->description_proc = Description;
  779.     plugin->extension_proc = Extension;
  780.     plugin->regexpr_proc = RegExpr;
  781.     plugin->open_proc = NULL;
  782.     plugin->close_proc = NULL;
  783.     plugin->pagecount_proc = NULL;
  784.     plugin->pagecapability_proc = NULL;
  785.     plugin->load_proc = Load;
  786.     plugin->save_proc = Save;
  787.     plugin->validate_proc = Validate;
  788.     plugin->mime_proc = MimeType;
  789.     plugin->supports_export_bpp_proc = SupportsExportDepth;
  790.     plugin->supports_export_type_proc = SupportsExportType;
  791.     plugin->supports_icc_profiles_proc = NULL;  // not implemented yet;
  792.     plugin->supports_no_pixels_proc = SupportsNoPixels;
  793. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement