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