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
|
---|