[Libreoffice-commits] core.git: include/vcl vcl/Library_vcl.mk vcl/source
Chris Sherlock
chris.sherlock79 at gmail.com
Fri Apr 20 06:32:41 UTC 2018
include/vcl/BitmapGaussianSeparableBlurFilter.hxx | 50 +++
include/vcl/bitmap.hxx | 16 -
vcl/Library_vcl.mk | 1
vcl/source/bitmap/BitmapGaussianSeparableBlurFilter.cxx | 217 ++++++++++++++++
vcl/source/gdi/bitmap3.cxx | 52 ---
vcl/source/gdi/bitmap4.cxx | 154 -----------
6 files changed, 280 insertions(+), 210 deletions(-)
New commits:
commit f9473a8d2ea6740d325ac35da74fec16476820f0
Author: Chris Sherlock <chris.sherlock79 at gmail.com>
Date: Wed Apr 18 07:51:50 2018 +1000
vcl: ImplSeparableBlurFilter() -> BitmapGaussianSeparableBlurFilter
Change-Id: I996c9fcb0524e14e0093142be0749f0e5836426b
Reviewed-on: https://gerrit.libreoffice.org/53071
Tested-by: Jenkins <ci at libreoffice.org>
Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>
diff --git a/include/vcl/BitmapGaussianSeparableBlurFilter.hxx b/include/vcl/BitmapGaussianSeparableBlurFilter.hxx
new file mode 100644
index 000000000000..6e6a3a09e6f0
--- /dev/null
+++ b/include/vcl/BitmapGaussianSeparableBlurFilter.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#ifndef INCLUDED_VCL_BITMAPGAUSSIANSEPARABLEBLURFILTER_HXX
+#define INCLUDED_VCL_BITMAPGAUSSIANSEPARABLEBLURFILTER_HXX
+
+#include <vcl/BitmapFilter.hxx>
+
+class BitmapEx;
+
+class VCL_DLLPUBLIC BitmapGaussianSeparableBlurFilter : public BitmapFilter
+{
+public:
+ BitmapGaussianSeparableBlurFilter(double fRadius)
+ : mfRadius(fRadius)
+ {
+ }
+
+ /** Separable Gaussian Blur filter and accepts a blur radius
+ as a parameter so the user can change the strength of the blur.
+ Radius of 1.0 is 3 * standard deviation of gauss function.
+
+ Separable Blur implementation uses 2x separable 1D convolution
+ to process the image.
+ */
+ virtual BitmapEx execute(BitmapEx const& rBitmapEx) override;
+
+private:
+ double mfRadius;
+
+ bool convolutionPass(Bitmap& rBitmap, Bitmap& aNewBitmap, BitmapReadAccess const* pReadAcc,
+ int aNumberOfContributions, const double* pWeights, int const* pPixels,
+ const int* pCount);
+
+ static double* makeBlurKernel(const double radius, int& rows);
+ static void blurContributions(const int aSize, const int aNumberOfContributions,
+ const double* pBlurVector, double*& pWeights, int*& pPixels,
+ int*& pCount);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx
index cc50a6dc9bcc..6370a63d116f 100644
--- a/include/vcl/bitmap.hxx
+++ b/include/vcl/bitmap.hxx
@@ -676,14 +676,6 @@ public:
SAL_DLLPRIVATE bool ImplScaleFast( const double& rScaleX, const double& rScaleY );
SAL_DLLPRIVATE bool ImplScaleInterpolate( const double& rScaleX, const double& rScaleY );
- SAL_DLLPRIVATE bool ImplConvolutionPass(
- Bitmap& aNewBitmap,
- BitmapReadAccess const * pReadAcc,
- int aNumberOfContributions,
- const double* pWeights,
- int const * pPixels,
- const int* pCount );
-
SAL_DLLPRIVATE bool ImplMakeGreyscales( sal_uInt16 nGreyscales );
SAL_DLLPRIVATE bool ImplDitherMatrix();
SAL_DLLPRIVATE bool ImplDitherFloyd();
@@ -707,16 +699,8 @@ public:
SAL_DLLPRIVATE bool ImplMosaic( const BmpFilterParam* pFilterParam );
SAL_DLLPRIVATE bool ImplPopArt();
- SAL_DLLPRIVATE bool ImplSeparableBlurFilter( const double aRadius );
SAL_DLLPRIVATE bool ImplSeparableUnsharpenFilter( const double aRadius );
SAL_DLLPRIVATE bool ImplDuotoneFilter( const sal_uLong nColorOne, sal_uLong nColorTwo );
- SAL_DLLPRIVATE static void ImplBlurContributions(
- const int aSize,
- const int aNumberOfContributions,
- const double* pBlurVector,
- double*& pWeights,
- int*& pPixels,
- int*& pCount );
public:
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 128541e5d0fd..03c705aa5544 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -317,6 +317,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/bitmap/BitmapDisabledImageFilter \
vcl/source/bitmap/BitmapColorizeFilter \
vcl/source/bitmap/bitmappaint \
+ vcl/source/bitmap/BitmapGaussianSeparableBlurFilter \
vcl/source/bitmap/BitmapFastScaleFilter \
vcl/source/bitmap/BitmapScaleSuperFilter \
vcl/source/bitmap/BitmapScaleConvolutionFilter \
diff --git a/vcl/source/bitmap/BitmapGaussianSeparableBlurFilter.cxx b/vcl/source/bitmap/BitmapGaussianSeparableBlurFilter.cxx
new file mode 100644
index 000000000000..b28ce99e8d19
--- /dev/null
+++ b/vcl/source/bitmap/BitmapGaussianSeparableBlurFilter.cxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <basegfx/color/bcolortools.hxx>
+
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/bitmapaccess.hxx>
+#include <vcl/BitmapGaussianSeparableBlurFilter.hxx>
+
+#include <bitmapwriteaccess.hxx>
+
+BitmapEx BitmapGaussianSeparableBlurFilter::execute(BitmapEx const& rBitmapEx)
+{
+ Bitmap aBitmap(rBitmapEx.GetBitmap());
+
+ const long nWidth = aBitmap.GetSizePixel().Width();
+ const long nHeight = aBitmap.GetSizePixel().Height();
+
+ // Prepare Blur Vector
+ int aNumberOfContributions;
+ double* pBlurVector = makeBlurKernel(mfRadius, aNumberOfContributions);
+
+ double* pWeights;
+ int* pPixels;
+ int* pCount;
+
+ // Do horizontal filtering
+ blurContributions(nWidth, aNumberOfContributions, pBlurVector, pWeights, pPixels, pCount);
+
+ Bitmap::ScopedReadAccess pReadAcc(aBitmap);
+
+ // switch coordinates as convolution pass transposes result
+ Bitmap aNewBitmap(Size(nHeight, nWidth), 24);
+
+ bool bResult = convolutionPass(aBitmap, aNewBitmap, pReadAcc.get(), aNumberOfContributions,
+ pWeights, pPixels, pCount);
+
+ // Cleanup
+ pReadAcc.reset();
+ delete[] pWeights;
+ delete[] pPixels;
+ delete[] pCount;
+
+ if (!bResult)
+ {
+ delete[] pBlurVector;
+ }
+ else
+ {
+ // Swap current bitmap with new bitmap
+ aBitmap.ReassignWithSize(aNewBitmap);
+
+ // Do vertical filtering
+ blurContributions(nHeight, aNumberOfContributions, pBlurVector, pWeights, pPixels, pCount);
+
+ pReadAcc = Bitmap::ScopedReadAccess(aBitmap);
+ aNewBitmap = Bitmap(Size(nWidth, nHeight), 24);
+ bResult = convolutionPass(aBitmap, aNewBitmap, pReadAcc.get(), aNumberOfContributions,
+ pWeights, pPixels, pCount);
+
+ // Cleanup
+ pReadAcc.reset();
+ delete[] pWeights;
+ delete[] pCount;
+ delete[] pPixels;
+ delete[] pBlurVector;
+
+ if (bResult)
+ aBitmap.ReassignWithSize(aNewBitmap); // swap current bitmap with new bitmap
+ }
+
+ if (bResult)
+ return BitmapEx(aBitmap);
+
+ return BitmapEx();
+}
+
+bool BitmapGaussianSeparableBlurFilter::convolutionPass(Bitmap& rBitmap, Bitmap& aNewBitmap,
+ BitmapReadAccess const* pReadAcc,
+ int aNumberOfContributions,
+ const double* pWeights, int const* pPixels,
+ const int* pCount)
+{
+ if (!pReadAcc)
+ return false;
+
+ BitmapScopedWriteAccess pWriteAcc(aNewBitmap);
+ if (!pWriteAcc)
+ return false;
+
+ const int nHeight = rBitmap.GetSizePixel().Height();
+ assert(rBitmap.GetSizePixel().Height() == aNewBitmap.GetSizePixel().Width());
+ const int nWidth = rBitmap.GetSizePixel().Width();
+ assert(rBitmap.GetSizePixel().Width() == aNewBitmap.GetSizePixel().Height());
+
+ BitmapColor aColor;
+ double aValueRed, aValueGreen, aValueBlue;
+ double aSum, aWeight;
+ int aBaseIndex, aIndex;
+
+ for (int nSourceY = 0; nSourceY < nHeight; ++nSourceY)
+ {
+ for (int nSourceX = 0; nSourceX < nWidth; ++nSourceX)
+ {
+ aBaseIndex = nSourceX * aNumberOfContributions;
+ aSum = aValueRed = aValueGreen = aValueBlue = 0.0;
+
+ for (int j = 0; j < pCount[nSourceX]; ++j)
+ {
+ aIndex = aBaseIndex + j;
+ aSum += aWeight = pWeights[aIndex];
+
+ aColor = pReadAcc->GetColor(nSourceY, pPixels[aIndex]);
+
+ aValueRed += aWeight * aColor.GetRed();
+ aValueGreen += aWeight * aColor.GetGreen();
+ aValueBlue += aWeight * aColor.GetBlue();
+ }
+
+ BitmapColor aResultColor(static_cast<sal_uInt8>(MinMax(aValueRed / aSum, 0, 255)),
+ static_cast<sal_uInt8>(MinMax(aValueGreen / aSum, 0, 255)),
+ static_cast<sal_uInt8>(MinMax(aValueBlue / aSum, 0, 255)));
+
+ int nDestX = nSourceY;
+ int nDestY = nSourceX;
+
+ pWriteAcc->SetPixel(nDestY, nDestX, aResultColor);
+ }
+ }
+ return true;
+}
+
+double* BitmapGaussianSeparableBlurFilter::makeBlurKernel(const double radius, int& rows)
+{
+ int intRadius = static_cast<int>(radius + 1.0);
+ rows = intRadius * 2 + 1;
+ double* matrix = new double[rows];
+
+ double sigma = radius / 3;
+ double radius2 = radius * radius;
+ int index = 0;
+ for (int row = -intRadius; row <= intRadius; row++)
+ {
+ double distance = row * row;
+ if (distance > radius2)
+ {
+ matrix[index] = 0.0;
+ }
+ else
+ {
+ matrix[index] = exp(-distance / (2.0 * sigma * sigma)) / sqrt(2.0 * M_PI * sigma);
+ }
+ index++;
+ }
+ return matrix;
+}
+
+void BitmapGaussianSeparableBlurFilter::blurContributions(const int aSize,
+ const int aNumberOfContributions,
+ const double* pBlurVector,
+ double*& pWeights, int*& pPixels,
+ int*& pCount)
+{
+ pWeights = new double[aSize * aNumberOfContributions];
+ pPixels = new int[aSize * aNumberOfContributions];
+ pCount = new int[aSize];
+
+ int aLeft, aRight, aCurrentCount, aPixelIndex;
+ double aWeight;
+
+ for (int i = 0; i < aSize; i++)
+ {
+ aLeft = i - aNumberOfContributions / 2;
+ aRight = i + aNumberOfContributions / 2;
+ aCurrentCount = 0;
+ for (int j = aLeft; j <= aRight; j++)
+ {
+ aWeight = pBlurVector[aCurrentCount];
+
+ // Mirror edges
+ if (j < 0)
+ {
+ aPixelIndex = -j;
+ }
+ else if (j >= aSize)
+ {
+ aPixelIndex = (aSize - j) + aSize - 1;
+ }
+ else
+ {
+ aPixelIndex = j;
+ }
+
+ // Edge case for small bitmaps
+ if (aPixelIndex < 0 || aPixelIndex >= aSize)
+ {
+ aWeight = 0.0;
+ }
+
+ pWeights[i * aNumberOfContributions + aCurrentCount] = aWeight;
+ pPixels[i * aNumberOfContributions + aCurrentCount] = aPixelIndex;
+
+ aCurrentCount++;
+ }
+ pCount[i] = aCurrentCount;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/gdi/bitmap3.cxx b/vcl/source/gdi/bitmap3.cxx
index b553130c6538..3bf068c3444a 100644
--- a/vcl/source/gdi/bitmap3.cxx
+++ b/vcl/source/gdi/bitmap3.cxx
@@ -1854,56 +1854,4 @@ bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
return bRet;
}
-bool Bitmap::ImplConvolutionPass(Bitmap& aNewBitmap, BitmapReadAccess const * pReadAcc, int aNumberOfContributions, const double* pWeights, int const * pPixels, const int* pCount)
-{
- if (!pReadAcc)
- return false;
-
- BitmapScopedWriteAccess pWriteAcc(aNewBitmap);
- if (!pWriteAcc)
- return false;
-
- const int nHeight = GetSizePixel().Height();
- assert(GetSizePixel().Height() == aNewBitmap.GetSizePixel().Width());
- const int nWidth = GetSizePixel().Width();
- assert(GetSizePixel().Width() == aNewBitmap.GetSizePixel().Height());
-
- BitmapColor aColor;
- double aValueRed, aValueGreen, aValueBlue;
- double aSum, aWeight;
- int aBaseIndex, aIndex;
-
- for (int nSourceY = 0; nSourceY < nHeight; ++nSourceY)
- {
- for (int nSourceX = 0; nSourceX < nWidth; ++nSourceX)
- {
- aBaseIndex = nSourceX * aNumberOfContributions;
- aSum = aValueRed = aValueGreen = aValueBlue = 0.0;
-
- for (int j = 0; j < pCount[nSourceX]; ++j)
- {
- aIndex = aBaseIndex + j;
- aSum += aWeight = pWeights[ aIndex ];
-
- aColor = pReadAcc->GetColor(nSourceY, pPixels[aIndex]);
-
- aValueRed += aWeight * aColor.GetRed();
- aValueGreen += aWeight * aColor.GetGreen();
- aValueBlue += aWeight * aColor.GetBlue();
- }
-
- BitmapColor aResultColor(
- static_cast<sal_uInt8>(MinMax( aValueRed / aSum, 0, 255 )),
- static_cast<sal_uInt8>(MinMax( aValueGreen / aSum, 0, 255 )),
- static_cast<sal_uInt8>(MinMax( aValueBlue / aSum, 0, 255 )) );
-
- int nDestX = nSourceY;
- int nDestY = nSourceX;
-
- pWriteAcc->SetPixel(nDestY, nDestX, aResultColor);
- }
- }
- return true;
-}
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/gdi/bitmap4.cxx b/vcl/source/gdi/bitmap4.cxx
index 71fd484170ae..e48a2edae9b3 100644
--- a/vcl/source/gdi/bitmap4.cxx
+++ b/vcl/source/gdi/bitmap4.cxx
@@ -17,13 +17,16 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
-#include <memory>
-#include <stdlib.h>
#include <osl/diagnose.h>
#include <vcl/bitmapaccess.hxx>
#include <vcl/bitmap.hxx>
+#include <vcl/BitmapGaussianSeparableBlurFilter.hxx>
+
#include <bitmapwriteaccess.hxx>
+#include <memory>
+#include <stdlib.h>
+
#define S2(a,b) { long t; if( ( t = b - a ) < 0 ) { a += t; b -= t; } }
#define MN3(a,b,c) S2(a,b); S2(a,c);
#define MX3(a,b,c) S2(b,c); S2(a,c);
@@ -51,7 +54,9 @@ bool Bitmap::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam )
// Blur for positive values of mnRadius
if (pFilterParam->mnRadius > 0.0)
{
- bRet = ImplSeparableBlurFilter(pFilterParam->mnRadius);
+ BitmapEx aBmpEx(*this);
+ bRet = BitmapFilter::Filter(aBmpEx, BitmapGaussianSeparableBlurFilter(pFilterParam->mnRadius));
+ *this = aBmpEx.GetBitmap();
}
// Unsharpen Mask for negative values of mnRadius
else if (pFilterParam->mnRadius < 0.0)
@@ -1062,144 +1067,6 @@ bool Bitmap::ImplPopArt()
return bRet;
}
-double* MakeBlurKernel(const double radius, int& rows) {
- int intRadius = static_cast<int>(radius + 1.0);
- rows = intRadius * 2 + 1;
- double* matrix = new double[rows];
-
- double sigma = radius / 3;
- double radius2 = radius * radius;
- int index = 0;
- for (int row = -intRadius; row <= intRadius; row++)
- {
- double distance = row*row;
- if (distance > radius2) {
- matrix[index] = 0.0;
- }else {
- matrix[index] = exp( -distance / (2.0 * sigma * sigma) ) / sqrt( 2.0 * M_PI * sigma );
- }
- index++;
- }
- return matrix;
-}
-
-void Bitmap::ImplBlurContributions( const int aSize, const int aNumberOfContributions,
- const double* pBlurVector, double*& pWeights, int*& pPixels, int*& pCount )
-{
- pWeights = new double[ aSize*aNumberOfContributions ];
- pPixels = new int[ aSize*aNumberOfContributions ];
- pCount = new int[ aSize ];
-
- int aLeft, aRight, aCurrentCount, aPixelIndex;
- double aWeight;
-
- for ( int i = 0; i < aSize; i++ )
- {
- aLeft = i - aNumberOfContributions / 2;
- aRight = i + aNumberOfContributions / 2;
- aCurrentCount = 0;
- for ( int j = aLeft; j <= aRight; j++ )
- {
- aWeight = pBlurVector[aCurrentCount];
-
- // Mirror edges
- if (j < 0)
- {
- aPixelIndex = -j;
- }
- else if ( j >= aSize )
- {
- aPixelIndex = (aSize - j) + aSize - 1;
- }
- else
- {
- aPixelIndex = j;
- }
-
- // Edge case for small bitmaps
- if ( aPixelIndex < 0 || aPixelIndex >= aSize )
- {
- aWeight = 0.0;
- }
-
- pWeights[ i*aNumberOfContributions + aCurrentCount ] = aWeight;
- pPixels[ i*aNumberOfContributions + aCurrentCount ] = aPixelIndex;
-
- aCurrentCount++;
- }
- pCount[ i ] = aCurrentCount;
- }
-}
-
-// Separable Gaussian Blur
-
-// Separable Gaussian Blur filter and accepts a blur radius
-// as a parameter so the user can change the strength of the blur.
-// Radius of 1.0 is 3 * standard deviation of gauss function.
-
-// Separable Blur implementation uses 2x separable 1D convolution
-// to process the image.
-bool Bitmap::ImplSeparableBlurFilter(const double radius)
-{
- const long nWidth = GetSizePixel().Width();
- const long nHeight = GetSizePixel().Height();
-
- // Prepare Blur Vector
- int aNumberOfContributions;
- double* pBlurVector = MakeBlurKernel(radius, aNumberOfContributions);
-
- double* pWeights;
- int* pPixels;
- int* pCount;
-
- // Do horizontal filtering
- ImplBlurContributions( nWidth, aNumberOfContributions, pBlurVector, pWeights, pPixels, pCount);
-
- ScopedReadAccess pReadAcc(*this);
-
- // switch coordinates as convolution pass transposes result
- Bitmap aNewBitmap( Size( nHeight, nWidth ), 24 );
-
- bool bResult = ImplConvolutionPass( aNewBitmap, pReadAcc.get(), aNumberOfContributions, pWeights, pPixels, pCount );
-
- // Cleanup
- pReadAcc.reset();
- delete[] pWeights;
- delete[] pPixels;
- delete[] pCount;
-
- if ( !bResult )
- {
- delete[] pBlurVector;
- return bResult;
- }
-
- // Swap current bitmap with new bitmap
- ReassignWithSize(aNewBitmap);
-
- // Do vertical filtering
- ImplBlurContributions(nHeight, aNumberOfContributions, pBlurVector, pWeights, pPixels, pCount );
-
- pReadAcc = ScopedReadAccess(*this);
- aNewBitmap = Bitmap( Size( nWidth, nHeight ), 24 );
- bResult = ImplConvolutionPass( aNewBitmap, pReadAcc.get(), aNumberOfContributions, pWeights, pPixels, pCount );
-
- // Cleanup
- pReadAcc.reset();
- delete[] pWeights;
- delete[] pCount;
- delete[] pPixels;
- delete[] pBlurVector;
-
- if ( !bResult )
- return bResult;
-
- // Swap current bitmap with new bitmap
- ReassignWithSize(aNewBitmap);
-
- return true;
-}
-
// Separable Unsharpen Mask filter is actually a subtracted blurred
// image from the original image.
bool Bitmap::ImplSeparableUnsharpenFilter(const double radius) {
@@ -1207,7 +1074,10 @@ bool Bitmap::ImplSeparableUnsharpenFilter(const double radius) {
const long nHeight = GetSizePixel().Height();
Bitmap aBlur( *this );
- aBlur.ImplSeparableBlurFilter(-radius);
+ BitmapEx aBlurEx(aBlur);
+
+ BitmapFilter::Filter(aBlurEx, BitmapGaussianSeparableBlurFilter(-radius));
+ aBlur = aBlurEx.GetBitmap();
// Amount of unsharpening effect on image - currently set to a fixed value
double aAmount = 2.0;
More information about the Libreoffice-commits
mailing list