1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 #include <tools/helpers.hxx>
13 #include <vcl/bitmap.hxx>
14 #include <vcl/bitmapex.hxx>
15 #include <vcl/BitmapGaussianSeparableBlurFilter.hxx>
17 #include <bitmap/BitmapWriteAccess.hxx>
19 BitmapEx
BitmapGaussianSeparableBlurFilter::execute(BitmapEx
const& rBitmapEx
) const
21 Bitmap
aBitmap(rBitmapEx
.GetBitmap());
23 const tools::Long nWidth
= aBitmap
.GetSizePixel().Width();
24 const tools::Long nHeight
= aBitmap
.GetSizePixel().Height();
26 // Prepare Blur Vector
27 int aNumberOfContributions
;
28 std::vector
<double> aBlurVector(makeBlurKernel(mfRadius
, aNumberOfContributions
));
29 std::vector
<double> aWeights
;
30 std::vector
<int> aPixels
;
31 std::vector
<int> aCounts
;
33 // Do horizontal filtering
34 blurContributions(nWidth
, aNumberOfContributions
, aBlurVector
, aWeights
, aPixels
, aCounts
);
36 Bitmap::ScopedReadAccess
pReadAcc(aBitmap
);
38 // switch coordinates as convolution pass transposes result
39 Bitmap
aNewBitmap(Size(nHeight
, nWidth
), vcl::PixelFormat::N24_BPP
);
41 bool bResult
= convolutionPass(aBitmap
, aNewBitmap
, pReadAcc
.get(), aNumberOfContributions
,
42 aWeights
.data(), aPixels
.data(), aCounts
.data());
56 // Swap current bitmap with new bitmap
57 aBitmap
.ReassignWithSize(aNewBitmap
);
59 // Do vertical filtering
60 blurContributions(nHeight
, aNumberOfContributions
, aBlurVector
, aWeights
, aPixels
, aCounts
);
62 pReadAcc
= Bitmap::ScopedReadAccess(aBitmap
);
63 aNewBitmap
= Bitmap(Size(nWidth
, nHeight
), vcl::PixelFormat::N24_BPP
);
64 bResult
= convolutionPass(aBitmap
, aNewBitmap
, pReadAcc
.get(), aNumberOfContributions
,
65 aWeights
.data(), aPixels
.data(), aCounts
.data());
75 aBitmap
.ReassignWithSize(aNewBitmap
); // swap current bitmap with new bitmap
79 return BitmapEx(aBitmap
);
84 bool BitmapGaussianSeparableBlurFilter::convolutionPass(const Bitmap
& rBitmap
, Bitmap
& aNewBitmap
,
85 BitmapReadAccess
const* pReadAcc
,
86 int aNumberOfContributions
,
87 const double* pWeights
, int const* pPixels
,
93 BitmapScopedWriteAccess
pWriteAcc(aNewBitmap
);
97 const int nHeight
= rBitmap
.GetSizePixel().Height();
98 assert(rBitmap
.GetSizePixel().Height() == aNewBitmap
.GetSizePixel().Width());
99 const int nWidth
= rBitmap
.GetSizePixel().Width();
100 assert(rBitmap
.GetSizePixel().Width() == aNewBitmap
.GetSizePixel().Height());
103 double aValueRed
, aValueGreen
, aValueBlue
;
104 double aSum
, aWeight
;
105 int aBaseIndex
, aIndex
;
107 for (int nSourceY
= 0; nSourceY
< nHeight
; ++nSourceY
)
109 for (int nSourceX
= 0; nSourceX
< nWidth
; ++nSourceX
)
111 aBaseIndex
= nSourceX
* aNumberOfContributions
;
112 aSum
= aValueRed
= aValueGreen
= aValueBlue
= 0.0;
114 for (int j
= 0; j
< pCount
[nSourceX
]; ++j
)
116 aIndex
= aBaseIndex
+ j
;
117 aWeight
= pWeights
[aIndex
];
120 aColor
= pReadAcc
->GetColor(nSourceY
, pPixels
[aIndex
]);
122 aValueRed
+= aWeight
* aColor
.GetRed();
123 aValueGreen
+= aWeight
* aColor
.GetGreen();
124 aValueBlue
+= aWeight
* aColor
.GetBlue();
127 BitmapColor
aResultColor(static_cast<sal_uInt8
>(MinMax(aValueRed
/ aSum
, 0, 255)),
128 static_cast<sal_uInt8
>(MinMax(aValueGreen
/ aSum
, 0, 255)),
129 static_cast<sal_uInt8
>(MinMax(aValueBlue
/ aSum
, 0, 255)));
131 int nDestX
= nSourceY
;
132 int nDestY
= nSourceX
;
134 pWriteAcc
->SetPixel(nDestY
, nDestX
, aResultColor
);
140 std::vector
<double> BitmapGaussianSeparableBlurFilter::makeBlurKernel(const double radius
,
143 int intRadius
= static_cast<int>(radius
+ 1.0);
144 rows
= intRadius
* 2 + 1;
145 std::vector
<double> matrix(rows
);
147 double sigma
= radius
/ 3;
148 double radius2
= radius
* radius
;
150 for (int row
= -intRadius
; row
<= intRadius
; row
++)
152 double distance
= row
* row
;
153 if (distance
> radius2
)
159 matrix
[index
] = exp(-distance
/ (2.0 * sigma
* sigma
)) / sqrt(2.0 * M_PI
* sigma
);
166 void BitmapGaussianSeparableBlurFilter::blurContributions(
167 const int aSize
, const int aNumberOfContributions
, const std::vector
<double>& rBlurVector
,
168 std::vector
<double>& rWeights
, std::vector
<int>& rPixels
, std::vector
<int>& rCounts
)
170 rWeights
.resize(aSize
* aNumberOfContributions
);
171 rPixels
.resize(aSize
* aNumberOfContributions
);
172 rCounts
.resize(aSize
);
174 int aLeft
, aRight
, aCurrentCount
, aPixelIndex
;
177 for (int i
= 0; i
< aSize
; i
++)
179 aLeft
= i
- aNumberOfContributions
/ 2;
180 aRight
= i
+ aNumberOfContributions
/ 2;
182 for (int j
= aLeft
; j
<= aRight
; j
++)
184 aWeight
= rBlurVector
[aCurrentCount
];
193 aPixelIndex
= (aSize
- j
) + aSize
- 1;
200 // Edge case for small bitmaps
201 if (aPixelIndex
< 0 || aPixelIndex
>= aSize
)
206 rWeights
[i
* aNumberOfContributions
+ aCurrentCount
] = aWeight
;
207 rPixels
[i
* aNumberOfContributions
+ aCurrentCount
] = aPixelIndex
;
211 rCounts
[i
] = aCurrentCount
;
215 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */