]> git.saurik.com Git - wxWidgets.git/blob - src/common/imagfill.cpp
Update to zlib 1.2.3
[wxWidgets.git] / src / common / imagfill.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: imagfill.cpp
3 // Purpose: FloodFill for wxImage
4 // Author: Julian Smart
5 // RCS-ID: $Id$
6 // Copyright: (c) Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #include "wx/defs.h"
19
20 #if wxUSE_IMAGE && !defined(__WXMSW__)
21 // we have no use for this code in wxMSW...
22
23 #include "wx/image.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/brush.h"
27 #include "wx/dc.h"
28 #include "wx/dcmemory.h"
29 #endif
30
31 // DoFloodFill
32 // Fills with the colour extracted from fillBrush, starting at x,y until either
33 // a color different from the start pixel is reached (wxFLOOD_SURFACE)
34 // or fill color is reached (wxFLOOD_BORDER)
35
36 static bool LINKAGEMODE MatchPixel(wxImage *img, int x, int y, int w, int h, const wxColour& c)
37 {
38 if ((x<0)||(x>=w)||(y<0)||(y>=h)) return false;
39
40 unsigned char r = img->GetRed(x,y);
41 unsigned char g = img->GetGreen(x,y);
42 unsigned char b = img->GetBlue(x,y);
43 return c.Red() == r && c.Green() == g && c.Blue() == b ;
44 }
45
46 static bool LINKAGEMODE MatchBoundaryPixel(wxImage *img, int x, int y, int w, int h, const wxColour & fill, const wxColour& bound)
47 {
48 if ((x<0)||(x>=w)||(y<0)||(y>=h)) return true;
49
50 unsigned char r = img->GetRed(x,y);
51 unsigned char g = img->GetGreen(x,y);
52 unsigned char b = img->GetBlue(x,y);
53 if ( fill.Red() == r && fill.Green() == g && fill.Blue() == b )
54 return true;
55 if ( bound.Red() == r && bound.Green() == g && bound.Blue() == b )
56 return true;
57 return false;
58 }
59
60
61 static void LINKAGEMODE
62 wxImageFloodFill(wxImage *image,
63 wxCoord x, wxCoord y, const wxBrush & fillBrush,
64 const wxColour& testColour, int style,
65 int WXUNUSED(LogicalFunction))
66 {
67 /* A diamond flood-fill using a circular queue system.
68 Each pixel surrounding the current pixel is added to
69 the queue if it meets the criteria, then is retrieved in
70 its turn. Code originally based on http://www.drawit.co.nz/Developers.htm,
71 with explicit permission to use this for wxWidgets granted by Andrew Empson
72 (no copyright claimed)
73 */
74
75 int width = image->GetWidth();
76 int height = image->GetHeight();
77
78 //Draw using a pen made from the current brush colour
79 //Potentially allows us to use patterned flood fills in future code
80 wxColour fillColour = fillBrush.GetColour();
81 unsigned char r = fillColour.Red();
82 unsigned char g = fillColour.Green();
83 unsigned char b = fillColour.Blue();
84
85 //initial test :
86 if (style == wxFLOOD_SURFACE)
87 {
88 //if wxFLOOD_SURFACE, if fill colour is same as required, we don't do anything
89 if ( image->GetRed(x,y) != r
90 || image->GetGreen(x,y) != g
91 || image->GetBlue (x,y) != b )
92 {
93 //prepare memory for queue
94 //queue save, start, read
95 size_t *qs, *qst, *qr;
96
97 //queue size (physical)
98 long qSz= height * width * 2;
99 qst = new size_t [qSz];
100
101 //temporary x and y locations
102 int xt, yt;
103
104 for (int i=0; i < qSz; i++)
105 qst[i] = 0;
106
107 // start queue
108 qs=qr=qst;
109 *qs=xt=x;
110 qs++;
111 *qs=yt=y;
112 qs++;
113
114 image->SetRGB(xt,yt,r,g,b);
115
116 //Main queue loop
117 while(qr!=qs)
118 {
119 //Add new members to queue
120 //Above current pixel
121 if(MatchPixel(image,xt,yt-1,width,height,testColour))
122 {
123 *qs=xt;
124 qs++;
125 *qs=yt-1;
126 qs++;
127 image->SetRGB(xt,yt-1,r,g,b);
128
129 //Loop back to beginning of queue
130 if(qs>=(qst+qSz)) qs=qst;
131 }
132
133 //Below current pixel
134 if(MatchPixel(image,xt,yt+1,width,height,testColour))
135 {
136 *qs=xt;
137 qs++;
138 *qs=yt+1;
139 qs++;
140 image->SetRGB(xt,yt+1,r,g,b);
141 if(qs>=(qst+qSz)) qs=qst;
142 }
143
144 //Left of current pixel
145 if(MatchPixel(image,xt-1,yt,width,height,testColour))
146 {
147 *qs=xt-1;
148 qs++;
149 *qs=yt;
150 qs++;
151 image->SetRGB(xt-1,yt,r,g,b);
152 if(qs>=(qst+qSz)) qs=qst;
153 }
154
155 //Right of current pixel
156 if(MatchPixel(image,xt+1,yt,width,height,testColour))
157 {
158 *qs=xt+1;
159 qs++;
160 *qs=yt;
161 qs++;
162 image->SetRGB(xt+1,yt,r,g,b);
163 if(qs>=(qst+qSz)) qs=qst;
164 }
165
166 //Retrieve current queue member
167 qr+=2;
168
169 //Loop back to the beginning
170 if(qr>=(qst+qSz)) qr=qst;
171 xt=*qr;
172 yt=*(qr+1);
173
174 //Go Back to beginning of loop
175 }
176
177 delete[] qst;
178 }
179 }
180 else
181 {
182 //style is wxFLOOD_BORDER
183 // fill up to testColor border - if already testColour don't do anything
184 if ( image->GetRed(x,y) != testColour.Red()
185 || image->GetGreen(x,y) != testColour.Green()
186 || image->GetBlue(x,y) != testColour.Blue() )
187 {
188 //prepare memory for queue
189 //queue save, start, read
190 size_t *qs, *qst, *qr;
191
192 //queue size (physical)
193 long qSz= height * width * 2;
194 qst = new size_t [qSz];
195
196 //temporary x and y locations
197 int xt, yt;
198
199 for (int i=0; i < qSz; i++)
200 qst[i] = 0;
201
202 // start queue
203 qs=qr=qst;
204 *qs=xt=x;
205 qs++;
206 *qs=yt=y;
207 qs++;
208
209 image->SetRGB(xt,yt,r,g,b);
210
211 //Main queue loop
212 while (qr!=qs)
213 {
214 //Add new members to queue
215 //Above current pixel
216 if(!MatchBoundaryPixel(image,xt,yt-1,width,height,fillColour,testColour))
217 {
218 *qs=xt;
219 qs++;
220 *qs=yt-1;
221 qs++;
222 image->SetRGB(xt,yt-1,r,g,b);
223
224 //Loop back to beginning of queue
225 if(qs>=(qst+qSz)) qs=qst;
226 }
227
228 //Below current pixel
229 if(!MatchBoundaryPixel(image,xt,yt+1,width,height,fillColour,testColour))
230 {
231 *qs=xt;
232 qs++;
233 *qs=yt+1;
234 qs++;
235 image->SetRGB(xt,yt+1,r,g,b);
236 if(qs>=(qst+qSz)) qs=qst;
237 }
238
239 //Left of current pixel
240 if(!MatchBoundaryPixel(image,xt-1,yt,width,height,fillColour,testColour))
241 {
242 *qs=xt-1;
243 qs++;
244 *qs=yt;
245 qs++;
246 image->SetRGB(xt-1,yt,r,g,b);
247 if(qs>=(qst+qSz)) qs=qst;
248 }
249
250 //Right of current pixel
251 if(!MatchBoundaryPixel(image,xt+1,yt,width,height,fillColour,testColour))
252 {
253 *qs=xt+1;
254 qs++;
255 *qs=yt;
256 qs++;
257 image->SetRGB(xt+1,yt,r,g,b);
258 if(qs>=(qst+qSz)) qs=qst;
259 }
260
261 //Retrieve current queue member
262 qr+=2;
263
264 //Loop back to the beginning
265 if(qr>=(qst+qSz)) qr=qst;
266 xt=*qr;
267 yt=*(qr+1);
268
269 //Go Back to beginning of loop
270 }
271
272 delete[] qst;
273 }
274 }
275 //all done,
276 }
277
278
279 bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
280 const wxColour& col, int style)
281 {
282 if (dc->GetBrush().GetStyle() == wxTRANSPARENT)
283 return true;
284
285 int height = 0;
286 int width = 0;
287 dc->GetSize(&width, &height);
288
289 //it would be nice to fail if we don't get a sensible size...
290 wxCHECK_MSG(width >= 1 && height >= 1, false,
291 wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC"));
292
293 //this is much faster than doing the individual pixels
294 wxMemoryDC memdc;
295 wxBitmap bitmap(width, height);
296 memdc.SelectObject(bitmap);
297 memdc.Blit(0, 0, width, height, dc, 0, 0);
298 memdc.SelectObject(wxNullBitmap);
299
300 wxImage image = bitmap.ConvertToImage();
301 wxImageFloodFill(&image, x,y, dc->GetBrush(), col, style,
302 dc->GetLogicalFunction());
303 bitmap = wxBitmap(image);
304 memdc.SelectObject(bitmap);
305 dc->Blit(0, 0, width, height, &memdc, 0, 0);
306 memdc.SelectObject(wxNullBitmap);
307
308 return true;
309 }
310
311 #endif // wxUSE_IMAGE