Click here to Skip to main content
15,886,199 members
Articles / Desktop Programming / MFC

WaterMarker

Rate me:
Please Sign up or sign in to vote.
4.75/5 (17 votes)
5 Apr 2006Zlib5 min read 103.8K   3K   64  
An utility to protect yout pictures with a stamp bitmap.
/*
 * 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

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The zlib/libpng License


Written By
Software Developer
France France
KOCH David, 41 years old
Coder (embedded, C/C++, ASM, Erlang)

Comments and Discussions