45constexpr int MAP_PRECISION = 7;
47typedef sal_Int32 BilinearWeightType;
49constexpr BilinearWeightType lclMaxWeight()
51 return BilinearWeightType(1) << MAP_PRECISION;
56 return sal_uInt8(((BilinearWeightType(cVal0) << MAP_PRECISION) + nFrac * (BilinearWeightType(cVal1) - BilinearWeightType(cVal0))) >> MAP_PRECISION);
66 std::vector<sal_Int32> maMapIX;
67 std::vector<sal_Int32> maMapIY;
68 std::vector<BilinearWeightType> maMapFX;
69 std::vector<BilinearWeightType> maMapFY;
73 sal_Int32 nSrcW, sal_Int32 nDestW,
74 sal_Int32 nSrcH, sal_Int32 nDestH,
75 bool bHMirr,
bool bVMirr)
86 generateMap(nSrcW, nDestW, bHMirr, maMapIX, maMapFX);
87 generateMap(nSrcH, nDestH, bVMirr, maMapIY, maMapFY);
90 static void generateMap(sal_Int32 nSourceLength, sal_Int32 nDestinationLength,
bool bMirrored,
91 std::vector<sal_Int32> & rMapIX, std::vector<BilinearWeightType> & rMapFX)
93 const double fRevScale = (nDestinationLength > 1) ?
double(nSourceLength - 1) / (nDestinationLength - 1) : 0.0;
95 sal_Int32 nTemp = nSourceLength - 2;
96 sal_Int32 nTempX = nSourceLength - 1;
98 for (sal_Int32 i = 0;
i < nDestinationLength;
i++)
100 double fTemp =
i * fRevScale;
102 fTemp = nTempX - fTemp;
103 rMapIX[
i] =
MinMax(sal_Int32(fTemp), 0, nTemp);
104 rMapFX[
i] = BilinearWeightType((fTemp - rMapIX[i]) * (BilinearWeightType(1) << MAP_PRECISION));
109constexpr sal_Int32 constScaleThreadStrip = 32;
111typedef void (*ScaleRangeFn)(
const ScaleContext & rContext, sal_Int32 nStartY, sal_Int32 nEndY);
113template <
size_t nSize>
struct ScaleFunc
117 static inline void generateSumRows(
Scanline& pTmpX, std::array<int, nSize>& sumRows)
119 for (
int& n : sumRows)
120 n += (*pTmpX++) << MAP_PRECISION;
123 static inline void generateSumRows(BilinearWeightType
const nWeightX,
Scanline& pTmpX,
124 std::array<int, nSize>& sumRows)
126 for (
int& n : sumRows)
127 n += (nWeightX * (*pTmpX++));
130 static inline void generateSumRows(BilinearWeightType
const nTotalWeightX,
131 std::array<int, nSize>& sumRows)
133 for (
int& n : sumRows)
137 static inline void generateSumNumbers(BilinearWeightType
const nWeightY,
138 std::array<int, nSize>& sumRows,
139 std::array<int, nSize>& sumNumbers)
141 std::transform(sumRows.begin(), sumRows.end(), sumNumbers.begin(), sumNumbers.begin(),
142 [nWeightY](
int n1,
int n2) { return nWeightY * n1 + n2; });
145 static inline void generateSumNumbers(BilinearWeightType
const nTotalWeightY,
146 std::array<int, nSize>& sumNumbers)
148 for (
int& n : sumNumbers)
152 static inline void calculateDestination(
Scanline& pScanDest, std::array<int, nSize>& sumNumbers)
154 pScanDest = std::copy(sumNumbers.begin(), sumNumbers.end(), pScanDest);
159 static inline void generateComponent(
Scanline pColorPtr0,
Scanline pColorPtr1,
160 BilinearWeightType
const nTempFX,
161 std::array<sal_uInt8, nSize>& nComponents)
163 for (
sal_uInt8& rComponent : nComponents)
164 rComponent =
MAP(*pColorPtr0++, *pColorPtr1++, nTempFX);
167 static inline void calculateDestination(
Scanline& pScanDest, BilinearWeightType
const nTempFY,
168 const std::array<sal_uInt8, nSize>& nComponents1,
169 const std::array<sal_uInt8, nSize>& nComponents2)
171 pScanDest = std::transform(
172 nComponents1.begin(), nComponents1.end(), nComponents2.begin(), pScanDest,
177template <
int nColorBits>
178void scaleDown (
const ScaleContext &rCtx, sal_Int32 nStartY, sal_Int32 nEndY)
181 constexpr int nColorComponents = nColorBits / 8;
182 static_assert(nColorComponents * 8 == nColorBits,
"nColorBits must be divisible by 8");
183 using ScaleFunction = ScaleFunc<nColorComponents>;
184 const sal_Int32 nStartX = 0;
185 const sal_Int32 nEndX = rCtx.mnDestW - 1;
187 for (sal_Int32 nY = nStartY; nY <= nEndY; nY++)
189 sal_Int32 nTop = rCtx.mbVMirr ? (nY + 1) : nY;
190 sal_Int32 nBottom = rCtx.mbVMirr ? nY : (nY + 1);
192 sal_Int32 nLineStart;
193 sal_Int32 nLineRange;
196 nLineStart = rCtx.maMapIY[nY];
201 nLineStart = rCtx.maMapIY[nTop];
202 nLineRange = (rCtx.maMapIY[nBottom] == rCtx.maMapIY[nTop]) ?
203 1 : (rCtx.maMapIY[nBottom] - rCtx.maMapIY[nTop]);
206 Scanline pScanDest = rCtx.mpDest->GetScanline(nY);
207 for (sal_Int32 nX = nStartX; nX <= nEndX; nX++)
209 sal_Int32 nLeft = rCtx.mbHMirr ? (nX + 1) : nX;
210 sal_Int32 nRight = rCtx.mbHMirr ? nX : (nX + 1);
216 nRowStart = rCtx.maMapIX[nX];
221 nRowStart = rCtx.maMapIX[nLeft];
222 nRowRange = (rCtx.maMapIX[nRight] == rCtx.maMapIX[nLeft]) ?
223 1 : (rCtx.maMapIX[nRight] - rCtx.maMapIX[nLeft]);
226 std::array<int, nColorComponents> sumNumbers{};
227 BilinearWeightType nTotalWeightY = 0;
229 for (sal_Int32 i = 0;
i<= nLineRange;
i++)
231 Scanline pTmpY = rCtx.mpSrc->GetScanline(nLineStart + i);
232 Scanline pTmpX = pTmpY + nColorComponents * nRowStart;
234 std::array<int, nColorComponents> sumRows{};
235 BilinearWeightType nTotalWeightX = 0;
237 for (sal_Int32 j = 0; j <= nRowRange; j++)
241 ScaleFunction::generateSumRows(pTmpX, sumRows);
242 nTotalWeightX += lclMaxWeight();
246 BilinearWeightType nWeightX = lclMaxWeight() - rCtx.maMapFX[nLeft];
247 ScaleFunction::generateSumRows(nWeightX, pTmpX, sumRows);
248 nTotalWeightX += nWeightX;
250 else if ( nRowRange == j )
252 BilinearWeightType nWeightX = rCtx.maMapFX[ nRight ] ;
253 ScaleFunction::generateSumRows(nWeightX, pTmpX, sumRows);
254 nTotalWeightX += nWeightX;
258 ScaleFunction::generateSumRows(pTmpX, sumRows);
259 nTotalWeightX += lclMaxWeight();
263 BilinearWeightType nWeightY = lclMaxWeight();
265 nWeightY = lclMaxWeight();
267 nWeightY = lclMaxWeight() - rCtx.maMapFY[nTop];
268 else if (nLineRange == 1)
269 nWeightY = rCtx.maMapFY[nTop];
270 else if (nLineRange == i)
271 nWeightY = rCtx.maMapFY[nBottom];
275 ScaleFunction::generateSumRows(nTotalWeightX, sumRows);
277 ScaleFunction::generateSumNumbers(nWeightY, sumRows, sumNumbers);
278 nTotalWeightY += nWeightY;
284 ScaleFunction::generateSumNumbers(nTotalWeightY, sumNumbers);
288 ScaleFunction::calculateDestination(pScanDest, sumNumbers);
293template <
int nColorBits>
294void scaleUp(
const ScaleContext &rCtx, sal_Int32 nStartY, sal_Int32 nEndY)
297 constexpr int nColorComponents = nColorBits / 8;
298 static_assert(nColorComponents * 8 == nColorBits,
"nColorBits must be divisible by 8");
299 using ScaleFunction = ScaleFunc<nColorComponents>;
300 const sal_Int32 nStartX = 0;
301 const sal_Int32 nEndX = rCtx.mnDestW - 1;
303 for (sal_Int32 nY = nStartY; nY <= nEndY; nY++)
305 sal_Int32 nTempY = rCtx.maMapIY[nY];
306 BilinearWeightType nTempFY = rCtx.maMapFY[nY];
308 Scanline pLine0 = rCtx.mpSrc->GetScanline(nTempY+0);
309 Scanline pLine1 = rCtx.mpSrc->GetScanline(nTempY+1);
310 Scanline pScanDest = rCtx.mpDest->GetScanline(nY);
312 std::array<sal_uInt8, nColorComponents> nComponents1;
313 std::array<sal_uInt8, nColorComponents> nComponents2;
318 for (sal_Int32 nX = nStartX; nX <= nEndX; nX++)
320 sal_Int32 nTempX = rCtx.maMapIX[nX];
321 BilinearWeightType nTempFX = rCtx.maMapFX[nX];
323 pColorPtr0 = pLine0 + nTempX * nColorComponents;
324 pColorPtr1 = pColorPtr0 + nColorComponents;
326 ScaleFunction::generateComponent(pColorPtr0, pColorPtr1, nTempFX, nComponents1);
328 pColorPtr0 = pLine1 + nTempX * nColorComponents;
329 pColorPtr1 = pColorPtr0 + nColorComponents;
331 ScaleFunction::generateComponent(pColorPtr0, pColorPtr1, nTempFX, nComponents2);
332 ScaleFunction::calculateDestination(pScanDest, nTempFY, nComponents1, nComponents2);
339 ScaleRangeFn mpScaleRangeFunction;
345 explicit ScaleTask(
const std::shared_ptr<comphelper::ThreadTaskTag>& pTag,
346 ScaleRangeFn pScaleRangeFunction,
347 const ScaleContext& rContext,
348 sal_Int32 nStartY, sal_Int32 nEndY)
350 , mpScaleRangeFunction(pScaleRangeFunction)
356 virtual void doWork()
override
358 mpScaleRangeFunction(mrContext, mnStartY, mnEndY);
362void scaleUpPalette8bit(
const ScaleContext &rCtx, sal_Int32 nStartY, sal_Int32 nEndY)
364 const sal_Int32 nStartX = 0, nEndX = rCtx.mnDestW - 1;
366 for( sal_Int32 nY = nStartY; nY <= nEndY; nY++ )
368 sal_Int32 nTempY = rCtx.maMapIY[ nY ];
369 BilinearWeightType nTempFY = rCtx.maMapFY[ nY ];
370 Scanline pLine0 = rCtx.mpSrc->GetScanline( nTempY );
371 Scanline pLine1 = rCtx.mpSrc->GetScanline( ++nTempY );
372 Scanline pScanDest = rCtx.mpDest->GetScanline( nY );
374 for(sal_Int32 nX = nStartX, nXDst = 0; nX <= nEndX; nX++ )
376 sal_Int32 nTempX = rCtx.maMapIX[ nX ];
377 BilinearWeightType nTempFX = rCtx.maMapFX[ nX ];
379 const BitmapColor& rCol0 = rCtx.mpSrc->GetPaletteColor( pLine0[ nTempX ] );
380 const BitmapColor& rCol2 = rCtx.mpSrc->GetPaletteColor( pLine1[ nTempX ] );
381 const BitmapColor& rCol1 = rCtx.mpSrc->GetPaletteColor( pLine0[ ++nTempX ] );
382 const BitmapColor& rCol3 = rCtx.mpSrc->GetPaletteColor( pLine1[ nTempX ] );
393 MAP( cG0, cG1, nTempFY ),
394 MAP( cB0, cB1, nTempFY ) );
395 rCtx.mpDest->SetPixelOnData( pScanDest, nXDst++, aColRes );
400void scaleUpPaletteGeneral(
const ScaleContext &rCtx, sal_Int32 nStartY, sal_Int32 nEndY)
402 const sal_Int32 nStartX = 0, nEndX = rCtx.mnDestW - 1;
404 for( sal_Int32 nY = nStartY; nY <= nEndY; nY++ )
406 sal_Int32 nTempY = rCtx.maMapIY[ nY ];
407 BilinearWeightType nTempFY = rCtx.maMapFY[ nY ];
408 Scanline pScanline = rCtx.mpDest->GetScanline( nY );
410 for( sal_Int32 nX = nStartX, nXDst = 0; nX <= nEndX; nX++ )
412 sal_Int32 nTempX = rCtx.maMapIX[ nX ];
413 BilinearWeightType nTempFX = rCtx.maMapFX[ nX ];
415 BitmapColor aCol0 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( nTempY, nTempX ) );
416 BitmapColor aCol1 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( nTempY, ++nTempX ) );
421 aCol1 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( ++nTempY, nTempX ) );
422 aCol0 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( nTempY--, --nTempX ) );
428 MAP( cG0, cG1, nTempFY ),
429 MAP( cB0, cB1, nTempFY ) );
430 rCtx.mpDest->SetPixelOnData( pScanline, nXDst++, aColRes );
435void scaleUpNonPaletteGeneral(
const ScaleContext &rCtx, sal_Int32 nStartY, sal_Int32 nEndY)
437 const sal_Int32 nStartX = 0, nEndX = rCtx.mnDestW - 1;
439 for( sal_Int32 nY = nStartY; nY <= nEndY; nY++ )
441 sal_Int32 nTempY = rCtx.maMapIY[ nY ];
442 BilinearWeightType nTempFY = rCtx.maMapFY[ nY ];
443 Scanline pScanDest = rCtx.mpDest->GetScanline( nY );
445 for( sal_Int32 nX = nStartX, nXDst = 0; nX <= nEndX; nX++ )
447 sal_Int32 nTempX = rCtx.maMapIX[ nX ];
448 BilinearWeightType nTempFX = rCtx.maMapFX[ nX ];
450 BitmapColor aCol0 = rCtx.mpSrc->GetPixel( nTempY, nTempX );
451 BitmapColor aCol1 = rCtx.mpSrc->GetPixel( nTempY, ++nTempX );
456 aCol1 = rCtx.mpSrc->GetPixel( ++nTempY, nTempX );
457 aCol0 = rCtx.mpSrc->GetPixel( nTempY--, --nTempX );
463 MAP( cG0, cG1, nTempFY ),
464 MAP( cB0, cB1, nTempFY ) );
465 rCtx.mpDest->SetPixelOnData( pScanDest, nXDst++, aColRes );
470void scaleDownPalette8bit(
const ScaleContext &rCtx, sal_Int32 nStartY, sal_Int32 nEndY)
472 const sal_Int32 nStartX = 0, nEndX = rCtx.mnDestW - 1;
474 for( sal_Int32 nY = nStartY; nY <= nEndY; nY++ )
476 sal_Int32 nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
477 sal_Int32 nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
479 sal_Int32 nLineStart, nLineRange;
482 nLineStart = rCtx.maMapIY[ nY ];
487 nLineStart = rCtx.maMapIY[ nTop ] ;
488 nLineRange = ( rCtx.maMapIY[ nBottom ] == rCtx.maMapIY[ nTop ] ) ? 1 :( rCtx.maMapIY[ nBottom ] - rCtx.maMapIY[ nTop ] );
491 Scanline pScanDest = rCtx.mpDest->GetScanline( nY );
492 for( sal_Int32 nX = nStartX , nXDst = 0; nX <= nEndX; nX++ )
494 sal_Int32 nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
495 sal_Int32 nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
501 nRowStart = rCtx.maMapIX[ nX ];
506 nRowStart = rCtx.maMapIX[ nLeft ];
507 nRowRange = ( rCtx.maMapIX[ nRight ] == rCtx.maMapIX[ nLeft ] )? 1 : ( rCtx.maMapIX[ nRight ] - rCtx.maMapIX[ nLeft ] );
513 BilinearWeightType nTotalWeightY = 0;
515 for(sal_Int32 i = 0;
i<= nLineRange;
i++)
517 Scanline pTmpY = rCtx.mpSrc->GetScanline( nLineStart + i );
521 BilinearWeightType nTotalWeightX = 0;
523 for(sal_Int32 j = 0; j <= nRowRange; j++)
525 const BitmapColor& rCol = rCtx.mpSrc->GetPaletteColor( pTmpY[ nRowStart + j ] );
529 nSumRowB += rCol.
GetBlue() << MAP_PRECISION;
530 nSumRowG += rCol.
GetGreen() << MAP_PRECISION;
531 nSumRowR += rCol.
GetRed() << MAP_PRECISION;
532 nTotalWeightX += lclMaxWeight();
536 BilinearWeightType nWeightX = lclMaxWeight() - rCtx.maMapFX[ nLeft ];
537 nSumRowB += ( nWeightX *rCol.
GetBlue()) ;
538 nSumRowG += ( nWeightX *rCol.
GetGreen()) ;
539 nSumRowR += ( nWeightX *rCol.
GetRed()) ;
540 nTotalWeightX += nWeightX;
542 else if ( nRowRange == j )
544 BilinearWeightType nWeightX = rCtx.maMapFX[ nRight ] ;
545 nSumRowB += ( nWeightX *rCol.
GetBlue() );
546 nSumRowG += ( nWeightX *rCol.
GetGreen() );
547 nSumRowR += ( nWeightX *rCol.
GetRed() );
548 nTotalWeightX += nWeightX;
552 nSumRowB += rCol.
GetBlue() << MAP_PRECISION;
553 nSumRowG += rCol.
GetGreen() << MAP_PRECISION;
554 nSumRowR += rCol.
GetRed() << MAP_PRECISION;
555 nTotalWeightX += lclMaxWeight();
559 BilinearWeightType nWeightY = lclMaxWeight();
561 nWeightY = lclMaxWeight();
563 nWeightY = lclMaxWeight() - rCtx.maMapFY[ nTop ];
564 else if( nLineRange == 1 )
565 nWeightY = rCtx.maMapFY[ nTop ];
566 else if ( nLineRange == i )
567 nWeightY = rCtx.maMapFY[ nBottom ];
571 nSumRowB /= nTotalWeightX;
572 nSumRowG /= nTotalWeightX;
573 nSumRowR /= nTotalWeightX;
576 nSumB += nWeightY * nSumRowB;
577 nSumG += nWeightY * nSumRowG;
578 nSumR += nWeightY * nSumRowR;
579 nTotalWeightY += nWeightY;
584 nSumR /= nTotalWeightY;
585 nSumG /= nTotalWeightY;
586 nSumB /= nTotalWeightY;
590 rCtx.mpDest->SetPixelOnData( pScanDest, nXDst++, aColRes );
595void scaleDownPaletteGeneral(
const ScaleContext &rCtx, sal_Int32 nStartY, sal_Int32 nEndY)
597 const sal_Int32 nStartX = 0, nEndX = rCtx.mnDestW - 1;
599 for( sal_Int32 nY = nStartY; nY <= nEndY; nY++ )
601 sal_Int32 nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
602 sal_Int32 nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
604 sal_Int32 nLineStart, nLineRange;
607 nLineStart = rCtx.maMapIY[ nY ];
612 nLineStart = rCtx.maMapIY[ nTop ] ;
613 nLineRange = ( rCtx.maMapIY[ nBottom ] == rCtx.maMapIY[ nTop ] ) ? 1 :( rCtx.maMapIY[ nBottom ] - rCtx.maMapIY[ nTop ] );
616 Scanline pScanDest = rCtx.mpDest->GetScanline( nY );
617 for( sal_Int32 nX = nStartX , nXDst = 0; nX <= nEndX; nX++ )
619 sal_Int32 nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
620 sal_Int32 nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
622 sal_Int32 nRowStart, nRowRange;
625 nRowStart = rCtx.maMapIX[ nX ];
630 nRowStart = rCtx.maMapIX[ nLeft ];
631 nRowRange = ( rCtx.maMapIX[ nRight ] == rCtx.maMapIX[ nLeft ] )? 1 : ( rCtx.maMapIX[ nRight ] - rCtx.maMapIX[ nLeft ] );
637 BilinearWeightType nTotalWeightY = 0;
639 for(sal_Int32 i = 0;
i<= nLineRange;
i++)
644 BilinearWeightType nTotalWeightX = 0;
646 Scanline pScanlineSrc = rCtx.mpSrc->GetScanline( nLineStart + i );
647 for(sal_Int32 j = 0; j <= nRowRange; j++)
649 BitmapColor aCol0 = rCtx.mpSrc->GetPaletteColor ( rCtx.mpSrc->GetIndexFromData( pScanlineSrc, nRowStart + j ) );
654 nSumRowB += aCol0.
GetBlue() << MAP_PRECISION;
655 nSumRowG += aCol0.
GetGreen() << MAP_PRECISION;
656 nSumRowR += aCol0.
GetRed() << MAP_PRECISION;
657 nTotalWeightX += lclMaxWeight();
662 BilinearWeightType nWeightX = lclMaxWeight() - rCtx.maMapFX[ nLeft ];
663 nSumRowB += ( nWeightX *aCol0.
GetBlue()) ;
664 nSumRowG += ( nWeightX *aCol0.
GetGreen()) ;
665 nSumRowR += ( nWeightX *aCol0.
GetRed()) ;
666 nTotalWeightX += nWeightX;
668 else if ( nRowRange == j )
671 BilinearWeightType nWeightX = rCtx.maMapFX[ nRight ] ;
672 nSumRowB += ( nWeightX *aCol0.
GetBlue() );
673 nSumRowG += ( nWeightX *aCol0.
GetGreen() );
674 nSumRowR += ( nWeightX *aCol0.
GetRed() );
675 nTotalWeightX += nWeightX;
680 nSumRowB += aCol0.
GetBlue() << MAP_PRECISION;
681 nSumRowG += aCol0.
GetGreen() << MAP_PRECISION;
682 nSumRowR += aCol0.
GetRed() << MAP_PRECISION;
683 nTotalWeightX += lclMaxWeight();
687 sal_Int32 nWeightY = lclMaxWeight();
689 nWeightY = lclMaxWeight();
691 nWeightY = lclMaxWeight() - rCtx.maMapFY[ nTop ];
692 else if( nLineRange == 1 )
693 nWeightY = rCtx.maMapFY[ nTop ];
694 else if ( nLineRange == i )
695 nWeightY = rCtx.maMapFY[ nBottom ];
699 nSumRowB /= nTotalWeightX;
700 nSumRowG /= nTotalWeightX;
701 nSumRowR /= nTotalWeightX;
704 nSumB += nWeightY * nSumRowB;
705 nSumG += nWeightY * nSumRowG;
706 nSumR += nWeightY * nSumRowR;
707 nTotalWeightY += nWeightY;
712 nSumR /= nTotalWeightY;
713 nSumG /= nTotalWeightY;
714 nSumB /= nTotalWeightY;
718 rCtx.mpDest->SetPixelOnData( pScanDest, nXDst++, aColRes );
723void scaleDownNonPaletteGeneral(
const ScaleContext &rCtx, sal_Int32 nStartY, sal_Int32 nEndY)
725 const sal_Int32 nStartX = 0, nEndX = rCtx.mnDestW - 1;
727 for( sal_Int32 nY = nStartY; nY <= nEndY; nY++ )
729 sal_Int32 nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
730 sal_Int32 nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
732 sal_Int32 nLineStart, nLineRange;
735 nLineStart = rCtx.maMapIY[ nY ];
740 nLineStart = rCtx.maMapIY[ nTop ] ;
741 nLineRange = ( rCtx.maMapIY[ nBottom ] == rCtx.maMapIY[ nTop ] ) ? 1 :( rCtx.maMapIY[ nBottom ] - rCtx.maMapIY[ nTop ] );
744 Scanline pScanDest = rCtx.mpDest->GetScanline( nY );
745 for( sal_Int32 nX = nStartX , nXDst = 0; nX <= nEndX; nX++ )
747 sal_Int32 nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
748 sal_Int32 nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
750 sal_Int32 nRowStart, nRowRange;
753 nRowStart = rCtx.maMapIX[ nX ];
758 nRowStart = rCtx.maMapIX[ nLeft ];
759 nRowRange = ( rCtx.maMapIX[ nRight ] == rCtx.maMapIX[ nLeft ] )? 1 : ( rCtx.maMapIX[ nRight ] - rCtx.maMapIX[ nLeft ] );
765 BilinearWeightType nTotalWeightY = 0;
767 for(sal_Int32 i = 0;
i<= nLineRange;
i++)
772 BilinearWeightType nTotalWeightX = 0;
774 Scanline pScanlineSrc = rCtx.mpSrc->GetScanline( nLineStart + i );
775 for(sal_Int32 j = 0; j <= nRowRange; j++)
777 BitmapColor aCol0 = rCtx.mpSrc->GetPixelFromData( pScanlineSrc, nRowStart + j );
782 nSumRowB += aCol0.
GetBlue() << MAP_PRECISION;
783 nSumRowG += aCol0.
GetGreen() << MAP_PRECISION;
784 nSumRowR += aCol0.
GetRed() << MAP_PRECISION;
785 nTotalWeightX += lclMaxWeight();
790 BilinearWeightType nWeightX = lclMaxWeight() - rCtx.maMapFX[ nLeft ];
791 nSumRowB += ( nWeightX *aCol0.
GetBlue()) ;
792 nSumRowG += ( nWeightX *aCol0.
GetGreen()) ;
793 nSumRowR += ( nWeightX *aCol0.
GetRed()) ;
794 nTotalWeightX += nWeightX;
796 else if ( nRowRange == j )
799 BilinearWeightType nWeightX = rCtx.maMapFX[ nRight ] ;
800 nSumRowB += ( nWeightX *aCol0.
GetBlue() );
801 nSumRowG += ( nWeightX *aCol0.
GetGreen() );
802 nSumRowR += ( nWeightX *aCol0.
GetRed() );
803 nTotalWeightX += nWeightX;
807 nSumRowB += aCol0.
GetBlue() << MAP_PRECISION;
808 nSumRowG += aCol0.
GetGreen() << MAP_PRECISION;
809 nSumRowR += aCol0.
GetRed() << MAP_PRECISION;
810 nTotalWeightX += lclMaxWeight();
814 BilinearWeightType nWeightY = lclMaxWeight();
816 nWeightY = lclMaxWeight();
818 nWeightY = lclMaxWeight() - rCtx.maMapFY[ nTop ];
819 else if( nLineRange == 1 )
820 nWeightY = rCtx.maMapFY[ nTop ];
821 else if ( nLineRange == i )
822 nWeightY = rCtx.maMapFY[ nBottom ];
826 nSumRowB /= nTotalWeightX;
827 nSumRowG /= nTotalWeightX;
828 nSumRowR /= nTotalWeightX;
831 nSumB += nWeightY * nSumRowB;
832 nSumG += nWeightY * nSumRowG;
833 nSumR += nWeightY * nSumRowR;
834 nTotalWeightY += nWeightY;
839 nSumR /= nTotalWeightY;
840 nSumG /= nTotalWeightY;
841 nSumB /= nTotalWeightY;
845 rCtx.mpDest->SetPixelOnData( pScanDest, nXDst++, aColRes );
870 double fScaleX = std::fabs(
mrScaleX);
871 double fScaleY = std::fabs(
mrScaleY);
873 const sal_Int32 nDstW =
FRound(aSizePix.
Width() * fScaleX);
874 const sal_Int32 nDstH =
FRound(aSizePix.
Height() * fScaleY);
876 constexpr double fScaleThresh = 0.6;
878 if (nDstW <= 1 || nDstH <= 1)
887 auto aFind = rCache.
find(aKey);
888 if (aFind != rCache.end())
890 if (aFind->second.GetSizePixel().Width() == nDstW && aFind->second.GetSizePixel().Height() == nDstH)
891 return aFind->second;
893 SAL_WARN(
"vcl.gdi",
"Error: size mismatch in scale cache");
901 auto ePixelFormat = eSourcePixelFormat;
902 if (sal_uInt16(eSourcePixelFormat) < 24)
905 Bitmap aOutBmp(
Size(nDstW, nDstH), ePixelFormat);
911 SAL_WARN(
"vcl.gdi",
"bmp creation failed");
917 const sal_Int32 nEndY = nDstH - 1;
919 if (pReadAccess && pWriteAccess)
921 ScaleRangeFn pScaleRangeFn;
922 const ScaleContext aContext( pReadAccess.
get(),
924 pReadAccess->
Width(),
925 pWriteAccess->Width(),
927 pWriteAccess->Height(),
930 bool bScaleUp = fScaleX >= fScaleThresh && fScaleY >= fScaleThresh;
939 pScaleRangeFn = bScaleUp ? scaleUpPalette8bit
940 : scaleDownPalette8bit;
943 pScaleRangeFn = bScaleUp ? scaleUpPaletteGeneral
944 : scaleDownPaletteGeneral;
953 else if (eSourcePixelFormat != eTargetPixelFormat)
955 pScaleRangeFn = bScaleUp ? scaleUpNonPaletteGeneral : scaleDownNonPaletteGeneral;
965 pScaleRangeFn = bScaleUp ? scaleUp<24> : scaleDown<24>;
971 pScaleRangeFn = bScaleUp ? scaleUp<32> : scaleDown<32>;
974 pScaleRangeFn = bScaleUp ? scaleUpNonPaletteGeneral
975 : scaleDownNonPaletteGeneral;
983 bool bHorizontalWork = pReadAccess->
Height() >= 512 && pReadAccess->
Width() >= 512;
984 bool bUseThreads =
true;
985 const sal_Int32 nStartY = 0;
987 static bool bDisableThreadedScaling = getenv (
"VCL_NO_THREAD_SCALE");
988 if (bDisableThreadedScaling || !bHorizontalWork)
990 SAL_INFO(
"vcl.gdi",
"Scale in main thread");
1002 vcl::bitmap::generateStripRanges<constScaleThreadStrip>(nStartY, nEndY,
1003 [&] (sal_Int32
const nStart, sal_Int32
const nEnd,
bool const bLast)
1007 auto pTask(std::make_unique<ScaleTask>(pTag, pScaleRangeFn, aContext, nStart, nEnd));
1008 rShared.
pushTask(std::move(pTask));
1011 pScaleRangeFn(aContext, nStart, nEnd);
1014 SAL_INFO(
"vcl.gdi",
"All threaded scaling tasks complete");
1018 SAL_WARN(
"vcl.gdi",
"threaded bitmap scaling failed");
1019 bUseThreads =
false;
1024 pScaleRangeFn( aContext, nStartY, nEndY );
1026 pWriteAccess.
reset();
1036 aBitmap.
Crop(aRect);
1038 rCache.insert(std::make_pair(aKey, aRet));
const NodeContext & mrContext
Bitmap GetBitmap(Color aTransparentReplaceColor) const
const Size & GetSizePixel() const
tools::Long Height() const
tools::Long Width() const
ScanlineFormat GetScanlineFormat() const
virtual BitmapEx execute(BitmapEx const &rBitmap) const override
BitmapScaleSuperFilter(const double &rScaleX, const double &rScaleY)
virtual ~BitmapScaleSuperFilter() override
const std::shared_ptr< SalBitmap > & ImplGetSalBitmap() const
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
Size GetSizePixel() const
void AdaptBitCount(Bitmap &rNew) const
vcl::PixelFormat getPixelFormat() const
sal_uInt8 GetBlue() const
sal_uInt8 GetGreen() const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
static ThreadPool & getSharedOptimalPool()
void waitUntilDone(const std::shared_ptr< ThreadTaskTag > &, bool bJoin=true)
static std::shared_ptr< ThreadTaskTag > createThreadTaskTag()
void pushTask(std::unique_ptr< ThreadTask > pTask)
list_const_iterator_t find(const Key &key)
tools::Long FRound(double fVal)
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)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
lru_scale_cache maScaleCache
Cache multiple scalings for the same bitmap.
ImplSVData * ImplGetSVData()
#define MAP(name, prefix, token, type, context)