www.pudn.com > CXIMAGE_SRC.ZIP > ximaico.cpp


/* 
 * File:	ximaico.cpp 
 * Purpose:	Platform Independent ICON Image Class Loader and Writer (MS version) 
 * 07/Aug/2001  
 * CxImage version 5.00 23/Aug/2002 
 */ 
 
#include "ximaico.h" 
 
#if CXIMAGE_SUPPORT_ICO 
 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImageICO::Decode(CxFile *hFile) 
{ 
	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 
	if ((icon_header.idReserved == 0) && (icon_header.idType == 1)) { 
 
		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 ((info.nFrame>=0)&&(info.nFrame 8)  c=icon_list[page].wBitCount; 
			else if (icon_list[page].bColorCount == 0)  c=8; 
			else if (icon_list[page].bColorCount <= 2)  c=1; 
			else if (icon_list[page].bColorCount <= 16) c=4; 
			else c=8; 
			// 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->Seek(icon_list[page].dwImageOffset+sizeof(BITMAPINFOHEADER), SEEK_SET); 
			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 (!HasAlpha()) AlphaCreate(); 
#endif //CXIMAGE_SUPPORT_ALPHA 
				for (long y = 0; y < head.biHeight; y++) { 
					for(long x=0;xRead(mask, c, 1); 
			bool bNeedAlpha = false; 
			if (!HasAlpha()){ 
				AlphaCreate(); 
				AlphaSet(255); 
			} 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(); 
			free(mask); 
 
#else // : CXIMAGE_SUPPORT_ALPHA == 0 
 
			//  - Transparency support w/o Alpha support 
			if (c <= 8){ // only for icons with less than 256 colors (XP icons need alpha). 
				   
				// Calculate size and read AND-mask now 
				int maskwdt = ((head.biWidth+31) / 32) * 4;	//line width of AND mask (always 1 Bpp) 
				c = head.biHeight * maskwdt;				//size of mask 
				BYTE *mask = (BYTE *)malloc(c); 
				hFile->Read(mask, c, 1); 
 
				// 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 (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); 
				} 
				free(mask); 
			} 
 
#endif //CXIMAGE_SUPPORT_ALPHA 
 
			free(icon_list); 
			// icon has been loaded successfully! 
			return true; 
		} 
		free(icon_list); 
	} 
	return false; 
} 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImageICO::Encode(CxFile * hFile) 
{ 
	if (hFile==NULL) 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 (HasAlpha() && 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 (HasAlpha() && 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;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 
	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 bHasAlphaPalette = HasAlphaPalette(); 
	bool bHasAlpha = HasAlpha(); 
#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 (bHasAlpha && AlphaGet(x,y)==0) i=1; 
			if (bHasAlphaPalette && GetPixelColor(x,y).rgbReserved==0) i=1; 
#endif 
			c=GetPixelColor(x,y); 
			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_ICO