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


// xImaTran.cpp : Transformation functions 
/* 07/08/2001 v1.00 - ing.davide.pizzolato@libero.it 
 * CxImage version 5.00 23/Aug/2002 
 */ 
 
#include "ximage.h" 
 
#if CXIMAGE_SUPPORT_BASICTRANSFORMATIONS 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::GrayScale() 
{ 
	if (!pDib) return false; 
	if (head.biBitCount<=8){ 
		RGBQUAD* ppal=GetPalette(); 
		int gray; 
		//converts the colors to gray, use the blue channel only 
		for(DWORD i=0;iinfo.pImage; 
    for(long y=0; y < head.biHeight; y++){ 
		memcpy(iDst,iSrc,info.dwEffWidth); 
		iSrc-=info.dwEffWidth; 
		iDst+=info.dwEffWidth; 
	} 
 
#if CXIMAGE_SUPPORT_ALPHA 
	imatmp->AlphaFlip(); 
#endif //CXIMAGE_SUPPORT_ALPHA 
 
	Transfer(*imatmp); 
	delete imatmp; 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::Mirror() 
{ 
	if (!pDib) return false; 
 
	CxImage* imatmp = new CxImage(*this,false,false,true); 
	if (!imatmp) return false; 
	BYTE *iSrc,*iDst; 
	long wdt=(head.biWidth-1) * (head.biBitCount==24 ? 3:1); 
	iSrc=info.pImage + wdt; 
	iDst=imatmp->info.pImage; 
	long x,y; 
	switch (head.biBitCount){ 
	case 24: 
		for(y=0; y < head.biHeight; y++){ 
			for(x=0; x <= wdt; x+=3){ 
				*(iDst+x)=*(iSrc-x); 
				*(iDst+x+1)=*(iSrc-x+1); 
				*(iDst+x+2)=*(iSrc-x+2); 
			} 
			iSrc+=info.dwEffWidth; 
			iDst+=info.dwEffWidth; 
		} 
		break; 
	case 8: 
		for(y=0; y < head.biHeight; y++){ 
			for(x=0; x <= wdt; x++) 
				*(iDst+x)=*(iSrc-x); 
			iSrc+=info.dwEffWidth; 
			iDst+=info.dwEffWidth; 
		} 
		break; 
	default: 
		for(y=0; y < head.biHeight; y++){ 
			for(x=0; x <= wdt; x++) 
				imatmp->SetPixelIndex(x,y,GetPixelIndex(wdt-x,y)); 
		} 
	} 
 
#if CXIMAGE_SUPPORT_ALPHA 
	imatmp->AlphaMirror(); 
#endif //CXIMAGE_SUPPORT_ALPHA 
 
	Transfer(*imatmp); 
	delete imatmp; 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::RotateLeft(CxImage* iDst) 
{ 
	if (!pDib) return false; 
 
	long newWidth = GetHeight(); 
	long newHeight = GetWidth(); 
 
	CxImage imgDest; 
	imgDest.CopyInfo(*this); 
	imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); 
	imgDest.SetPalette(GetPalette()); 
 
	long x,y,x2; 
	for (x = 0; x < newWidth; x++){ 
		x2=newWidth-x-1; 
		for (y = 0; y < newHeight; y++){ 
			if(head.biClrUsed==0)	//RGB 
				imgDest.SetPixelColor(x, y, GetPixelColor(y, x2)); 
			else					//PALETTE 
				imgDest.SetPixelIndex(x, y, GetPixelIndex(y, x2)); 
		} 
	} 
 
#if CXIMAGE_SUPPORT_ALPHA 
	if (HasAlpha()){ 
		imgDest.AlphaCreate(); 
		for (x = 0; x < newWidth; x++){ 
			x2=newWidth-x-1; 
			for (y = 0; y < newHeight; y++){ 
				imgDest.AlphaSet(x,y,AlphaGet(y, x2)); 
			} 
		} 
	} 
#endif //CXIMAGE_SUPPORT_ALPHA 
 
	//select the destination 
	if (iDst) iDst->Transfer(imgDest); 
	else Transfer(imgDest); 
	return true; 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::RotateRight(CxImage* iDst) 
{ 
	if (!pDib) return false; 
 
	long newWidth = GetHeight(); 
	long newHeight = GetWidth(); 
 
	CxImage imgDest; 
	imgDest.CopyInfo(*this); 
	imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); 
	imgDest.SetPalette(GetPalette()); 
 
	long x,y,y2; 
	for (y = 0; y < newHeight; y++){ 
		y2=newHeight-y-1; 
		for (x = 0; x < newWidth; x++){ 
			if(head.biClrUsed==0)	//RGB 
				imgDest.SetPixelColor(x, y, GetPixelColor(y2, x)); 
			else					//PALETTE 
				imgDest.SetPixelIndex(x, y, GetPixelIndex(y2, x)); 
		} 
	} 
 
#if CXIMAGE_SUPPORT_ALPHA 
	if (HasAlpha()){ 
		imgDest.AlphaCreate(); 
		for (y = 0; y < newHeight; y++){ 
			y2=newHeight-y-1; 
			for (x = 0; x < newWidth; x++){ 
				imgDest.AlphaSet(x,y,AlphaGet(y2, x)); 
			} 
		} 
	} 
#endif //CXIMAGE_SUPPORT_ALPHA 
 
	//select the destination 
	if (iDst) iDst->Transfer(imgDest); 
	else Transfer(imgDest); 
	return true; 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
#endif //CXIMAGE_SUPPORT_BASICTRANSFORMATIONS 
//////////////////////////////////////////////////////////////////////////////// 
#if CXIMAGE_SUPPORT_TRANSFORMATION 
//////////////////////////////////////////////////////////////////////////////// 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::Negative() 
{ 
	if (!pDib) return false; 
 
	if (head.biBitCount<=8){ 
		if (IsGrayScale()){ //GRAYSCALE, selection 
			if (pSelection){ 
				for(long y=info.rSelectionBox.bottom; y invert transparent color too 
		info.nBkgndColor.rgbBlue = (BYTE)(255-info.nBkgndColor.rgbBlue); 
		info.nBkgndColor.rgbGreen = (BYTE)(255-info.nBkgndColor.rgbGreen); 
		info.nBkgndColor.rgbRed = (BYTE)(255-info.nBkgndColor.rgbRed); 
	} 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::Rotate(float angle, CxImage* iDst) 
{ 
	if (!pDib) return false; 
 
//  $Id: FilterRotate.cpp,v 1.10 2000/12/18 22:42:53 uzadow Exp $ 
//  Copyright (c) 1996-1998 Ulrich von Zadow 
 
	// Negative the angle, because the y-axis is negative. 
	double ang = -angle*acos(0)/90; 
	int newWidth, newHeight; 
	int nWidth = GetWidth(); 
	int nHeight= GetHeight(); 
	double cos_angle = cos(ang); 
	double sin_angle = sin(ang); 
 
	// Calculate the size of the new bitmap 
	POINT p1={0,0}; 
	POINT p2={nWidth,0}; 
	POINT p3={0,nHeight}; 
	POINT p4={nWidth-1,nHeight}; 
	POINT newP1,newP2,newP3,newP4, leftTop, rightTop, leftBottom, rightBottom; 
 
	newP1.x = p1.x; 
	newP1.y = p1.y; 
	newP2.x = (long)(p2.x*cos_angle - p2.y*sin_angle); 
	newP2.y = (long)(p2.x*sin_angle + p2.y*cos_angle); 
	newP3.x = (long)(p3.x*cos_angle - p3.y*sin_angle); 
	newP3.y = (long)(p3.x*sin_angle + p3.y*cos_angle); 
	newP4.x = (long)(p4.x*cos_angle - p4.y*sin_angle); 
	newP4.y = (long)(p4.x*sin_angle + p4.y*cos_angle); 
 
	leftTop.x = min(min(newP1.x,newP2.x),min(newP3.x,newP4.x)); 
	leftTop.y = min(min(newP1.y,newP2.y),min(newP3.y,newP4.y)); 
	rightBottom.x = max(max(newP1.x,newP2.x),max(newP3.x,newP4.x)); 
	rightBottom.y = max(max(newP1.y,newP2.y),max(newP3.y,newP4.y)); 
	leftBottom.x = leftTop.x; 
	leftBottom.y = rightBottom.y; 
	rightTop.x = rightBottom.x; 
	rightTop.y = leftTop.y; 
 
	newWidth = rightTop.x - leftTop.x; 
	newHeight= leftBottom.y - leftTop.y; 
	CxImage imgDest; 
	imgDest.CopyInfo(*this); 
	imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); 
	imgDest.SetPalette(GetPalette()); 
 
#if CXIMAGE_SUPPORT_ALPHA 
	if(HasAlpha())	//MTA: Fix for rotation problem when the image has an alpha channel 
	{ 
		imgDest.AlphaCreate(); 
		imgDest.AlphaClear(); 
	} 
#endif //CXIMAGE_SUPPORT_ALPHA 
 
	int x,y,newX,newY,oldX,oldY; 
 
	if (head.biClrUsed==0){ //RGB 
		for (y = leftTop.y, newY = 0; y<=leftBottom.y; y++,newY++){ 
			info.nProgress = (long)(100*newY/newHeight); 
			if (info.nEscape) break; 
			for (x = leftTop.x, newX = 0; x<=rightTop.x; x++,newX++){ 
				oldX = (long)(x*cos_angle + y*sin_angle - 0.5); 
				oldY = (long)(y*cos_angle - x*sin_angle - 0.5); 
				imgDest.SetPixelColor(newX,newY,GetPixelColor(oldX,oldY)); 
#if CXIMAGE_SUPPORT_ALPHA 
				imgDest.AlphaSet(newX,newY,AlphaGet(oldX,oldY));				//MTA: copy the alpha value 
#endif //CXIMAGE_SUPPORT_ALPHA 
			} 
		} 
	} else { //PALETTE 
		for (y = leftTop.y, newY = 0; y<=leftBottom.y; y++,newY++){ 
			info.nProgress = (long)(100*newY/newHeight); 
			if (info.nEscape) break; 
			for (x = leftTop.x, newX = 0; x<=rightTop.x; x++,newX++){ 
				oldX = (long)(x*cos_angle + y*sin_angle - 0.5); 
				oldY = (long)(y*cos_angle - x*sin_angle - 0.5); 
				imgDest.SetPixelIndex(newX,newY,GetPixelIndex(oldX,oldY)); 
#if CXIMAGE_SUPPORT_ALPHA 
				imgDest.AlphaSet(newX,newY,AlphaGet(oldX,oldY));				//MTA: copy the alpha value 
#endif //CXIMAGE_SUPPORT_ALPHA 
			} 
		} 
	} 
	//select the destination 
	if (iDst) iDst->Transfer(imgDest); 
	else Transfer(imgDest); 
 
	return true; 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::Rotate180(CxImage* iDst) 
{ 
	if (!pDib) return false; 
 
	long wid = GetWidth(); 
	long ht = GetHeight(); 
 
	CxImage imgDest; 
	imgDest.CopyInfo(*this); 
	imgDest.Create(wid,ht,GetBpp(),GetType()); 
	imgDest.SetPalette(GetPalette()); 
 
	long x,y,y2; 
	for (y = 0; y < ht; y++){ 
		y2=ht-y-1; 
		for (x = 0; x < wid; x++){ 
			if(head.biClrUsed==0)//RGB 
				imgDest.SetPixelColor(wid-x-1, y2, GetPixelColor(x, y)); 
			else  //PALETTE 
				imgDest.SetPixelIndex(wid-x-1, y2, GetPixelIndex(x, y)); 
		} 
			 
	} 
 
#if CXIMAGE_SUPPORT_ALPHA 
	if (HasAlpha()){ 
		imgDest.AlphaCreate(); 
		for (y = 0; y < ht; y++){ 
			y2=ht-y-1; 
			for (x = 0; x < wid; x++){ 
				imgDest.AlphaSet(wid-x-1, y2,AlphaGet(x, y)); 
			} 
		} 
	} 
#endif //CXIMAGE_SUPPORT_ALPHA 
 
	//select the destination 
	if (iDst) iDst->Transfer(imgDest); 
	else Transfer(imgDest); 
	return true; 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::Resample(long newx, long newy, int fast) 
{ 
	if (newx==0 || newy==0) return false; 
	if (head.biWidth==newx && head.biHeight==newy) return true; 
 
	float xScale, yScale, fX, fY; 
	xScale = (float)head.biWidth  / (float)newx; 
	yScale = (float)head.biHeight / (float)newy; 
 
	CxImage newImage; 
	newImage.CopyInfo(*this); 
	newImage.Create(newx,newy,head.biBitCount,GetType()); 
	newImage.SetPalette(GetPalette()); 
	if (!newImage.IsValid()) return false; 
 
	if (head.biWidth==newx && head.biHeight==newy){ 
		Transfer(newImage); 
		return true; 
	} 
 
	if (fast) { 
		for(long y=0; ynewx && head.biHeight>newy && head.biBitCount==24)) { 
			//© 1999 Steve McMahon (steve@dogma.demon.co.uk) 
			long ifX, ifY, ifX1, ifY1, xmax, ymax; 
			float ir1, ir2, ig1, ig2, ib1, ib2, dx, dy; 
			BYTE r,g,b; 
			RGBQUAD rgb1, rgb2, rgb3, rgb4; 
			xmax = head.biWidth-1; 
			ymax = head.biHeight-1; 
			for(long y=0; y 
			const long ACCURACY = 1000; 
			long i,j; // index for faValue 
			long x,y; // coordinates in  source image 
			BYTE* pSource; 
			BYTE* pDest = newImage.info.pImage; 
			long* naAccu  = new long[3 * newx + 3]; 
			long* naCarry = new long[3 * newx + 3]; 
			long* naTemp; 
			long  nWeightX,nWeightY; 
			float fEndX; 
			long nScale = (long)(ACCURACY * xScale * yScale); 
 
			memset(naAccu,  0, sizeof(long) * 3 * newx); 
			memset(naCarry, 0, sizeof(long) * 3 * newx); 
 
			int u, v = 0; // coordinates in dest image 
			float fEndY = yScale - 1.0f; 
			for (y = 0; y < head.biHeight; y++){ 
				pSource = info.pImage + y * info.dwEffWidth; 
				u = i = 0; 
				fEndX = xScale - 1.0f; 
				if ((float)y < fEndY) {       // complete source row goes into dest row 
					for (x = 0; x < head.biWidth; x++){ 
						if ((float)x < fEndX){       // complete source pixel goes into dest pixel 
							for (j = 0; j < 3; j++)	naAccu[i + j] += (*pSource++) * ACCURACY; 
						} else {       // source pixel is splitted for 2 dest pixels 
							nWeightX = (long)(((float)x - fEndX) * ACCURACY); 
							for (j = 0; j < 3; j++){ 
								naAccu[i] += (ACCURACY - nWeightX) * (*pSource); 
								naAccu[3 + i++] += nWeightX * (*pSource++); 
							} 
							fEndX += xScale; 
							u++; 
						} 
					} 
				} else {       // source row is splitted for 2 dest rows        
					nWeightY = (long)(((float)y - fEndY) * ACCURACY); 
					for (x = 0; x < head.biWidth; x++){ 
						if ((float)x < fEndX){       // complete source pixel goes into 2 pixel 
							for (j = 0; j < 3; j++){ 
								naAccu[i + j] += ((ACCURACY - nWeightY) * (*pSource)); 
								naCarry[i + j] += nWeightY * (*pSource++); 
							} 
						} else {       // source pixel is splitted for 4 dest pixels 
							nWeightX = (int)(((float)x - fEndX) * ACCURACY); 
							for (j = 0; j < 3; j++) { 
								naAccu[i] += ((ACCURACY - nWeightY) * (ACCURACY - nWeightX)) * (*pSource) / ACCURACY; 
								*pDest++ = (BYTE)(naAccu[i] / nScale); 
								naCarry[i] += (nWeightY * (ACCURACY - nWeightX) * (*pSource)) / ACCURACY; 
								naAccu[i + 3] += ((ACCURACY - nWeightY) * nWeightX * (*pSource)) / ACCURACY; 
								naCarry[i + 3] = (nWeightY * nWeightX * (*pSource)) / ACCURACY; 
								i++; 
								pSource++; 
							} 
							fEndX += xScale; 
							u++; 
						} 
					} 
					if (u < newx){ // possibly not completed due to rounding errors 
						for (j = 0; j < 3; j++) *pDest++ = (BYTE)(naAccu[i++] / nScale); 
					} 
					naTemp = naCarry; 
					naCarry = naAccu; 
					naAccu = naTemp; 
					memset(naCarry, 0, sizeof(int) * 3);    // need only to set first pixel zero 
					pDest = newImage.info.pImage + (++v * newImage.info.dwEffWidth); 
					fEndY += yScale; 
				} 
			} 
			if (v < newy){	// possibly not completed due to rounding errors 
				for (i = 0; i < 3 * newx; i++) *pDest++ = (BYTE)(naAccu[i] / nScale); 
			} 
			delete [] naAccu; 
			delete [] naCarry; 
		} 
	} 
 
#if CXIMAGE_SUPPORT_ALPHA 
	if (HasAlpha()){ 
		newImage.AlphaCreate(); 
		for(long y=0; y4) return false; 
 
			CxImage tmp(head.biWidth,head.biHeight,4,info.dwType); 
			tmp.SetPalette(GetPalette(),GetNumColors()); 
 
#if CXIMAGE_SUPPORT_SELECTION 
			tmp.SelectionCopy(*this); 
#endif //CXIMAGE_SUPPORT_SELECTION 
 
#if CXIMAGE_SUPPORT_ALPHA 
			tmp.AlphaCopy(*this); 
#endif //CXIMAGE_SUPPORT_ALPHA 
 
			for (long y=0;y8) return false; 
 
			CxImage tmp(head.biWidth,head.biHeight,8,info.dwType); 
			tmp.SetPalette(GetPalette(),GetNumColors()); 
 
#if CXIMAGE_SUPPORT_SELECTION 
			tmp.SelectionCopy(*this); 
#endif //CXIMAGE_SUPPORT_SELECTION 
 
#if CXIMAGE_SUPPORT_ALPHA 
			tmp.AlphaCopy(*this); 
#endif //CXIMAGE_SUPPORT_ALPHA 
 
			for (long y=0;y24) return false; 
 
			CxImage tmp(head.biWidth,head.biHeight,24,info.dwType); 
 
#if CXIMAGE_SUPPORT_SELECTION 
			tmp.SelectionCopy(*this); 
#endif //CXIMAGE_SUPPORT_SELECTION 
 
#if CXIMAGE_SUPPORT_ALPHA 
			tmp.AlphaCopy(*this); 
#endif //CXIMAGE_SUPPORT_ALPHA 
 
			for (long y=0;y 128){ 
					tmp.SetPixelIndex(x,y,1); 
					error = level-255; 
				} else { 
					tmp.SetPixelIndex(x,y,0); 
					error = level; 
				} 
 
				nlevel = GetPixelIndex(x+1,y) + (error * 7)/16; 
				level = (BYTE)min(255,max(0,(int)nlevel)); 
				SetPixelIndex(x+1,y,level); 
				for(int i=-1; i<2; i++){ 
					switch(i){ 
					case -1: 
						coeff=3; break; 
					case 0: 
						coeff=5; break; 
					case 1: 
						coeff=1; break; 
					} 
					nlevel = GetPixelIndex(x+i,y+1) + (error * coeff)/16; 
					level = (BYTE)min(255,max(0,(int)nlevel)); 
					SetPixelIndex(x+i,y+1,level); 
				} 
			} 
		} 
		tmp.SetPaletteIndex(0,0,0,0); 
		tmp.SetPaletteIndex(1,255,255,255); 
		Transfer(tmp); 
	} 
	} 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::Crop(long left, long top, long right, long bottom, CxImage* iDst) 
{ 
	if (!pDib) return false; 
 
	long startx = max(0L,min(left,head.biWidth)); 
	long endx = max(0L,min(right,head.biWidth)); 
	long starty = head.biHeight - max(0L,min(top,head.biHeight)); 
	long endy = head.biHeight - max(0L,min(bottom,head.biHeight)); 
 
	if (startx==endx || starty==endy) return false; 
 
	if (startx>endx) {long tmp=startx; startx=endx; endx=tmp;} 
	if (starty>endy) {long tmp=starty; starty=endy; endy=tmp;} 
 
	CxImage tmp(endx-startx,endy-starty,head.biBitCount,info.dwType); 
	tmp.SetPalette(GetPalette(),head.biClrUsed); 
	tmp.info.nBkgndIndex = info.nBkgndIndex; 
	tmp.info.nBkgndColor = info.nBkgndColor; 
 
	switch (head.biBitCount) { 
	case 1: 
	case 4: 
	{ 
		for(long y=starty, yd=0; y> 3); 
		for(long y=starty; yTransfer(tmp); 
	else Transfer(tmp); 
 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
#endif //CXIMAGE_SUPPORT_TRANSFORMATION