| /* |
| * File: ximaico.cpp |
| * Purpose: Platform Independent ICON Image Class Loader and Writer (MS version) |
| * 07/Aug/2001 Davide Pizzolato - www.xdp.it |
| * CxImage version 5.99c 17/Oct/2004 |
| */ |
| |
| #include "ximaico.h" |
| |
| #if CXIMAGE_SUPPORT_ICO |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| 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); |
| // 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); |
| |
| if ((page>=0)&&(page<icon_header.idCount)){ |
| |
| // get the bit count for the colors in the icon <CoreyRLucier> |
| BITMAPINFOHEADER bih; |
| hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET); |
| hFile->Read(&bih,sizeof(BITMAPINFOHEADER),1); |
| 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]; |
| 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* dst = info.pImage; |
| 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++) { |
| 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 |
| } |
| for (int y = 0; y < head.biHeight; y++) { |
| for (int 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 |
| |
| if (c==24){ //check if there is only one transparent color |
| RGBQUAD cc,ct; |
| long* pcc = (long*)&cc; |
| long* pct = (long*)&ct; |
| int nTransColors=0; |
| for (int y = 0; y < head.biHeight; y++){ |
| for (int x = 0; x < head.biWidth; x++){ |
| if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){ |
| cc = GetPixelColor(x,y,false); |
| if (nTransColors==0){ |
| nTransColors++; |
| ct = cc; |
| } else { |
| if (*pct!=*pcc){ |
| nTransColors++; |
| } |
| } |
| } |
| } |
| } |
| if (nTransColors==1){ |
| SetTransColor(ct); |
| SetTransIndex(0); |
| #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 (int y = 0; y < head.biHeight; y++){ |
| for (int x = 0; x < head.biWidth; x++){ |
| colorsUsed[GetPixelIndex(x,y)] = 1; |
| } |
| } |
| |
| int iTransIdx = -1; |
| for (int x = 0; x < (int)head.biClrUsed; 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 (int y = 0; y < head.biHeight; y++){ |
| for (int 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, 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; |
| } |
| //////////////////////////////////////////////////////////////////////////////// |
| #if CXIMAGE_SUPPORT_ENCODE |
| //////////////////////////////////////////////////////////////////////////////// |
| bool CxImageICO::Encode(CxFile * hFile) |
| { |
| if (EncodeSafeCheck(hFile)) return false; |
| |
| //check format limits |
| if ((head.biWidth>255)||(head.biHeight>255)){ |
| strcpy(info.szLastError,"Can't save this image as icon"); |
| return false; |
| } |
| |
| //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 |
| ICONHEADER icon_header={0,1,1}; |
| ICONDIRENTRY icon_list={(BYTE)head.biWidth,(BYTE)head.biHeight,(BYTE)head.biClrUsed ,0,0,(WORD)bitcount, |
| sizeof(BITMAPINFOHEADER)+head.biClrUsed*sizeof(RGBQUAD)+ |
| imagesize+masksize, |
| sizeof(ICONHEADER)+sizeof(ICONDIRENTRY)}; |
| BITMAPINFOHEADER bi={sizeof(BITMAPINFOHEADER),head.biWidth,2*head.biHeight,1,(WORD)bitcount, |
| 0,imagesize,0,0,0,0}; |
| |
| hFile->Write(&icon_header,sizeof(ICONHEADER),1); //write the headers |
| hFile->Write(&icon_list,sizeof(ICONDIRENTRY),1); |
| hFile->Write(&bi,sizeof(BITMAPINFOHEADER),1); |
| if (pal) hFile->Write(pal,head.biClrUsed*sizeof(RGBQUAD),1); //write palette |
| |
| #if CXIMAGE_SUPPORT_ALPHA |
| if (AlphaIsValid() && head.biClrUsed==0){ |
| BYTE* src = info.pImage; |
| BYTE* buf=(BYTE*)malloc(imagesize); |
| BYTE* dst = buf; |
| for (long y = 0; y < head.biHeight; 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}; |
| RGBQUAD ct = GetTransColor(); |
| long* pc = (long*)&c; |
| long* pct= (long*)&ct; |
| bool bTransparent = info.nBkgndIndex != -1; |
| #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 && GetPixelColor(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 |
| |