]>
git.saurik.com Git - wxWidgets.git/blob - src/common/imagfill.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/imagfill.cpp
3 // Purpose: FloodFill for wxImage
4 // Author: Julian Smart
5 // Copyright: (c) Julian Smart
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
17 #if wxUSE_IMAGE && !defined(__WXMSW__)
18 // we have no use for this code in wxMSW...
23 #include "wx/dcmemory.h"
28 // Fills with the colour extracted from fillBrush, starting at x,y until either
29 // a color different from the start pixel is reached (wxFLOOD_SURFACE)
30 // or fill color is reached (wxFLOOD_BORDER)
32 static bool LINKAGEMODE
MatchPixel(wxImage
*img
, int x
, int y
, int w
, int h
, const wxColour
& c
)
34 if ((x
<0)||(x
>=w
)||(y
<0)||(y
>=h
)) return false;
36 unsigned char r
= img
->GetRed(x
,y
);
37 unsigned char g
= img
->GetGreen(x
,y
);
38 unsigned char b
= img
->GetBlue(x
,y
);
39 return c
.Red() == r
&& c
.Green() == g
&& c
.Blue() == b
;
42 static bool LINKAGEMODE
MatchBoundaryPixel(wxImage
*img
, int x
, int y
, int w
, int h
, const wxColour
& fill
, const wxColour
& bound
)
44 if ((x
<0)||(x
>=w
)||(y
<0)||(y
>=h
)) return true;
46 unsigned char r
= img
->GetRed(x
,y
);
47 unsigned char g
= img
->GetGreen(x
,y
);
48 unsigned char b
= img
->GetBlue(x
,y
);
49 if ( fill
.Red() == r
&& fill
.Green() == g
&& fill
.Blue() == b
)
51 if ( bound
.Red() == r
&& bound
.Green() == g
&& bound
.Blue() == b
)
57 static void LINKAGEMODE
58 wxImageFloodFill(wxImage
*image
,
59 wxCoord x
, wxCoord y
, const wxBrush
& fillBrush
,
60 const wxColour
& testColour
, int style
)
62 /* A diamond flood-fill using a circular queue system.
63 Each pixel surrounding the current pixel is added to
64 the queue if it meets the criteria, then is retrieved in
65 its turn. Code originally based on http://www.drawit.co.nz/Developers.htm,
66 with explicit permission to use this for wxWidgets granted by Andrew Empson
67 (no copyright claimed)
70 int width
= image
->GetWidth();
71 int height
= image
->GetHeight();
73 //Draw using a pen made from the current brush colour
74 //Potentially allows us to use patterned flood fills in future code
75 wxColour fillColour
= fillBrush
.GetColour();
76 unsigned char r
= fillColour
.Red();
77 unsigned char g
= fillColour
.Green();
78 unsigned char b
= fillColour
.Blue();
81 if (style
== wxFLOOD_SURFACE
)
83 //if wxFLOOD_SURFACE, if fill colour is same as required, we don't do anything
84 if ( image
->GetRed(x
,y
) != r
85 || image
->GetGreen(x
,y
) != g
86 || image
->GetBlue (x
,y
) != b
)
88 //prepare memory for queue
89 //queue save, start, read
90 size_t *qs
, *qst
, *qr
;
92 //queue size (physical)
93 long qSz
= height
* width
* 2;
94 qst
= new size_t [qSz
];
96 //temporary x and y locations
99 for (int i
=0; i
< qSz
; i
++)
109 image
->SetRGB(xt
,yt
,r
,g
,b
);
114 //Add new members to queue
115 //Above current pixel
116 if(MatchPixel(image
,xt
,yt
-1,width
,height
,testColour
))
122 image
->SetRGB(xt
,yt
-1,r
,g
,b
);
124 //Loop back to beginning of queue
125 if(qs
>=(qst
+qSz
)) qs
=qst
;
128 //Below current pixel
129 if(MatchPixel(image
,xt
,yt
+1,width
,height
,testColour
))
135 image
->SetRGB(xt
,yt
+1,r
,g
,b
);
136 if(qs
>=(qst
+qSz
)) qs
=qst
;
139 //Left of current pixel
140 if(MatchPixel(image
,xt
-1,yt
,width
,height
,testColour
))
146 image
->SetRGB(xt
-1,yt
,r
,g
,b
);
147 if(qs
>=(qst
+qSz
)) qs
=qst
;
150 //Right of current pixel
151 if(MatchPixel(image
,xt
+1,yt
,width
,height
,testColour
))
157 image
->SetRGB(xt
+1,yt
,r
,g
,b
);
158 if(qs
>=(qst
+qSz
)) qs
=qst
;
161 //Retrieve current queue member
164 //Loop back to the beginning
165 if(qr
>=(qst
+qSz
)) qr
=qst
;
169 //Go Back to beginning of loop
177 //style is wxFLOOD_BORDER
178 // fill up to testColor border - if already testColour don't do anything
179 if ( image
->GetRed(x
,y
) != testColour
.Red()
180 || image
->GetGreen(x
,y
) != testColour
.Green()
181 || image
->GetBlue(x
,y
) != testColour
.Blue() )
183 //prepare memory for queue
184 //queue save, start, read
185 size_t *qs
, *qst
, *qr
;
187 //queue size (physical)
188 long qSz
= height
* width
* 2;
189 qst
= new size_t [qSz
];
191 //temporary x and y locations
194 for (int i
=0; i
< qSz
; i
++)
204 image
->SetRGB(xt
,yt
,r
,g
,b
);
209 //Add new members to queue
210 //Above current pixel
211 if(!MatchBoundaryPixel(image
,xt
,yt
-1,width
,height
,fillColour
,testColour
))
217 image
->SetRGB(xt
,yt
-1,r
,g
,b
);
219 //Loop back to beginning of queue
220 if(qs
>=(qst
+qSz
)) qs
=qst
;
223 //Below current pixel
224 if(!MatchBoundaryPixel(image
,xt
,yt
+1,width
,height
,fillColour
,testColour
))
230 image
->SetRGB(xt
,yt
+1,r
,g
,b
);
231 if(qs
>=(qst
+qSz
)) qs
=qst
;
234 //Left of current pixel
235 if(!MatchBoundaryPixel(image
,xt
-1,yt
,width
,height
,fillColour
,testColour
))
241 image
->SetRGB(xt
-1,yt
,r
,g
,b
);
242 if(qs
>=(qst
+qSz
)) qs
=qst
;
245 //Right of current pixel
246 if(!MatchBoundaryPixel(image
,xt
+1,yt
,width
,height
,fillColour
,testColour
))
252 image
->SetRGB(xt
+1,yt
,r
,g
,b
);
253 if(qs
>=(qst
+qSz
)) qs
=qst
;
256 //Retrieve current queue member
259 //Loop back to the beginning
260 if(qr
>=(qst
+qSz
)) qr
=qst
;
264 //Go Back to beginning of loop
274 bool wxDoFloodFill(wxDC
*dc
, wxCoord x
, wxCoord y
,
275 const wxColour
& col
, wxFloodFillStyle style
)
277 if (dc
->GetBrush().IsTransparent())
282 dc
->GetSize(&width
, &height
);
284 //it would be nice to fail if we don't get a sensible size...
285 wxCHECK_MSG(width
>= 1 && height
>= 1, false,
286 wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC"));
288 const int x_dev
= dc
->LogicalToDeviceX(x
);
289 const int y_dev
= dc
->LogicalToDeviceY(y
);
291 // if start point is outside dc, can't do anything
292 if (!wxRect(0, 0, width
, height
).Contains(x_dev
, y_dev
))
295 wxBitmap
bitmap(width
, height
);
296 wxMemoryDC
memdc(bitmap
);
299 dc
->GetUserScale(&sx
, &sy
);
300 memdc
.SetUserScale(sx
, sy
);
301 dc
->GetLogicalScale(&sx
, &sy
);
302 memdc
.SetLogicalScale(sx
, sy
);
304 // get logical size and origin
305 const int w_log
= dc
->DeviceToLogicalXRel(width
);
306 const int h_log
= dc
->DeviceToLogicalYRel(height
);
307 const int x0_log
= dc
->DeviceToLogicalX(0);
308 const int y0_log
= dc
->DeviceToLogicalY(0);
310 memdc
.Blit(0, 0, w_log
, h_log
, dc
, x0_log
, y0_log
);
311 memdc
.SelectObject(wxNullBitmap
);
313 wxImage image
= bitmap
.ConvertToImage();
314 wxImageFloodFill(&image
, x_dev
, y_dev
, dc
->GetBrush(), col
, style
);
315 bitmap
= wxBitmap(image
);
316 memdc
.SelectObject(bitmap
);
317 dc
->Blit(x0_log
, y0_log
, w_log
, h_log
, &memdc
, 0, 0);
322 #endif // wxUSE_IMAGE