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