]> Creatis software - clitk.git/blobdiff - utilities/CxImage/ximabmp.cpp
cosmetic
[clitk.git] / utilities / CxImage / ximabmp.cpp
index 4793707bfa4bc7884e4bbaca33ae6572e501faf3..a621ba5586d3ff97699a6718118e5839d4755e21 100644 (file)
-/*\r
- * File:       ximabmp.cpp\r
- * Purpose:    Platform Independent BMP Image Class Loader and Writer\r
- * 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
- * CxImage version 6.0.0 02/Feb/2008\r
- */\r
-\r
-#include "ximabmp.h"\r
-\r
-#if CXIMAGE_SUPPORT_BMP\r
-\r
-#include "ximaiter.h" \r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#if CXIMAGE_SUPPORT_ENCODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-bool CxImageBMP::Encode(CxFile * hFile)\r
-{\r
-\r
-       if (EncodeSafeCheck(hFile)) return false;\r
-\r
-       BITMAPFILEHEADER        hdr;\r
-\r
-       hdr.bfType = 0x4d42;   // 'BM' WINDOWS_BITMAP_SIGNATURE\r
-       hdr.bfSize = GetSize() + 14 /*sizeof(BITMAPFILEHEADER)*/;\r
-       hdr.bfReserved1 = hdr.bfReserved2 = 0;\r
-       hdr.bfOffBits = 14 /*sizeof(BITMAPFILEHEADER)*/ + head.biSize + GetPaletteSize();\r
-\r
-       hdr.bfType = ntohs(hdr.bfType); \r
-       hdr.bfSize = ntohl(hdr.bfSize); \r
-       hdr.bfOffBits = ntohl(hdr.bfOffBits); \r
-\r
-#if CXIMAGE_SUPPORT_ALPHA\r
-       if (GetNumColors()==0 && AlphaIsValid()){\r
-       \r
-               BITMAPINFOHEADER  infohdr;\r
-               memcpy(&infohdr,&head,sizeof(BITMAPINFOHEADER));\r
-               infohdr.biCompression = BI_RGB;\r
-               infohdr.biBitCount = 32;\r
-               DWORD dwEffWidth = ((((infohdr.biBitCount * infohdr.biWidth) + 31) / 32) * 4);\r
-               infohdr.biSizeImage = dwEffWidth * infohdr.biHeight;\r
-\r
-               hdr.bfSize = infohdr.biSize + infohdr.biSizeImage + 14 /*sizeof(BITMAPFILEHEADER)*/;\r
-\r
-               hdr.bfSize = ntohl(hdr.bfSize);\r
-               bihtoh(&infohdr);\r
-\r
-               // Write the file header\r
-               hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1);\r
-               hFile->Write(&infohdr,sizeof(BITMAPINFOHEADER),1);\r
-                //and DIB+ALPHA interlaced\r
-               BYTE *srcalpha = AlphaGetPointer();\r
-               for(long y = 0; y < infohdr.biHeight; ++y){\r
-                       BYTE *srcdib = GetBits(y);\r
-                       for(long x = 0; x < infohdr.biWidth; ++x){\r
-                               hFile->Write(srcdib,3,1);\r
-                               hFile->Write(srcalpha,1,1);\r
-                               srcdib += 3;\r
-                               ++srcalpha;\r
-                       }\r
-               }\r
-\r
-       } else \r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
-       {\r
-               // Write the file header\r
-               hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1);\r
-               //copy attributes\r
-               memcpy(pDib,&head,sizeof(BITMAPINFOHEADER));\r
-               bihtoh((BITMAPINFOHEADER*)pDib);\r
-               // Write the DIB header and the pixels\r
-               hFile->Write(pDib,GetSize(),1);\r
-               bihtoh((BITMAPINFOHEADER*)pDib);\r
-       }\r
-       return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif //CXIMAGE_SUPPORT_ENCODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-#if CXIMAGE_SUPPORT_DECODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-bool CxImageBMP::Decode(CxFile * hFile)\r
-{\r
-       if (hFile == NULL) return false;\r
-\r
-       BITMAPFILEHEADER   bf;\r
-       DWORD off = hFile->Tell(); //<CSC>\r
-  cx_try {\r
-       if (hFile->Read(&bf,min(14,sizeof(bf)),1)==0) cx_throw("Not a BMP");\r
-\r
-       bf.bfSize = ntohl(bf.bfSize); \r
-       bf.bfOffBits = ntohl(bf.bfOffBits); \r
-\r
-    if (bf.bfType != BFT_BITMAP) { //do we have a RC HEADER?\r
-        bf.bfOffBits = 0L;\r
-        hFile->Seek(off,SEEK_SET);\r
-    }\r
-\r
-       BITMAPINFOHEADER bmpHeader;\r
-       if (!DibReadBitmapInfo(hFile,&bmpHeader)) cx_throw("Error reading BMP info");\r
-       DWORD dwCompression=bmpHeader.biCompression;\r
-       DWORD dwBitCount=bmpHeader.biBitCount; //preserve for BI_BITFIELDS compression <Thomas Ernst>\r
-       bool bIsOldBmp = bmpHeader.biSize == sizeof(BITMAPCOREHEADER);\r
-\r
-       bool bTopDownDib = bmpHeader.biHeight<0; //<Flanders> check if it's a top-down bitmap\r
-       if (bTopDownDib) bmpHeader.biHeight=-bmpHeader.biHeight;\r
-\r
-       if (info.nEscape == -1) {\r
-               // Return output dimensions only\r
-               head.biWidth = bmpHeader.biWidth;\r
-               head.biHeight = bmpHeader.biHeight;\r
-               info.dwType = CXIMAGE_FORMAT_BMP;\r
-               cx_throw("output dimensions returned");\r
-       }\r
-\r
-       if (!Create(bmpHeader.biWidth,bmpHeader.biHeight,bmpHeader.biBitCount,CXIMAGE_FORMAT_BMP))\r
-               cx_throw("");\r
-\r
-       SetXDPI((long) floor(bmpHeader.biXPelsPerMeter * 254.0 / 10000.0 + 0.5));\r
-       SetYDPI((long) floor(bmpHeader.biYPelsPerMeter * 254.0 / 10000.0 + 0.5));\r
-\r
-       if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
-\r
-    RGBQUAD *pRgb = GetPalette();\r
-    if (pRgb){\r
-        if (bIsOldBmp){\r
-             // convert a old color table (3 byte entries) to a new\r
-             // color table (4 byte entries)\r
-            hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBTRIPLE),1);\r
-            for (int i=DibNumColors(&head)-1; i>=0; i--){\r
-                pRgb[i].rgbRed      = ((RGBTRIPLE *)pRgb)[i].rgbtRed;\r
-                pRgb[i].rgbBlue     = ((RGBTRIPLE *)pRgb)[i].rgbtBlue;\r
-                pRgb[i].rgbGreen    = ((RGBTRIPLE *)pRgb)[i].rgbtGreen;\r
-                pRgb[i].rgbReserved = (BYTE)0;\r
-            }\r
-        } else {\r
-            hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBQUAD),1);\r
-                       //force rgbReserved=0, to avoid problems with some WinXp bitmaps\r
-                       for (unsigned int i=0; i<head.biClrUsed; i++) pRgb[i].rgbReserved=0;\r
-        }\r
-    }\r
-\r
-       if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
-\r
-       switch (dwBitCount) {\r
-               case 32 :\r
-                       DWORD bfmask[3];\r
-                       if (dwCompression == BI_BITFIELDS)\r
-                       {\r
-                               hFile->Read(bfmask, 12, 1);\r
-                       } else {\r
-                               bfmask[0]=0x00FF0000;\r
-                               bfmask[1]=0x0000FF00;\r
-                               bfmask[2]=0x000000FF;\r
-                       }\r
-                       if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);\r
-                       if (dwCompression == BI_BITFIELDS || dwCompression == BI_RGB){\r
-                               long imagesize=4*head.biHeight*head.biWidth;\r
-                               BYTE* buff32=(BYTE*)malloc(imagesize);\r
-                               if (buff32){\r
-                                       hFile->Read(buff32, imagesize,1); // read in the pixels\r
-\r
-#if CXIMAGE_SUPPORT_ALPHA\r
-                                       if (dwCompression == BI_RGB){\r
-                                               AlphaCreate();\r
-                                               if (AlphaIsValid()){\r
-                                                       bool bAlphaOk = false;\r
-                                                       BYTE* p;\r
-                                                       for (long y=0; y<head.biHeight; y++){\r
-                                                               p = buff32 + 3 + head.biWidth * 4 * y;\r
-                                                               for (long x=0; x<head.biWidth; x++){\r
-                                                                       if (*p) bAlphaOk = true;\r
-                                                                       AlphaSet(x,y,*p);\r
-                                                                       p+=4;\r
-                                                               }\r
-                                                       }\r
-                                                       // fix if alpha pixels are all zero\r
-                                                       if (!bAlphaOk) AlphaInvert();\r
-                                               }\r
-                                       }\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
-\r
-                                       Bitfield2RGB(buff32,bfmask[0],bfmask[1],bfmask[2],32);\r
-                                       free(buff32);\r
-                               } else cx_throw("can't allocate memory");\r
-                       } else cx_throw("unknown compression");\r
-                       break;\r
-               case 24 :\r
-                       if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);\r
-                       if (dwCompression == BI_RGB){\r
-                               hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels\r
-                       } else cx_throw("unknown compression");\r
-                       break;\r
-               case 16 :\r
-               {\r
-                       DWORD bfmask[3];\r
-                       if (dwCompression == BI_BITFIELDS)\r
-                       {\r
-                               hFile->Read(bfmask, 12, 1);\r
-                       } else {\r
-                               bfmask[0]=0x7C00; bfmask[1]=0x3E0; bfmask[2]=0x1F; //RGB555\r
-                       }\r
-                       // bf.bfOffBits required after the bitfield mask <Cui Ying Jie>\r
-                       if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);\r
-                       // read in the pixels\r
-                       hFile->Read(info.pImage, head.biHeight*((head.biWidth+1)/2)*4,1);\r
-                       // transform into RGB\r
-                       Bitfield2RGB(info.pImage,bfmask[0],bfmask[1],bfmask[2],16);\r
-                       break;\r
-               }\r
-               case 8 :\r
-               case 4 :\r
-               case 1 :\r
-               if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);\r
-               switch (dwCompression) {\r
-                       case BI_RGB :\r
-                               hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels\r
-                               break;\r
-                       case BI_RLE4 :\r
-                       {\r
-                               BYTE status_byte = 0;\r
-                               BYTE second_byte = 0;\r
-                               int scanline = 0;\r
-                               int bits = 0;\r
-                               BOOL low_nibble = FALSE;\r
-                               CImageIterator iter(this);\r
-\r
-                               for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(BYTE), 1);) {\r
-                                       \r
-                                       switch (status_byte) {\r
-                                               case RLE_COMMAND :\r
-                                                       hFile->Read(&status_byte, sizeof(BYTE), 1);\r
-                                                       switch (status_byte) {\r
-                                                               case RLE_ENDOFLINE :\r
-                                                                       bits = 0;\r
-                                                                       scanline++;\r
-                                                                       low_nibble = FALSE;\r
-                                                                       break;\r
-                                                               case RLE_ENDOFBITMAP :\r
-                                                                       bContinue=FALSE;\r
-                                                                       break;\r
-                                                               case RLE_DELTA :\r
-                                                               {\r
-                                                                       // read the delta values\r
-                                                                       BYTE delta_x;\r
-                                                                       BYTE delta_y;\r
-                                                                       hFile->Read(&delta_x, sizeof(BYTE), 1);\r
-                                                                       hFile->Read(&delta_y, sizeof(BYTE), 1);\r
-                                                                       // apply them\r
-                                                                       bits       += delta_x / 2;\r
-                                                                       scanline   += delta_y;\r
-                                                                       break;\r
-                                                               }\r
-                                                               default :\r
-                                                                       hFile->Read(&second_byte, sizeof(BYTE), 1);\r
-                                                                       BYTE *sline = iter.GetRow(scanline);\r
-                                                                       for (int i = 0; i < status_byte; i++) {\r
-                                                                               if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){\r
-                                                                                       if (low_nibble) {\r
-                                                                                               if (i&1)\r
-                                                                                                       *(sline + bits) |= (second_byte & 0x0f);\r
-                                                                                               else\r
-                                                                                                       *(sline + bits) |= (second_byte & 0xf0)>>4;\r
-                                                                                               bits++;\r
-                                                                                       } else {\r
-                                                                                               if (i&1)\r
-                                                                                                       *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4;\r
-                                                                                               else\r
-                                                                                                       *(sline + bits) = (BYTE)(second_byte & 0xf0);\r
-                                                                                       }\r
-                                                                               }\r
-\r
-                                                                               if ((i & 1) && (i != (status_byte - 1)))\r
-                                                                                       hFile->Read(&second_byte, sizeof(BYTE), 1);\r
-\r
-                                                                               low_nibble = !low_nibble;\r
-                                                                       }\r
-                                                                       if ((((status_byte+1) >> 1) & 1 ) == 1)\r
-                                                                               hFile->Read(&second_byte, sizeof(BYTE), 1);                                                                                             \r
-                                                                       break;\r
-                                                       };\r
-                                                       break;\r
-                                               default :\r
-                                               {\r
-                                                       BYTE *sline = iter.GetRow(scanline);\r
-                                                       hFile->Read(&second_byte, sizeof(BYTE), 1);\r
-                                                       for (unsigned i = 0; i < status_byte; i++) {\r
-                                                               if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){\r
-                                                                       if (low_nibble) {\r
-                                                                               if (i&1)\r
-                                                                                       *(sline + bits) |= (second_byte & 0x0f);\r
-                                                                               else\r
-                                                                                       *(sline + bits) |= (second_byte & 0xf0)>>4;\r
-                                                                               bits++;\r
-                                                                       } else {\r
-                                                                               if (i&1)\r
-                                                                                       *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4;\r
-                                                                               else\r
-                                                                                       *(sline + bits) = (BYTE)(second_byte & 0xf0);\r
-                                                                       }\r
-                                                               }\r
-                                                               low_nibble = !low_nibble;\r
-                                                       }\r
-                                               }\r
-                                               break;\r
-                                       };\r
-                               }\r
-                               break;\r
-                       }\r
-                       case BI_RLE8 :\r
-                       {\r
-                               BYTE status_byte = 0;\r
-                               BYTE second_byte = 0;\r
-                               int scanline = 0;\r
-                               int bits = 0;\r
-                               CImageIterator iter(this);\r
-\r
-                               for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(BYTE), 1);) {\r
-                                       switch (status_byte) {\r
-                                               case RLE_COMMAND :\r
-                                                       hFile->Read(&status_byte, sizeof(BYTE), 1);\r
-                                                       switch (status_byte) {\r
-                                                               case RLE_ENDOFLINE :\r
-                                                                       bits = 0;\r
-                                                                       scanline++;\r
-                                                                       break;\r
-                                                               case RLE_ENDOFBITMAP :\r
-                                                                       bContinue=FALSE;\r
-                                                                       break;\r
-                                                               case RLE_DELTA :\r
-                                                               {\r
-                                                                       // read the delta values\r
-                                                                       BYTE delta_x;\r
-                                                                       BYTE delta_y;\r
-                                                                       hFile->Read(&delta_x, sizeof(BYTE), 1);\r
-                                                                       hFile->Read(&delta_y, sizeof(BYTE), 1);\r
-                                                                       // apply them\r
-                                                                       bits     += delta_x;\r
-                                                                       scanline += delta_y;\r
-                                                                       break;\r
-                                                               }\r
-                                                               default :\r
-                                                                       hFile->Read((void *)(iter.GetRow(scanline) + bits), sizeof(BYTE) * status_byte, 1);\r
-                                                                       // align run length to even number of bytes \r
-                                                                       if ((status_byte & 1) == 1)\r
-                                                                               hFile->Read(&second_byte, sizeof(BYTE), 1);                                                                                             \r
-                                                                       bits += status_byte;                                                                                                    \r
-                                                                       break;                                                          \r
-                                                       };\r
-                                                       break;\r
-                                               default :\r
-                                                       BYTE *sline = iter.GetRow(scanline);\r
-                                                       hFile->Read(&second_byte, sizeof(BYTE), 1);\r
-                                                       for (unsigned i = 0; i < status_byte; i++) {\r
-                                                               if ((DWORD)bits<info.dwEffWidth){\r
-                                                                       *(sline + bits) = second_byte;\r
-                                                                       bits++;                                 \r
-                                                               } else {\r
-                                                                       break;\r
-                                                               }\r
-                                                       }\r
-                                                       break;\r
-                                       };\r
-                               }\r
-                               break;\r
-                       }\r
-                       default :                                                               \r
-                               cx_throw("compression type not supported");\r
-               }\r
-       }\r
-\r
-       if (bTopDownDib) Flip(); //<Flanders>\r
-\r
-  } cx_catch {\r
-       if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
-       if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_BMP) return true;\r
-       return false;\r
-  }\r
-    return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/*  ReadDibBitmapInfo()\r
- *\r
- *  Will read a file in DIB format and return a global HANDLE to its\r
- *  BITMAPINFO.  This function will work with both "old" and "new"\r
- *  bitmap formats, but will always return a "new" BITMAPINFO.\r
- */\r
-bool CxImageBMP::DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib)\r
-{\r
-       if ((fh==NULL)||(pdib==NULL)) return false;\r
-\r
-    if (fh->Read(pdib,sizeof(BITMAPINFOHEADER),1)==0) return false;\r
-\r
-       bihtoh(pdib);\r
-\r
-    switch (pdib->biSize) // what type of bitmap info is this?\r
-    {\r
-        case sizeof(BITMAPINFOHEADER):\r
-            break;\r
-\r
-               case 64: //sizeof(OS2_BMP_HEADER):\r
-            fh->Seek((long)(64 - sizeof(BITMAPINFOHEADER)),SEEK_CUR);\r
-                       break;\r
-\r
-        case sizeof(BITMAPCOREHEADER):\r
-               {\r
-            BITMAPCOREHEADER bc = *(BITMAPCOREHEADER*)pdib;\r
-            pdib->biSize               = bc.bcSize;\r
-            pdib->biWidth              = (DWORD)bc.bcWidth;\r
-            pdib->biHeight             = (DWORD)bc.bcHeight;\r
-            pdib->biPlanes             =  bc.bcPlanes;\r
-            pdib->biBitCount           =  bc.bcBitCount;\r
-            pdib->biCompression        = BI_RGB;\r
-            pdib->biSizeImage          = 0;\r
-            pdib->biXPelsPerMeter      = 0;\r
-            pdib->biYPelsPerMeter      = 0;\r
-            pdib->biClrUsed            = 0;\r
-            pdib->biClrImportant       = 0;\r
-\r
-                       fh->Seek((long)(sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER)), SEEK_CUR);\r
-               }\r
-            break;\r
-        default:\r
-                       //give a last chance\r
-                        if (pdib->biSize>(sizeof(BITMAPINFOHEADER))&&\r
-                               (pdib->biSizeImage>=(unsigned long)(pdib->biHeight*((((pdib->biBitCount*pdib->biWidth)+31)/32)*4)))&&\r
-                               (pdib->biPlanes==1)&&(pdib->biClrUsed==0))\r
-                        {\r
-                    if (pdib->biCompression==BI_RGB)\r
-                                        fh->Seek((long)(pdib->biSize - sizeof(BITMAPINFOHEADER)),SEEK_CUR);\r
-                                break;\r
-                        }\r
-                       return false;\r
-    }\r
-\r
-    FixBitmapInfo(pdib);\r
-\r
-    return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif //CXIMAGE_SUPPORT_DECODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif         // CXIMAGE_SUPPORT_BMP\r
-////////////////////////////////////////////////////////////////////////////////\r
+/*
+ * File:       ximabmp.cpp
+ * Purpose:    Platform Independent BMP Image Class Loader and Writer
+ * 07/Aug/2001 Davide Pizzolato - www.xdp.it
+ * CxImage version 6.0.0 02/Feb/2008
+ */
+
+#include "ximabmp.h"
+
+#if CXIMAGE_SUPPORT_BMP
+
+#include "ximaiter.h" 
+
+////////////////////////////////////////////////////////////////////////////////
+#if CXIMAGE_SUPPORT_ENCODE
+////////////////////////////////////////////////////////////////////////////////
+bool CxImageBMP::Encode(CxFile * hFile)
+{
+
+       if (EncodeSafeCheck(hFile)) return false;
+
+       BITMAPFILEHEADER        hdr;
+
+       hdr.bfType = 0x4d42;   // 'BM' WINDOWS_BITMAP_SIGNATURE
+       hdr.bfSize = GetSize() + 14 /*sizeof(BITMAPFILEHEADER)*/;
+       hdr.bfReserved1 = hdr.bfReserved2 = 0;
+       hdr.bfOffBits = 14 /*sizeof(BITMAPFILEHEADER)*/ + head.biSize + GetPaletteSize();
+
+       hdr.bfType = ntohs(hdr.bfType); 
+       hdr.bfSize = ntohl(hdr.bfSize); 
+       hdr.bfOffBits = ntohl(hdr.bfOffBits); 
+
+#if CXIMAGE_SUPPORT_ALPHA
+       if (GetNumColors()==0 && AlphaIsValid()){
+       
+               BITMAPINFOHEADER  infohdr;
+               memcpy(&infohdr,&head,sizeof(BITMAPINFOHEADER));
+               infohdr.biCompression = BI_RGB;
+               infohdr.biBitCount = 32;
+               DWORD dwEffWidth = ((((infohdr.biBitCount * infohdr.biWidth) + 31) / 32) * 4);
+               infohdr.biSizeImage = dwEffWidth * infohdr.biHeight;
+
+               hdr.bfSize = infohdr.biSize + infohdr.biSizeImage + 14 /*sizeof(BITMAPFILEHEADER)*/;
+
+               hdr.bfSize = ntohl(hdr.bfSize);
+               bihtoh(&infohdr);
+
+               // Write the file header
+               hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1);
+               hFile->Write(&infohdr,sizeof(BITMAPINFOHEADER),1);
+                //and DIB+ALPHA interlaced
+               BYTE *srcalpha = AlphaGetPointer();
+               for(long y = 0; y < infohdr.biHeight; ++y){
+                       BYTE *srcdib = GetBits(y);
+                       for(long x = 0; x < infohdr.biWidth; ++x){
+                               hFile->Write(srcdib,3,1);
+                               hFile->Write(srcalpha,1,1);
+                               srcdib += 3;
+                               ++srcalpha;
+                       }
+               }
+
+       } else 
+#endif //CXIMAGE_SUPPORT_ALPHA
+       {
+               // Write the file header
+               hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1);
+               //copy attributes
+               memcpy(pDib,&head,sizeof(BITMAPINFOHEADER));
+               bihtoh((BITMAPINFOHEADER*)pDib);
+               // Write the DIB header and the pixels
+               hFile->Write(pDib,GetSize(),1);
+               bihtoh((BITMAPINFOHEADER*)pDib);
+       }
+       return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif //CXIMAGE_SUPPORT_ENCODE
+////////////////////////////////////////////////////////////////////////////////
+#if CXIMAGE_SUPPORT_DECODE
+////////////////////////////////////////////////////////////////////////////////
+bool CxImageBMP::Decode(CxFile * hFile)
+{
+       if (hFile == NULL) return false;
+
+       BITMAPFILEHEADER   bf;
+       DWORD off = hFile->Tell(); //<CSC>
+  cx_try {
+       if (hFile->Read(&bf,min(14,sizeof(bf)),1)==0) cx_throw("Not a BMP");
+
+       bf.bfSize = ntohl(bf.bfSize); 
+       bf.bfOffBits = ntohl(bf.bfOffBits); 
+
+    if (bf.bfType != BFT_BITMAP) { //do we have a RC HEADER?
+        bf.bfOffBits = 0L;
+        hFile->Seek(off,SEEK_SET);
+    }
+
+       BITMAPINFOHEADER bmpHeader;
+       if (!DibReadBitmapInfo(hFile,&bmpHeader)) cx_throw("Error reading BMP info");
+       DWORD dwCompression=bmpHeader.biCompression;
+       DWORD dwBitCount=bmpHeader.biBitCount; //preserve for BI_BITFIELDS compression <Thomas Ernst>
+       bool bIsOldBmp = bmpHeader.biSize == sizeof(BITMAPCOREHEADER);
+
+       bool bTopDownDib = bmpHeader.biHeight<0; //<Flanders> check if it's a top-down bitmap
+       if (bTopDownDib) bmpHeader.biHeight=-bmpHeader.biHeight;
+
+       if (info.nEscape == -1) {
+               // Return output dimensions only
+               head.biWidth = bmpHeader.biWidth;
+               head.biHeight = bmpHeader.biHeight;
+               info.dwType = CXIMAGE_FORMAT_BMP;
+               cx_throw("output dimensions returned");
+       }
+
+       if (!Create(bmpHeader.biWidth,bmpHeader.biHeight,bmpHeader.biBitCount,CXIMAGE_FORMAT_BMP))
+               cx_throw("");
+
+       SetXDPI((long) floor(bmpHeader.biXPelsPerMeter * 254.0 / 10000.0 + 0.5));
+       SetYDPI((long) floor(bmpHeader.biYPelsPerMeter * 254.0 / 10000.0 + 0.5));
+
+       if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
+
+    RGBQUAD *pRgb = GetPalette();
+    if (pRgb){
+        if (bIsOldBmp){
+             // convert a old color table (3 byte entries) to a new
+             // color table (4 byte entries)
+            hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBTRIPLE),1);
+            for (int i=DibNumColors(&head)-1; i>=0; i--){
+                pRgb[i].rgbRed      = ((RGBTRIPLE *)pRgb)[i].rgbtRed;
+                pRgb[i].rgbBlue     = ((RGBTRIPLE *)pRgb)[i].rgbtBlue;
+                pRgb[i].rgbGreen    = ((RGBTRIPLE *)pRgb)[i].rgbtGreen;
+                pRgb[i].rgbReserved = (BYTE)0;
+            }
+        } else {
+            hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBQUAD),1);
+                       //force rgbReserved=0, to avoid problems with some WinXp bitmaps
+                       for (unsigned int i=0; i<head.biClrUsed; i++) pRgb[i].rgbReserved=0;
+        }
+    }
+
+       if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
+
+       switch (dwBitCount) {
+               case 32 :
+                       DWORD bfmask[3];
+                       if (dwCompression == BI_BITFIELDS)
+                       {
+                               hFile->Read(bfmask, 12, 1);
+                       } else {
+                               bfmask[0]=0x00FF0000;
+                               bfmask[1]=0x0000FF00;
+                               bfmask[2]=0x000000FF;
+                       }
+                       if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
+                       if (dwCompression == BI_BITFIELDS || dwCompression == BI_RGB){
+                               long imagesize=4*head.biHeight*head.biWidth;
+                               BYTE* buff32=(BYTE*)malloc(imagesize);
+                               if (buff32){
+                                       hFile->Read(buff32, imagesize,1); // read in the pixels
+
+#if CXIMAGE_SUPPORT_ALPHA
+                                       if (dwCompression == BI_RGB){
+                                               AlphaCreate();
+                                               if (AlphaIsValid()){
+                                                       bool bAlphaOk = false;
+                                                       BYTE* p;
+                                                       for (long y=0; y<head.biHeight; y++){
+                                                               p = buff32 + 3 + head.biWidth * 4 * y;
+                                                               for (long x=0; x<head.biWidth; x++){
+                                                                       if (*p) bAlphaOk = true;
+                                                                       AlphaSet(x,y,*p);
+                                                                       p+=4;
+                                                               }
+                                                       }
+                                                       // fix if alpha pixels are all zero
+                                                       if (!bAlphaOk) AlphaInvert();
+                                               }
+                                       }
+#endif //CXIMAGE_SUPPORT_ALPHA
+
+                                       Bitfield2RGB(buff32,bfmask[0],bfmask[1],bfmask[2],32);
+                                       free(buff32);
+                               } else cx_throw("can't allocate memory");
+                       } else cx_throw("unknown compression");
+                       break;
+               case 24 :
+                       if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
+                       if (dwCompression == BI_RGB){
+                               hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels
+                       } else cx_throw("unknown compression");
+                       break;
+               case 16 :
+               {
+                       DWORD bfmask[3];
+                       if (dwCompression == BI_BITFIELDS)
+                       {
+                               hFile->Read(bfmask, 12, 1);
+                       } else {
+                               bfmask[0]=0x7C00; bfmask[1]=0x3E0; bfmask[2]=0x1F; //RGB555
+                       }
+                       // bf.bfOffBits required after the bitfield mask <Cui Ying Jie>
+                       if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
+                       // read in the pixels
+                       hFile->Read(info.pImage, head.biHeight*((head.biWidth+1)/2)*4,1);
+                       // transform into RGB
+                       Bitfield2RGB(info.pImage,bfmask[0],bfmask[1],bfmask[2],16);
+                       break;
+               }
+               case 8 :
+               case 4 :
+               case 1 :
+               if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
+               switch (dwCompression) {
+                       case BI_RGB :
+                               hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels
+                               break;
+                       case BI_RLE4 :
+                       {
+                               BYTE status_byte = 0;
+                               BYTE second_byte = 0;
+                               int scanline = 0;
+                               int bits = 0;
+                               BOOL low_nibble = FALSE;
+                               CImageIterator iter(this);
+
+                               for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(BYTE), 1);) {
+                                       
+                                       switch (status_byte) {
+                                               case RLE_COMMAND :
+                                                       hFile->Read(&status_byte, sizeof(BYTE), 1);
+                                                       switch (status_byte) {
+                                                               case RLE_ENDOFLINE :
+                                                                       bits = 0;
+                                                                       scanline++;
+                                                                       low_nibble = FALSE;
+                                                                       break;
+                                                               case RLE_ENDOFBITMAP :
+                                                                       bContinue=FALSE;
+                                                                       break;
+                                                               case RLE_DELTA :
+                                                               {
+                                                                       // read the delta values
+                                                                       BYTE delta_x;
+                                                                       BYTE delta_y;
+                                                                       hFile->Read(&delta_x, sizeof(BYTE), 1);
+                                                                       hFile->Read(&delta_y, sizeof(BYTE), 1);
+                                                                       // apply them
+                                                                       bits       += delta_x / 2;
+                                                                       scanline   += delta_y;
+                                                                       break;
+                                                               }
+                                                               default :
+                                                                       hFile->Read(&second_byte, sizeof(BYTE), 1);
+                                                                       BYTE *sline = iter.GetRow(scanline);
+                                                                       for (int i = 0; i < status_byte; i++) {
+                                                                               if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){
+                                                                                       if (low_nibble) {
+                                                                                               if (i&1)
+                                                                                                       *(sline + bits) |= (second_byte & 0x0f);
+                                                                                               else
+                                                                                                       *(sline + bits) |= (second_byte & 0xf0)>>4;
+                                                                                               bits++;
+                                                                                       } else {
+                                                                                               if (i&1)
+                                                                                                       *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4;
+                                                                                               else
+                                                                                                       *(sline + bits) = (BYTE)(second_byte & 0xf0);
+                                                                                       }
+                                                                               }
+
+                                                                               if ((i & 1) && (i != (status_byte - 1)))
+                                                                                       hFile->Read(&second_byte, sizeof(BYTE), 1);
+
+                                                                               low_nibble = !low_nibble;
+                                                                       }
+                                                                       if ((((status_byte+1) >> 1) & 1 ) == 1)
+                                                                               hFile->Read(&second_byte, sizeof(BYTE), 1);                                                                                             
+                                                                       break;
+                                                       };
+                                                       break;
+                                               default :
+                                               {
+                                                       BYTE *sline = iter.GetRow(scanline);
+                                                       hFile->Read(&second_byte, sizeof(BYTE), 1);
+                                                       for (unsigned i = 0; i < status_byte; i++) {
+                                                               if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){
+                                                                       if (low_nibble) {
+                                                                               if (i&1)
+                                                                                       *(sline + bits) |= (second_byte & 0x0f);
+                                                                               else
+                                                                                       *(sline + bits) |= (second_byte & 0xf0)>>4;
+                                                                               bits++;
+                                                                       } else {
+                                                                               if (i&1)
+                                                                                       *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4;
+                                                                               else
+                                                                                       *(sline + bits) = (BYTE)(second_byte & 0xf0);
+                                                                       }
+                                                               }
+                                                               low_nibble = !low_nibble;
+                                                       }
+                                               }
+                                               break;
+                                       };
+                               }
+                               break;
+                       }
+                       case BI_RLE8 :
+                       {
+                               BYTE status_byte = 0;
+                               BYTE second_byte = 0;
+                               int scanline = 0;
+                               int bits = 0;
+                               CImageIterator iter(this);
+
+                               for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(BYTE), 1);) {
+                                       switch (status_byte) {
+                                               case RLE_COMMAND :
+                                                       hFile->Read(&status_byte, sizeof(BYTE), 1);
+                                                       switch (status_byte) {
+                                                               case RLE_ENDOFLINE :
+                                                                       bits = 0;
+                                                                       scanline++;
+                                                                       break;
+                                                               case RLE_ENDOFBITMAP :
+                                                                       bContinue=FALSE;
+                                                                       break;
+                                                               case RLE_DELTA :
+                                                               {
+                                                                       // read the delta values
+                                                                       BYTE delta_x;
+                                                                       BYTE delta_y;
+                                                                       hFile->Read(&delta_x, sizeof(BYTE), 1);
+                                                                       hFile->Read(&delta_y, sizeof(BYTE), 1);
+                                                                       // apply them
+                                                                       bits     += delta_x;
+                                                                       scanline += delta_y;
+                                                                       break;
+                                                               }
+                                                               default :
+                                                                       hFile->Read((void *)(iter.GetRow(scanline) + bits), sizeof(BYTE) * status_byte, 1);
+                                                                       // align run length to even number of bytes 
+                                                                       if ((status_byte & 1) == 1)
+                                                                               hFile->Read(&second_byte, sizeof(BYTE), 1);                                                                                             
+                                                                       bits += status_byte;                                                                                                    
+                                                                       break;                                                          
+                                                       };
+                                                       break;
+                                               default :
+                                                       BYTE *sline = iter.GetRow(scanline);
+                                                       hFile->Read(&second_byte, sizeof(BYTE), 1);
+                                                       for (unsigned i = 0; i < status_byte; i++) {
+                                                               if ((DWORD)bits<info.dwEffWidth){
+                                                                       *(sline + bits) = second_byte;
+                                                                       bits++;                                 
+                                                               } else {
+                                                                       break;
+                                                               }
+                                                       }
+                                                       break;
+                                       };
+                               }
+                               break;
+                       }
+                       default :                                                               
+                               cx_throw("compression type not supported");
+               }
+       }
+
+       if (bTopDownDib) Flip(); //<Flanders>
+
+  } cx_catch {
+       if (strcmp(message,"")) strncpy(info.szLastError,message,255);
+       if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_BMP) return true;
+       return false;
+  }
+    return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+/*  ReadDibBitmapInfo()
+ *
+ *  Will read a file in DIB format and return a global HANDLE to its
+ *  BITMAPINFO.  This function will work with both "old" and "new"
+ *  bitmap formats, but will always return a "new" BITMAPINFO.
+ */
+bool CxImageBMP::DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib)
+{
+       if ((fh==NULL)||(pdib==NULL)) return false;
+
+    if (fh->Read(pdib,sizeof(BITMAPINFOHEADER),1)==0) return false;
+
+       bihtoh(pdib);
+
+    switch (pdib->biSize) // what type of bitmap info is this?
+    {
+        case sizeof(BITMAPINFOHEADER):
+            break;
+
+               case 64: //sizeof(OS2_BMP_HEADER):
+            fh->Seek((long)(64 - sizeof(BITMAPINFOHEADER)),SEEK_CUR);
+                       break;
+
+        case sizeof(BITMAPCOREHEADER):
+               {
+            BITMAPCOREHEADER bc = *(BITMAPCOREHEADER*)pdib;
+            pdib->biSize               = bc.bcSize;
+            pdib->biWidth              = (DWORD)bc.bcWidth;
+            pdib->biHeight             = (DWORD)bc.bcHeight;
+            pdib->biPlanes             =  bc.bcPlanes;
+            pdib->biBitCount           =  bc.bcBitCount;
+            pdib->biCompression        = BI_RGB;
+            pdib->biSizeImage          = 0;
+            pdib->biXPelsPerMeter      = 0;
+            pdib->biYPelsPerMeter      = 0;
+            pdib->biClrUsed            = 0;
+            pdib->biClrImportant       = 0;
+
+                       fh->Seek((long)(sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER)), SEEK_CUR);
+               }
+            break;
+        default:
+                       //give a last chance
+                        if (pdib->biSize>(sizeof(BITMAPINFOHEADER))&&
+                               (pdib->biSizeImage>=(unsigned long)(pdib->biHeight*((((pdib->biBitCount*pdib->biWidth)+31)/32)*4)))&&
+                               (pdib->biPlanes==1)&&(pdib->biClrUsed==0))
+                        {
+                    if (pdib->biCompression==BI_RGB)
+                                        fh->Seek((long)(pdib->biSize - sizeof(BITMAPINFOHEADER)),SEEK_CUR);
+                                break;
+                        }
+                       return false;
+    }
+
+    FixBitmapInfo(pdib);
+
+    return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif //CXIMAGE_SUPPORT_DECODE
+////////////////////////////////////////////////////////////////////////////////
+#endif         // CXIMAGE_SUPPORT_BMP
+////////////////////////////////////////////////////////////////////////////////