-/*\r
- * File: ximaico.cpp\r
- * Purpose: Platform Independent ICON Image Class Loader and Writer (MS version)\r
- * 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
- * CxImage version 6.0.0 02/Feb/2008\r
- */\r
-\r
-#include "ximaico.h"\r
-\r
-#if CXIMAGE_SUPPORT_ICO\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#if CXIMAGE_SUPPORT_DECODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-bool CxImageICO::Decode(CxFile *hFile)\r
-{\r
- if (hFile==NULL) return false;\r
-\r
- DWORD off = hFile->Tell(); //<yuandi>\r
- int page=info.nFrame; //internal icon structure indexes\r
-\r
- // read the first part of the header\r
- ICONHEADER icon_header;\r
- hFile->Read(&icon_header,sizeof(ICONHEADER),1);\r
-\r
- icon_header.idType = ntohs(icon_header.idType);\r
- icon_header.idCount = ntohs(icon_header.idCount);\r
-\r
- // check if it's an icon or a cursor\r
- if ((icon_header.idReserved == 0) && ((icon_header.idType == 1)||(icon_header.idType == 2))) {\r
-\r
- info.nNumFrames = icon_header.idCount;\r
-\r
- // load the icon descriptions\r
- ICONDIRENTRY *icon_list = (ICONDIRENTRY *)malloc(icon_header.idCount * sizeof(ICONDIRENTRY));\r
- int c;\r
- for (c = 0; c < icon_header.idCount; c++) {\r
- hFile->Read(icon_list + c, sizeof(ICONDIRENTRY), 1);\r
-\r
- icon_list[c].wPlanes = ntohs(icon_list[c].wPlanes);\r
- icon_list[c].wBitCount = ntohs(icon_list[c].wBitCount);\r
- icon_list[c].dwBytesInRes = ntohl(icon_list[c].dwBytesInRes);\r
- icon_list[c].dwImageOffset = ntohl(icon_list[c].dwImageOffset);\r
- }\r
- \r
- if ((page>=0)&&(page<icon_header.idCount)){\r
-\r
- if (info.nEscape == -1) {\r
- // Return output dimensions only\r
- head.biWidth = icon_list[page].bWidth;\r
- head.biHeight = icon_list[page].bHeight;\r
-#if CXIMAGE_SUPPORT_PNG\r
- if (head.biWidth==0 && head.biHeight==0)\r
- { // Vista icon support\r
- hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET);\r
- CxImage png;\r
- png.SetEscape(-1);\r
- if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){\r
- Transfer(png);\r
- info.nNumFrames = icon_header.idCount;\r
- }\r
- }\r
-#endif //CXIMAGE_SUPPORT_PNG\r
- free(icon_list);\r
- info.dwType = CXIMAGE_FORMAT_ICO;\r
- return true;\r
- }\r
-\r
- // get the bit count for the colors in the icon <CoreyRLucier>\r
- BITMAPINFOHEADER bih;\r
- hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET);\r
-\r
- if (icon_list[page].bWidth==0 && icon_list[page].bHeight==0)\r
- { // Vista icon support\r
-#if CXIMAGE_SUPPORT_PNG\r
- CxImage png;\r
- if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){\r
- Transfer(png);\r
- info.nNumFrames = icon_header.idCount;\r
- }\r
- SetType(CXIMAGE_FORMAT_ICO);\r
-#endif //CXIMAGE_SUPPORT_PNG\r
- }\r
- else\r
- { // standard icon\r
- hFile->Read(&bih,sizeof(BITMAPINFOHEADER),1);\r
-\r
- bihtoh(&bih);\r
-\r
- c = bih.biBitCount;\r
-\r
- // allocate memory for one icon\r
- Create(icon_list[page].bWidth,icon_list[page].bHeight, c, CXIMAGE_FORMAT_ICO); //image creation\r
-\r
- // read the palette\r
- RGBQUAD pal[256];\r
- if (bih.biClrUsed)\r
- hFile->Read(pal,bih.biClrUsed*sizeof(RGBQUAD), 1);\r
- else\r
- hFile->Read(pal,head.biClrUsed*sizeof(RGBQUAD), 1);\r
-\r
- SetPalette(pal,head.biClrUsed); //palette assign\r
-\r
- //read the icon\r
- if (c<=24){\r
- hFile->Read(info.pImage, head.biSizeImage, 1);\r
- } else { // 32 bit icon\r
- BYTE* buf=(BYTE*)malloc(4*head.biHeight*head.biWidth);\r
- BYTE* src = buf;\r
- hFile->Read(buf, 4*head.biHeight*head.biWidth, 1);\r
-#if CXIMAGE_SUPPORT_ALPHA\r
- if (!AlphaIsValid()) AlphaCreate();\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
- for (long y = 0; y < head.biHeight; y++) {\r
- BYTE* dst = GetBits(y);\r
- for(long x=0;x<head.biWidth;x++){\r
- *dst++=src[0];\r
- *dst++=src[1];\r
- *dst++=src[2];\r
-#if CXIMAGE_SUPPORT_ALPHA\r
- AlphaSet(x,y,src[3]);\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
- src+=4;\r
- }\r
- }\r
- free(buf);\r
- }\r
- // apply the AND and XOR masks\r
- int maskwdt = ((head.biWidth+31) / 32) * 4; //line width of AND mask (always 1 Bpp)\r
- int masksize = head.biHeight * maskwdt; //size of mask\r
- BYTE *mask = (BYTE *)malloc(masksize);\r
- if (hFile->Read(mask, masksize, 1)){\r
-\r
- bool bGoodMask=false;\r
- for (int im=0;im<masksize;im++){\r
- if (mask[im]!=255){\r
- bGoodMask=true;\r
- break;\r
- }\r
- }\r
-\r
- if (bGoodMask){\r
-#if CXIMAGE_SUPPORT_ALPHA\r
- bool bNeedAlpha = false;\r
- if (!AlphaIsValid()){\r
- AlphaCreate();\r
- } else { \r
- bNeedAlpha=true; //32bit icon\r
- }\r
- int x,y;\r
- for (y = 0; y < head.biHeight; y++) {\r
- for (x = 0; x < head.biWidth; x++) {\r
- if (((mask[y*maskwdt+(x>>3)]>>(7-x%8))&0x01)){\r
- AlphaSet(x,y,0);\r
- bNeedAlpha=true;\r
- }\r
- }\r
- }\r
- if (!bNeedAlpha) AlphaDelete();\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
-\r
- //check if there is only one transparent color\r
- RGBQUAD cc,ct;\r
- long* pcc = (long*)&cc;\r
- long* pct = (long*)&ct;\r
- int nTransColors=0;\r
- int nTransIndex=0;\r
- for (y = 0; y < head.biHeight; y++){\r
- for (x = 0; x < head.biWidth; x++){\r
- if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){\r
- cc = GetPixelColor(x,y,false);\r
- if (nTransColors==0){\r
- nTransIndex = GetPixelIndex(x,y);\r
- nTransColors++;\r
- ct = cc;\r
- } else {\r
- if (*pct!=*pcc){\r
- nTransColors++;\r
- }\r
- }\r
- }\r
- }\r
- }\r
- if (nTransColors==1){\r
- SetTransColor(ct);\r
- SetTransIndex(nTransIndex);\r
-#if CXIMAGE_SUPPORT_ALPHA\r
- AlphaDelete(); //because we have a unique transparent color in the image\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
- }\r
-\r
- // <vho> - Transparency support w/o Alpha support\r
- if (c <= 8){ // only for icons with less than 256 colors (XP icons need alpha).\r
- \r
- // find a color index, which is not used in the image\r
- // it is almost sure to find one, bcs. nobody uses all possible colors for an icon\r
-\r
- BYTE colorsUsed[256];\r
- memset(colorsUsed, 0, sizeof(colorsUsed));\r
-\r
- for (y = 0; y < head.biHeight; y++){\r
- for (x = 0; x < head.biWidth; x++){\r
- colorsUsed[BlindGetPixelIndex(x,y)] = 1;\r
- }\r
- }\r
-\r
- int iTransIdx = -1;\r
- for (x = (int)(head.biClrUsed-1); x>=0 ; x--){\r
- if (colorsUsed[x] == 0){\r
- iTransIdx = x; // this one is not in use. we may use it as transparent color\r
- break;\r
- }\r
- }\r
-\r
- // Go thru image and set unused color as transparent index if needed\r
- if (iTransIdx >= 0){\r
- bool bNeedTrans = false;\r
- for (y = 0; y < head.biHeight; y++){\r
- for (x = 0; x < head.biWidth; x++){\r
- // AND mask (Each Byte represents 8 Pixels)\r
- if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){\r
- // AND mask is set (!=0). This is a transparent part\r
- SetPixelIndex(x, y, (BYTE)iTransIdx);\r
- bNeedTrans = true;\r
- }\r
- }\r
- }\r
- // set transparent index if needed\r
- if (bNeedTrans) SetTransIndex(iTransIdx);\r
-#if CXIMAGE_SUPPORT_ALPHA\r
- AlphaDelete(); //because we have a transparent color in the palette\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
- }\r
- }\r
- } else {\r
- SetTransIndex(0); //empty mask, set black as transparent color\r
- Negative();\r
- }\r
- } \r
- free(mask);\r
- }\r
- free(icon_list);\r
- // icon has been loaded successfully!\r
- return true;\r
- }\r
- free(icon_list);\r
- }\r
- return false;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif //CXIMAGE_SUPPORT_DECODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-#if CXIMAGE_SUPPORT_ENCODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Thanks to <Alas>\r
-bool CxImageICO::Encode(CxFile * hFile, CxImage ** pImages, int nPageCount)\r
-{\r
- cx_try\r
- {\r
- if (hFile==NULL) cx_throw("invalid file pointer");\r
- if (pImages==NULL || nPageCount<=0) cx_throw("multipage ICO, no images!");\r
-\r
- int i;\r
- for (i=0; i<nPageCount; i++){\r
- if (pImages[i]==NULL)\r
- cx_throw("Bad image pointer");\r
- if (!(pImages[i]->IsValid()))\r
- cx_throw("Empty image");\r
- }\r
-\r
- CxImageICO ghost;\r
- for (i=0; i<nPageCount; i++){ //write headers\r
- ghost.Ghost(pImages[i]);\r
- ghost.info.nNumFrames = nPageCount;\r
- if (i==0) {\r
- if (!ghost.Encode(hFile,false,nPageCount))\r
- cx_throw("Error writing ICO file header");\r
- }\r
- if (!ghost.Encode(hFile,true,nPageCount)) \r
- cx_throw("Error saving ICO image header");\r
- }\r
- for (i=0; i<nPageCount; i++){ //write bodies\r
- ghost.Ghost(pImages[i]);\r
- ghost.info.nNumFrames = nPageCount;\r
- if (!ghost.Encode(hFile,true,i)) \r
- cx_throw("Error saving ICO body");\r
- }\r
-\r
- } cx_catch {\r
- if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
- return false;\r
- }\r
- return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-bool CxImageICO::Encode(CxFile * hFile, bool bAppend, int nPageCount)\r
-{\r
- if (EncodeSafeCheck(hFile)) return false;\r
-\r
-#if CXIMAGE_SUPPORT_PNG == 0\r
- //check format limits\r
- if ((head.biWidth>255)||(head.biHeight>255)){\r
- strcpy(info.szLastError,"Can't save this image as icon");\r
- return false;\r
- }\r
-#endif\r
-\r
- //prepare the palette struct\r
- RGBQUAD* pal=GetPalette();\r
- if (head.biBitCount<=8 && pal==NULL) return false;\r
-\r
- int maskwdt=((head.biWidth+31)/32)*4; //mask line width\r
- int masksize=head.biHeight * maskwdt; //size of mask\r
- int bitcount=head.biBitCount;\r
- int imagesize=head.biSizeImage;\r
-#if CXIMAGE_SUPPORT_ALPHA\r
- if (AlphaIsValid() && head.biClrUsed==0){\r
- bitcount=32;\r
- imagesize=4*head.biHeight*head.biWidth;\r
- }\r
-#endif\r
-\r
- //fill the icon headers\r
- int nPages = nPageCount;\r
- if (nPages<1) nPages = 1;\r
-\r
- ICONHEADER icon_header={0,1,nPages};\r
-\r
- if (!bAppend)\r
- m_dwImageOffset = sizeof(ICONHEADER) + nPages * sizeof(ICONDIRENTRY);\r
-\r
- DWORD dwBytesInRes = sizeof(BITMAPINFOHEADER)+head.biClrUsed*sizeof(RGBQUAD)+imagesize+masksize;\r
-\r
- ICONDIRENTRY icon_list={\r
- (BYTE)head.biWidth,\r
- (BYTE)head.biHeight,\r
- (BYTE)head.biClrUsed,\r
- 0, 0,\r
- (WORD)bitcount,\r
- dwBytesInRes,\r
- m_dwImageOffset\r
- };\r
-\r
- BITMAPINFOHEADER bi={\r
- sizeof(BITMAPINFOHEADER),\r
- head.biWidth,\r
- 2*head.biHeight,\r
- 1,\r
- (WORD)bitcount,\r
- 0, imagesize,\r
- 0, 0, 0, 0\r
- };\r
-\r
-#if CXIMAGE_SUPPORT_PNG // Vista icon support\r
- CxImage png(*this);\r
- CxMemFile memfile;\r
- if (head.biWidth>255 || head.biHeight>255){\r
- icon_list.bWidth = icon_list.bHeight = 0;\r
- memfile.Open();\r
- png.Encode(&memfile,CXIMAGE_FORMAT_PNG);\r
- icon_list.dwBytesInRes = dwBytesInRes = memfile.Size();\r
- }\r
-#endif //CXIMAGE_SUPPORT_PNG\r
-\r
- if (!bAppend){\r
- icon_header.idType = ntohs(icon_header.idType);\r
- icon_header.idCount = ntohs(icon_header.idCount);\r
- hFile->Write(&icon_header,sizeof(ICONHEADER),1); //write the file header\r
- icon_header.idType = ntohs(icon_header.idType);\r
- icon_header.idCount = ntohs(icon_header.idCount);\r
- }\r
-\r
-\r
- if ((bAppend && nPageCount==info.nNumFrames) || (!bAppend && nPageCount==0)){\r
- icon_list.wPlanes = ntohs(icon_list.wPlanes);\r
- icon_list.wBitCount = ntohs(icon_list.wBitCount);\r
- icon_list.dwBytesInRes = ntohl(icon_list.dwBytesInRes);\r
- icon_list.dwImageOffset = ntohl(icon_list.dwImageOffset);\r
- hFile->Write(&icon_list,sizeof(ICONDIRENTRY),1); //write the image entry\r
- icon_list.wPlanes = ntohs(icon_list.wPlanes);\r
- icon_list.wBitCount = ntohs(icon_list.wBitCount);\r
- icon_list.dwBytesInRes = ntohl(icon_list.dwBytesInRes);\r
- icon_list.dwImageOffset = ntohl(icon_list.dwImageOffset);\r
-\r
- m_dwImageOffset += dwBytesInRes; //update offset for next header\r
- }\r
-\r
- if ((bAppend && nPageCount<info.nNumFrames) || (!bAppend && nPageCount==0))\r
- {\r
-#if CXIMAGE_SUPPORT_PNG\r
- if (icon_list.bWidth==0 && icon_list.bHeight==0) { // Vista icon support\r
- hFile->Write(memfile.GetBuffer(false),dwBytesInRes,1);\r
- } else\r
-#endif //CXIMAGE_SUPPORT_PNG\r
- { // standard icon\r
- bihtoh(&bi);\r
- hFile->Write(&bi,sizeof(BITMAPINFOHEADER),1); //write the image header\r
- bihtoh(&bi);\r
-\r
- bool bTransparent = info.nBkgndIndex >= 0;\r
- RGBQUAD ct = GetTransColor();\r
- if (pal){\r
- if (bTransparent) SetPaletteColor((BYTE)info.nBkgndIndex,0,0,0,0);\r
- hFile->Write(pal,head.biClrUsed*sizeof(RGBQUAD),1); //write palette\r
- if (bTransparent) SetPaletteColor((BYTE)info.nBkgndIndex,ct);\r
- }\r
-\r
-#if CXIMAGE_SUPPORT_ALPHA\r
- if (AlphaIsValid() && head.biClrUsed==0){\r
- BYTE* buf=(BYTE*)malloc(imagesize);\r
- BYTE* dst = buf;\r
- for (long y = 0; y < head.biHeight; y++) {\r
- BYTE* src = GetBits(y);\r
- for(long x=0;x<head.biWidth;x++){\r
- *dst++=*src++;\r
- *dst++=*src++;\r
- *dst++=*src++;\r
- *dst++=AlphaGet(x,y);\r
- }\r
- }\r
- hFile->Write(buf,imagesize, 1);\r
- free(buf);\r
- } else {\r
- hFile->Write(info.pImage,imagesize,1); //write image\r
- }\r
-#else\r
- hFile->Write(info.pImage,imagesize,1); //write image\r
-#endif\r
-\r
- //save transparency mask\r
- BYTE* mask=(BYTE*)calloc(masksize,1); //create empty AND/XOR masks\r
- if (!mask) return false;\r
-\r
- //prepare the variables to build the mask\r
- BYTE* iDst;\r
- int pos,i;\r
- RGBQUAD c={0,0,0,0};\r
- long* pc = (long*)&c;\r
- long* pct= (long*)&ct;\r
-#if CXIMAGE_SUPPORT_ALPHA\r
- bool bAlphaPaletteIsValid = AlphaPaletteIsValid();\r
- bool bAlphaIsValid = AlphaIsValid();\r
-#endif\r
- //build the mask\r
- for (int y = 0; y < head.biHeight; y++) {\r
- for (int x = 0; x < head.biWidth; x++) {\r
- i=0;\r
-#if CXIMAGE_SUPPORT_ALPHA\r
- if (bAlphaIsValid && AlphaGet(x,y)==0) i=1;\r
- if (bAlphaPaletteIsValid && BlindGetPixelColor(x,y).rgbReserved==0) i=1;\r
-#endif\r
- c=GetPixelColor(x,y,false);\r
- if (bTransparent && *pc==*pct) i=1;\r
- iDst = mask + y*maskwdt + (x>>3);\r
- pos = 7-x%8;\r
- *iDst &= ~(0x01<<pos);\r
- *iDst |= ((i & 0x01)<<pos);\r
- }\r
- }\r
- //write AND/XOR masks\r
- hFile->Write(mask,masksize,1);\r
- free(mask);\r
- }\r
- }\r
-\r
- return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif // CXIMAGE_SUPPORT_ENCODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif // CXIMAGE_SUPPORT_ICO\r
-\r
+/*
+ * File: ximaico.cpp
+ * Purpose: Platform Independent ICON Image Class Loader and Writer (MS version)
+ * 07/Aug/2001 Davide Pizzolato - www.xdp.it
+ * CxImage version 6.0.0 02/Feb/2008
+ */
+
+#include "ximaico.h"
+
+#if CXIMAGE_SUPPORT_ICO
+
+////////////////////////////////////////////////////////////////////////////////
+#if CXIMAGE_SUPPORT_DECODE
+////////////////////////////////////////////////////////////////////////////////
+bool CxImageICO::Decode(CxFile *hFile)
+{
+ if (hFile==NULL) return false;
+
+ DWORD off = hFile->Tell(); //<yuandi>
+ int page=info.nFrame; //internal icon structure indexes
+
+ // read the first part of the header
+ ICONHEADER icon_header;
+ hFile->Read(&icon_header,sizeof(ICONHEADER),1);
+
+ icon_header.idType = ntohs(icon_header.idType);
+ icon_header.idCount = ntohs(icon_header.idCount);
+
+ // check if it's an icon or a cursor
+ if ((icon_header.idReserved == 0) && ((icon_header.idType == 1)||(icon_header.idType == 2))) {
+
+ info.nNumFrames = icon_header.idCount;
+
+ // load the icon descriptions
+ ICONDIRENTRY *icon_list = (ICONDIRENTRY *)malloc(icon_header.idCount * sizeof(ICONDIRENTRY));
+ int c;
+ for (c = 0; c < icon_header.idCount; c++) {
+ hFile->Read(icon_list + c, sizeof(ICONDIRENTRY), 1);
+
+ icon_list[c].wPlanes = ntohs(icon_list[c].wPlanes);
+ icon_list[c].wBitCount = ntohs(icon_list[c].wBitCount);
+ icon_list[c].dwBytesInRes = ntohl(icon_list[c].dwBytesInRes);
+ icon_list[c].dwImageOffset = ntohl(icon_list[c].dwImageOffset);
+ }
+
+ if ((page>=0)&&(page<icon_header.idCount)){
+
+ if (info.nEscape == -1) {
+ // Return output dimensions only
+ head.biWidth = icon_list[page].bWidth;
+ head.biHeight = icon_list[page].bHeight;
+#if CXIMAGE_SUPPORT_PNG
+ if (head.biWidth==0 && head.biHeight==0)
+ { // Vista icon support
+ hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET);
+ CxImage png;
+ png.SetEscape(-1);
+ if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){
+ Transfer(png);
+ info.nNumFrames = icon_header.idCount;
+ }
+ }
+#endif //CXIMAGE_SUPPORT_PNG
+ free(icon_list);
+ info.dwType = CXIMAGE_FORMAT_ICO;
+ return true;
+ }
+
+ // get the bit count for the colors in the icon <CoreyRLucier>
+ BITMAPINFOHEADER bih;
+ hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET);
+
+ if (icon_list[page].bWidth==0 && icon_list[page].bHeight==0)
+ { // Vista icon support
+#if CXIMAGE_SUPPORT_PNG
+ CxImage png;
+ if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){
+ Transfer(png);
+ info.nNumFrames = icon_header.idCount;
+ }
+ SetType(CXIMAGE_FORMAT_ICO);
+#endif //CXIMAGE_SUPPORT_PNG
+ }
+ else
+ { // standard icon
+ hFile->Read(&bih,sizeof(BITMAPINFOHEADER),1);
+
+ bihtoh(&bih);
+
+ c = bih.biBitCount;
+
+ // allocate memory for one icon
+ Create(icon_list[page].bWidth,icon_list[page].bHeight, c, CXIMAGE_FORMAT_ICO); //image creation
+
+ // read the palette
+ RGBQUAD pal[256];
+ if (bih.biClrUsed)
+ hFile->Read(pal,bih.biClrUsed*sizeof(RGBQUAD), 1);
+ else
+ hFile->Read(pal,head.biClrUsed*sizeof(RGBQUAD), 1);
+
+ SetPalette(pal,head.biClrUsed); //palette assign
+
+ //read the icon
+ if (c<=24){
+ hFile->Read(info.pImage, head.biSizeImage, 1);
+ } else { // 32 bit icon
+ BYTE* buf=(BYTE*)malloc(4*head.biHeight*head.biWidth);
+ BYTE* src = buf;
+ hFile->Read(buf, 4*head.biHeight*head.biWidth, 1);
+#if CXIMAGE_SUPPORT_ALPHA
+ if (!AlphaIsValid()) AlphaCreate();
+#endif //CXIMAGE_SUPPORT_ALPHA
+ for (long y = 0; y < head.biHeight; y++) {
+ BYTE* dst = GetBits(y);
+ for(long x=0;x<head.biWidth;x++){
+ *dst++=src[0];
+ *dst++=src[1];
+ *dst++=src[2];
+#if CXIMAGE_SUPPORT_ALPHA
+ AlphaSet(x,y,src[3]);
+#endif //CXIMAGE_SUPPORT_ALPHA
+ src+=4;
+ }
+ }
+ free(buf);
+ }
+ // apply the AND and XOR masks
+ int maskwdt = ((head.biWidth+31) / 32) * 4; //line width of AND mask (always 1 Bpp)
+ int masksize = head.biHeight * maskwdt; //size of mask
+ BYTE *mask = (BYTE *)malloc(masksize);
+ if (hFile->Read(mask, masksize, 1)){
+
+ bool bGoodMask=false;
+ for (int im=0;im<masksize;im++){
+ if (mask[im]!=255){
+ bGoodMask=true;
+ break;
+ }
+ }
+
+ if (bGoodMask){
+#if CXIMAGE_SUPPORT_ALPHA
+ bool bNeedAlpha = false;
+ if (!AlphaIsValid()){
+ AlphaCreate();
+ } else {
+ bNeedAlpha=true; //32bit icon
+ }
+ int x,y;
+ for (y = 0; y < head.biHeight; y++) {
+ for (x = 0; x < head.biWidth; x++) {
+ if (((mask[y*maskwdt+(x>>3)]>>(7-x%8))&0x01)){
+ AlphaSet(x,y,0);
+ bNeedAlpha=true;
+ }
+ }
+ }
+ if (!bNeedAlpha) AlphaDelete();
+#endif //CXIMAGE_SUPPORT_ALPHA
+
+ //check if there is only one transparent color
+ RGBQUAD cc,ct;
+ long* pcc = (long*)&cc;
+ long* pct = (long*)&ct;
+ int nTransColors=0;
+ int nTransIndex=0;
+ for (y = 0; y < head.biHeight; y++){
+ for (x = 0; x < head.biWidth; x++){
+ if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){
+ cc = GetPixelColor(x,y,false);
+ if (nTransColors==0){
+ nTransIndex = GetPixelIndex(x,y);
+ nTransColors++;
+ ct = cc;
+ } else {
+ if (*pct!=*pcc){
+ nTransColors++;
+ }
+ }
+ }
+ }
+ }
+ if (nTransColors==1){
+ SetTransColor(ct);
+ SetTransIndex(nTransIndex);
+#if CXIMAGE_SUPPORT_ALPHA
+ AlphaDelete(); //because we have a unique transparent color in the image
+#endif //CXIMAGE_SUPPORT_ALPHA
+ }
+
+ // <vho> - Transparency support w/o Alpha support
+ if (c <= 8){ // only for icons with less than 256 colors (XP icons need alpha).
+
+ // find a color index, which is not used in the image
+ // it is almost sure to find one, bcs. nobody uses all possible colors for an icon
+
+ BYTE colorsUsed[256];
+ memset(colorsUsed, 0, sizeof(colorsUsed));
+
+ for (y = 0; y < head.biHeight; y++){
+ for (x = 0; x < head.biWidth; x++){
+ colorsUsed[BlindGetPixelIndex(x,y)] = 1;
+ }
+ }
+
+ int iTransIdx = -1;
+ for (x = (int)(head.biClrUsed-1); x>=0 ; x--){
+ if (colorsUsed[x] == 0){
+ iTransIdx = x; // this one is not in use. we may use it as transparent color
+ break;
+ }
+ }
+
+ // Go thru image and set unused color as transparent index if needed
+ if (iTransIdx >= 0){
+ bool bNeedTrans = false;
+ for (y = 0; y < head.biHeight; y++){
+ for (x = 0; x < head.biWidth; x++){
+ // AND mask (Each Byte represents 8 Pixels)
+ if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){
+ // AND mask is set (!=0). This is a transparent part
+ SetPixelIndex(x, y, (BYTE)iTransIdx);
+ bNeedTrans = true;
+ }
+ }
+ }
+ // set transparent index if needed
+ if (bNeedTrans) SetTransIndex(iTransIdx);
+#if CXIMAGE_SUPPORT_ALPHA
+ AlphaDelete(); //because we have a transparent color in the palette
+#endif //CXIMAGE_SUPPORT_ALPHA
+ }
+ }
+ } else {
+ SetTransIndex(0); //empty mask, set black as transparent color
+ Negative();
+ }
+ }
+ free(mask);
+ }
+ free(icon_list);
+ // icon has been loaded successfully!
+ return true;
+ }
+ free(icon_list);
+ }
+ return false;
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif //CXIMAGE_SUPPORT_DECODE
+////////////////////////////////////////////////////////////////////////////////
+#if CXIMAGE_SUPPORT_ENCODE
+////////////////////////////////////////////////////////////////////////////////
+// Thanks to <Alas>
+bool CxImageICO::Encode(CxFile * hFile, CxImage ** pImages, int nPageCount)
+{
+ cx_try
+ {
+ if (hFile==NULL) cx_throw("invalid file pointer");
+ if (pImages==NULL || nPageCount<=0) cx_throw("multipage ICO, no images!");
+
+ int i;
+ for (i=0; i<nPageCount; i++){
+ if (pImages[i]==NULL)
+ cx_throw("Bad image pointer");
+ if (!(pImages[i]->IsValid()))
+ cx_throw("Empty image");
+ }
+
+ CxImageICO ghost;
+ for (i=0; i<nPageCount; i++){ //write headers
+ ghost.Ghost(pImages[i]);
+ ghost.info.nNumFrames = nPageCount;
+ if (i==0) {
+ if (!ghost.Encode(hFile,false,nPageCount))
+ cx_throw("Error writing ICO file header");
+ }
+ if (!ghost.Encode(hFile,true,nPageCount))
+ cx_throw("Error saving ICO image header");
+ }
+ for (i=0; i<nPageCount; i++){ //write bodies
+ ghost.Ghost(pImages[i]);
+ ghost.info.nNumFrames = nPageCount;
+ if (!ghost.Encode(hFile,true,i))
+ cx_throw("Error saving ICO body");
+ }
+
+ } cx_catch {
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);
+ return false;
+ }
+ return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+bool CxImageICO::Encode(CxFile * hFile, bool bAppend, int nPageCount)
+{
+ if (EncodeSafeCheck(hFile)) return false;
+
+#if CXIMAGE_SUPPORT_PNG == 0
+ //check format limits
+ if ((head.biWidth>255)||(head.biHeight>255)){
+ strcpy(info.szLastError,"Can't save this image as icon");
+ return false;
+ }
+#endif
+
+ //prepare the palette struct
+ RGBQUAD* pal=GetPalette();
+ if (head.biBitCount<=8 && pal==NULL) return false;
+
+ int maskwdt=((head.biWidth+31)/32)*4; //mask line width
+ int masksize=head.biHeight * maskwdt; //size of mask
+ int bitcount=head.biBitCount;
+ int imagesize=head.biSizeImage;
+#if CXIMAGE_SUPPORT_ALPHA
+ if (AlphaIsValid() && head.biClrUsed==0){
+ bitcount=32;
+ imagesize=4*head.biHeight*head.biWidth;
+ }
+#endif
+
+ //fill the icon headers
+ int nPages = nPageCount;
+ if (nPages<1) nPages = 1;
+
+ ICONHEADER icon_header={0,1,nPages};
+
+ if (!bAppend)
+ m_dwImageOffset = sizeof(ICONHEADER) + nPages * sizeof(ICONDIRENTRY);
+
+ DWORD dwBytesInRes = sizeof(BITMAPINFOHEADER)+head.biClrUsed*sizeof(RGBQUAD)+imagesize+masksize;
+
+ ICONDIRENTRY icon_list={
+ (BYTE)head.biWidth,
+ (BYTE)head.biHeight,
+ (BYTE)head.biClrUsed,
+ 0, 0,
+ (WORD)bitcount,
+ dwBytesInRes,
+ m_dwImageOffset
+ };
+
+ BITMAPINFOHEADER bi={
+ sizeof(BITMAPINFOHEADER),
+ head.biWidth,
+ 2*head.biHeight,
+ 1,
+ (WORD)bitcount,
+ 0, imagesize,
+ 0, 0, 0, 0
+ };
+
+#if CXIMAGE_SUPPORT_PNG // Vista icon support
+ CxImage png(*this);
+ CxMemFile memfile;
+ if (head.biWidth>255 || head.biHeight>255){
+ icon_list.bWidth = icon_list.bHeight = 0;
+ memfile.Open();
+ png.Encode(&memfile,CXIMAGE_FORMAT_PNG);
+ icon_list.dwBytesInRes = dwBytesInRes = memfile.Size();
+ }
+#endif //CXIMAGE_SUPPORT_PNG
+
+ if (!bAppend){
+ icon_header.idType = ntohs(icon_header.idType);
+ icon_header.idCount = ntohs(icon_header.idCount);
+ hFile->Write(&icon_header,sizeof(ICONHEADER),1); //write the file header
+ icon_header.idType = ntohs(icon_header.idType);
+ icon_header.idCount = ntohs(icon_header.idCount);
+ }
+
+
+ if ((bAppend && nPageCount==info.nNumFrames) || (!bAppend && nPageCount==0)){
+ icon_list.wPlanes = ntohs(icon_list.wPlanes);
+ icon_list.wBitCount = ntohs(icon_list.wBitCount);
+ icon_list.dwBytesInRes = ntohl(icon_list.dwBytesInRes);
+ icon_list.dwImageOffset = ntohl(icon_list.dwImageOffset);
+ hFile->Write(&icon_list,sizeof(ICONDIRENTRY),1); //write the image entry
+ icon_list.wPlanes = ntohs(icon_list.wPlanes);
+ icon_list.wBitCount = ntohs(icon_list.wBitCount);
+ icon_list.dwBytesInRes = ntohl(icon_list.dwBytesInRes);
+ icon_list.dwImageOffset = ntohl(icon_list.dwImageOffset);
+
+ m_dwImageOffset += dwBytesInRes; //update offset for next header
+ }
+
+ if ((bAppend && nPageCount<info.nNumFrames) || (!bAppend && nPageCount==0))
+ {
+#if CXIMAGE_SUPPORT_PNG
+ if (icon_list.bWidth==0 && icon_list.bHeight==0) { // Vista icon support
+ hFile->Write(memfile.GetBuffer(false),dwBytesInRes,1);
+ } else
+#endif //CXIMAGE_SUPPORT_PNG
+ { // standard icon
+ bihtoh(&bi);
+ hFile->Write(&bi,sizeof(BITMAPINFOHEADER),1); //write the image header
+ bihtoh(&bi);
+
+ bool bTransparent = info.nBkgndIndex >= 0;
+ RGBQUAD ct = GetTransColor();
+ if (pal){
+ if (bTransparent) SetPaletteColor((BYTE)info.nBkgndIndex,0,0,0,0);
+ hFile->Write(pal,head.biClrUsed*sizeof(RGBQUAD),1); //write palette
+ if (bTransparent) SetPaletteColor((BYTE)info.nBkgndIndex,ct);
+ }
+
+#if CXIMAGE_SUPPORT_ALPHA
+ if (AlphaIsValid() && head.biClrUsed==0){
+ BYTE* buf=(BYTE*)malloc(imagesize);
+ BYTE* dst = buf;
+ for (long y = 0; y < head.biHeight; y++) {
+ BYTE* src = GetBits(y);
+ for(long x=0;x<head.biWidth;x++){
+ *dst++=*src++;
+ *dst++=*src++;
+ *dst++=*src++;
+ *dst++=AlphaGet(x,y);
+ }
+ }
+ hFile->Write(buf,imagesize, 1);
+ free(buf);
+ } else {
+ hFile->Write(info.pImage,imagesize,1); //write image
+ }
+#else
+ hFile->Write(info.pImage,imagesize,1); //write image
+#endif
+
+ //save transparency mask
+ BYTE* mask=(BYTE*)calloc(masksize,1); //create empty AND/XOR masks
+ if (!mask) return false;
+
+ //prepare the variables to build the mask
+ BYTE* iDst;
+ int pos,i;
+ RGBQUAD c={0,0,0,0};
+ long* pc = (long*)&c;
+ long* pct= (long*)&ct;
+#if CXIMAGE_SUPPORT_ALPHA
+ bool bAlphaPaletteIsValid = AlphaPaletteIsValid();
+ bool bAlphaIsValid = AlphaIsValid();
+#endif
+ //build the mask
+ for (int y = 0; y < head.biHeight; y++) {
+ for (int x = 0; x < head.biWidth; x++) {
+ i=0;
+#if CXIMAGE_SUPPORT_ALPHA
+ if (bAlphaIsValid && AlphaGet(x,y)==0) i=1;
+ if (bAlphaPaletteIsValid && BlindGetPixelColor(x,y).rgbReserved==0) i=1;
+#endif
+ c=GetPixelColor(x,y,false);
+ if (bTransparent && *pc==*pct) i=1;
+ iDst = mask + y*maskwdt + (x>>3);
+ pos = 7-x%8;
+ *iDst &= ~(0x01<<pos);
+ *iDst |= ((i & 0x01)<<pos);
+ }
+ }
+ //write AND/XOR masks
+ hFile->Write(mask,masksize,1);
+ free(mask);
+ }
+ }
+
+ return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif // CXIMAGE_SUPPORT_ENCODE
+////////////////////////////////////////////////////////////////////////////////
+#endif // CXIMAGE_SUPPORT_ICO
+