/* * File: ximaico.cpp * Purpose: Platform Independent ICON Image Class Loader and Writer (MS version) * 07/Aug/2001 Davide Pizzolato - www.xdp.it * CxImage version 7.0.0 31/Dec/2010 */ #include "ximaico.h" #if CXIMAGE_SUPPORT_ICO //////////////////////////////////////////////////////////////////////////////// #if CXIMAGE_SUPPORT_DECODE //////////////////////////////////////////////////////////////////////////////// bool CxImageICO::Decode(CxFile *hFile) { if (hFile==NULL) return false; uint32_t off = hFile->Tell(); // int32_t 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 = m_ntohs(icon_header.idType); icon_header.idCount = m_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)); int32_t c; for (c = 0; c < icon_header.idCount; c++) { hFile->Read(icon_list + c, sizeof(ICONDIRENTRY), 1); icon_list[c].wPlanes = m_ntohs(icon_list[c].wPlanes); icon_list[c].wBitCount = m_ntohs(icon_list[c].wBitCount); icon_list[c].dwBytesInRes = m_ntohl(icon_list[c].dwBytesInRes); icon_list[c].dwImageOffset = m_ntohl(icon_list[c].dwImageOffset); } if ((page>=0)&&(pageSeek(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 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 uint8_t* buf=(uint8_t*)malloc(4*head.biHeight*head.biWidth); uint8_t* src = buf; hFile->Read(buf, 4*head.biHeight*head.biWidth, 1); #if CXIMAGE_SUPPORT_ALPHA if (!AlphaIsValid()) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA for (int32_t y = 0; y < head.biHeight; y++) { uint8_t* dst = GetBits(y); for(int32_t x=0;xRead(mask, masksize, 1)){ bool bGoodMask=false; for (int32_t im=0;im>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; int32_t nTransColors=0; int32_t 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 (memcmp(&cc, &ct, sizeof(RGBQUAD)) != 0){ nTransColors++; } } } } } if (nTransColors==1 && c<=8){ SetTransColor(ct); SetTransIndex(nTransIndex); #if CXIMAGE_SUPPORT_ALPHA AlphaDelete(); //because we have a unique transparent color in the image #endif //CXIMAGE_SUPPORT_ALPHA } // - 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 uint8_t 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; } } int32_t iTransIdx = -1; for (x = (int32_t)(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, (uint8_t)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 bool CxImageICO::Encode(CxFile * hFile, CxImage ** pImages, int32_t nPageCount) { cx_try { if (hFile==NULL) cx_throw("invalid file pointer"); if (pImages==NULL || nPageCount<=0) cx_throw("multipage ICO, no images!"); int32_t i; for (i=0; iIsValid())) cx_throw("Empty image"); } CxImageICO ghost; for (i=0; i255)||(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; int32_t maskwdt=((head.biWidth+31)/32)*4; //mask line width int32_t masksize=head.biHeight * maskwdt; //size of mask int32_t bitcount=head.biBitCount; int32_t 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 int32_t nPages = nPageCount; if (nPages<1) nPages = 1; ICONHEADER icon_header={0,1,nPages}; if (!bAppend) m_dwImageOffset = sizeof(ICONHEADER) + nPages * sizeof(ICONDIRENTRY); uint32_t dwBytesInRes = sizeof(BITMAPINFOHEADER)+head.biClrUsed*sizeof(RGBQUAD)+imagesize+masksize; ICONDIRENTRY icon_list={ (uint8_t)head.biWidth, (uint8_t)head.biHeight, (uint8_t)head.biClrUsed, 0, 0, (uint16_t)bitcount, dwBytesInRes, m_dwImageOffset }; BITMAPINFOHEADER bi={ sizeof(BITMAPINFOHEADER), head.biWidth, 2*head.biHeight, 1, (uint16_t)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 = m_ntohs(icon_header.idType); icon_header.idCount = m_ntohs(icon_header.idCount); hFile->Write(&icon_header,sizeof(ICONHEADER),1); //write the file header icon_header.idType = m_ntohs(icon_header.idType); icon_header.idCount = m_ntohs(icon_header.idCount); } if ((bAppend && nPageCount==info.nNumFrames) || (!bAppend && nPageCount==0)){ icon_list.wPlanes = m_ntohs(icon_list.wPlanes); icon_list.wBitCount = m_ntohs(icon_list.wBitCount); icon_list.dwBytesInRes = m_ntohl(icon_list.dwBytesInRes); icon_list.dwImageOffset = m_ntohl(icon_list.dwImageOffset); hFile->Write(&icon_list,sizeof(ICONDIRENTRY),1); //write the image entry icon_list.wPlanes = m_ntohs(icon_list.wPlanes); icon_list.wBitCount = m_ntohs(icon_list.wBitCount); icon_list.dwBytesInRes = m_ntohl(icon_list.dwBytesInRes); icon_list.dwImageOffset = m_ntohl(icon_list.dwImageOffset); m_dwImageOffset += dwBytesInRes; //update offset for next header } if ((bAppend && nPageCountWrite(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((uint8_t)info.nBkgndIndex,0,0,0,0); hFile->Write(pal,head.biClrUsed*sizeof(RGBQUAD),1); //write palette if (bTransparent) SetPaletteColor((uint8_t)info.nBkgndIndex,ct); } #if CXIMAGE_SUPPORT_ALPHA if (AlphaIsValid() && head.biClrUsed==0){ uint8_t* buf=(uint8_t*)malloc(imagesize); uint8_t* dst = buf; for (int32_t y = 0; y < head.biHeight; y++) { uint8_t* src = GetBits(y); for(int32_t x=0;xWrite(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 uint8_t* mask=(uint8_t*)calloc(masksize,1); //create empty AND/XOR masks if (!mask) return false; //prepare the variables to build the mask uint8_t* iDst; int32_t pos,i; RGBQUAD c={0,0,0,0}; int32_t* pc = (int32_t*)&c; int32_t* pct= (int32_t*)&ct; #if CXIMAGE_SUPPORT_ALPHA bool bAlphaPaletteIsValid = AlphaPaletteIsValid(); bool bAlphaIsValid = AlphaIsValid(); #endif //build the mask for (int32_t y = 0; y < head.biHeight; y++) { for (int32_t 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<Write(mask,masksize,1); free(mask); } } return true; } //////////////////////////////////////////////////////////////////////////////// #endif // CXIMAGE_SUPPORT_ENCODE //////////////////////////////////////////////////////////////////////////////// #endif // CXIMAGE_SUPPORT_ICO