]> Creatis software - clitk.git/blobdiff - utilities/CxImage/ximaico.cpp
cosmetic
[clitk.git] / utilities / CxImage / ximaico.cpp
index 0cb3b060f2895fb7420fedcb6b2bbb1568540b70..8ae5047d20c4d241eefbcd3a2180cf4548e88306 100644 (file)
-/*\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
+