X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=utilities%2FCxImage%2Fximasel.cpp;h=3e7d20298342be5971b3b88e634180808fd1a959;hb=22aac696ea46e2e4f989d8893bcb978f63715aef;hp=bf61078ab425939a3d9f0f49a79e92c5e13ac4fd;hpb=3fd15028ab81e6746d3af96695526d7d973a26c8;p=clitk.git diff --git a/utilities/CxImage/ximasel.cpp b/utilities/CxImage/ximasel.cpp index bf61078..3e7d202 100644 --- a/utilities/CxImage/ximasel.cpp +++ b/utilities/CxImage/ximasel.cpp @@ -1,697 +1,697 @@ -// 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 +// 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; y<__min(ycenter,ymax); y++){ + for (long x=xmin; xy) 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