-/*\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
+////////////////////////////////////////////////////////////////////////////////