bump product version to 7.2.5.1
[LibreOffice.git] / vcl / source / bitmap / BitmapScaleConvolutionFilter.cxx
blobb1115a1dfe56d9018917b88683129ebab7999222
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <osl/diagnose.h>
21 #include <tools/helpers.hxx>
23 #include <bitmap/BitmapWriteAccess.hxx>
24 #include <bitmap/BitmapScaleConvolutionFilter.hxx>
26 #include <algorithm>
27 #include <memory>
29 namespace vcl
32 namespace
35 void ImplCalculateContributions(
36 const tools::Long aSourceSize,
37 const tools::Long aDestinationSize,
38 tools::Long& aNumberOfContributions,
39 std::vector<sal_Int16>& rWeights,
40 std::vector<sal_Int32>& rPixels,
41 std::vector<sal_Int32>& rCounts,
42 const Kernel& aKernel)
44 const double fSamplingRadius(aKernel.GetWidth());
45 const double fScale(aDestinationSize / static_cast< double >(aSourceSize));
46 const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius);
47 const double fFilterFactor(std::min(fScale, 1.0));
49 aNumberOfContributions = (tools::Long(fabs(ceil(fScaledRadius))) * 2) + 1;
50 const tools::Long nAllocSize(aDestinationSize * aNumberOfContributions);
51 rWeights.resize(nAllocSize);
52 rPixels.resize(nAllocSize);
53 rCounts.resize(aDestinationSize);
55 for(tools::Long i(0); i < aDestinationSize; i++)
57 const tools::Long aIndex(i * aNumberOfContributions);
58 const double aCenter(i / fScale);
59 const sal_Int32 aLeft(static_cast< sal_Int32 >(floor(aCenter - fScaledRadius)));
60 const sal_Int32 aRight(static_cast< sal_Int32 >(ceil(aCenter + fScaledRadius)));
61 tools::Long aCurrentCount(0);
63 for(sal_Int32 j(aLeft); j <= aRight; j++)
65 const double aWeight(aKernel.Calculate(fFilterFactor * (aCenter - static_cast< double>(j))));
67 // Reduce calculations with ignoring weights of 0.0
68 if(fabs(aWeight) < 0.0001)
70 continue;
73 // Handling on edges
74 const tools::Long aPixelIndex(MinMax(j, 0, aSourceSize - 1));
75 const tools::Long nIndex(aIndex + aCurrentCount);
77 // scale the weight by 255 since we're converting from float to int
78 rWeights[nIndex] = aWeight * 255;
79 rPixels[nIndex] = aPixelIndex;
81 aCurrentCount++;
84 rCounts[i] = aCurrentCount;
88 bool ImplScaleConvolutionHor(Bitmap& rSource, Bitmap& rTarget, const double& rScaleX, const Kernel& aKernel)
90 // Do horizontal filtering
91 OSL_ENSURE(rScaleX > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
92 const tools::Long nWidth(rSource.GetSizePixel().Width());
93 const tools::Long nNewWidth(FRound(nWidth * rScaleX));
95 if(nWidth == nNewWidth)
97 return true;
100 Bitmap::ScopedReadAccess pReadAcc(rSource);
102 if(pReadAcc)
104 std::vector<sal_Int16> aWeights;
105 std::vector<sal_Int32> aPixels;
106 std::vector<sal_Int32> aCounts;
107 tools::Long aNumberOfContributions(0);
109 const tools::Long nHeight(rSource.GetSizePixel().Height());
110 ImplCalculateContributions(nWidth, nNewWidth, aNumberOfContributions, aWeights, aPixels, aCounts, aKernel);
111 rTarget = Bitmap(Size(nNewWidth, nHeight), vcl::PixelFormat::N24_BPP);
112 BitmapScopedWriteAccess pWriteAcc(rTarget);
113 bool bResult(pWriteAcc);
115 if(bResult)
117 for(tools::Long y(0); y < nHeight; y++)
119 Scanline pScanline = pWriteAcc->GetScanline( y );
120 Scanline pScanlineRead = pReadAcc->GetScanline( y );
121 for(tools::Long x(0); x < nNewWidth; x++)
123 const tools::Long aBaseIndex(x * aNumberOfContributions);
124 sal_Int32 aSum(0);
125 sal_Int32 aValueRed(0);
126 sal_Int32 aValueGreen(0);
127 sal_Int32 aValueBlue(0);
129 for(tools::Long j(0); j < aCounts[x]; j++)
131 const tools::Long aIndex(aBaseIndex + j);
132 const sal_Int16 aWeight(aWeights[aIndex]);
133 BitmapColor aColor;
135 aSum += aWeight;
137 if(pReadAcc->HasPalette())
139 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, aPixels[aIndex]));
141 else
143 aColor = pReadAcc->GetPixelFromData(pScanlineRead, aPixels[aIndex]);
146 aValueRed += aWeight * aColor.GetRed();
147 aValueGreen += aWeight * aColor.GetGreen();
148 aValueBlue += aWeight * aColor.GetBlue();
151 assert(aSum != 0);
153 const BitmapColor aResultColor(
154 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
155 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
156 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
158 pWriteAcc->SetPixelOnData(pScanline, x, aResultColor);
162 pWriteAcc.reset();
165 aWeights.clear();
166 aCounts.clear();
167 aPixels.clear();
169 if(bResult)
171 return true;
175 return false;
178 bool ImplScaleConvolutionVer(Bitmap& rSource, Bitmap& rTarget, const double& rScaleY, const Kernel& aKernel)
180 // Do vertical filtering
181 OSL_ENSURE(rScaleY > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
182 const tools::Long nHeight(rSource.GetSizePixel().Height());
183 const tools::Long nNewHeight(FRound(nHeight * rScaleY));
185 if(nHeight == nNewHeight)
187 return true;
190 Bitmap::ScopedReadAccess pReadAcc(rSource);
192 if(pReadAcc)
194 std::vector<sal_Int16> aWeights;
195 std::vector<sal_Int32> aPixels;
196 std::vector<sal_Int32> aCounts;
197 tools::Long aNumberOfContributions(0);
199 const tools::Long nWidth(rSource.GetSizePixel().Width());
200 ImplCalculateContributions(nHeight, nNewHeight, aNumberOfContributions, aWeights, aPixels, aCounts, aKernel);
201 rTarget = Bitmap(Size(nWidth, nNewHeight), vcl::PixelFormat::N24_BPP);
202 BitmapScopedWriteAccess pWriteAcc(rTarget);
203 bool bResult(pWriteAcc);
205 if(pWriteAcc)
207 std::vector<BitmapColor> aScanline(nHeight);
208 for(tools::Long x(0); x < nWidth; x++)
210 for(tools::Long y(0); y < nHeight; y++)
211 if(pReadAcc->HasPalette())
212 aScanline[y] = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(y, x));
213 else
214 aScanline[y] = pReadAcc->GetPixel(y, x);
215 for(tools::Long y(0); y < nNewHeight; y++)
217 const tools::Long aBaseIndex(y * aNumberOfContributions);
218 sal_Int32 aSum(0);
219 sal_Int32 aValueRed(0);
220 sal_Int32 aValueGreen(0);
221 sal_Int32 aValueBlue(0);
223 for(tools::Long j(0); j < aCounts[y]; j++)
225 const tools::Long aIndex(aBaseIndex + j);
226 const sal_Int16 aWeight(aWeights[aIndex]);
227 aSum += aWeight;
228 const BitmapColor & aColor = aScanline[aPixels[aIndex]];
229 aValueRed += aWeight * aColor.GetRed();
230 aValueGreen += aWeight * aColor.GetGreen();
231 aValueBlue += aWeight * aColor.GetBlue();
234 assert(aSum != 0);
236 const BitmapColor aResultColor(
237 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
238 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
239 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
241 if(pWriteAcc->HasPalette())
243 pWriteAcc->SetPixelIndex(y, x, static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(aResultColor)));
245 else
247 pWriteAcc->SetPixel(y, x, aResultColor);
253 aWeights.clear();
254 aCounts.clear();
255 aPixels.clear();
257 if(bResult)
259 return true;
263 return false;
266 bool ImplScaleConvolution(Bitmap& rBitmap, const double& rScaleX, const double& rScaleY, const Kernel& aKernel)
268 const bool bMirrorHor(rScaleX < 0.0);
269 const bool bMirrorVer(rScaleY < 0.0);
270 const double fScaleX(bMirrorHor ? -rScaleX : rScaleX);
271 const double fScaleY(bMirrorVer ? -rScaleY : rScaleY);
272 const tools::Long nWidth(rBitmap.GetSizePixel().Width());
273 const tools::Long nHeight(rBitmap.GetSizePixel().Height());
274 const tools::Long nNewWidth(FRound(nWidth * fScaleX));
275 const tools::Long nNewHeight(FRound(nHeight * fScaleY));
276 const bool bScaleHor(nWidth != nNewWidth);
277 const bool bScaleVer(nHeight != nNewHeight);
278 const bool bMirror(bMirrorHor || bMirrorVer);
280 if (!bMirror && !bScaleHor && !bScaleVer)
282 return true;
285 bool bResult(true);
286 BmpMirrorFlags nMirrorFlags(BmpMirrorFlags::NONE);
287 bool bMirrorAfter(false);
289 if (bMirror)
291 if(bMirrorHor)
293 nMirrorFlags |= BmpMirrorFlags::Horizontal;
296 if(bMirrorVer)
298 nMirrorFlags |= BmpMirrorFlags::Vertical;
301 const tools::Long nStartSize(nWidth * nHeight);
302 const tools::Long nEndSize(nNewWidth * nNewHeight);
304 bMirrorAfter = nStartSize > nEndSize;
306 if(!bMirrorAfter)
308 bResult = rBitmap.Mirror(nMirrorFlags);
312 Bitmap aResult;
314 if (bResult)
316 const tools::Long nInBetweenSizeHorFirst(nHeight * nNewWidth);
317 const tools::Long nInBetweenSizeVerFirst(nNewHeight * nWidth);
318 Bitmap aSource(rBitmap);
320 if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst)
322 if(bScaleHor)
324 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
327 if(bResult && bScaleVer)
329 if(bScaleHor)
331 // copy partial result, independent of color depth
332 aSource = aResult;
335 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
338 else
340 if(bScaleVer)
342 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
345 if(bResult && bScaleHor)
347 if(bScaleVer)
349 // copy partial result, independent of color depth
350 aSource = aResult;
353 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
358 if(bResult && bMirrorAfter)
360 bResult = aResult.Mirror(nMirrorFlags);
363 if(bResult)
365 rBitmap.AdaptBitCount(aResult);
366 rBitmap = aResult;
369 return bResult;
372 } // end anonymous namespace
374 BitmapEx BitmapScaleConvolutionFilter::execute(BitmapEx const& rBitmapEx) const
376 bool bRetval = false;
377 Bitmap aBitmap(rBitmapEx.GetBitmap());
379 bRetval = ImplScaleConvolution(aBitmap, mrScaleX, mrScaleY, *mxKernel);
381 if (bRetval)
382 return BitmapEx(aBitmap);
384 return BitmapEx();
389 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */