]> Creatis software - clitk.git/blob - utilities/CxImage/ximasel.cpp
bf61078ab425939a3d9f0f49a79e92c5e13ac4fd
[clitk.git] / utilities / CxImage / ximasel.cpp
1 // xImaSel.cpp : Selection functions\r
2 /* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it\r
3  * CxImage version 6.0.0 02/Feb/2008\r
4  */\r
5 \r
6 #include "ximage.h"\r
7 \r
8 #if CXIMAGE_SUPPORT_SELECTION\r
9 \r
10 ////////////////////////////////////////////////////////////////////////////////\r
11 /**\r
12  * Checks if the image has a valid selection.\r
13  */\r
14 bool CxImage::SelectionIsValid()\r
15 {\r
16         return pSelection!=0;\r
17 }\r
18 ////////////////////////////////////////////////////////////////////////////////\r
19 /**\r
20  * Gets the smallest rectangle that contains the selection \r
21  */\r
22 void CxImage::SelectionGetBox(RECT& r)\r
23 {\r
24         memcpy(&r,&info.rSelectionBox,sizeof(RECT));\r
25 }\r
26 ////////////////////////////////////////////////////////////////////////////////\r
27 /**\r
28  * Empties the selection.\r
29  */\r
30 bool CxImage::SelectionClear(BYTE level)\r
31 {\r
32         if (pSelection){\r
33                 if (level==0){\r
34                         memset(pSelection,0,head.biWidth * head.biHeight);\r
35                         info.rSelectionBox.left = head.biWidth;\r
36                         info.rSelectionBox.bottom = head.biHeight;\r
37                         info.rSelectionBox.right = info.rSelectionBox.top = 0;\r
38                 } else {\r
39                         memset(pSelection,level,head.biWidth * head.biHeight);\r
40                         info.rSelectionBox.right = head.biWidth;\r
41                         info.rSelectionBox.top = head.biHeight;\r
42                         info.rSelectionBox.left = info.rSelectionBox.bottom = 0;\r
43                 }\r
44                 return true;\r
45         }\r
46         return false;\r
47 }\r
48 ////////////////////////////////////////////////////////////////////////////////\r
49 /**\r
50  * Allocates an empty selection.\r
51  */\r
52 bool CxImage::SelectionCreate()\r
53 {\r
54         SelectionDelete();\r
55         pSelection = (BYTE*)calloc(head.biWidth * head.biHeight, 1);\r
56         return (pSelection!=0);\r
57 }\r
58 ////////////////////////////////////////////////////////////////////////////////\r
59 /**\r
60  * Deallocates the selction.\r
61  */\r
62 bool CxImage::SelectionDelete()\r
63 {\r
64         if (pSelection){\r
65                 free(pSelection);\r
66                 pSelection=NULL;\r
67         }\r
68         info.rSelectionBox.left = head.biWidth;\r
69         info.rSelectionBox.bottom = head.biHeight;\r
70         info.rSelectionBox.right = info.rSelectionBox.top = 0;\r
71         return true;\r
72 }\r
73 ////////////////////////////////////////////////////////////////////////////////\r
74 /**\r
75  * Checks if the coordinates are inside the selection.\r
76  */\r
77 bool CxImage::SelectionIsInside(long x, long y)\r
78 {\r
79         if (IsInside(x,y)){\r
80                 if (pSelection==NULL) return true;\r
81                 return pSelection[x+y*head.biWidth]!=0;\r
82         }\r
83         return false;\r
84 }\r
85 ////////////////////////////////////////////////////////////////////////////////\r
86 /**\r
87  * Checks if the coordinates are inside the selection.\r
88  * "blind" version assumes that (x,y) is inside to the image.\r
89  */\r
90 bool CxImage::BlindSelectionIsInside(long x, long y)\r
91 {\r
92 #ifdef _DEBUG\r
93         if (!IsInside(x,y))\r
94   #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
95                 throw 0;\r
96   #else\r
97                 return 0;\r
98   #endif\r
99 #endif\r
100         if (pSelection==NULL) return true;\r
101         return pSelection[x+y*head.biWidth]!=0;\r
102 }\r
103 ////////////////////////////////////////////////////////////////////////////////\r
104 /**\r
105  * Adds a rectangle to the existing selection.\r
106  */\r
107 bool CxImage::SelectionAddRect(RECT r, BYTE level)\r
108 {\r
109         if (pSelection==NULL) SelectionCreate();\r
110         if (pSelection==NULL) return false;\r
111 \r
112         RECT r2;\r
113         if (r.left<r.right) {r2.left=r.left; r2.right=r.right; } else {r2.left=r.right ; r2.right=r.left; }\r
114         if (r.bottom<r.top) {r2.bottom=r.bottom; r2.top=r.top; } else {r2.bottom=r.top ; r2.top=r.bottom; }\r
115 \r
116         if (info.rSelectionBox.top <= r2.top) info.rSelectionBox.top = max(0L,min(head.biHeight,r2.top+1));\r
117         if (info.rSelectionBox.left > r2.left) info.rSelectionBox.left = max(0L,min(head.biWidth,r2.left));\r
118         if (info.rSelectionBox.right <= r2.right) info.rSelectionBox.right = max(0L,min(head.biWidth,r2.right+1));\r
119         if (info.rSelectionBox.bottom > r2.bottom) info.rSelectionBox.bottom = max(0L,min(head.biHeight,r2.bottom));\r
120 \r
121         long ymin = max(0L,min(head.biHeight,r2.bottom));\r
122         long ymax = max(0L,min(head.biHeight,r2.top+1));\r
123         long xmin = max(0L,min(head.biWidth,r2.left));\r
124         long xmax = max(0L,min(head.biWidth,r2.right+1));\r
125 \r
126         for (long y=ymin; y<ymax; y++)\r
127                 memset(pSelection + xmin + y * head.biWidth, level, xmax-xmin);\r
128 \r
129         return true;\r
130 }\r
131 ////////////////////////////////////////////////////////////////////////////////\r
132 /**\r
133  * Adds an ellipse to the existing selection.\r
134  */\r
135 bool CxImage::SelectionAddEllipse(RECT r, BYTE level)\r
136 {\r
137         if (pSelection==NULL) SelectionCreate();\r
138         if (pSelection==NULL) return false;\r
139 \r
140         long xradius = abs(r.right - r.left)/2;\r
141         long yradius = abs(r.top - r.bottom)/2;\r
142         if (xradius==0 || yradius==0) return false;\r
143 \r
144         long xcenter = (r.right + r.left)/2;\r
145         long ycenter = (r.top + r.bottom)/2;\r
146 \r
147         if (info.rSelectionBox.left > (xcenter - xradius)) info.rSelectionBox.left = max(0L,min(head.biWidth,(xcenter - xradius)));\r
148         if (info.rSelectionBox.right <= (xcenter + xradius)) info.rSelectionBox.right = max(0L,min(head.biWidth,(xcenter + xradius + 1)));\r
149         if (info.rSelectionBox.bottom > (ycenter - yradius)) info.rSelectionBox.bottom = max(0L,min(head.biHeight,(ycenter - yradius)));\r
150         if (info.rSelectionBox.top <= (ycenter + yradius)) info.rSelectionBox.top = max(0L,min(head.biHeight,(ycenter + yradius + 1)));\r
151 \r
152         long xmin = max(0L,min(head.biWidth,xcenter - xradius));\r
153         long xmax = max(0L,min(head.biWidth,xcenter + xradius + 1));\r
154         long ymin = max(0L,min(head.biHeight,ycenter - yradius));\r
155         long ymax = max(0L,min(head.biHeight,ycenter + yradius + 1));\r
156 \r
157         long y,yo;\r
158         for (y=ymin; y<min(ycenter,ymax); y++){\r
159                 for (long x=xmin; x<xmax; x++){\r
160                         yo = (long)(ycenter - yradius * sqrt(1-pow((float)(x - xcenter)/(float)xradius,2)));\r
161                         if (yo<y) pSelection[x + y * head.biWidth] = level;\r
162                 }\r
163         }\r
164         for (y=ycenter; y<ymax; y++){\r
165                 for (long x=xmin; x<xmax; x++){\r
166                         yo = (long)(ycenter + yradius * sqrt(1-pow((float)(x - xcenter)/(float)xradius,2)));\r
167                         if (yo>y) pSelection[x + y * head.biWidth] = level;\r
168                 }\r
169         }\r
170         return true;\r
171 }\r
172 ////////////////////////////////////////////////////////////////////////////////\r
173 /**\r
174  * Inverts the selection.\r
175  * Note: the SelectionBox is set to "full image", call SelectionGetBox before (if necessary)\r
176  */\r
177 bool CxImage::SelectionInvert()\r
178 {\r
179         if (pSelection) {\r
180                 BYTE *iSrc=pSelection;\r
181                 long n=head.biHeight*head.biWidth;\r
182                 for(long i=0; i < n; i++){\r
183                         *iSrc=(BYTE)~(*(iSrc));\r
184                         iSrc++;\r
185                 }\r
186 \r
187                 SelectionRebuildBox();\r
188 \r
189                 return true;\r
190         }\r
191         return false;\r
192 }\r
193 ////////////////////////////////////////////////////////////////////////////////\r
194 /**\r
195  * Imports an existing region from another image with the same width and height.\r
196  */\r
197 bool CxImage::SelectionCopy(CxImage &from)\r
198 {\r
199         if (from.pSelection == NULL || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false;\r
200         if (pSelection==NULL) pSelection = (BYTE*)malloc(head.biWidth * head.biHeight);\r
201         if (pSelection==NULL) return false;\r
202         memcpy(pSelection,from.pSelection,head.biWidth * head.biHeight);\r
203         memcpy(&info.rSelectionBox,&from.info.rSelectionBox,sizeof(RECT));\r
204         return true;\r
205 }\r
206 ////////////////////////////////////////////////////////////////////////////////\r
207 /**\r
208  * Adds a polygonal region to the existing selection. points points to an array of POINT structures.\r
209  * Each structure specifies the x-coordinate and y-coordinate of one vertex of the polygon.\r
210  * npoints specifies the number of POINT structures in the array pointed to by points.\r
211  */\r
212 bool CxImage::SelectionAddPolygon(POINT *points, long npoints, BYTE level)\r
213 {\r
214         if (points==NULL || npoints<3) return false;\r
215 \r
216         if (pSelection==NULL) SelectionCreate();\r
217         if (pSelection==NULL) return false;\r
218 \r
219         BYTE* plocal = (BYTE*)calloc(head.biWidth*head.biHeight, 1);\r
220         RECT localbox = {head.biWidth,0,0,head.biHeight};\r
221 \r
222         long x,y,i=0;\r
223         POINT *current;\r
224         POINT *next = NULL;\r
225         POINT *start = NULL;\r
226         //trace contour\r
227         while (i < npoints){\r
228                 current = &points[i];\r
229                 if (current->x!=-1){\r
230                         if (i==0 || (i>0 && points[i-1].x==-1)) start = &points[i];\r
231 \r
232                         if ((i+1)==npoints || points[i+1].x==-1)\r
233                                 next = start;\r
234                         else\r
235                                 next = &points[i+1];\r
236 \r
237                         float beta;\r
238                         if (current->x != next->x){\r
239                                 beta = (float)(next->y - current->y)/(float)(next->x - current->x);\r
240                                 if (current->x < next->x){\r
241                                         for (x=current->x; x<=next->x; x++){\r
242                                                 y = (long)(current->y + (x - current->x) * beta);\r
243                                                 if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255;\r
244                                         }\r
245                                 } else {\r
246                                         for (x=current->x; x>=next->x; x--){\r
247                                                 y = (long)(current->y + (x - current->x) * beta);\r
248                                                 if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255;\r
249                                         }\r
250                                 }\r
251                         }\r
252                         if (current->y != next->y){\r
253                                 beta = (float)(next->x - current->x)/(float)(next->y - current->y);\r
254                                 if (current->y < next->y){\r
255                                         for (y=current->y; y<=next->y; y++){\r
256                                                 x = (long)(current->x + (y - current->y) * beta);\r
257                                                 if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255;\r
258                                         }\r
259                                 } else {\r
260                                         for (y=current->y; y>=next->y; y--){\r
261                                                 x = (long)(current->x + (y - current->y) * beta);\r
262                                                 if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255;\r
263                                         }\r
264                                 }\r
265                         }\r
266                 }\r
267 \r
268                 RECT r2;\r
269                 if (current->x < next->x) {r2.left=current->x; r2.right=next->x; } else {r2.left=next->x ; r2.right=current->x; }\r
270                 if (current->y < next->y) {r2.bottom=current->y; r2.top=next->y; } else {r2.bottom=next->y ; r2.top=current->y; }\r
271                 if (localbox.top < r2.top) localbox.top = max(0L,min(head.biHeight-1,r2.top+1));\r
272                 if (localbox.left > r2.left) localbox.left = max(0L,min(head.biWidth-1,r2.left-1));\r
273                 if (localbox.right < r2.right) localbox.right = max(0L,min(head.biWidth-1,r2.right+1));\r
274                 if (localbox.bottom > r2.bottom) localbox.bottom = max(0L,min(head.biHeight-1,r2.bottom-1));\r
275 \r
276                 i++;\r
277         }\r
278 \r
279         //fill the outer region\r
280         long npix=(localbox.right - localbox.left)*(localbox.top - localbox.bottom);\r
281         POINT* pix = (POINT*)calloc(npix,sizeof(POINT));\r
282         BYTE back=0, mark=1;\r
283         long fx, fy, fxx, fyy, first, last;\r
284         long xmin = 0;\r
285         long xmax = 0;\r
286         long ymin = 0;\r
287         long ymax = 0;\r
288 \r
289         for (int side=0; side<4; side++){\r
290                 switch(side){\r
291                 case 0:\r
292                         xmin=localbox.left; xmax=localbox.right+1; ymin=localbox.bottom; ymax=localbox.bottom+1;\r
293                         break;\r
294                 case 1:\r
295                         xmin=localbox.right; xmax=localbox.right+1; ymin=localbox.bottom; ymax=localbox.top+1;\r
296                         break;\r
297                 case 2:\r
298                         xmin=localbox.left; xmax=localbox.right+1; ymin=localbox.top; ymax=localbox.top+1;\r
299                         break;\r
300                 case 3:\r
301                         xmin=localbox.left; xmax=localbox.left+1; ymin=localbox.bottom; ymax=localbox.top+1;\r
302                         break;\r
303                 }\r
304                 //fill from the border points\r
305                 for(y=ymin;y<ymax;y++){\r
306                         for(x=xmin;x<xmax;x++){\r
307                                 if (plocal[x+y*head.biWidth]==0){\r
308                                         // Subject: FLOOD FILL ROUTINE              Date: 12-23-97 (00:57)       \r
309                                         // Author:  Petter Holmberg                 Code: QB, QBasic, PDS        \r
310                                         // Origin:  petter.holmberg@usa.net         Packet: GRAPHICS.ABC\r
311                                         first=0;\r
312                                         last=1;\r
313                                         while(first!=last){\r
314                                                 fx = pix[first].x;\r
315                                                 fy = pix[first].y;\r
316                                                 fxx = fx + x;\r
317                                                 fyy = fy + y;\r
318                                                 for(;;)\r
319                                                 {\r
320                                                         if ((plocal[fxx + fyy*head.biWidth] == back) &&\r
321                                                                 fxx>=localbox.left && fxx<=localbox.right && fyy>=localbox.bottom && fyy<=localbox.top )\r
322                                                         {\r
323                                                                 plocal[fxx + fyy*head.biWidth] = mark;\r
324                                                                 if (fyy > 0 && plocal[fxx + (fyy - 1)*head.biWidth] == back){\r
325                                                                         pix[last].x = fx;\r
326                                                                         pix[last].y = fy - 1;\r
327                                                                         last++;\r
328                                                                         if (last == npix) last = 0;\r
329                                                                 }\r
330                                                                 if ((fyy + 1)<head.biHeight && plocal[fxx + (fyy + 1)*head.biWidth] == back){\r
331                                                                         pix[last].x = fx;\r
332                                                                         pix[last].y = fy + 1;\r
333                                                                         last++;\r
334                                                                         if (last == npix) last = 0;\r
335                                                                 }\r
336                                                         } else {\r
337                                                                 break;\r
338                                                         }\r
339                                                         fx++;\r
340                                                         fxx++;\r
341                                                 };\r
342 \r
343                                                 fx = pix[first].x - 1;\r
344                                                 fy = pix[first].y;\r
345                                                 fxx = fx + x;\r
346                                                 fyy = fy + y;\r
347 \r
348                                                 for( ;; )\r
349                                                 {\r
350                                                         if ((plocal[fxx + fyy*head.biWidth] == back) &&\r
351                                                                 fxx>=localbox.left && fxx<=localbox.right && fyy>=localbox.bottom && fyy<=localbox.top )\r
352                                                         {\r
353                                                                 plocal[fxx + (y + fy)*head.biWidth] = mark;\r
354                                                                 if (fyy > 0 && plocal[fxx + (fyy - 1)*head.biWidth] == back){\r
355                                                                         pix[last].x = fx;\r
356                                                                         pix[last].y = fy - 1;\r
357                                                                         last++;\r
358                                                                         if (last == npix) last = 0;\r
359                                                                 }\r
360                                                                 if ((fyy + 1)<head.biHeight && plocal[fxx + (fyy + 1)*head.biWidth] == back){\r
361                                                                         pix[last].x = fx;\r
362                                                                         pix[last].y = fy + 1;\r
363                                                                         last++;\r
364                                                                         if (last == npix) last = 0;\r
365                                                                 }\r
366                                                         } else {\r
367                                                                 break;\r
368                                                         }\r
369                                                         fx--;\r
370                                                         fxx--;\r
371                                                 }\r
372                                                 \r
373                                                 first++;\r
374                                                 if (first == npix) first = 0;\r
375                                         }\r
376                                 }\r
377                         }\r
378                 }\r
379         }\r
380 \r
381         //transfer the region\r
382         long yoffset;\r
383         for (y=localbox.bottom; y<=localbox.top; y++){\r
384                 yoffset = y * head.biWidth;\r
385                 for (x=localbox.left; x<=localbox.right; x++)\r
386                         if (plocal[x + yoffset]!=1) pSelection[x + yoffset]=level;\r
387         }\r
388         if (info.rSelectionBox.top <= localbox.top) info.rSelectionBox.top = min(head.biHeight,localbox.top + 1);\r
389         if (info.rSelectionBox.left > localbox.left) info.rSelectionBox.left = min(head.biWidth,localbox.left);\r
390         if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = min(head.biWidth,localbox.right + 1);\r
391         if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = min(head.biHeight,localbox.bottom);\r
392 \r
393         free(plocal);\r
394         free(pix);\r
395 \r
396         return true;\r
397 }\r
398 ////////////////////////////////////////////////////////////////////////////////\r
399 /**\r
400  * Adds to the selection all the pixels matching the specified color.\r
401  */\r
402 bool CxImage::SelectionAddColor(RGBQUAD c, BYTE level)\r
403 {\r
404     if (pSelection==NULL) SelectionCreate();\r
405         if (pSelection==NULL) return false;\r
406 \r
407         RECT localbox = {head.biWidth,0,0,head.biHeight};\r
408 \r
409     for (long y = 0; y < head.biHeight; y++){\r
410         for (long x = 0; x < head.biWidth; x++){\r
411             RGBQUAD color = BlindGetPixelColor(x, y);\r
412             if (color.rgbRed   == c.rgbRed &&\r
413                                 color.rgbGreen == c.rgbGreen &&\r
414                 color.rgbBlue  == c.rgbBlue)\r
415             {\r
416                 pSelection[x + y * head.biWidth] = level;\r
417 \r
418                                 if (localbox.top < y) localbox.top = y;\r
419                                 if (localbox.left > x) localbox.left = x;\r
420                                 if (localbox.right < x) localbox.right = x;\r
421                                 if (localbox.bottom > y) localbox.bottom = y;\r
422             }\r
423         }\r
424     }\r
425 \r
426         if (info.rSelectionBox.top <= localbox.top) info.rSelectionBox.top = localbox.top + 1;\r
427         if (info.rSelectionBox.left > localbox.left) info.rSelectionBox.left = localbox.left;\r
428         if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = localbox.right + 1;\r
429         if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = localbox.bottom;\r
430 \r
431         return true;\r
432 }\r
433 ////////////////////////////////////////////////////////////////////////////////\r
434 /**\r
435  * Adds a single pixel to the existing selection.\r
436  */\r
437 bool CxImage::SelectionAddPixel(long x, long y, BYTE level)\r
438 {\r
439     if (pSelection==NULL) SelectionCreate();\r
440         if (pSelection==NULL) return false;\r
441 \r
442     if (IsInside(x,y)) {\r
443         pSelection[x + y * head.biWidth] = level; // set the correct mask bit\r
444 \r
445                 if (info.rSelectionBox.top <= y) info.rSelectionBox.top = y+1;\r
446                 if (info.rSelectionBox.left > x) info.rSelectionBox.left = x;\r
447                 if (info.rSelectionBox.right <= x) info.rSelectionBox.right = x+1;\r
448                 if (info.rSelectionBox.bottom > y) info.rSelectionBox.bottom = y;\r
449 \r
450         return true;\r
451     }\r
452 \r
453     return false;\r
454 }\r
455 ////////////////////////////////////////////////////////////////////////////////\r
456 /**\r
457  * Exports the selection channel in a 8bpp grayscale image.\r
458  */\r
459 bool CxImage::SelectionSplit(CxImage *dest)\r
460 {\r
461         if (!pSelection || !dest) return false;\r
462 \r
463         CxImage tmp(head.biWidth,head.biHeight,8);\r
464         if (!tmp.IsValid()){\r
465                 strcpy(info.szLastError,tmp.GetLastError());\r
466                 return false;\r
467         }\r
468 \r
469         for(long y=0; y<head.biHeight; y++){\r
470                 for(long x=0; x<head.biWidth; x++){\r
471                         tmp.BlindSetPixelIndex(x,y,pSelection[x+y*head.biWidth]);\r
472                 }\r
473         }\r
474 \r
475         tmp.SetGrayPalette();\r
476         dest->Transfer(tmp);\r
477 \r
478         return true;\r
479 }\r
480 ////////////////////////////////////////////////////////////////////////////////\r
481 /**\r
482  * Creates the selection channel from a gray scale image.\r
483  * black = unselected\r
484  */\r
485 bool CxImage::SelectionSet(CxImage &from)\r
486 {\r
487         if (!from.IsGrayScale() || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight){\r
488                 strcpy(info.szLastError,"CxImage::SelectionSet: wrong width or height, or image is not gray scale");\r
489                 return false;\r
490         }\r
491 \r
492         if (pSelection==NULL) pSelection = (BYTE*)malloc(head.biWidth * head.biHeight);\r
493 \r
494         BYTE* src = from.info.pImage;\r
495         BYTE* dst = pSelection;\r
496         if (src==NULL || dst==NULL){\r
497                 strcpy(info.szLastError,"CxImage::SelectionSet: null pointer");\r
498                 return false;\r
499         }\r
500 \r
501         for (long y=0; y<head.biHeight; y++){\r
502                 memcpy(dst,src,head.biWidth);\r
503                 dst += head.biWidth;\r
504                 src += from.info.dwEffWidth;\r
505         }\r
506 \r
507         SelectionRebuildBox();\r
508 \r
509         return true;\r
510 }\r
511 ////////////////////////////////////////////////////////////////////////////////\r
512 /**\r
513  * Sets the Selection level for a single pixel\r
514  * internal use only: doesn't set SelectionBox. Use SelectionAddPixel\r
515  */\r
516 void CxImage::SelectionSet(const long x,const long y,const BYTE level)\r
517 {\r
518         if (pSelection && IsInside(x,y)) pSelection[x+y*head.biWidth]=level;\r
519 }\r
520 ////////////////////////////////////////////////////////////////////////////////\r
521 /**\r
522  * Gets the Selection level for a single pixel \r
523  */\r
524 BYTE CxImage::SelectionGet(const long x,const long y)\r
525 {\r
526         if (pSelection && IsInside(x,y)) return pSelection[x+y*head.biWidth];\r
527         return 0;\r
528 }\r
529 ////////////////////////////////////////////////////////////////////////////////\r
530 /**\r
531  * Rebuilds the SelectionBox \r
532  */\r
533 void CxImage::SelectionRebuildBox()\r
534 {\r
535         info.rSelectionBox.left = head.biWidth;\r
536         info.rSelectionBox.bottom = head.biHeight;\r
537         info.rSelectionBox.right = info.rSelectionBox.top = 0;\r
538 \r
539         if (!pSelection)\r
540                 return;\r
541 \r
542         long x,y;\r
543 \r
544         for (y=0; y<head.biHeight; y++){\r
545                 for (x=0; x<info.rSelectionBox.left; x++){\r
546                         if (pSelection[x+y*head.biWidth]){\r
547                                 info.rSelectionBox.left = x;\r
548                                 continue;\r
549                         }\r
550                 }\r
551         }\r
552 \r
553         for (y=0; y<head.biHeight; y++){\r
554                 for (x=head.biWidth-1; x>=info.rSelectionBox.right; x--){\r
555                         if (pSelection[x+y*head.biWidth]){\r
556                                 info.rSelectionBox.right = x+1;\r
557                                 continue;\r
558                         }\r
559                 }\r
560         }\r
561 \r
562         for (x=0; x<head.biWidth; x++){\r
563                 for (y=0; y<info.rSelectionBox.bottom; y++){\r
564                         if (pSelection[x+y*head.biWidth]){\r
565                                 info.rSelectionBox.bottom = y;\r
566                                 continue;\r
567                         }\r
568                 }\r
569         }\r
570 \r
571         for (x=0; x<head.biWidth; x++){\r
572                 for (y=head.biHeight-1; y>=info.rSelectionBox.top; y--){\r
573                         if (pSelection[x+y*head.biWidth]){\r
574                                 info.rSelectionBox.top = y+1;\r
575                                 continue;\r
576                         }\r
577                 }\r
578         }\r
579 \r
580 }\r
581 ////////////////////////////////////////////////////////////////////////////////\r
582 /**\r
583  * Gets the Selection level for a single pixel \r
584  * "blind" version assumes that (x,y) is inside to the image.\r
585  */\r
586 BYTE CxImage::BlindSelectionGet(const long x,const long y)\r
587 {\r
588 #ifdef _DEBUG\r
589         if (!IsInside(x,y) || (pSelection==0))\r
590   #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
591                 throw 0;\r
592   #else\r
593                 return 0;\r
594   #endif\r
595 #endif\r
596         return pSelection[x+y*head.biWidth];\r
597 }\r
598 ////////////////////////////////////////////////////////////////////////////////\r
599 /**\r
600  * Returns pointer to selection data for pixel (x,y).\r
601  */\r
602 BYTE* CxImage::SelectionGetPointer(const long x,const long y)\r
603 {\r
604         if (pSelection && IsInside(x,y)) return pSelection+x+y*head.biWidth;\r
605         return 0;\r
606 }\r
607 ////////////////////////////////////////////////////////////////////////////////\r
608 bool CxImage::SelectionFlip()\r
609 {\r
610         if (!pSelection) return false;\r
611 \r
612         BYTE *buff = (BYTE*)malloc(head.biWidth);\r
613         if (!buff) return false;\r
614 \r
615         BYTE *iSrc,*iDst;\r
616         iSrc = pSelection + (head.biHeight-1)*head.biWidth;\r
617         iDst = pSelection;\r
618         for (long i=0; i<(head.biHeight/2); ++i)\r
619         {\r
620                 memcpy(buff, iSrc, head.biWidth);\r
621                 memcpy(iSrc, iDst, head.biWidth);\r
622                 memcpy(iDst, buff, head.biWidth);\r
623                 iSrc-=head.biWidth;\r
624                 iDst+=head.biWidth;\r
625         }\r
626 \r
627         free(buff);\r
628 \r
629         long top = info.rSelectionBox.top;\r
630         info.rSelectionBox.top = head.biHeight - info.rSelectionBox.bottom;\r
631         info.rSelectionBox.bottom = head.biHeight - top;\r
632         return true;\r
633 }\r
634 ////////////////////////////////////////////////////////////////////////////////\r
635 bool CxImage::SelectionMirror()\r
636 {\r
637         if (!pSelection) return false;\r
638         BYTE* pSelection2 = (BYTE*)malloc(head.biWidth * head.biHeight);\r
639         if (!pSelection2) return false;\r
640         \r
641         BYTE *iSrc,*iDst;\r
642         long wdt=head.biWidth-1;\r
643         iSrc=pSelection + wdt;\r
644         iDst=pSelection2;\r
645         for(long y=0; y < head.biHeight; y++){\r
646                 for(long x=0; x <= wdt; x++)\r
647                         *(iDst+x)=*(iSrc-x);\r
648                 iSrc+=head.biWidth;\r
649                 iDst+=head.biWidth;\r
650         }\r
651         free(pSelection);\r
652         pSelection=pSelection2;\r
653         \r
654         long left = info.rSelectionBox.left;\r
655         info.rSelectionBox.left = head.biWidth - info.rSelectionBox.right;\r
656         info.rSelectionBox.right = head.biWidth - left;\r
657         return true;\r
658 }\r
659 ////////////////////////////////////////////////////////////////////////////////\r
660 #if CXIMAGE_SUPPORT_WINDOWS\r
661 /**\r
662  * Converts the selection in a HRGN object.\r
663  */\r
664 bool CxImage::SelectionToHRGN(HRGN& region)\r
665 {\r
666         if (pSelection && region){           \r
667         for(int y = 0; y < head.biHeight; y++){\r
668             HRGN hTemp = NULL;\r
669             int iStart = -1;\r
670             int x = 0;\r
671                         for(; x < head.biWidth; x++){\r
672                 if (pSelection[x + y * head.biWidth] != 0){\r
673                                         if (iStart == -1) iStart = x;\r
674                                         continue;\r
675                 }else{\r
676                     if (iStart >= 0){\r
677                         hTemp = CreateRectRgn(iStart, y, x, y + 1);\r
678                         CombineRgn(region, hTemp, region, RGN_OR);\r
679                         DeleteObject(hTemp);\r
680                         iStart = -1;\r
681                     }\r
682                 }\r
683             }\r
684             if (iStart >= 0){\r
685                 hTemp = CreateRectRgn(iStart, y, x, y + 1);\r
686                 CombineRgn(region, hTemp, region, RGN_OR);\r
687                 DeleteObject(hTemp);\r
688                 iStart = -1;\r
689             }\r
690         }\r
691                 return true;\r
692     }\r
693         return false;\r
694 }\r
695 #endif //CXIMAGE_SUPPORT_WINDOWS\r
696 ////////////////////////////////////////////////////////////////////////////////\r
697 #endif //CXIMAGE_SUPPORT_SELECTION\r