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