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 <comphelper/threadpool.hxx>
21
22 #include <tools/helpers.hxx>
23 #include <vcl/bitmapaccess.hxx>
24
25 #include <bitmapwriteaccess.hxx>
26 #include <BitmapScaleSuperFilter.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
lclMaxWeight()39 constexpr BilinearWeightType lclMaxWeight()
40 {
41 return BilinearWeightType(1) << MAP_PRECISION;
42 }
43
MAP(sal_uInt8 cVal0,sal_uInt8 cVal1,BilinearWeightType nFrac)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
ScaleContext__anon747b35800111::ScaleContext61 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
generateMap__anon747b35800111::ScaleContext80 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:
ScaleTask(const std::shared_ptr<comphelper::ThreadTaskTag> & pTag,ScaleRangeFn pScaleRangeFunction,ScaleContext & rContext,long nStartY,long nEndY)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
doWork()122 virtual void doWork() override
123 {
124 mpScaleRangeFunction(mrContext, mnStartY, mnEndY);
125 }
126 };
127
scaleUp32bit(ScaleContext & rCtx,long nStartY,long nEndY)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
scaleUpPalette8bit(ScaleContext & rCtx,long nStartY,long nEndY)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
scaleUpPaletteGeneral(ScaleContext & rCtx,long nStartY,long nEndY)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
scaleUp24bit(ScaleContext & rCtx,long nStartY,long nEndY)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
scaleUpNonPaletteGeneral(ScaleContext & rCtx,long nStartY,long nEndY)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
scaleDown32bit(ScaleContext & rCtx,long nStartY,long nEndY)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
scaleDownPalette8bit(ScaleContext & rCtx,long nStartY,long nEndY)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
scaleDownPaletteGeneral(ScaleContext & rCtx,long nStartY,long nEndY)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
scaleDown24bit(ScaleContext & rCtx,long nStartY,long nEndY)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
scaleDownNonPaletteGeneral(ScaleContext & rCtx,long nStartY,long nEndY)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
BitmapScaleSuperFilter(const double & rScaleX,const double & rScaleY)1008 BitmapScaleSuperFilter::BitmapScaleSuperFilter(const double& rScaleX, const double& rScaleY) :
1009 mrScaleX(rScaleX),
1010 mrScaleY(rScaleY)
1011 {}
1012
~BitmapScaleSuperFilter()1013 BitmapScaleSuperFilter::~BitmapScaleSuperFilter()
1014 {}
1015
execute(BitmapEx const & rBitmap) const1016 BitmapEx BitmapScaleSuperFilter::execute(BitmapEx const& rBitmap) const
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 {
1088 case ScanlineFormat::N8BitPal:
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 {
1113 case ScanlineFormat::N24BitTcBgr:
1114 case ScanlineFormat::N24BitTcRgb:
1115 pScaleRangeFn = bScaleUp ? scaleUp24bit : scaleDown24bit;
1116 break;
1117 case ScanlineFormat::N32BitTcRgba:
1118 case ScanlineFormat::N32BitTcBgra:
1119 case ScanlineFormat::N32BitTcArgb:
1120 case ScanlineFormat::N32BitTcAbgr:
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
1148 comphelper::ThreadPool &rShared = comphelper::ThreadPool::getSharedOptimalPool();
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: */
1199