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