summaryrefslogtreecommitdiff
path: root/src/graphics/FilterFloodfill.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/graphics/FilterFloodfill.h')
-rw-r--r--src/graphics/FilterFloodfill.h165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/graphics/FilterFloodfill.h b/src/graphics/FilterFloodfill.h
new file mode 100644
index 0000000..f4a7ebf
--- /dev/null
+++ b/src/graphics/FilterFloodfill.h
@@ -0,0 +1,165 @@
+//
+// libavg - Media Playback Engine.
+// Copyright (C) 2003-2014 Ulrich von Zadow
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Current versions can be found at www.libavg.de
+//
+
+
+#ifndef _FilterFloodfill_H_
+#define _FilterFloodfill_H_
+
+#include "../api.h"
+#include "Filter.h"
+
+#include "../base/GLMHelper.h"
+
+#include <stack>
+
+namespace avg {
+
+struct Segment {
+ Segment(int iy, int ix1, int ix2, int idy)
+ : y(iy),
+ x1(ix1),
+ x2(ix2),
+ dy(idy)
+ {}
+
+ int y;
+ int x1;
+ int x2;
+ int dy;
+};
+
+class ColorTester {
+public:
+ ColorTester(Pixel32 color)
+ : m_Color(color)
+ {
+ }
+
+ bool operator()(unsigned char * pPixel)
+ {
+ return *(Pixel32*)(pPixel) == m_Color;
+ }
+
+private:
+ Pixel32 m_Color;
+};
+
+// Flood fill filter. The comparison functor used to determine whether a pixel
+// belongs to the area is passed as template parameter. Pixels in the flooded area
+// are made transparent.
+template<class PixelTester>
+class AVG_TEMPLATE_API FilterFloodfill : public Filter
+{
+public:
+ FilterFloodfill(PixelTester tester, const IntPoint& pt);
+ virtual ~FilterFloodfill();
+
+ virtual void applyInPlace(BitmapPtr pBmp) ;
+
+private:
+ void pushSeg(BitmapPtr pBmp, std::stack<Segment>& segments,
+ int y, int x1, int x2, int dy);
+ void setTransparent(unsigned char* pPixel);
+
+ PixelTester m_Tester;
+ IntPoint m_Pt;
+};
+
+template<class PixelTester>
+FilterFloodfill<PixelTester>::FilterFloodfill(PixelTester tester, const IntPoint& pt)
+ : m_Tester(tester),
+ m_Pt(pt)
+{
+}
+
+template<class PixelTester>
+FilterFloodfill<PixelTester>::~FilterFloodfill()
+{
+}
+
+template<class PixelTester>
+void FilterFloodfill<PixelTester>::applyInPlace(BitmapPtr pBmp)
+{
+ // Algorithm from Graphics Gems I, pp 296ff.
+ std::stack<Segment> segments;
+ unsigned char * pPixels = (unsigned char *)(pBmp->getPixels());
+ int stride = pBmp->getStride();
+ pushSeg(pBmp, segments, m_Pt.y, m_Pt.x, m_Pt.x, 1);
+ pushSeg(pBmp, segments, m_Pt.y+1, m_Pt.x, m_Pt.x, -1);
+ int l;
+ while (!segments.empty()) {
+ Segment seg = segments.top();
+ seg.y += seg.dy;
+ segments.pop();
+ int x = seg.x1;
+ unsigned char * pCurPixel = pPixels+x*4+seg.y*stride;
+ for (; x>=0 && m_Tester(pCurPixel); x--) {
+ setTransparent(pCurPixel);
+ pCurPixel-=4;
+ }
+ if (x >= seg.x1) {
+ goto skip;
+ }
+ l = x+1;
+ if (l<seg.x1) {
+ pushSeg(pBmp, segments, seg.y, l, seg.x1-1, -seg.dy);
+ }
+ x = seg.x1+1;
+ do {
+ pCurPixel = pPixels+x*4+seg.y*stride;
+ for (; x<pBmp->getSize().x && m_Tester(pCurPixel); x++) {
+ setTransparent(pCurPixel);
+ pCurPixel+=4;
+ }
+ pushSeg(pBmp, segments, seg.y, l, x-1, seg.dy);
+ if (x>seg.x2+1) {
+ pushSeg(pBmp, segments, seg.y, seg.x2+1, x-1, -seg.dy);
+ }
+skip: x++;
+ pCurPixel = pPixels+x*4+seg.y*stride;
+ for (; x<=seg.x2 && !m_Tester(pCurPixel); x++) {
+ pCurPixel+=4;
+ }
+ l = x;
+ } while (x<=seg.x2);
+
+ }
+}
+
+template<class PixelTester>
+void FilterFloodfill<PixelTester>::pushSeg(BitmapPtr pBmp, std::stack<Segment>& segments,
+ int y, int x1, int x2, int dy)
+{
+ if (y+dy >= 0 && y+dy < pBmp->getSize().y) {
+ segments.push(Segment(y, x1, x2, dy));
+ }
+}
+
+template<class PixelTester>
+void FilterFloodfill<PixelTester>::setTransparent(unsigned char* pPixel)
+{
+ *(Pixel32*)(pPixel) = Pixel32(0,0,255,0);
+}
+
+
+}
+
+#endif