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