LibreOffice Module vcl (master)  1
BitmapScaleSuperFilter.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 
21 
22 #include <tools/helpers.hxx>
23 #include <vcl/bitmapaccess.hxx>
24 
25 #include <bitmapwriteaccess.hxx>
27 
28 #include <algorithm>
29 #include <memory>
30 #include <svdata.hxx>
31 #include <sal/log.hxx>
32 
33 namespace {
34 
35 #define MAP_PRECISION 7
36 
37 typedef sal_Int32 BilinearWeightType;
38 
39 constexpr BilinearWeightType lclMaxWeight()
40 {
41  return BilinearWeightType(1) << MAP_PRECISION;
42 }
43 
44 constexpr sal_uInt8 MAP(sal_uInt8 cVal0, sal_uInt8 cVal1, BilinearWeightType nFrac)
45 {
46  return sal_uInt8(((BilinearWeightType(cVal0) << MAP_PRECISION) + nFrac * (BilinearWeightType(cVal1) - BilinearWeightType(cVal0))) >> MAP_PRECISION);
47 }
48 
49 struct ScaleContext
50 {
51  BitmapReadAccess* const mpSrc;
52  BitmapWriteAccess* mpDest;
53  long mnDestW;
54  bool mbHMirr;
55  bool mbVMirr;
56  std::vector<long> maMapIX;
57  std::vector<long> maMapIY;
58  std::vector<BilinearWeightType> maMapFX;
59  std::vector<BilinearWeightType> maMapFY;
60 
61  ScaleContext( BitmapReadAccess *pSrc,
62  BitmapWriteAccess *pDest,
63  long nSrcW, long nDestW,
64  long nSrcH, long nDestH,
65  bool bHMirr, bool bVMirr)
66  : mpSrc(pSrc)
67  , mpDest(pDest)
68  , mnDestW(nDestW)
69  , mbHMirr(bHMirr)
70  , mbVMirr(bVMirr)
71  , maMapIX(nDestW)
72  , maMapIY(nDestH)
73  , maMapFX(nDestW)
74  , maMapFY(nDestH)
75  {
76  generateMap(nSrcW, nDestW, bHMirr, maMapIX, maMapFX);
77  generateMap(nSrcH, nDestH, bVMirr, maMapIY, maMapFY);
78  }
79 
80  static void generateMap(long nSourceLength, long nDestinationLength, bool bMirrored,
81  std::vector<long> & rMapIX, std::vector<BilinearWeightType> & rMapFX)
82  {
83  const double fRevScale = (nDestinationLength > 1) ? double(nSourceLength - 1) / (nDestinationLength - 1) : 0.0;
84 
85  long nTemp = nSourceLength - 2;
86  long nTempX = nSourceLength - 1;
87 
88  for (long i = 0; i < nDestinationLength; i++)
89  {
90  double fTemp = i * fRevScale;
91  if (bMirrored)
92  fTemp = nTempX - fTemp;
93  rMapIX[i] = MinMax(long(fTemp), 0, nTemp);
94  rMapFX[i] = BilinearWeightType((fTemp - rMapIX[i]) * (BilinearWeightType(1) << MAP_PRECISION));
95  }
96  }
97 };
98 
99 constexpr long constScaleThreadStrip = 32;
100 
101 typedef void (*ScaleRangeFn)(ScaleContext &rContext, long nStartY, long nEndY);
102 
103 class ScaleTask : public comphelper::ThreadTask
104 {
105  ScaleRangeFn const mpScaleRangeFunction;
106  ScaleContext& mrContext;
107  const long mnStartY;
108  const long mnEndY;
109 
110 public:
111  explicit ScaleTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag,
112  ScaleRangeFn pScaleRangeFunction,
113  ScaleContext& rContext,
114  long nStartY, long nEndY)
115  : comphelper::ThreadTask(pTag)
116  , mpScaleRangeFunction(pScaleRangeFunction)
117  , mrContext(rContext)
118  , mnStartY(nStartY)
119  , mnEndY(nEndY)
120  {}
121 
122  virtual void doWork() override
123  {
124  mpScaleRangeFunction(mrContext, mnStartY, mnEndY);
125  }
126 };
127 
128 void scaleUp32bit(ScaleContext &rCtx, long nStartY, long nEndY)
129 {
130  const int nColorComponents = 4;
131 
132  const long nStartX = 0;
133  const long nEndX = rCtx.mnDestW - 1;
134 
135  for (long nY = nStartY; nY <= nEndY; nY++)
136  {
137  long nTempY = rCtx.maMapIY[nY];
138  BilinearWeightType nTempFY = rCtx.maMapFY[nY];
139 
140  Scanline pLine0 = rCtx.mpSrc->GetScanline(nTempY+0);
141  Scanline pLine1 = rCtx.mpSrc->GetScanline(nTempY+1);
142  Scanline pScanDest = rCtx.mpDest->GetScanline(nY);
143 
144  sal_uInt8 nComponent1[nColorComponents];
145  sal_uInt8 nComponent2[nColorComponents];
146 
147  Scanline pColorPtr0;
148  Scanline pColorPtr1;
149 
150  for (long nX = nStartX; nX <= nEndX; nX++)
151  {
152  long nTempX = rCtx.maMapIX[nX];
153  BilinearWeightType nTempFX = rCtx.maMapFX[nX];
154 
155  pColorPtr0 = pLine0 + nTempX * nColorComponents;
156  pColorPtr1 = pColorPtr0 + nColorComponents;
157 
158  nComponent1[0] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
159  pColorPtr0++; pColorPtr1++;
160  nComponent1[1] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
161  pColorPtr0++; pColorPtr1++;
162  nComponent1[2] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
163  pColorPtr0++; pColorPtr1++;
164  nComponent1[3] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
165 
166  pColorPtr0 = pLine1 + nTempX * nColorComponents;
167  pColorPtr1 = pColorPtr0 + nColorComponents;
168 
169  nComponent2[0] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
170  pColorPtr0++; pColorPtr1++;
171  nComponent2[1] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
172  pColorPtr0++; pColorPtr1++;
173  nComponent2[2] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
174  pColorPtr0++; pColorPtr1++;
175  nComponent2[3] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
176 
177  *pScanDest = MAP(nComponent1[0], nComponent2[0], nTempFY);
178  pScanDest++;
179  *pScanDest = MAP(nComponent1[1], nComponent2[1], nTempFY);
180  pScanDest++;
181  *pScanDest = MAP(nComponent1[2], nComponent2[2], nTempFY);
182  pScanDest++;
183  *pScanDest = MAP(nComponent1[3], nComponent2[3], nTempFY);
184  pScanDest++;
185  }
186  }
187 }
188 
189 void scaleUpPalette8bit(ScaleContext &rCtx, long nStartY, long nEndY)
190 {
191  const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
192 
193  for( long nY = nStartY; nY <= nEndY; nY++ )
194  {
195  long nTempY = rCtx.maMapIY[ nY ];
196  BilinearWeightType nTempFY = rCtx.maMapFY[ nY ];
197  Scanline pLine0 = rCtx.mpSrc->GetScanline( nTempY );
198  Scanline pLine1 = rCtx.mpSrc->GetScanline( ++nTempY );
199  Scanline pScanDest = rCtx.mpDest->GetScanline( nY );
200 
201  for(long nX = nStartX, nXDst = 0; nX <= nEndX; nX++ )
202  {
203  long nTempX = rCtx.maMapIX[ nX ];
204  BilinearWeightType nTempFX = rCtx.maMapFX[ nX ];
205 
206  const BitmapColor& rCol0 = rCtx.mpSrc->GetPaletteColor( pLine0[ nTempX ] );
207  const BitmapColor& rCol2 = rCtx.mpSrc->GetPaletteColor( pLine1[ nTempX ] );
208  const BitmapColor& rCol1 = rCtx.mpSrc->GetPaletteColor( pLine0[ ++nTempX ] );
209  const BitmapColor& rCol3 = rCtx.mpSrc->GetPaletteColor( pLine1[ nTempX ] );
210 
211  sal_uInt8 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTempFX );
212  sal_uInt8 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTempFX );
213  sal_uInt8 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTempFX );
214 
215  sal_uInt8 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTempFX );
216  sal_uInt8 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTempFX );
217  sal_uInt8 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTempFX );
218 
219  BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
220  MAP( cG0, cG1, nTempFY ),
221  MAP( cB0, cB1, nTempFY ) );
222  rCtx.mpDest->SetPixelOnData( pScanDest, nXDst++, aColRes );
223  }
224  }
225 }
226 
227 void scaleUpPaletteGeneral(ScaleContext &rCtx, long nStartY, long nEndY)
228 {
229  const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
230 
231  for( long nY = nStartY; nY <= nEndY; nY++ )
232  {
233  long nTempY = rCtx.maMapIY[ nY ];
234  BilinearWeightType nTempFY = rCtx.maMapFY[ nY ];
235  Scanline pScanline = rCtx.mpDest->GetScanline( nY );
236 
237  for( long nX = nStartX, nXDst = 0; nX <= nEndX; nX++ )
238  {
239  long nTempX = rCtx.maMapIX[ nX ];
240  BilinearWeightType nTempFX = rCtx.maMapFX[ nX ];
241 
242  BitmapColor aCol0 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( nTempY, nTempX ) );
243  BitmapColor aCol1 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( nTempY, ++nTempX ) );
244  sal_uInt8 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
245  sal_uInt8 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
246  sal_uInt8 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
247 
248  aCol1 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( ++nTempY, nTempX ) );
249  aCol0 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( nTempY--, --nTempX ) );
250  sal_uInt8 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
251  sal_uInt8 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
252  sal_uInt8 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
253 
254  BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
255  MAP( cG0, cG1, nTempFY ),
256  MAP( cB0, cB1, nTempFY ) );
257  rCtx.mpDest->SetPixelOnData( pScanline, nXDst++, aColRes );
258  }
259  }
260 }
261 
262 void scaleUp24bit(ScaleContext &rCtx, long nStartY, long nEndY)
263 {
264  const int nColorComponents = 3;
265 
266  const long nStartX = 0;
267  const long nEndX = rCtx.mnDestW - 1;
268 
269  for (long nY = nStartY; nY <= nEndY; nY++)
270  {
271  long nTempY = rCtx.maMapIY[nY];
272  BilinearWeightType nTempFY = rCtx.maMapFY[nY];
273 
274  Scanline pLine0 = rCtx.mpSrc->GetScanline(nTempY+0);
275  Scanline pLine1 = rCtx.mpSrc->GetScanline(nTempY+1);
276  Scanline pScanDest = rCtx.mpDest->GetScanline(nY);
277 
278  sal_uInt8 nComponent1[nColorComponents];
279  sal_uInt8 nComponent2[nColorComponents];
280 
281  Scanline pColorPtr0;
282  Scanline pColorPtr1;
283 
284  for (long nX = nStartX; nX <= nEndX; nX++)
285  {
286  long nTempX = rCtx.maMapIX[nX];
287  BilinearWeightType nTempFX = rCtx.maMapFX[nX];
288 
289  pColorPtr0 = pLine0 + nTempX * nColorComponents;
290  pColorPtr1 = pColorPtr0 + nColorComponents;
291 
292  nComponent1[0] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
293  pColorPtr0++; pColorPtr1++;
294  nComponent1[1] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
295  pColorPtr0++; pColorPtr1++;
296  nComponent1[2] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
297 
298  pColorPtr0 = pLine1 + nTempX * nColorComponents;
299  pColorPtr1 = pColorPtr0 + nColorComponents;
300 
301  nComponent2[0] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
302  pColorPtr0++; pColorPtr1++;
303  nComponent2[1] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
304  pColorPtr0++; pColorPtr1++;
305  nComponent2[2] = MAP(*pColorPtr0, *pColorPtr1, nTempFX);
306 
307  *pScanDest = MAP(nComponent1[0], nComponent2[0], nTempFY);
308  pScanDest++;
309  *pScanDest = MAP(nComponent1[1], nComponent2[1], nTempFY);
310  pScanDest++;
311  *pScanDest = MAP(nComponent1[2], nComponent2[2], nTempFY);
312  pScanDest++;
313  }
314  }
315 }
316 
317 void scaleUpNonPaletteGeneral(ScaleContext &rCtx, long nStartY, long nEndY)
318 {
319  const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
320 
321  for( long nY = nStartY; nY <= nEndY; nY++ )
322  {
323  long nTempY = rCtx.maMapIY[ nY ];
324  BilinearWeightType nTempFY = rCtx.maMapFY[ nY ];
325  Scanline pScanDest = rCtx.mpDest->GetScanline( nY );
326 
327  for( long nX = nStartX, nXDst = 0; nX <= nEndX; nX++ )
328  {
329  long nTempX = rCtx.maMapIX[ nX ];
330  BilinearWeightType nTempFX = rCtx.maMapFX[ nX ];
331 
332  BitmapColor aCol0 = rCtx.mpSrc->GetPixel( nTempY, nTempX );
333  BitmapColor aCol1 = rCtx.mpSrc->GetPixel( nTempY, ++nTempX );
334  sal_uInt8 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
335  sal_uInt8 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
336  sal_uInt8 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
337 
338  aCol1 = rCtx.mpSrc->GetPixel( ++nTempY, nTempX );
339  aCol0 = rCtx.mpSrc->GetPixel( nTempY--, --nTempX );
340  sal_uInt8 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
341  sal_uInt8 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
342  sal_uInt8 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
343 
344  BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
345  MAP( cG0, cG1, nTempFY ),
346  MAP( cB0, cB1, nTempFY ) );
347  rCtx.mpDest->SetPixelOnData( pScanDest, nXDst++, aColRes );
348  }
349  }
350 }
351 
352 void scaleDown32bit(ScaleContext &rCtx, long nStartY, long nEndY)
353 {
354  const int constColorComponents = 4;
355 
356  const long nStartX = 0;
357  const long nEndX = rCtx.mnDestW - 1;
358 
359  for (long nY = nStartY; nY <= nEndY; nY++)
360  {
361  long nTop = rCtx.mbVMirr ? (nY + 1) : nY;
362  long nBottom = rCtx.mbVMirr ? nY : (nY + 1);
363 
364  long nLineStart;
365  long nLineRange;
366  if (nY == nEndY)
367  {
368  nLineStart = rCtx.maMapIY[nY];
369  nLineRange = 0;
370  }
371  else
372  {
373  nLineStart = rCtx.maMapIY[nTop];
374  nLineRange = (rCtx.maMapIY[nBottom] == rCtx.maMapIY[nTop]) ?
375  1 : (rCtx.maMapIY[nBottom] - rCtx.maMapIY[nTop]);
376  }
377 
378  Scanline pScanDest = rCtx.mpDest->GetScanline(nY);
379  for (long nX = nStartX; nX <= nEndX; nX++)
380  {
381  long nLeft = rCtx.mbHMirr ? (nX + 1) : nX;
382  long nRight = rCtx.mbHMirr ? nX : (nX + 1);
383 
384  long nRowStart;
385  long nRowRange;
386  if (nX == nEndX)
387  {
388  nRowStart = rCtx.maMapIX[nX];
389  nRowRange = 0;
390  }
391  else
392  {
393  nRowStart = rCtx.maMapIX[nLeft];
394  nRowRange = (rCtx.maMapIX[nRight] == rCtx.maMapIX[nLeft]) ?
395  1 : (rCtx.maMapIX[nRight] - rCtx.maMapIX[nLeft]);
396  }
397 
398  int nSum1 = 0;
399  int nSum2 = 0;
400  int nSum3 = 0;
401  int nSum4 = 0;
402  BilinearWeightType nTotalWeightY = 0;
403 
404  for (long i = 0; i<= nLineRange; i++)
405  {
406  Scanline pTmpY = rCtx.mpSrc->GetScanline(nLineStart + i);
407  Scanline pTmpX = pTmpY + constColorComponents * nRowStart;
408 
409  int nSumRow1 = 0;
410  int nSumRow2 = 0;
411  int nSumRow3 = 0;
412  int nSumRow4 = 0;
413  BilinearWeightType nTotalWeightX = 0;
414 
415  for (long j = 0; j <= nRowRange; j++)
416  {
417  if (nX == nEndX)
418  {
419  nSumRow1 += (*pTmpX) << MAP_PRECISION; pTmpX++;
420  nSumRow2 += (*pTmpX) << MAP_PRECISION; pTmpX++;
421  nSumRow3 += (*pTmpX) << MAP_PRECISION; pTmpX++;
422  nSumRow4 += (*pTmpX) << MAP_PRECISION; pTmpX++;
423  nTotalWeightX += lclMaxWeight();
424  }
425  else if(j == 0)
426  {
427  BilinearWeightType nWeightX = lclMaxWeight() - rCtx.maMapFX[nLeft];
428  nSumRow1 += (nWeightX * (*pTmpX)); pTmpX++;
429  nSumRow2 += (nWeightX * (*pTmpX)); pTmpX++;
430  nSumRow3 += (nWeightX * (*pTmpX)); pTmpX++;
431  nSumRow4 += (nWeightX * (*pTmpX)); pTmpX++;
432  nTotalWeightX += nWeightX;
433  }
434  else if ( nRowRange == j )
435  {
436  BilinearWeightType nWeightX = rCtx.maMapFX[ nRight ] ;
437  nSumRow1 += (nWeightX * (*pTmpX)); pTmpX++;
438  nSumRow2 += (nWeightX * (*pTmpX)); pTmpX++;
439  nSumRow3 += (nWeightX * (*pTmpX)); pTmpX++;
440  nSumRow4 += (nWeightX * (*pTmpX)); pTmpX++;
441  nTotalWeightX += nWeightX;
442  }
443  else
444  {
445  nSumRow1 += (*pTmpX) << MAP_PRECISION; pTmpX++;
446  nSumRow2 += (*pTmpX) << MAP_PRECISION; pTmpX++;
447  nSumRow3 += (*pTmpX) << MAP_PRECISION; pTmpX++;
448  nSumRow4 += (*pTmpX) << MAP_PRECISION; pTmpX++;
449  nTotalWeightX += lclMaxWeight();
450  }
451  }
452 
453  BilinearWeightType nWeightY = lclMaxWeight();
454  if (nY == nEndY)
455  nWeightY = lclMaxWeight();
456  else if (i == 0)
457  nWeightY = lclMaxWeight() - rCtx.maMapFY[nTop];
458  else if (nLineRange == 1)
459  nWeightY = rCtx.maMapFY[nTop];
460  else if (nLineRange == i)
461  nWeightY = rCtx.maMapFY[nBottom];
462 
463  if (nTotalWeightX)
464  {
465  nSumRow1 /= nTotalWeightX;
466  nSumRow2 /= nTotalWeightX;
467  nSumRow3 /= nTotalWeightX;
468  nSumRow4 /= nTotalWeightX;
469  }
470  nSum1 += nWeightY * nSumRow1;
471  nSum2 += nWeightY * nSumRow2;
472  nSum3 += nWeightY * nSumRow3;
473  nSum4 += nWeightY * nSumRow4;
474  nTotalWeightY += nWeightY;
475  }
476 
477  if (nTotalWeightY)
478  {
479  nSum1 /= nTotalWeightY;
480  nSum2 /= nTotalWeightY;
481  nSum3 /= nTotalWeightY;
482  nSum4 /= nTotalWeightY;
483  }
484 
485  // Write the calculated color components to the destination
486  *pScanDest = nSum1; pScanDest++;
487  *pScanDest = nSum2; pScanDest++;
488  *pScanDest = nSum3; pScanDest++;
489  *pScanDest = nSum4; pScanDest++;
490  }
491  }
492 }
493 
494 void scaleDownPalette8bit(ScaleContext &rCtx, long nStartY, long nEndY)
495 {
496  const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
497 
498  for( long nY = nStartY; nY <= nEndY; nY++ )
499  {
500  long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
501  long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
502 
503  long nLineStart, nLineRange;
504  if( nY == nEndY )
505  {
506  nLineStart = rCtx.maMapIY[ nY ];
507  nLineRange = 0;
508  }
509  else
510  {
511  nLineStart = rCtx.maMapIY[ nTop ] ;
512  nLineRange = ( rCtx.maMapIY[ nBottom ] == rCtx.maMapIY[ nTop ] ) ? 1 :( rCtx.maMapIY[ nBottom ] - rCtx.maMapIY[ nTop ] );
513  }
514 
515  Scanline pScanDest = rCtx.mpDest->GetScanline( nY );
516  for( long nX = nStartX , nXDst = 0; nX <= nEndX; nX++ )
517  {
518  long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
519  long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
520 
521  long nRowStart;
522  long nRowRange;
523  if( nX == nEndX )
524  {
525  nRowStart = rCtx.maMapIX[ nX ];
526  nRowRange = 0;
527  }
528  else
529  {
530  nRowStart = rCtx.maMapIX[ nLeft ];
531  nRowRange = ( rCtx.maMapIX[ nRight ] == rCtx.maMapIX[ nLeft ] )? 1 : ( rCtx.maMapIX[ nRight ] - rCtx.maMapIX[ nLeft ] );
532  }
533 
534  int nSumR = 0;
535  int nSumG = 0;
536  int nSumB = 0;
537  BilinearWeightType nTotalWeightY = 0;
538 
539  for(long i = 0; i<= nLineRange; i++)
540  {
541  Scanline pTmpY = rCtx.mpSrc->GetScanline( nLineStart + i );
542  int nSumRowR = 0;
543  int nSumRowG = 0;
544  int nSumRowB = 0;
545  BilinearWeightType nTotalWeightX = 0;
546 
547  for(long j = 0; j <= nRowRange; j++)
548  {
549  const BitmapColor& rCol = rCtx.mpSrc->GetPaletteColor( pTmpY[ nRowStart + j ] );
550 
551  if(nX == nEndX )
552  {
553  nSumRowB += rCol.GetBlue() << MAP_PRECISION;
554  nSumRowG += rCol.GetGreen() << MAP_PRECISION;
555  nSumRowR += rCol.GetRed() << MAP_PRECISION;
556  nTotalWeightX += lclMaxWeight();
557  }
558  else if( j == 0 )
559  {
560  BilinearWeightType nWeightX = lclMaxWeight() - rCtx.maMapFX[ nLeft ];
561  nSumRowB += ( nWeightX *rCol.GetBlue()) ;
562  nSumRowG += ( nWeightX *rCol.GetGreen()) ;
563  nSumRowR += ( nWeightX *rCol.GetRed()) ;
564  nTotalWeightX += nWeightX;
565  }
566  else if ( nRowRange == j )
567  {
568  BilinearWeightType nWeightX = rCtx.maMapFX[ nRight ] ;
569  nSumRowB += ( nWeightX *rCol.GetBlue() );
570  nSumRowG += ( nWeightX *rCol.GetGreen() );
571  nSumRowR += ( nWeightX *rCol.GetRed() );
572  nTotalWeightX += nWeightX;
573  }
574  else
575  {
576  nSumRowB += rCol.GetBlue() << MAP_PRECISION;
577  nSumRowG += rCol.GetGreen() << MAP_PRECISION;
578  nSumRowR += rCol.GetRed() << MAP_PRECISION;
579  nTotalWeightX += lclMaxWeight();
580  }
581  }
582 
583  BilinearWeightType nWeightY = lclMaxWeight();
584  if( nY == nEndY )
585  nWeightY = lclMaxWeight();
586  else if( i == 0 )
587  nWeightY = lclMaxWeight() - rCtx.maMapFY[ nTop ];
588  else if( nLineRange == 1 )
589  nWeightY = rCtx.maMapFY[ nTop ];
590  else if ( nLineRange == i )
591  nWeightY = rCtx.maMapFY[ nBottom ];
592 
593  if (nTotalWeightX)
594  {
595  nSumRowB /= nTotalWeightX;
596  nSumRowG /= nTotalWeightX;
597  nSumRowR /= nTotalWeightX;
598  }
599 
600  nSumB += nWeightY * nSumRowB;
601  nSumG += nWeightY * nSumRowG;
602  nSumR += nWeightY * nSumRowR;
603  nTotalWeightY += nWeightY;
604  }
605 
606  if (nTotalWeightY)
607  {
608  nSumR /= nTotalWeightY;
609  nSumG /= nTotalWeightY;
610  nSumB /= nTotalWeightY;
611  }
612 
613  BitmapColor aColRes(static_cast<sal_uInt8>(nSumR), static_cast<sal_uInt8>(nSumG), static_cast<sal_uInt8>(nSumB));
614  rCtx.mpDest->SetPixelOnData( pScanDest, nXDst++, aColRes );
615  }
616  }
617 }
618 
619 void scaleDownPaletteGeneral(ScaleContext &rCtx, long nStartY, long nEndY)
620 {
621  const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
622 
623  for( long nY = nStartY; nY <= nEndY; nY++ )
624  {
625  long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
626  long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
627 
628  long nLineStart, nLineRange;
629  if( nY ==nEndY )
630  {
631  nLineStart = rCtx.maMapIY[ nY ];
632  nLineRange = 0;
633  }
634  else
635  {
636  nLineStart = rCtx.maMapIY[ nTop ] ;
637  nLineRange = ( rCtx.maMapIY[ nBottom ] == rCtx.maMapIY[ nTop ] ) ? 1 :( rCtx.maMapIY[ nBottom ] - rCtx.maMapIY[ nTop ] );
638  }
639 
640  Scanline pScanDest = rCtx.mpDest->GetScanline( nY );
641  for( long nX = nStartX , nXDst = 0; nX <= nEndX; nX++ )
642  {
643  long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
644  long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
645 
646  long nRowStart, nRowRange;
647  if( nX == nEndX )
648  {
649  nRowStart = rCtx.maMapIX[ nX ];
650  nRowRange = 0;
651  }
652  else
653  {
654  nRowStart = rCtx.maMapIX[ nLeft ];
655  nRowRange = ( rCtx.maMapIX[ nRight ] == rCtx.maMapIX[ nLeft ] )? 1 : ( rCtx.maMapIX[ nRight ] - rCtx.maMapIX[ nLeft ] );
656  }
657 
658  int nSumR = 0;
659  int nSumG = 0;
660  int nSumB = 0;
661  BilinearWeightType nTotalWeightY = 0;
662 
663  for(long i = 0; i<= nLineRange; i++)
664  {
665  int nSumRowR = 0;
666  int nSumRowG = 0;
667  int nSumRowB = 0;
668  BilinearWeightType nTotalWeightX = 0;
669 
670  Scanline pScanlineSrc = rCtx.mpSrc->GetScanline( nLineStart + i );
671  for(long j = 0; j <= nRowRange; j++)
672  {
673  BitmapColor aCol0 = rCtx.mpSrc->GetPaletteColor ( rCtx.mpSrc->GetIndexFromData( pScanlineSrc, nRowStart + j ) );
674 
675  if(nX == nEndX )
676  {
677 
678  nSumRowB += aCol0.GetBlue() << MAP_PRECISION;
679  nSumRowG += aCol0.GetGreen() << MAP_PRECISION;
680  nSumRowR += aCol0.GetRed() << MAP_PRECISION;
681  nTotalWeightX += lclMaxWeight();
682  }
683  else if( j == 0 )
684  {
685 
686  BilinearWeightType nWeightX = lclMaxWeight() - rCtx.maMapFX[ nLeft ];
687  nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
688  nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
689  nSumRowR += ( nWeightX *aCol0.GetRed()) ;
690  nTotalWeightX += nWeightX;
691  }
692  else if ( nRowRange == j )
693  {
694 
695  BilinearWeightType nWeightX = rCtx.maMapFX[ nRight ] ;
696  nSumRowB += ( nWeightX *aCol0.GetBlue() );
697  nSumRowG += ( nWeightX *aCol0.GetGreen() );
698  nSumRowR += ( nWeightX *aCol0.GetRed() );
699  nTotalWeightX += nWeightX;
700  }
701  else
702  {
703 
704  nSumRowB += aCol0.GetBlue() << MAP_PRECISION;
705  nSumRowG += aCol0.GetGreen() << MAP_PRECISION;
706  nSumRowR += aCol0.GetRed() << MAP_PRECISION;
707  nTotalWeightX += lclMaxWeight();
708  }
709  }
710 
711  long nWeightY = lclMaxWeight();
712  if( nY == nEndY )
713  nWeightY = lclMaxWeight();
714  else if( i == 0 )
715  nWeightY = lclMaxWeight() - rCtx.maMapFY[ nTop ];
716  else if( nLineRange == 1 )
717  nWeightY = rCtx.maMapFY[ nTop ];
718  else if ( nLineRange == i )
719  nWeightY = rCtx.maMapFY[ nBottom ];
720 
721  if (nTotalWeightX)
722  {
723  nSumRowB /= nTotalWeightX;
724  nSumRowG /= nTotalWeightX;
725  nSumRowR /= nTotalWeightX;
726  }
727 
728  nSumB += nWeightY * nSumRowB;
729  nSumG += nWeightY * nSumRowG;
730  nSumR += nWeightY * nSumRowR;
731  nTotalWeightY += nWeightY;
732  }
733 
734  if (nTotalWeightY)
735  {
736  nSumR /= nTotalWeightY;
737  nSumG /= nTotalWeightY;
738  nSumB /= nTotalWeightY;
739  }
740 
741  BitmapColor aColRes(static_cast<sal_uInt8>(nSumR), static_cast<sal_uInt8>(nSumG), static_cast<sal_uInt8>(nSumB));
742  rCtx.mpDest->SetPixelOnData( pScanDest, nXDst++, aColRes );
743  }
744  }
745 }
746 
747 void scaleDown24bit(ScaleContext &rCtx, long nStartY, long nEndY)
748 {
749  const int constColorComponents = 3;
750 
751  const long nStartX = 0;
752  const long nEndX = rCtx.mnDestW - 1;
753 
754  for (long nY = nStartY; nY <= nEndY; nY++)
755  {
756  long nTop = rCtx.mbVMirr ? (nY + 1) : nY;
757  long nBottom = rCtx.mbVMirr ? nY : (nY + 1);
758 
759  long nLineStart;
760  long nLineRange;
761  if (nY == nEndY)
762  {
763  nLineStart = rCtx.maMapIY[nY];
764  nLineRange = 0;
765  }
766  else
767  {
768  nLineStart = rCtx.maMapIY[nTop];
769  nLineRange = (rCtx.maMapIY[nBottom] == rCtx.maMapIY[nTop]) ?
770  1 : (rCtx.maMapIY[nBottom] - rCtx.maMapIY[nTop]);
771  }
772 
773  Scanline pScanDest = rCtx.mpDest->GetScanline(nY);
774  for (long nX = nStartX; nX <= nEndX; nX++)
775  {
776  long nLeft = rCtx.mbHMirr ? (nX + 1) : nX;
777  long nRight = rCtx.mbHMirr ? nX : (nX + 1);
778 
779  long nRowStart;
780  long nRowRange;
781  if (nX == nEndX)
782  {
783  nRowStart = rCtx.maMapIX[nX];
784  nRowRange = 0;
785  }
786  else
787  {
788  nRowStart = rCtx.maMapIX[nLeft];
789  nRowRange = (rCtx.maMapIX[nRight] == rCtx.maMapIX[nLeft]) ?
790  1 : (rCtx.maMapIX[nRight] - rCtx.maMapIX[nLeft]);
791  }
792 
793  int nSum1 = 0;
794  int nSum2 = 0;
795  int nSum3 = 0;
796  BilinearWeightType nTotalWeightY = 0;
797 
798  for (long i = 0; i<= nLineRange; i++)
799  {
800  Scanline pTmpY = rCtx.mpSrc->GetScanline(nLineStart + i);
801  Scanline pTmpX = pTmpY + constColorComponents * nRowStart;
802 
803  int nSumRow1 = 0;
804  int nSumRow2 = 0;
805  int nSumRow3 = 0;
806  BilinearWeightType nTotalWeightX = 0;
807 
808  for (long j = 0; j <= nRowRange; j++)
809  {
810  if (nX == nEndX)
811  {
812  nSumRow1 += (*pTmpX) << MAP_PRECISION; pTmpX++;
813  nSumRow2 += (*pTmpX) << MAP_PRECISION; pTmpX++;
814  nSumRow3 += (*pTmpX) << MAP_PRECISION; pTmpX++;
815  nTotalWeightX += lclMaxWeight();
816  }
817  else if(j == 0)
818  {
819  BilinearWeightType nWeightX = lclMaxWeight() - rCtx.maMapFX[nLeft];
820  nSumRow1 += (nWeightX * (*pTmpX)); pTmpX++;
821  nSumRow2 += (nWeightX * (*pTmpX)); pTmpX++;
822  nSumRow3 += (nWeightX * (*pTmpX)); pTmpX++;
823  nTotalWeightX += nWeightX;
824  }
825  else if ( nRowRange == j )
826  {
827  BilinearWeightType nWeightX = rCtx.maMapFX[ nRight ] ;
828  nSumRow1 += (nWeightX * (*pTmpX)); pTmpX++;
829  nSumRow2 += (nWeightX * (*pTmpX)); pTmpX++;
830  nSumRow3 += (nWeightX * (*pTmpX)); pTmpX++;
831  nTotalWeightX += nWeightX;
832  }
833  else
834  {
835  nSumRow1 += (*pTmpX) << MAP_PRECISION; pTmpX++;
836  nSumRow2 += (*pTmpX) << MAP_PRECISION; pTmpX++;
837  nSumRow3 += (*pTmpX) << MAP_PRECISION; pTmpX++;
838  nTotalWeightX += lclMaxWeight();
839  }
840  }
841 
842  BilinearWeightType nWeightY = lclMaxWeight();
843  if (nY == nEndY)
844  nWeightY = lclMaxWeight();
845  else if (i == 0)
846  nWeightY = lclMaxWeight() - rCtx.maMapFY[nTop];
847  else if (nLineRange == 1)
848  nWeightY = rCtx.maMapFY[nTop];
849  else if (nLineRange == i)
850  nWeightY = rCtx.maMapFY[nBottom];
851 
852  if (nTotalWeightX)
853  {
854  nSumRow1 /= nTotalWeightX;
855  nSumRow2 /= nTotalWeightX;
856  nSumRow3 /= nTotalWeightX;
857  }
858  nSum1 += nWeightY * nSumRow1;
859  nSum2 += nWeightY * nSumRow2;
860  nSum3 += nWeightY * nSumRow3;
861  nTotalWeightY += nWeightY;
862  }
863 
864  if (nTotalWeightY)
865  {
866  nSum1 /= nTotalWeightY;
867  nSum2 /= nTotalWeightY;
868  nSum3 /= nTotalWeightY;
869  }
870 
871  // Write the calculated color components to the destination
872  *pScanDest = nSum1; pScanDest++;
873  *pScanDest = nSum2; pScanDest++;
874  *pScanDest = nSum3; pScanDest++;
875  }
876  }
877 }
878 
879 void scaleDownNonPaletteGeneral(ScaleContext &rCtx, long nStartY, long nEndY)
880 {
881  const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
882 
883  for( long nY = nStartY; nY <= nEndY; nY++ )
884  {
885  long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
886  long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
887 
888  long nLineStart, nLineRange;
889  if( nY ==nEndY )
890  {
891  nLineStart = rCtx.maMapIY[ nY ];
892  nLineRange = 0;
893  }
894  else
895  {
896  nLineStart = rCtx.maMapIY[ nTop ] ;
897  nLineRange = ( rCtx.maMapIY[ nBottom ] == rCtx.maMapIY[ nTop ] ) ? 1 :( rCtx.maMapIY[ nBottom ] - rCtx.maMapIY[ nTop ] );
898  }
899 
900  Scanline pScanDest = rCtx.mpDest->GetScanline( nY );
901  for( long nX = nStartX , nXDst = 0; nX <= nEndX; nX++ )
902  {
903  long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
904  long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
905 
906  long nRowStart, nRowRange;
907  if( nX == nEndX )
908  {
909  nRowStart = rCtx.maMapIX[ nX ];
910  nRowRange = 0;
911  }
912  else
913  {
914  nRowStart = rCtx.maMapIX[ nLeft ];
915  nRowRange = ( rCtx.maMapIX[ nRight ] == rCtx.maMapIX[ nLeft ] )? 1 : ( rCtx.maMapIX[ nRight ] - rCtx.maMapIX[ nLeft ] );
916  }
917 
918  int nSumR = 0;
919  int nSumG = 0;
920  int nSumB = 0;
921  BilinearWeightType nTotalWeightY = 0;
922 
923  for(long i = 0; i<= nLineRange; i++)
924  {
925  int nSumRowR = 0;
926  int nSumRowG = 0;
927  int nSumRowB = 0;
928  BilinearWeightType nTotalWeightX = 0;
929 
930  Scanline pScanlineSrc = rCtx.mpSrc->GetScanline( nLineStart + i );
931  for(long j = 0; j <= nRowRange; j++)
932  {
933  BitmapColor aCol0 = rCtx.mpSrc->GetPixelFromData( pScanlineSrc, nRowStart + j );
934 
935  if(nX == nEndX )
936  {
937 
938  nSumRowB += aCol0.GetBlue() << MAP_PRECISION;
939  nSumRowG += aCol0.GetGreen() << MAP_PRECISION;
940  nSumRowR += aCol0.GetRed() << MAP_PRECISION;
941  nTotalWeightX += lclMaxWeight();
942  }
943  else if( j == 0 )
944  {
945 
946  BilinearWeightType nWeightX = lclMaxWeight() - rCtx.maMapFX[ nLeft ];
947  nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
948  nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
949  nSumRowR += ( nWeightX *aCol0.GetRed()) ;
950  nTotalWeightX += nWeightX;
951  }
952  else if ( nRowRange == j )
953  {
954 
955  BilinearWeightType nWeightX = rCtx.maMapFX[ nRight ] ;
956  nSumRowB += ( nWeightX *aCol0.GetBlue() );
957  nSumRowG += ( nWeightX *aCol0.GetGreen() );
958  nSumRowR += ( nWeightX *aCol0.GetRed() );
959  nTotalWeightX += nWeightX;
960  }
961  else
962  {
963  nSumRowB += aCol0.GetBlue() << MAP_PRECISION;
964  nSumRowG += aCol0.GetGreen() << MAP_PRECISION;
965  nSumRowR += aCol0.GetRed() << MAP_PRECISION;
966  nTotalWeightX += lclMaxWeight();
967  }
968  }
969 
970  BilinearWeightType nWeightY = lclMaxWeight();
971  if( nY == nEndY )
972  nWeightY = lclMaxWeight();
973  else if( i == 0 )
974  nWeightY = lclMaxWeight() - rCtx.maMapFY[ nTop ];
975  else if( nLineRange == 1 )
976  nWeightY = rCtx.maMapFY[ nTop ];
977  else if ( nLineRange == i )
978  nWeightY = rCtx.maMapFY[ nBottom ];
979 
980  if (nTotalWeightX)
981  {
982  nSumRowB /= nTotalWeightX;
983  nSumRowG /= nTotalWeightX;
984  nSumRowR /= nTotalWeightX;
985  }
986 
987  nSumB += nWeightY * nSumRowB;
988  nSumG += nWeightY * nSumRowG;
989  nSumR += nWeightY * nSumRowR;
990  nTotalWeightY += nWeightY;
991  }
992 
993  if (nTotalWeightY)
994  {
995  nSumR /= nTotalWeightY;
996  nSumG /= nTotalWeightY;
997  nSumB /= nTotalWeightY;
998  }
999 
1000  BitmapColor aColRes(static_cast<sal_uInt8>(nSumR), static_cast<sal_uInt8>(nSumG), static_cast<sal_uInt8>(nSumB));
1001  rCtx.mpDest->SetPixelOnData( pScanDest, nXDst++, aColRes );
1002  }
1003  }
1004 }
1005 
1006 } // end anonymous namespace
1007 
1008 BitmapScaleSuperFilter::BitmapScaleSuperFilter(const double& rScaleX, const double& rScaleY) :
1009  mrScaleX(rScaleX),
1010  mrScaleY(rScaleY)
1011 {}
1012 
1014 {}
1015 
1017 {
1018  Bitmap aBitmap(rBitmap.GetBitmap());
1019  SalBitmap* pKey = aBitmap.ImplGetSalBitmap().get();
1020 
1021  bool bRet = false;
1022 
1023  const Size aSizePix(rBitmap.GetSizePixel());
1024 
1025  bool bHMirr = mrScaleX < 0;
1026  bool bVMirr = mrScaleY < 0;
1027 
1028  double fScaleX = std::fabs(mrScaleX);
1029  double fScaleY = std::fabs(mrScaleY);
1030 
1031  const long nDstW = FRound(aSizePix.Width() * fScaleX);
1032  const long nDstH = FRound(aSizePix.Height() * fScaleY);
1033 
1034  const double fScaleThresh = 0.6;
1035 
1036  if (nDstW <= 1 || nDstH <= 1)
1037  return BitmapEx();
1038 
1039  // check cache for a previously scaled version of this
1040  ImplSVData* pSVData = ImplGetSVData();
1041  auto& rCache = pSVData->maGDIData.maScaleCache;
1042  auto aFind = rCache.find(pKey);
1043  if (aFind != rCache.end())
1044  {
1045  if (aFind->second.GetSizePixel().Width() == nDstW && aFind->second.GetSizePixel().Height() == nDstH)
1046  return aFind->second;
1047  }
1048 
1049  {
1050  Bitmap::ScopedReadAccess pReadAccess(aBitmap);
1051 
1052  sal_uInt16 nSourceBitcount = aBitmap.GetBitCount();
1053 
1054  Bitmap aOutBmp(Size(nDstW, nDstH), std::max(nSourceBitcount, sal_uInt16(24)));
1055  Size aOutSize = aOutBmp.GetSizePixel();
1056  sal_uInt16 nTargetBitcount = aOutBmp.GetBitCount();
1057 
1058  if (!aOutSize.Width() || !aOutSize.Height())
1059  {
1060  SAL_WARN("vcl.gdi", "bmp creation failed");
1061  return BitmapEx();
1062  }
1063 
1064  BitmapScopedWriteAccess pWriteAccess(aOutBmp);
1065 
1066  const long nStartY = 0;
1067  const long nEndY = nDstH - 1;
1068 
1069  if (pReadAccess && pWriteAccess)
1070  {
1071  ScaleRangeFn pScaleRangeFn;
1072  ScaleContext aContext( pReadAccess.get(),
1073  pWriteAccess.get(),
1074  pReadAccess->Width(),
1075  pWriteAccess->Width(),
1076  pReadAccess->Height(),
1077  pWriteAccess->Height(),
1078  bVMirr, bHMirr );
1079 
1080  bool bScaleUp = fScaleX >= fScaleThresh && fScaleY >= fScaleThresh;
1081  // If we have a source bitmap with a palette the scaling converts
1082  // from up to 8 bit image -> 24 bit non-palette, which is then
1083  // adapted back to the same type as original.
1084  if (pReadAccess->HasPalette())
1085  {
1086  switch( pReadAccess->GetScanlineFormat() )
1087  {
1089  pScaleRangeFn = bScaleUp ? scaleUpPalette8bit
1090  : scaleDownPalette8bit;
1091  break;
1092  default:
1093  pScaleRangeFn = bScaleUp ? scaleUpPaletteGeneral
1094  : scaleDownPaletteGeneral;
1095  break;
1096  }
1097  }
1098  // Here we know that we are dealing with a non-palette source bitmap.
1099  // The target is either 24 or 32 bit, depending on the image and
1100  // the capabilities of the backend. If for some reason the destination
1101  // is not the same bit-depth as the source, then we can't use
1102  // a fast path, so we always need to process with a general scaler.
1103  else if (nSourceBitcount != nTargetBitcount)
1104  {
1105  pScaleRangeFn = bScaleUp ? scaleUpNonPaletteGeneral : scaleDownNonPaletteGeneral;
1106  }
1107  // If we get here then we can only use a fast path, but let's
1108  // still keep the fallback to the general scaler alive.
1109  else
1110  {
1111  switch( pReadAccess->GetScanlineFormat() )
1112  {
1115  pScaleRangeFn = bScaleUp ? scaleUp24bit : scaleDown24bit;
1116  break;
1121  pScaleRangeFn = bScaleUp ? scaleUp32bit : scaleDown32bit;
1122  break;
1123  default:
1124  pScaleRangeFn = bScaleUp ? scaleUpNonPaletteGeneral
1125  : scaleDownNonPaletteGeneral;
1126  break;
1127  }
1128  }
1129 
1130  // We want to thread - only if there is a lot of work to do:
1131  // We work hard when there is a large destination image, or
1132  // A large source image.
1133  bool bHorizontalWork = pReadAccess->Height() >= 512 && pReadAccess->Width() >= 512;
1134  bool bUseThreads = true;
1135 
1136  static bool bDisableThreadedScaling = getenv ("VCL_NO_THREAD_SCALE");
1137  if (bDisableThreadedScaling || !bHorizontalWork)
1138  {
1139  SAL_INFO("vcl.gdi", "Scale in main thread");
1140  bUseThreads = false;
1141  }
1142 
1143  if (bUseThreads)
1144  {
1145  try
1146  {
1147  // partition and queue work
1149  std::shared_ptr<comphelper::ThreadTaskTag> pTag = comphelper::ThreadPool::createThreadTaskTag();
1150 
1151  long nStripYStart = nStartY;
1152  long nStripYEnd = nStripYStart + constScaleThreadStrip - 1;
1153 
1154  while (nStripYEnd < nEndY)
1155  {
1156  std::unique_ptr<ScaleTask> pTask(new ScaleTask(pTag, pScaleRangeFn, aContext, nStripYStart, nStripYEnd));
1157  rShared.pushTask(std::move(pTask));
1158  nStripYStart += constScaleThreadStrip;
1159  nStripYEnd += constScaleThreadStrip;
1160  }
1161  if (nStripYStart <= nEndY)
1162  {
1163  std::unique_ptr<ScaleTask> pTask(new ScaleTask(pTag, pScaleRangeFn, aContext, nStripYStart, nEndY));
1164  rShared.pushTask(std::move(pTask));
1165  }
1166  rShared.waitUntilDone(pTag);
1167  SAL_INFO("vcl.gdi", "All threaded scaling tasks complete");
1168  }
1169  catch (...)
1170  {
1171  SAL_WARN("vcl.gdi", "threaded bitmap scaling failed");
1172  bUseThreads = false;
1173  }
1174  }
1175 
1176  if (!bUseThreads)
1177  pScaleRangeFn( aContext, nStartY, nEndY );
1178 
1179  bRet = true;
1180  aBitmap.AdaptBitCount(aOutBmp);
1181  aBitmap = aOutBmp;
1182  }
1183  }
1184 
1185  if (bRet)
1186  {
1187  tools::Rectangle aRect(Point(0, 0), Point(nDstW, nDstH));
1188  aBitmap.Crop(aRect);
1189  BitmapEx aRet(aBitmap);
1190  rCache.insert(std::make_pair(pKey, aRet));
1191  return aRet;
1192  }
1193 
1194  return BitmapEx();
1195 
1196 }
1197 
1198 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
long Width() const
sal_uInt8 GetRed() const
virtual ~BitmapScaleSuperFilter() override
long FRound(double fVal)
void waitUntilDone(const std::shared_ptr< ThreadTaskTag > &, bool bJoinAll=true)
long Height() const
virtual void doWork()=0
#define MAP_PRECISION
virtual BitmapEx execute(BitmapEx const &rBitmap) const override
Size GetSizePixel() const
long Width() const
#define MAP(name, prefix, token, type, context)
ImplSVGDIData maGDIData
Definition: svdata.hxx:348
o3tl::lru_map< SalBitmap *, BitmapEx > maScaleCache
Definition: svdata.hxx:184
sal_uInt8 GetBlue() const
static ThreadPool & getSharedOptimalPool()
Bitmap GetBitmap(const Color *pTransReplaceColor=nullptr) const
Definition: bitmapex.cxx:236
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:67
sal_uInt8 * Scanline
Definition: Scanline.hxx:25
bool HasPalette() const
void pushTask(std::unique_ptr< ThreadTask > pTask)
ScanlineFormat GetScanlineFormat() const
int i
list_const_iterator_t find(const Key &key)
const NodeContext & mrContext
sal_uInt8 GetGreen() const
long Height() const
unsigned char sal_uInt8
#define SAL_INFO(area, stream)
BitmapScaleSuperFilter(const double &rScaleX, const double &rScaleY)
static std::shared_ptr< ThreadTaskTag > createThreadTaskTag()
#define SAL_WARN(area, stream)
sal_uInt16 GetBitCount() const
std::enable_if< std::is_signed< T >::value||std::is_floating_point< T >::value, long >::type MinMax(T nVal, long nMin, long nMax)
const Size & GetSizePixel() const
Definition: bitmapex.hxx:83
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo