www.pudn.com > cximage602_full.rar > ximasel.cpp


// xImaSel.cpp : Selection functions 
/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it 
 * CxImage version 6.0.0 02/Feb/2008 
 */ 
 
#include "ximage.h" 
 
#if CXIMAGE_SUPPORT_SELECTION 
 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Checks if the image has a valid selection. 
 */ 
bool CxImage::SelectionIsValid() 
{ 
	return pSelection!=0; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Gets the smallest rectangle that contains the selection  
 */ 
void CxImage::SelectionGetBox(RECT& r) 
{ 
	memcpy(&r,&info.rSelectionBox,sizeof(RECT)); 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Empties the selection. 
 */ 
bool CxImage::SelectionClear(BYTE level) 
{ 
	if (pSelection){ 
		if (level==0){ 
			memset(pSelection,0,head.biWidth * head.biHeight); 
			info.rSelectionBox.left = head.biWidth; 
			info.rSelectionBox.bottom = head.biHeight; 
			info.rSelectionBox.right = info.rSelectionBox.top = 0; 
		} else { 
			memset(pSelection,level,head.biWidth * head.biHeight); 
			info.rSelectionBox.right = head.biWidth; 
			info.rSelectionBox.top = head.biHeight; 
			info.rSelectionBox.left = info.rSelectionBox.bottom = 0; 
		} 
		return true; 
	} 
	return false; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Allocates an empty selection. 
 */ 
bool CxImage::SelectionCreate() 
{ 
	SelectionDelete(); 
	pSelection = (BYTE*)calloc(head.biWidth * head.biHeight, 1); 
	return (pSelection!=0); 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Deallocates the selction. 
 */ 
bool CxImage::SelectionDelete() 
{ 
	if (pSelection){ 
		free(pSelection); 
		pSelection=NULL; 
	} 
	info.rSelectionBox.left = head.biWidth; 
	info.rSelectionBox.bottom = head.biHeight; 
	info.rSelectionBox.right = info.rSelectionBox.top = 0; 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Checks if the coordinates are inside the selection. 
 */ 
bool CxImage::SelectionIsInside(long x, long y) 
{ 
	if (IsInside(x,y)){ 
		if (pSelection==NULL) return true; 
		return pSelection[x+y*head.biWidth]!=0; 
	} 
	return false; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Checks if the coordinates are inside the selection. 
 * "blind" version assumes that (x,y) is inside to the image. 
 */ 
bool CxImage::BlindSelectionIsInside(long x, long y) 
{ 
#ifdef _DEBUG 
	if (!IsInside(x,y)) 
  #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING 
		throw 0; 
  #else 
		return 0; 
  #endif 
#endif 
	if (pSelection==NULL) return true; 
	return pSelection[x+y*head.biWidth]!=0; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Adds a rectangle to the existing selection. 
 */ 
bool CxImage::SelectionAddRect(RECT r, BYTE level) 
{ 
	if (pSelection==NULL) SelectionCreate(); 
	if (pSelection==NULL) return false; 
 
	RECT r2; 
	if (r.left r2.left) info.rSelectionBox.left = max(0L,min(head.biWidth,r2.left)); 
	if (info.rSelectionBox.right <= r2.right) info.rSelectionBox.right = max(0L,min(head.biWidth,r2.right+1)); 
	if (info.rSelectionBox.bottom > r2.bottom) info.rSelectionBox.bottom = max(0L,min(head.biHeight,r2.bottom)); 
 
	long ymin = max(0L,min(head.biHeight,r2.bottom)); 
	long ymax = max(0L,min(head.biHeight,r2.top+1)); 
	long xmin = max(0L,min(head.biWidth,r2.left)); 
	long xmax = max(0L,min(head.biWidth,r2.right+1)); 
 
	for (long y=ymin; y (xcenter - xradius)) info.rSelectionBox.left = max(0L,min(head.biWidth,(xcenter - xradius))); 
	if (info.rSelectionBox.right <= (xcenter + xradius)) info.rSelectionBox.right = max(0L,min(head.biWidth,(xcenter + xradius + 1))); 
	if (info.rSelectionBox.bottom > (ycenter - yradius)) info.rSelectionBox.bottom = max(0L,min(head.biHeight,(ycenter - yradius))); 
	if (info.rSelectionBox.top <= (ycenter + yradius)) info.rSelectionBox.top = max(0L,min(head.biHeight,(ycenter + yradius + 1))); 
 
	long xmin = max(0L,min(head.biWidth,xcenter - xradius)); 
	long xmax = max(0L,min(head.biWidth,xcenter + xradius + 1)); 
	long ymin = max(0L,min(head.biHeight,ycenter - yradius)); 
	long ymax = max(0L,min(head.biHeight,ycenter + yradius + 1)); 
 
	long y,yo; 
	for (y=ymin; yy) pSelection[x + y * head.biWidth] = level; 
		} 
	} 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Inverts the selection. 
 * Note: the SelectionBox is set to "full image", call SelectionGetBox before (if necessary) 
 */ 
bool CxImage::SelectionInvert() 
{ 
	if (pSelection) { 
		BYTE *iSrc=pSelection; 
		long n=head.biHeight*head.biWidth; 
		for(long i=0; i < n; i++){ 
			*iSrc=(BYTE)~(*(iSrc)); 
			iSrc++; 
		} 
 
		SelectionRebuildBox(); 
 
		return true; 
	} 
	return false; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Imports an existing region from another image with the same width and height. 
 */ 
bool CxImage::SelectionCopy(CxImage &from) 
{ 
	if (from.pSelection == NULL || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false; 
	if (pSelection==NULL) pSelection = (BYTE*)malloc(head.biWidth * head.biHeight); 
	if (pSelection==NULL) return false; 
	memcpy(pSelection,from.pSelection,head.biWidth * head.biHeight); 
	memcpy(&info.rSelectionBox,&from.info.rSelectionBox,sizeof(RECT)); 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Adds a polygonal region to the existing selection. points points to an array of POINT structures. 
 * Each structure specifies the x-coordinate and y-coordinate of one vertex of the polygon. 
 * npoints specifies the number of POINT structures in the array pointed to by points. 
 */ 
bool CxImage::SelectionAddPolygon(POINT *points, long npoints, BYTE level) 
{ 
	if (points==NULL || npoints<3) return false; 
 
	if (pSelection==NULL) SelectionCreate(); 
	if (pSelection==NULL) return false; 
 
	BYTE* plocal = (BYTE*)calloc(head.biWidth*head.biHeight, 1); 
	RECT localbox = {head.biWidth,0,0,head.biHeight}; 
 
	long x,y,i=0; 
	POINT *current; 
	POINT *next = NULL; 
	POINT *start = NULL; 
	//trace contour 
	while (i < npoints){ 
		current = &points[i]; 
		if (current->x!=-1){ 
			if (i==0 || (i>0 && points[i-1].x==-1)) start = &points[i]; 
 
			if ((i+1)==npoints || points[i+1].x==-1) 
				next = start; 
			else 
				next = &points[i+1]; 
 
			float beta; 
			if (current->x != next->x){ 
				beta = (float)(next->y - current->y)/(float)(next->x - current->x); 
				if (current->x < next->x){ 
					for (x=current->x; x<=next->x; x++){ 
						y = (long)(current->y + (x - current->x) * beta); 
						if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255; 
					} 
				} else { 
					for (x=current->x; x>=next->x; x--){ 
						y = (long)(current->y + (x - current->x) * beta); 
						if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255; 
					} 
				} 
			} 
			if (current->y != next->y){ 
				beta = (float)(next->x - current->x)/(float)(next->y - current->y); 
				if (current->y < next->y){ 
					for (y=current->y; y<=next->y; y++){ 
						x = (long)(current->x + (y - current->y) * beta); 
						if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255; 
					} 
				} else { 
					for (y=current->y; y>=next->y; y--){ 
						x = (long)(current->x + (y - current->y) * beta); 
						if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255; 
					} 
				} 
			} 
		} 
 
		RECT r2; 
		if (current->x < next->x) {r2.left=current->x; r2.right=next->x; } else {r2.left=next->x ; r2.right=current->x; } 
		if (current->y < next->y) {r2.bottom=current->y; r2.top=next->y; } else {r2.bottom=next->y ; r2.top=current->y; } 
		if (localbox.top < r2.top) localbox.top = max(0L,min(head.biHeight-1,r2.top+1)); 
		if (localbox.left > r2.left) localbox.left = max(0L,min(head.biWidth-1,r2.left-1)); 
		if (localbox.right < r2.right) localbox.right = max(0L,min(head.biWidth-1,r2.right+1)); 
		if (localbox.bottom > r2.bottom) localbox.bottom = max(0L,min(head.biHeight-1,r2.bottom-1)); 
 
		i++; 
	} 
 
	//fill the outer region 
	long npix=(localbox.right - localbox.left)*(localbox.top - localbox.bottom); 
	POINT* pix = (POINT*)calloc(npix,sizeof(POINT)); 
	BYTE back=0, mark=1; 
	long fx, fy, fxx, fyy, first, last; 
	long xmin = 0; 
	long xmax = 0; 
	long ymin = 0; 
	long ymax = 0; 
 
	for (int side=0; side<4; side++){ 
		switch(side){ 
		case 0: 
			xmin=localbox.left; xmax=localbox.right+1; ymin=localbox.bottom; ymax=localbox.bottom+1; 
			break; 
		case 1: 
			xmin=localbox.right; xmax=localbox.right+1; ymin=localbox.bottom; ymax=localbox.top+1; 
			break; 
		case 2: 
			xmin=localbox.left; xmax=localbox.right+1; ymin=localbox.top; ymax=localbox.top+1; 
			break; 
		case 3: 
			xmin=localbox.left; xmax=localbox.left+1; ymin=localbox.bottom; ymax=localbox.top+1; 
			break; 
		} 
		//fill from the border points 
		for(y=ymin;y=localbox.left && fxx<=localbox.right && fyy>=localbox.bottom && fyy<=localbox.top ) 
							{ 
								plocal[fxx + fyy*head.biWidth] = mark; 
								if (fyy > 0 && plocal[fxx + (fyy - 1)*head.biWidth] == back){ 
									pix[last].x = fx; 
									pix[last].y = fy - 1; 
									last++; 
									if (last == npix) last = 0; 
								} 
								if ((fyy + 1)=localbox.left && fxx<=localbox.right && fyy>=localbox.bottom && fyy<=localbox.top ) 
							{ 
								plocal[fxx + (y + fy)*head.biWidth] = mark; 
								if (fyy > 0 && plocal[fxx + (fyy - 1)*head.biWidth] == back){ 
									pix[last].x = fx; 
									pix[last].y = fy - 1; 
									last++; 
									if (last == npix) last = 0; 
								} 
								if ((fyy + 1) localbox.left) info.rSelectionBox.left = min(head.biWidth,localbox.left); 
	if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = min(head.biWidth,localbox.right + 1); 
	if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = min(head.biHeight,localbox.bottom); 
 
	free(plocal); 
	free(pix); 
 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Adds to the selection all the pixels matching the specified color. 
 */ 
bool CxImage::SelectionAddColor(RGBQUAD c, BYTE level) 
{ 
    if (pSelection==NULL) SelectionCreate(); 
	if (pSelection==NULL) return false; 
 
	RECT localbox = {head.biWidth,0,0,head.biHeight}; 
 
    for (long y = 0; y < head.biHeight; y++){ 
        for (long x = 0; x < head.biWidth; x++){ 
            RGBQUAD color = BlindGetPixelColor(x, y); 
            if (color.rgbRed   == c.rgbRed && 
				color.rgbGreen == c.rgbGreen && 
                color.rgbBlue  == c.rgbBlue) 
            { 
                pSelection[x + y * head.biWidth] = level; 
 
				if (localbox.top < y) localbox.top = y; 
				if (localbox.left > x) localbox.left = x; 
				if (localbox.right < x) localbox.right = x; 
				if (localbox.bottom > y) localbox.bottom = y; 
            } 
        } 
    } 
 
	if (info.rSelectionBox.top <= localbox.top) info.rSelectionBox.top = localbox.top + 1; 
	if (info.rSelectionBox.left > localbox.left) info.rSelectionBox.left = localbox.left; 
	if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = localbox.right + 1; 
	if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = localbox.bottom; 
 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Adds a single pixel to the existing selection. 
 */ 
bool CxImage::SelectionAddPixel(long x, long y, BYTE level) 
{ 
    if (pSelection==NULL) SelectionCreate(); 
	if (pSelection==NULL) return false; 
 
    if (IsInside(x,y)) { 
        pSelection[x + y * head.biWidth] = level; // set the correct mask bit 
 
		if (info.rSelectionBox.top <= y) info.rSelectionBox.top = y+1; 
		if (info.rSelectionBox.left > x) info.rSelectionBox.left = x; 
		if (info.rSelectionBox.right <= x) info.rSelectionBox.right = x+1; 
		if (info.rSelectionBox.bottom > y) info.rSelectionBox.bottom = y; 
 
        return true; 
    } 
 
    return false; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Exports the selection channel in a 8bpp grayscale image. 
 */ 
bool CxImage::SelectionSplit(CxImage *dest) 
{ 
	if (!pSelection || !dest) return false; 
 
	CxImage tmp(head.biWidth,head.biHeight,8); 
	if (!tmp.IsValid()){ 
		strcpy(info.szLastError,tmp.GetLastError()); 
		return false; 
	} 
 
	for(long y=0; yTransfer(tmp); 
 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Creates the selection channel from a gray scale image. 
 * black = unselected 
 */ 
bool CxImage::SelectionSet(CxImage &from) 
{ 
	if (!from.IsGrayScale() || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight){ 
		strcpy(info.szLastError,"CxImage::SelectionSet: wrong width or height, or image is not gray scale"); 
		return false; 
	} 
 
	if (pSelection==NULL) pSelection = (BYTE*)malloc(head.biWidth * head.biHeight); 
 
	BYTE* src = from.info.pImage; 
	BYTE* dst = pSelection; 
	if (src==NULL || dst==NULL){ 
		strcpy(info.szLastError,"CxImage::SelectionSet: null pointer"); 
		return false; 
	} 
 
	for (long y=0; y=info.rSelectionBox.right; x--){ 
			if (pSelection[x+y*head.biWidth]){ 
				info.rSelectionBox.right = x+1; 
				continue; 
			} 
		} 
	} 
 
	for (x=0; x=info.rSelectionBox.top; y--){ 
			if (pSelection[x+y*head.biWidth]){ 
				info.rSelectionBox.top = y+1; 
				continue; 
			} 
		} 
	} 
 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Gets the Selection level for a single pixel  
 * "blind" version assumes that (x,y) is inside to the image. 
 */ 
BYTE CxImage::BlindSelectionGet(const long x,const long y) 
{ 
#ifdef _DEBUG 
	if (!IsInside(x,y) || (pSelection==0)) 
  #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING 
		throw 0; 
  #else 
		return 0; 
  #endif 
#endif 
	return pSelection[x+y*head.biWidth]; 
} 
//////////////////////////////////////////////////////////////////////////////// 
/** 
 * Returns pointer to selection data for pixel (x,y). 
 */ 
BYTE* CxImage::SelectionGetPointer(const long x,const long y) 
{ 
	if (pSelection && IsInside(x,y)) return pSelection+x+y*head.biWidth; 
	return 0; 
} 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::SelectionFlip() 
{ 
	if (!pSelection) return false; 
 
	BYTE *buff = (BYTE*)malloc(head.biWidth); 
	if (!buff) return false; 
 
	BYTE *iSrc,*iDst; 
	iSrc = pSelection + (head.biHeight-1)*head.biWidth; 
	iDst = pSelection; 
	for (long i=0; i<(head.biHeight/2); ++i) 
	{ 
		memcpy(buff, iSrc, head.biWidth); 
		memcpy(iSrc, iDst, head.biWidth); 
		memcpy(iDst, buff, head.biWidth); 
		iSrc-=head.biWidth; 
		iDst+=head.biWidth; 
	} 
 
	free(buff); 
 
	long top = info.rSelectionBox.top; 
	info.rSelectionBox.top = head.biHeight - info.rSelectionBox.bottom; 
	info.rSelectionBox.bottom = head.biHeight - top; 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::SelectionMirror() 
{ 
	if (!pSelection) return false; 
	BYTE* pSelection2 = (BYTE*)malloc(head.biWidth * head.biHeight); 
	if (!pSelection2) return false; 
	 
	BYTE *iSrc,*iDst; 
	long wdt=head.biWidth-1; 
	iSrc=pSelection + wdt; 
	iDst=pSelection2; 
	for(long y=0; y < head.biHeight; y++){ 
		for(long x=0; x <= wdt; x++) 
			*(iDst+x)=*(iSrc-x); 
		iSrc+=head.biWidth; 
		iDst+=head.biWidth; 
	} 
	free(pSelection); 
	pSelection=pSelection2; 
	 
	long left = info.rSelectionBox.left; 
	info.rSelectionBox.left = head.biWidth - info.rSelectionBox.right; 
	info.rSelectionBox.right = head.biWidth - left; 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
#if CXIMAGE_SUPPORT_WINDOWS 
/** 
 * Converts the selection in a HRGN object. 
 */ 
bool CxImage::SelectionToHRGN(HRGN& region) 
{ 
	if (pSelection && region){            
        for(int y = 0; y < head.biHeight; y++){ 
            HRGN hTemp = NULL; 
            int iStart = -1; 
            int x = 0; 
			for(; x < head.biWidth; x++){ 
                if (pSelection[x + y * head.biWidth] != 0){ 
					if (iStart == -1) iStart = x; 
					continue; 
                }else{ 
                    if (iStart >= 0){ 
                        hTemp = CreateRectRgn(iStart, y, x, y + 1); 
                        CombineRgn(region, hTemp, region, RGN_OR); 
                        DeleteObject(hTemp); 
                        iStart = -1; 
                    } 
                } 
            } 
            if (iStart >= 0){ 
                hTemp = CreateRectRgn(iStart, y, x, y + 1); 
                CombineRgn(region, hTemp, region, RGN_OR); 
                DeleteObject(hTemp); 
                iStart = -1; 
            } 
        } 
		return true; 
    } 
	return false; 
} 
#endif //CXIMAGE_SUPPORT_WINDOWS 
//////////////////////////////////////////////////////////////////////////////// 
#endif //CXIMAGE_SUPPORT_SELECTION