LibreOffice Module vcl (master) 1
BitmapInterpolateScaleFilter.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <tools/helpers.hxx>
21#include <osl/diagnose.h>
22
23#include <vcl/bitmapex.hxx>
24
28
30{
31 Bitmap aBitmap(rBitmapEx.GetBitmap());
32
33 const Size aSizePix(aBitmap.GetSizePixel());
34 const sal_Int32 nNewWidth = FRound(aSizePix.Width() * mfScaleX);
35 const sal_Int32 nNewHeight = FRound(aSizePix.Height() * mfScaleY);
36 bool bRet = false;
37
38 if ((nNewWidth > 1) && (nNewHeight > 1))
39 {
40 Bitmap::ScopedReadAccess pReadAcc(aBitmap);
41 if (pReadAcc)
42 {
43 sal_Int32 nWidth = pReadAcc->Width();
44 sal_Int32 nHeight = pReadAcc->Height();
45 Bitmap aNewBmp(Size(nNewWidth, nHeight), vcl::PixelFormat::N24_BPP);
46 BitmapScopedWriteAccess pWriteAcc(aNewBmp);
47
48 if (pWriteAcc)
49 {
50 if (1 == nWidth)
51 {
52 for (sal_Int32 nY = 0; nY < nHeight; nY++)
53 {
54 Scanline pScanlineRead = pReadAcc->GetScanline(nY);
55 BitmapColor aCol0;
56 if (pReadAcc->HasPalette())
57 {
58 aCol0 = pReadAcc->GetPaletteColor(
59 pReadAcc->GetIndexFromData(pScanlineRead, 0));
60 }
61 else
62 {
63 aCol0 = pReadAcc->GetPixelFromData(pScanlineRead, 0);
64 }
65
66 Scanline pScanline = pWriteAcc->GetScanline(nY);
67 for (sal_Int32 nX = 0; nX < nNewWidth; nX++)
68 {
69 pWriteAcc->SetPixelOnData(pScanline, nX, aCol0);
70 }
71 }
72 }
73 else
74 {
75 const sal_Int32 nNewWidth1 = nNewWidth - 1;
76 const sal_Int32 nWidth1 = pReadAcc->Width() - 1;
77 const double fRevScaleX = static_cast<double>(nWidth1) / nNewWidth1;
78
79 std::unique_ptr<sal_Int32[]> pLutInt(new sal_Int32[nNewWidth]);
80 std::unique_ptr<sal_Int32[]> pLutFrac(new sal_Int32[nNewWidth]);
81
82 for (sal_Int32 nX = 0, nTemp = nWidth - 2; nX < nNewWidth; nX++)
83 {
84 double fTemp = nX * fRevScaleX;
85 pLutInt[nX] = MinMax(static_cast<sal_Int32>(fTemp), 0, nTemp);
86 fTemp -= pLutInt[nX];
87 pLutFrac[nX] = static_cast<sal_Int32>(fTemp * 1024.);
88 }
89
90 for (sal_Int32 nY = 0; nY < nHeight; nY++)
91 {
92 Scanline pScanlineRead = pReadAcc->GetScanline(nY);
93 Scanline pScanline = pWriteAcc->GetScanline(nY);
94 for (sal_Int32 nX = 0; nX < nNewWidth; nX++)
95 {
96 sal_Int32 nTemp = pLutInt[nX];
97
98 BitmapColor aCol0, aCol1;
99 if (pReadAcc->HasPalette())
100 {
101 aCol0 = pReadAcc->GetPaletteColor(
102 pReadAcc->GetIndexFromData(pScanlineRead, nTemp++));
103 aCol1 = pReadAcc->GetPaletteColor(
104 pReadAcc->GetIndexFromData(pScanlineRead, nTemp));
105 }
106 else
107 {
108 aCol0 = pReadAcc->GetPixelFromData(pScanlineRead, nTemp++);
109 aCol1 = pReadAcc->GetPixelFromData(pScanlineRead, nTemp);
110 }
111
112 nTemp = pLutFrac[nX];
113
114 sal_Int32 lXR0 = aCol0.GetRed();
115 sal_Int32 lXG0 = aCol0.GetGreen();
116 sal_Int32 lXB0 = aCol0.GetBlue();
117 sal_Int32 lXR1 = aCol1.GetRed() - lXR0;
118 sal_Int32 lXG1 = aCol1.GetGreen() - lXG0;
119 sal_Int32 lXB1 = aCol1.GetBlue() - lXB0;
120
121 aCol0.SetRed(
122 static_cast<sal_uInt8>((lXR1 * nTemp + (lXR0 << 10)) >> 10));
123 aCol0.SetGreen(
124 static_cast<sal_uInt8>((lXG1 * nTemp + (lXG0 << 10)) >> 10));
125 aCol0.SetBlue(
126 static_cast<sal_uInt8>((lXB1 * nTemp + (lXB0 << 10)) >> 10));
127
128 pWriteAcc->SetPixelOnData(pScanline, nX, aCol0);
129 }
130 }
131 }
132
133 bRet = true;
134 }
135
136 pReadAcc.reset();
137 pWriteAcc.reset();
138
139 if (bRet)
140 {
141 bRet = false;
142 const Bitmap aOriginal(aBitmap);
143 aBitmap = aNewBmp;
144 aNewBmp = Bitmap(Size(nNewWidth, nNewHeight), vcl::PixelFormat::N24_BPP);
145 pReadAcc = Bitmap::ScopedReadAccess(aBitmap);
146 pWriteAcc = BitmapScopedWriteAccess(aNewBmp);
147
148 if (pReadAcc && pWriteAcc)
149 {
150 // after 1st step, bitmap *is* 24bit format (see above)
151 OSL_ENSURE(!pReadAcc->HasPalette(), "OOps, somehow ImplScaleInterpolate "
152 "in-between format has palette, should not "
153 "happen (!)");
154
155 if (1 == nHeight)
156 {
157 for (sal_Int32 nX = 0; nX < nNewWidth; nX++)
158 {
159 BitmapColor aCol0 = pReadAcc->GetPixel(0, nX);
160
161 for (sal_Int32 nY = 0; nY < nNewHeight; nY++)
162 {
163 pWriteAcc->SetPixel(nY, nX, aCol0);
164 }
165 }
166 }
167 else
168 {
169 const sal_Int32 nNewHeight1 = nNewHeight - 1;
170 const sal_Int32 nHeight1 = pReadAcc->Height() - 1;
171 const double fRevScaleY = static_cast<double>(nHeight1) / nNewHeight1;
172
173 std::unique_ptr<sal_Int32[]> pLutInt(new sal_Int32[nNewHeight]);
174 std::unique_ptr<sal_Int32[]> pLutFrac(new sal_Int32[nNewHeight]);
175
176 for (sal_Int32 nY = 0, nTemp = nHeight - 2; nY < nNewHeight; nY++)
177 {
178 double fTemp = nY * fRevScaleY;
179 pLutInt[nY] = MinMax(static_cast<sal_Int32>(fTemp), 0, nTemp);
180 fTemp -= pLutInt[nY];
181 pLutFrac[nY] = static_cast<sal_Int32>(fTemp * 1024.);
182 }
183
184 for (sal_Int32 nX = 0; nX < nNewWidth; nX++)
185 {
186 for (sal_Int32 nY = 0; nY < nNewHeight; nY++)
187 {
188 sal_Int32 nTemp = pLutInt[nY];
189
190 BitmapColor aCol0 = pReadAcc->GetPixel(nTemp++, nX);
191 BitmapColor aCol1 = pReadAcc->GetPixel(nTemp, nX);
192
193 nTemp = pLutFrac[nY];
194
195 sal_Int32 lXR0 = aCol0.GetRed();
196 sal_Int32 lXG0 = aCol0.GetGreen();
197 sal_Int32 lXB0 = aCol0.GetBlue();
198 sal_Int32 lXR1 = aCol1.GetRed() - lXR0;
199 sal_Int32 lXG1 = aCol1.GetGreen() - lXG0;
200 sal_Int32 lXB1 = aCol1.GetBlue() - lXB0;
201
202 aCol0.SetRed(
203 static_cast<sal_uInt8>((lXR1 * nTemp + (lXR0 << 10)) >> 10));
204 aCol0.SetGreen(
205 static_cast<sal_uInt8>((lXG1 * nTemp + (lXG0 << 10)) >> 10));
206 aCol0.SetBlue(
207 static_cast<sal_uInt8>((lXB1 * nTemp + (lXB0 << 10)) >> 10));
208
209 pWriteAcc->SetPixel(nY, nX, aCol0);
210 }
211 }
212 }
213
214 bRet = true;
215 }
216
217 pReadAcc.reset();
218 pWriteAcc.reset();
219
220 if (bRet)
221 {
222 aOriginal.AdaptBitCount(aNewBmp);
223 aBitmap = aNewBmp;
224 }
225 }
226 }
227 }
228
229 if (!bRet)
230 {
231 // fallback to fast scale filter
232 BitmapEx aBmpEx(aBitmap);
234 aBitmap = aBmpEx.GetBitmap();
235 }
236
237 if (bRet)
238 return BitmapEx(aBitmap);
239
240 return BitmapEx();
241}
242
243/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
vcl::ScopedBitmapAccess< BitmapWriteAccess, Bitmap, &Bitmap::AcquireWriteAccess > BitmapScopedWriteAccess
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:217
static bool Filter(BitmapEx &rBmpEx, BitmapFilter const &rFilter)
tools::Long Height() const
tools::Long Width() const
bool HasPalette() const
const BitmapColor & GetPaletteColor(sal_uInt16 nColor) const
virtual BitmapEx execute(BitmapEx const &rBitmapEx) const override
BitmapColor GetPixel(tools::Long nY, tools::Long nX) const
BitmapColor GetPixelFromData(const sal_uInt8 *pData, tools::Long nX) const
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, tools::Long nX) const
Scanline GetScanline(tools::Long nY) const
Size GetSizePixel() const
vcl::ScopedBitmapAccess< BitmapReadAccess, Bitmap, &Bitmap::AcquireReadAccess > ScopedReadAccess
void AdaptBitCount(Bitmap &rNew) const
sal_uInt8 GetBlue() const
void SetGreen(sal_uInt8 nGreen)
void SetRed(sal_uInt8 nRed)
sal_uInt8 GetRed() const
sal_uInt8 GetGreen() const
void SetBlue(sal_uInt8 nBlue)
constexpr tools::Long Height() const
constexpr tools::Long Width() const
tools::Long FRound(double fVal)
std::enable_if< std::is_signed< T >::value||std::is_floating_point< T >::value, long >::type MinMax(T nVal, tools::Long nMin, tools::Long nMax)
unsigned char sal_uInt8