]>
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
6 // Copyright: (c) Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
18 #if wxUSE_IMAGE && !defined(__WXMSW__)
19 // we have no use for this code in wxMSW...
24 #include "wx/dcmemory.h"
29 // Fills with the colour extracted from fillBrush, starting at x,y until either
30 // a color different from the start pixel is reached (wxFLOOD_SURFACE)
31 // or fill color is reached (wxFLOOD_BORDER)
33 static bool LINKAGEMODE
MatchPixel(wxImage
*img
, int x
, int y
, int w
, int h
, const wxColour
& c
)
35 if ((x
<0)||(x
>=w
)||(y
<0)||(y
>=h
)) return false;
37 unsigned char r
= img
->GetRed(x
,y
);
38 unsigned char g
= img
->GetGreen(x
,y
);
39 unsigned char b
= img
->GetBlue(x
,y
);
40 return c
.Red() == r
&& c
.Green() == g
&& c
.Blue() == b
;
43 static bool LINKAGEMODE
MatchBoundaryPixel(wxImage
*img
, int x
, int y
, int w
, int h
, const wxColour
& fill
, const wxColour
& bound
)
45 if ((x
<0)||(x
>=w
)||(y
<0)||(y
>=h
)) return true;
47 unsigned char r
= img
->GetRed(x
,y
);
48 unsigned char g
= img
->GetGreen(x
,y
);
49 unsigned char b
= img
->GetBlue(x
,y
);
50 if ( fill
.Red() == r
&& fill
.Green() == g
&& fill
.Blue() == b
)
52 if ( bound
.Red() == r
&& bound
.Green() == g
&& bound
.Blue() == b
)
58 static void LINKAGEMODE
59 wxImageFloodFill(wxImage
*image
,
60 wxCoord x
, wxCoord y
, const wxBrush
& fillBrush
,
61 const wxColour
& testColour
, int style
)
63 /* A diamond flood-fill using a circular queue system.
64 Each pixel surrounding the current pixel is added to
65 the queue if it meets the criteria, then is retrieved in
66 its turn. Code originally based on http://www.drawit.co.nz/Developers.htm,
67 with explicit permission to use this for wxWidgets granted by Andrew Empson
68 (no copyright claimed)
71 int width
= image
->GetWidth();
72 int height
= image
->GetHeight();
74 //Draw using a pen made from the current brush colour
75 //Potentially allows us to use patterned flood fills in future code
76 wxColour fillColour
= fillBrush
.GetColour();
77 unsigned char r
= fillColour
.Red();
78 unsigned char g
= fillColour
.Green();
79 unsigned char b
= fillColour
.Blue();
82 if (style
== wxFLOOD_SURFACE
)
84 //if wxFLOOD_SURFACE, if fill colour is same as required, we don't do anything
85 if ( image
->GetRed(x
,y
) != r
86 || image
->GetGreen(x
,y
) != g
87 || image
->GetBlue (x
,y
) != b
)
89 //prepare memory for queue
90 //queue save, start, read
91 size_t *qs
, *qst
, *qr
;
93 //queue size (physical)
94 long qSz
= height
* width
* 2;
95 qst
= new size_t [qSz
];
97 //temporary x and y locations
100 for (int i
=0; i
< qSz
; i
++)
110 image
->SetRGB(xt
,yt
,r
,g
,b
);
115 //Add new members to queue
116 //Above current pixel
117 if(MatchPixel(image
,xt
,yt
-1,width
,height
,testColour
))
123 image
->SetRGB(xt
,yt
-1,r
,g
,b
);
125 //Loop back to beginning of queue
126 if(qs
>=(qst
+qSz
)) qs
=qst
;
129 //Below current pixel
130 if(MatchPixel(image
,xt
,yt
+1,width
,height
,testColour
))
136 image
->SetRGB(xt
,yt
+1,r
,g
,b
);
137 if(qs
>=(qst
+qSz
)) qs
=qst
;
140 //Left of current pixel
141 if(MatchPixel(image
,xt
-1,yt
,width
,height
,testColour
))
147 image
->SetRGB(xt
-1,yt
,r
,g
,b
);
148 if(qs
>=(qst
+qSz
)) qs
=qst
;
151 //Right of current pixel
152 if(MatchPixel(image
,xt
+1,yt
,width
,height
,testColour
))
158 image
->SetRGB(xt
+1,yt
,r
,g
,b
);
159 if(qs
>=(qst
+qSz
)) qs
=qst
;
162 //Retrieve current queue member
165 //Loop back to the beginning
166 if(qr
>=(qst
+qSz
)) qr
=qst
;
170 //Go Back to beginning of loop
178 //style is wxFLOOD_BORDER
179 // fill up to testColor border - if already testColour don't do anything
180 if ( image
->GetRed(x
,y
) != testColour
.Red()
181 || image
->GetGreen(x
,y
) != testColour
.Green()
182 || image
->GetBlue(x
,y
) != testColour
.Blue() )
184 //prepare memory for queue
185 //queue save, start, read
186 size_t *qs
, *qst
, *qr
;
188 //queue size (physical)
189 long qSz
= height
* width
* 2;
190 qst
= new size_t [qSz
];
192 //temporary x and y locations
195 for (int i
=0; i
< qSz
; i
++)
205 image
->SetRGB(xt
,yt
,r
,g
,b
);
210 //Add new members to queue
211 //Above current pixel
212 if(!MatchBoundaryPixel(image
,xt
,yt
-1,width
,height
,fillColour
,testColour
))
218 image
->SetRGB(xt
,yt
-1,r
,g
,b
);
220 //Loop back to beginning of queue
221 if(qs
>=(qst
+qSz
)) qs
=qst
;
224 //Below current pixel
225 if(!MatchBoundaryPixel(image
,xt
,yt
+1,width
,height
,fillColour
,testColour
))
231 image
->SetRGB(xt
,yt
+1,r
,g
,b
);
232 if(qs
>=(qst
+qSz
)) qs
=qst
;
235 //Left of current pixel
236 if(!MatchBoundaryPixel(image
,xt
-1,yt
,width
,height
,fillColour
,testColour
))
242 image
->SetRGB(xt
-1,yt
,r
,g
,b
);
243 if(qs
>=(qst
+qSz
)) qs
=qst
;
246 //Right of current pixel
247 if(!MatchBoundaryPixel(image
,xt
+1,yt
,width
,height
,fillColour
,testColour
))
253 image
->SetRGB(xt
+1,yt
,r
,g
,b
);
254 if(qs
>=(qst
+qSz
)) qs
=qst
;
257 //Retrieve current queue member
260 //Loop back to the beginning
261 if(qr
>=(qst
+qSz
)) qr
=qst
;
265 //Go Back to beginning of loop
275 bool wxDoFloodFill(wxDC
*dc
, wxCoord x
, wxCoord y
,
276 const wxColour
& col
, wxFloodFillStyle style
)
278 if (dc
->GetBrush().IsTransparent())
283 dc
->GetSize(&width
, &height
);
285 //it would be nice to fail if we don't get a sensible size...
286 wxCHECK_MSG(width
>= 1 && height
>= 1, false,
287 wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC"));
289 const int x_dev
= dc
->LogicalToDeviceX(x
);
290 const int y_dev
= dc
->LogicalToDeviceY(y
);
292 // if start point is outside dc, can't do anything
293 if (!wxRect(0, 0, width
, height
).Contains(x_dev
, y_dev
))
296 wxBitmap
bitmap(width
, height
);
297 wxMemoryDC
memdc(bitmap
);
300 dc
->GetUserScale(&sx
, &sy
);
301 memdc
.SetUserScale(sx
, sy
);
302 dc
->GetLogicalScale(&sx
, &sy
);
303 memdc
.SetLogicalScale(sx
, sy
);
305 // get logical size and origin
306 const int w_log
= dc
->DeviceToLogicalXRel(width
);
307 const int h_log
= dc
->DeviceToLogicalYRel(height
);
308 const int x0_log
= dc
->DeviceToLogicalX(0);
309 const int y0_log
= dc
->DeviceToLogicalY(0);
311 memdc
.Blit(0, 0, w_log
, h_log
, dc
, x0_log
, y0_log
);
312 memdc
.SelectObject(wxNullBitmap
);
314 wxImage image
= bitmap
.ConvertToImage();
315 wxImageFloodFill(&image
, x_dev
, y_dev
, dc
->GetBrush(), col
, style
);
316 bitmap
= wxBitmap(image
);
317 memdc
.SelectObject(bitmap
);
318 dc
->Blit(x0_log
, y0_log
, w_log
, h_log
, &memdc
, 0, 0);
323 #endif // wxUSE_IMAGE