tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / vcl / source / bitmap / BitmapScaleConvolutionFilter.cxx
blob19bd391ad9c5aa9a974f580c8a191592804ac088
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 <vcl/BitmapWriteAccess.hxx>
24 #include <bitmap/BitmapScaleConvolutionFilter.hxx>
26 #include <algorithm>
27 #include <memory>
29 namespace vcl
32 namespace
35 void ImplCalculateContributions(const sal_Int32 nSoureSize, const sal_Int32 nDestinationSize,
36 sal_Int32& rNumberOfContributions, std::vector<sal_Int16>& rWeights,
37 std::vector<sal_Int32>& rPixels, std::vector<sal_Int32>& rCounts,
38 const Kernel& rKernel)
40 const double fSamplingRadius(rKernel.GetWidth());
41 const double fScale(nDestinationSize / static_cast< double >(nSoureSize));
42 const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius);
43 const double fFilterFactor(std::min(fScale, 1.0));
45 rNumberOfContributions = (sal_Int32(fabs(ceil(fScaledRadius))) * 2) + 1;
46 const sal_Int32 nAllocSize(nDestinationSize * rNumberOfContributions);
47 rWeights.resize(nAllocSize);
48 rPixels.resize(nAllocSize);
49 rCounts.resize(nDestinationSize);
51 for(sal_Int32 i(0); i < nDestinationSize; i++)
53 const sal_Int32 nIndexes(i * rNumberOfContributions);
54 const double aCenter(i / fScale);
55 const sal_Int32 nLeft(static_cast< sal_Int32 >(floor(aCenter - fScaledRadius)));
56 const sal_Int32 nRight(static_cast< sal_Int32 >(ceil(aCenter + fScaledRadius)));
57 sal_Int32 nCurrentCount(0);
59 for(sal_Int32 j(nLeft); j <= nRight; j++)
61 const double fWeight(rKernel.Calculate(fFilterFactor * (aCenter - static_cast< double>(j))));
63 // Reduce calculations with ignoring weights of 0.0
64 if(fabs(fWeight) < 0.0001)
65 continue;
67 // Handling on edges
68 const sal_Int32 nPixelIndex(std::clamp(j, sal_Int32(0), nSoureSize - 1));
69 const sal_Int32 nIndex(nIndexes + nCurrentCount);
71 // scale the weight by 255 since we're converting from float to int
72 rWeights[nIndex] = fWeight * 255;
73 rPixels[nIndex] = nPixelIndex;
75 nCurrentCount++;
78 rCounts[i] = nCurrentCount;
82 bool ImplScaleConvolutionHor(Bitmap& rSource, Bitmap& rTarget, const double& rScaleX, const Kernel& rKernel)
84 // Do horizontal filtering
85 OSL_ENSURE(rScaleX > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
86 const sal_Int32 nWidth(rSource.GetSizePixel().Width());
87 const sal_Int32 nNewWidth(basegfx::fround(nWidth * rScaleX));
89 if (nWidth == nNewWidth)
90 return true;
92 BitmapScopedReadAccess pReadAcc(rSource);
94 if (!pReadAcc)
95 return false;
97 std::vector<sal_Int16> aWeights;
98 std::vector<sal_Int32> aPixels;
99 std::vector<sal_Int32> aCounts;
100 sal_Int32 nNumberOfContributions(0);
102 const sal_Int32 nHeight(rSource.GetSizePixel().Height());
103 ImplCalculateContributions(nWidth, nNewWidth, nNumberOfContributions, aWeights, aPixels, aCounts, rKernel);
104 rTarget = Bitmap(Size(nNewWidth, nHeight), vcl::PixelFormat::N24_BPP);
105 BitmapScopedWriteAccess pWriteAcc(rTarget);
107 if (!pWriteAcc)
108 return false;
110 for (sal_Int32 y(0); y < nHeight; y++)
112 Scanline pScanline = pWriteAcc->GetScanline( y );
113 Scanline pScanlineRead = pReadAcc->GetScanline( y );
115 for (sal_Int32 x(0); x < nNewWidth; x++)
117 const sal_Int32 nBaseIndex(x * nNumberOfContributions);
118 sal_Int32 nSum(0);
119 sal_Int32 nValueRed(0);
120 sal_Int32 nValueGreen(0);
121 sal_Int32 nValueBlue(0);
123 for (sal_Int32 j(0); j < aCounts[x]; j++)
125 const sal_Int32 nIndex(nBaseIndex + j);
126 const sal_Int16 nWeight(aWeights[nIndex]);
127 BitmapColor aColor;
129 nSum += nWeight;
131 if (pReadAcc->HasPalette())
132 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, aPixels[nIndex]));
133 else
134 aColor = pReadAcc->GetPixelFromData(pScanlineRead, aPixels[nIndex]);
136 nValueRed += nWeight * aColor.GetRed();
137 nValueGreen += nWeight * aColor.GetGreen();
138 nValueBlue += nWeight * aColor.GetBlue();
141 assert(nSum != 0);
143 const BitmapColor aResultColor(
144 static_cast< sal_uInt8 >(std::clamp< sal_Int32 >(nValueRed / nSum, 0, 255)),
145 static_cast< sal_uInt8 >(std::clamp< sal_Int32 >(nValueGreen / nSum, 0, 255)),
146 static_cast< sal_uInt8 >(std::clamp< sal_Int32 >(nValueBlue / nSum, 0, 255)));
148 pWriteAcc->SetPixelOnData(pScanline, x, aResultColor);
152 pWriteAcc.reset();
154 return true;
157 bool ImplScaleConvolutionVer(Bitmap& rSource, Bitmap& rTarget, const double& rScaleY, const Kernel& rKernel)
159 // Do vertical filtering
160 OSL_ENSURE(rScaleY > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
161 const sal_Int32 nHeight(rSource.GetSizePixel().Height());
162 const sal_Int32 nNewHeight(basegfx::fround(nHeight * rScaleY));
164 if(nHeight == nNewHeight)
166 return true;
169 BitmapScopedReadAccess pReadAcc(rSource);
170 if(!pReadAcc)
171 return false;
173 std::vector<sal_Int16> aWeights;
174 std::vector<sal_Int32> aPixels;
175 std::vector<sal_Int32> aCounts;
176 sal_Int32 nNumberOfContributions(0);
178 const sal_Int32 nWidth(rSource.GetSizePixel().Width());
179 ImplCalculateContributions(nHeight, nNewHeight, nNumberOfContributions, aWeights, aPixels, aCounts, rKernel);
180 rTarget = Bitmap(Size(nWidth, nNewHeight), vcl::PixelFormat::N24_BPP);
181 BitmapScopedWriteAccess pWriteAcc(rTarget);
182 if(!pWriteAcc)
183 return false;
185 std::vector<BitmapColor> aScanline(nHeight);
186 for(sal_Int32 x(0); x < nWidth; x++)
188 for(sal_Int32 y(0); y < nHeight; y++)
189 if(pReadAcc->HasPalette())
190 aScanline[y] = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(y, x));
191 else
192 aScanline[y] = pReadAcc->GetPixel(y, x);
193 for(sal_Int32 y(0); y < nNewHeight; y++)
195 const sal_Int32 nBaseIndex = y * nNumberOfContributions;
196 sal_Int32 nSum(0);
197 sal_Int32 nValueRed(0);
198 sal_Int32 nValueGreen(0);
199 sal_Int32 nValueBlue(0);
201 for(sal_Int32 j(0); j < aCounts[y]; j++)
203 const sal_Int32 nIndex(nBaseIndex + j);
204 const sal_Int16 nWeight(aWeights[nIndex]);
205 nSum += nWeight;
206 const BitmapColor & aColor = aScanline[aPixels[nIndex]];
207 nValueRed += nWeight * aColor.GetRed();
208 nValueGreen += nWeight * aColor.GetGreen();
209 nValueBlue += nWeight * aColor.GetBlue();
212 assert(nSum != 0);
214 const BitmapColor aResultColor(
215 static_cast< sal_uInt8 >(std::clamp< sal_Int32 >(nValueRed / nSum, 0, 255)),
216 static_cast< sal_uInt8 >(std::clamp< sal_Int32 >(nValueGreen / nSum, 0, 255)),
217 static_cast< sal_uInt8 >(std::clamp< sal_Int32 >(nValueBlue / nSum, 0, 255)));
219 if(pWriteAcc->HasPalette())
221 pWriteAcc->SetPixelIndex(y, x, static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(aResultColor)));
223 else
225 pWriteAcc->SetPixel(y, x, aResultColor);
230 return true;
233 bool ImplScaleConvolution(Bitmap& rBitmap, const double& rScaleX, const double& rScaleY, const Kernel& rKernel)
235 const bool bMirrorHor(rScaleX < 0.0);
236 const bool bMirrorVer(rScaleY < 0.0);
237 const double fScaleX(bMirrorHor ? -rScaleX : rScaleX);
238 const double fScaleY(bMirrorVer ? -rScaleY : rScaleY);
239 const sal_Int32 nWidth(rBitmap.GetSizePixel().Width());
240 const sal_Int32 nHeight(rBitmap.GetSizePixel().Height());
241 const sal_Int32 nNewWidth(basegfx::fround(nWidth * fScaleX));
242 const sal_Int32 nNewHeight(basegfx::fround(nHeight * fScaleY));
243 const bool bScaleHor(nWidth != nNewWidth);
244 const bool bScaleVer(nHeight != nNewHeight);
245 const bool bMirror(bMirrorHor || bMirrorVer);
247 if (!bMirror && !bScaleHor && !bScaleVer)
249 return true;
252 bool bResult(true);
253 BmpMirrorFlags nMirrorFlags(BmpMirrorFlags::NONE);
254 bool bMirrorAfter(false);
256 if (bMirror)
258 if(bMirrorHor)
260 nMirrorFlags |= BmpMirrorFlags::Horizontal;
263 if(bMirrorVer)
265 nMirrorFlags |= BmpMirrorFlags::Vertical;
268 const sal_Int32 nStartSize(nWidth * nHeight);
269 const sal_Int32 nEndSize(nNewWidth * nNewHeight);
271 bMirrorAfter = nStartSize > nEndSize;
273 if(!bMirrorAfter)
275 bResult = rBitmap.Mirror(nMirrorFlags);
279 Bitmap aResult;
281 if (bResult)
283 const sal_Int32 nInBetweenSizeHorFirst(nHeight * nNewWidth);
284 const sal_Int32 nInBetweenSizeVerFirst(nNewHeight * nWidth);
285 Bitmap aSource(rBitmap);
287 if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst)
289 if(bScaleHor)
291 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, rKernel);
294 if(bResult && bScaleVer)
296 if(bScaleHor)
298 // copy partial result, independent of color depth
299 aSource = aResult;
302 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, rKernel);
305 else
307 if(bScaleVer)
309 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, rKernel);
312 if(bResult && bScaleHor)
314 if(bScaleVer)
316 // copy partial result, independent of color depth
317 aSource = aResult;
320 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, rKernel);
325 if(bResult && bMirrorAfter)
327 bResult = aResult.Mirror(nMirrorFlags);
330 if(bResult)
332 rBitmap.AdaptBitCount(aResult);
333 rBitmap = std::move(aResult);
336 return bResult;
339 } // end anonymous namespace
341 BitmapEx BitmapScaleConvolutionFilter::execute(BitmapEx const& rBitmapEx) const
343 bool bRetval = false;
344 Bitmap aBitmap(rBitmapEx.GetBitmap());
346 bRetval = ImplScaleConvolution(aBitmap, mrScaleX, mrScaleY, *mxKernel);
348 if (bRetval)
349 return BitmapEx(aBitmap);
351 return BitmapEx();
356 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */