27struct FilterSharedData
37 : mpReadAccess(rReadAccess.
get())
38 , mpWriteAccess(rWriteAccess.
get())
40 , mnOutsideVal(nOutsideVal)
41 , maOutsideColor(
ColorTransparency, nOutsideVal, nOutsideVal, nOutsideVal, nOutsideVal)
62template <
typename MorphologyOp,
int nComponentW
idth>
struct Value
64 static constexpr int nWidthBytes = nComponentWidth / 8;
65 static_assert(nWidthBytes * 8 == nComponentWidth);
70 Value(FilterSharedData
const& rShared,
bool bLookOutside)
72 std::fill_n(aResult, nWidthBytes,
73 bLookOutside ? rShared.mnOutsideVal : MorphologyOp::initVal);
80 std::transform(pSource, pSource + nWidthBytes, aResult, aResult, MorphologyOp::apply);
87 std::copy_n(aResult, nWidthBytes, pDest);
93template <
typename MorphologyOp>
struct Value<MorphologyOp, 0>
96 MorphologyOp::initVal, MorphologyOp::initVal,
97 MorphologyOp::initVal };
102 Value(FilterSharedData
const& rShared,
bool bLookOutside)
103 : aResult(bLookOutside ? rShared.maOutsideColor : initColor)
110 const auto& rSource = pReadAccess->
GetColor(y, x);
111 aResult =
Color(ColorAlpha, MorphologyOp::apply(rSource.GetAlpha(), aResult.
GetAlpha()),
112 MorphologyOp::apply(rSource.GetRed(), aResult.
GetRed()),
113 MorphologyOp::apply(rSource.GetGreen(), aResult.
GetGreen()),
114 MorphologyOp::apply(rSource.GetBlue(), aResult.
GetBlue()));
120 pWriteAccess->
SetPixel(y, x, aResult);
124bool GetMinMax(sal_Int32 nCenter, sal_Int32 nRadius, sal_Int32 nMaxLimit, sal_Int32& nMin,
127 nMin = nCenter - nRadius;
128 nMax = nCenter + nRadius;
129 bool bLookOutside =
false;
135 if (nMax > nMaxLimit)
143template <
typename MorphologyOp,
int nComponentW
idth>
struct pass
145 static void Horizontal(FilterSharedData
const& rShared,
const sal_Int32 nStart,
146 const sal_Int32 nEnd)
151 const sal_Int32 nLastIndex = pReadAccess->
Width() - 1;
153 for (sal_Int32 y = nStart;
y <= nEnd;
y++)
158 for (sal_Int32 x = 0;
x <= nLastIndex;
x++)
162 sal_Int32 iMin, iMax;
163 const bool bLookOutside = GetMinMax(x, rShared.mnRadius, nLastIndex, iMin, iMax);
164 Value<MorphologyOp, nComponentWidth> aResult(rShared, bLookOutside);
165 for (sal_Int32 i = iMin;
i <= iMax; ++
i)
166 aResult.apply(pReadAccess, i, y, pSourceHint);
168 aResult.copy(pWriteAccess, x, y, pDestHint);
173 static void Vertical(FilterSharedData
const& rShared,
const sal_Int32 nStart,
174 const sal_Int32 nEnd)
179 const sal_Int32 nLastIndex = pReadAccess->
Height() - 1;
181 for (sal_Int32 x = nStart;
x <= nEnd;
x++)
183 for (sal_Int32 y = 0;
y <= nLastIndex;
y++)
187 sal_Int32 iMin, iMax;
188 const bool bLookOutside = GetMinMax(y, rShared.mnRadius, nLastIndex, iMin, iMax);
189 Value<MorphologyOp, nComponentWidth> aResult(rShared, bLookOutside);
190 for (sal_Int32 i = iMin;
i <= iMax; ++
i)
191 aResult.apply(pReadAccess, x, i);
193 aResult.copy(pWriteAccess, x, y);
199typedef void (*passFn)(FilterSharedData
const& rShared, sal_Int32 nStart, sal_Int32 nEnd);
204 FilterSharedData& mrShared;
209 explicit FilterTask(
const std::shared_ptr<comphelper::ThreadTaskTag>& pTag, passFn pFunction,
210 FilterSharedData& rShared, sal_Int32 nStart, sal_Int32 nEnd)
212 , mpFunction(pFunction)
219 virtual void doWork()
override { mpFunction(mrShared, mnStart, mnEnd); }
222constexpr sal_Int32 nThreadStrip = 16;
224template <
typename MorphologyOp,
int nComponentW
idth>
225void runFilter(
Bitmap& rBitmap,
const sal_Int32 nRadius,
const bool bParallel,
226 bool bUseValueOutside,
sal_uInt8 nValueOutside)
228 using myPass = pass<MorphologyOp, nComponentWidth>;
229 const sal_uInt8 nOutsideVal = bUseValueOutside ? nValueOutside : MorphologyOp::initVal;
240 FilterSharedData aSharedData(pReadAccess, pWriteAccess, nRadius, nOutsideVal);
242 const sal_Int32 nLastIndex = pReadAccess->
Height() - 1;
243 sal_Int32 nStripStart = 0;
244 for (; nStripStart < nLastIndex - nThreadStrip; nStripStart += nThreadStrip)
246 sal_Int32 nStripEnd = nStripStart + nThreadStrip - 1;
247 auto pTask(std::make_unique<FilterTask>(pTag, myPass::Horizontal, aSharedData,
248 nStripStart, nStripEnd));
252 myPass::Horizontal(aSharedData, nStripStart, nLastIndex);
258 FilterSharedData aSharedData(pReadAccess, pWriteAccess, nRadius, nOutsideVal);
260 const sal_Int32 nLastIndex = pReadAccess->
Width() - 1;
261 sal_Int32 nStripStart = 0;
262 for (; nStripStart < nLastIndex - nThreadStrip; nStripStart += nThreadStrip)
264 sal_Int32 nStripEnd = nStripStart + nThreadStrip - 1;
265 auto pTask(std::make_unique<FilterTask>(pTag, myPass::Vertical, aSharedData,
266 nStripStart, nStripEnd));
270 myPass::Vertical(aSharedData, nStripStart, nLastIndex);
276 SAL_WARN(
"vcl.gdi",
"threaded bitmap blurring failed");
284 FilterSharedData aSharedData(pReadAccess, pWriteAccess, nRadius, nOutsideVal);
285 sal_Int32 nFirstIndex = 0;
286 sal_Int32 nLastIndex = pReadAccess->
Height() - 1;
287 myPass::Horizontal(aSharedData, nFirstIndex, nLastIndex);
292 FilterSharedData aSharedData(pReadAccess, pWriteAccess, nRadius, nOutsideVal);
293 sal_Int32 nFirstIndex = 0;
294 sal_Int32 nLastIndex = pReadAccess->
Width() - 1;
295 myPass::Vertical(aSharedData, nFirstIndex, nLastIndex);
300template <
int nComponentW
idth>
304 const bool bParallel =
true;
307 runFilter<ErodeOp, nComponentWidth>(rBitmap, nRadius, bParallel, bUseValueOutside,
310 runFilter<DilateOp, nComponentWidth>(rBitmap, nRadius, bParallel, bUseValueOutside,
326 , m_nValueOutside(nValueOutside)
327 , m_bUseValueOutside(true)
341 Bitmap bitmapCopy(rBitmap);
348 switch (nScanlineFormat)
virtual BitmapEx execute(BitmapEx const &rBitmap) const override
Bitmap filter(Bitmap const &rBitmap) const
BitmapBasicMorphologyFilter(BasicMorphologyOp op, sal_Int32 nRadius)
sal_uInt8 m_nValueOutside
virtual ~BitmapBasicMorphologyFilter()
const AlphaMask & GetAlphaMask() const
Bitmap GetBitmap(Color aTransparentReplaceColor) const
tools::Long Height() const
tools::Long Width() const
ScanlineFormat GetScanlineFormat() const
BitmapColor GetColor(tools::Long nY, tools::Long nX) const
Scanline GetScanline(tools::Long nY) const
void SetPixel(tools::Long nY, tools::Long nX, const BitmapColor &rBitmapColor)
sal_uInt8 GetBlue() const
sal_uInt8 GetAlpha() const
sal_uInt8 GetGreen() const
static ThreadPool & getSharedOptimalPool()
void waitUntilDone(const std::shared_ptr< ThreadTaskTag > &, bool bJoin=true)
static std::shared_ptr< ThreadTaskTag > createThreadTaskTag()
void pushTask(std::unique_ptr< ThreadTask > pTask)
#define SAL_WARN(area, stream)
void copy(const fs::path &src, const fs::path &dest)
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)