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: */
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, tools::Long nX) const
tools::Long Height() const
sal_uInt8 GetRed() const
void SetBlue(sal_uInt8 nBlue)
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)
vcl::ScopedBitmapAccess< BitmapWriteAccess, Bitmap,&Bitmap::AcquireWriteAccess > BitmapScopedWriteAccess
Scanline GetScanline(tools::Long nY) const
static bool Filter(BitmapEx &rBmpEx, BitmapFilter const &rFilter)
sal_uInt8 GetBlue() const
virtual BitmapEx execute(BitmapEx const &rBitmapEx) const override
vcl::ScopedBitmapAccess< BitmapReadAccess, Bitmap,&Bitmap::AcquireReadAccess > ScopedReadAccess
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
bool HasPalette() const
tools::Long FRound(double fVal)
tools::Long Width() const
void SetRed(sal_uInt8 nRed)
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:203
sal_uInt8 GetGreen() const
void SetGreen(sal_uInt8 nGreen)
BitmapColor GetPixelFromData(const sal_uInt8 *pData, tools::Long nX) const
void AdaptBitCount(Bitmap &rNew) const
const BitmapColor & GetPaletteColor(sal_uInt16 nColor) const
BitmapColor GetPixel(tools::Long nY, tools::Long nX) const