]>
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
,
62 int WXUNUSED(LogicalFunction
))
64 /* A diamond flood-fill using a circular queue system.
65 Each pixel surrounding the current pixel is added to
66 the queue if it meets the criteria, then is retrieved in
67 its turn. Code originally based on http://www.drawit.co.nz/Developers.htm,
68 with explicit permission to use this for wxWidgets granted by Andrew Empson
69 (no copyright claimed)
72 int width
= image
->GetWidth();
73 int height
= image
->GetHeight();
75 //Draw using a pen made from the current brush colour
76 //Potentially allows us to use patterned flood fills in future code
77 wxColour fillColour
= fillBrush
.GetColour();
78 unsigned char r
= fillColour
.Red();
79 unsigned char g
= fillColour
.Green();
80 unsigned char b
= fillColour
.Blue();
83 if (style
== wxFLOOD_SURFACE
)
85 //if wxFLOOD_SURFACE, if fill colour is same as required, we don't do anything
86 if ( image
->GetRed(x
,y
) != r
87 || image
->GetGreen(x
,y
) != g
88 || image
->GetBlue (x
,y
) != b
)
90 //prepare memory for queue
91 //queue save, start, read
92 size_t *qs
, *qst
, *qr
;
94 //queue size (physical)
95 long qSz
= height
* width
* 2;
96 qst
= new size_t [qSz
];
98 //temporary x and y locations
101 for (int i
=0; i
< qSz
; i
++)
111 image
->SetRGB(xt
,yt
,r
,g
,b
);
116 //Add new members to queue
117 //Above current pixel
118 if(MatchPixel(image
,xt
,yt
-1,width
,height
,testColour
))
124 image
->SetRGB(xt
,yt
-1,r
,g
,b
);
126 //Loop back to beginning of queue
127 if(qs
>=(qst
+qSz
)) qs
=qst
;
130 //Below current pixel
131 if(MatchPixel(image
,xt
,yt
+1,width
,height
,testColour
))
137 image
->SetRGB(xt
,yt
+1,r
,g
,b
);
138 if(qs
>=(qst
+qSz
)) qs
=qst
;
141 //Left of current pixel
142 if(MatchPixel(image
,xt
-1,yt
,width
,height
,testColour
))
148 image
->SetRGB(xt
-1,yt
,r
,g
,b
);
149 if(qs
>=(qst
+qSz
)) qs
=qst
;
152 //Right of current pixel
153 if(MatchPixel(image
,xt
+1,yt
,width
,height
,testColour
))
159 image
->SetRGB(xt
+1,yt
,r
,g
,b
);
160 if(qs
>=(qst
+qSz
)) qs
=qst
;
163 //Retrieve current queue member
166 //Loop back to the beginning
167 if(qr
>=(qst
+qSz
)) qr
=qst
;
171 //Go Back to beginning of loop
179 //style is wxFLOOD_BORDER
180 // fill up to testColor border - if already testColour don't do anything
181 if ( image
->GetRed(x
,y
) != testColour
.Red()
182 || image
->GetGreen(x
,y
) != testColour
.Green()
183 || image
->GetBlue(x
,y
) != testColour
.Blue() )
185 //prepare memory for queue
186 //queue save, start, read
187 size_t *qs
, *qst
, *qr
;
189 //queue size (physical)
190 long qSz
= height
* width
* 2;
191 qst
= new size_t [qSz
];
193 //temporary x and y locations
196 for (int i
=0; i
< qSz
; i
++)
206 image
->SetRGB(xt
,yt
,r
,g
,b
);
211 //Add new members to queue
212 //Above current pixel
213 if(!MatchBoundaryPixel(image
,xt
,yt
-1,width
,height
,fillColour
,testColour
))
219 image
->SetRGB(xt
,yt
-1,r
,g
,b
);
221 //Loop back to beginning of queue
222 if(qs
>=(qst
+qSz
)) qs
=qst
;
225 //Below current pixel
226 if(!MatchBoundaryPixel(image
,xt
,yt
+1,width
,height
,fillColour
,testColour
))
232 image
->SetRGB(xt
,yt
+1,r
,g
,b
);
233 if(qs
>=(qst
+qSz
)) qs
=qst
;
236 //Left of current pixel
237 if(!MatchBoundaryPixel(image
,xt
-1,yt
,width
,height
,fillColour
,testColour
))
243 image
->SetRGB(xt
-1,yt
,r
,g
,b
);
244 if(qs
>=(qst
+qSz
)) qs
=qst
;
247 //Right of current pixel
248 if(!MatchBoundaryPixel(image
,xt
+1,yt
,width
,height
,fillColour
,testColour
))
254 image
->SetRGB(xt
+1,yt
,r
,g
,b
);
255 if(qs
>=(qst
+qSz
)) qs
=qst
;
258 //Retrieve current queue member
261 //Loop back to the beginning
262 if(qr
>=(qst
+qSz
)) qr
=qst
;
266 //Go Back to beginning of loop
276 bool wxDoFloodFill(wxDC
*dc
, wxCoord x
, wxCoord y
,
277 const wxColour
& col
, wxFloodFillStyle style
)
279 if (dc
->GetBrush().GetStyle() == wxBRUSHSTYLE_TRANSPARENT
)
284 dc
->GetSize(&width
, &height
);
286 //it would be nice to fail if we don't get a sensible size...
287 wxCHECK_MSG(width
>= 1 && height
>= 1, false,
288 wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC"));
290 const int x_dev
= dc
->LogicalToDeviceX(x
);
291 const int y_dev
= dc
->LogicalToDeviceY(y
);
293 // if start point is outside dc, can't do anything
294 if (!wxRect(0, 0, width
, height
).Contains(x_dev
, y_dev
))
297 wxBitmap
bitmap(width
, height
);
298 wxMemoryDC
memdc(bitmap
);
301 dc
->GetUserScale(&sx
, &sy
);
302 memdc
.SetUserScale(sx
, sy
);
303 dc
->GetLogicalScale(&sx
, &sy
);
304 memdc
.SetLogicalScale(sx
, sy
);
306 // get logical size and origin
307 const int w_log
= dc
->DeviceToLogicalXRel(width
);
308 const int h_log
= dc
->DeviceToLogicalYRel(height
);
309 const int x0_log
= dc
->DeviceToLogicalX(0);
310 const int y0_log
= dc
->DeviceToLogicalY(0);
312 memdc
.Blit(0, 0, w_log
, h_log
, dc
, x0_log
, y0_log
);
313 memdc
.SelectObject(wxNullBitmap
);
315 wxImage image
= bitmap
.ConvertToImage();
316 wxImageFloodFill(&image
, x_dev
, y_dev
, dc
->GetBrush(), col
, style
,
317 dc
->GetLogicalFunction());
318 bitmap
= wxBitmap(image
);
319 memdc
.SelectObject(bitmap
);
320 dc
->Blit(x0_log
, y0_log
, w_log
, h_log
, &memdc
, 0, 0);
325 #endif // wxUSE_IMAGE