build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / bitmap / bitmapscalesuper.cxx
blobdc7dcd56cbc2f209e9b0f96a7d0c82b84eb8e886
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <vcl/bitmapaccess.hxx>
21 #include <bitmapscalesuper.hxx>
23 #include <algorithm>
24 #include <memory>
25 #include <comphelper/threadpool.hxx>
27 namespace {
29 #define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<7)+nFrac*((long)(cVal1)-(cVal0)))>>7))
31 void generateMap(long nW, long nDstW, bool bHMirr, long* pMapIX, long* pMapFX)
33 const double fRevScaleX = (nDstW > 1) ? (double) (nW - 1) / (nDstW - 1) : 0.0;
35 long nTemp = nW - 2;
36 long nTempX = nW - 1;
37 for (long nX = 0; nX < nDstW; nX++)
39 double fTemp = nX * fRevScaleX;
40 if (bHMirr)
41 fTemp = nTempX - fTemp;
42 pMapIX[nX] = MinMax((long) fTemp, 0, nTemp);
43 pMapFX[nX] = (long) ((fTemp - pMapIX[nX]) * 128.0);
47 struct ScaleContext {
48 BitmapReadAccess *mpSrc;
49 BitmapWriteAccess *mpDest;
50 long mnSrcW, mnDestW;
51 long mnSrcH, mnDestH;
52 bool mbHMirr, mbVMirr;
53 std::unique_ptr<long[]> mpMapIX;
54 std::unique_ptr<long[]> mpMapIY;
55 std::unique_ptr<long[]> mpMapFX;
56 std::unique_ptr<long[]> mpMapFY;
57 ScaleContext( BitmapReadAccess *pSrc,
58 BitmapWriteAccess *pDest,
59 long nSrcW, long nDestW,
60 long nSrcH, long nDestH,
61 bool bHMirr, bool bVMirr)
62 : mpSrc( pSrc ), mpDest( pDest )
63 , mnSrcW( nSrcW ), mnDestW( nDestW )
64 , mnSrcH( nSrcH ), mnDestH( nDestH )
65 , mbHMirr( bHMirr ), mbVMirr( bVMirr )
66 , mpMapIX( new long[ nDestW ] )
67 , mpMapIY( new long[ nDestH ] )
68 , mpMapFX( new long[ nDestW ] )
69 , mpMapFY( new long[ nDestH ] )
71 generateMap(nSrcW, nDestW, bHMirr, mpMapIX.get(), mpMapFX.get());
72 generateMap(nSrcH, nDestH, bVMirr, mpMapIY.get(), mpMapFY.get());
76 #define SCALE_THREAD_STRIP 32
77 struct ScaleRangeContext {
78 ScaleContext *mrCtx;
79 long mnStartY, mnEndY;
80 ScaleRangeContext( ScaleContext *rCtx, long nStartY )
81 : mrCtx( rCtx ), mnStartY( nStartY ),
82 mnEndY( nStartY + SCALE_THREAD_STRIP ) {}
85 typedef void (*ScaleRangeFn)(ScaleContext &rCtx, long nStartY, long nEndY);
87 class ScaleTask : public comphelper::ThreadTask
89 ScaleRangeFn mpFn;
90 std::vector< ScaleRangeContext > maStrips;
91 public:
92 explicit ScaleTask( const std::shared_ptr<comphelper::ThreadTaskTag>& pTag, ScaleRangeFn pFn )
93 : comphelper::ThreadTask(pTag), mpFn( pFn ) {}
94 void push( ScaleRangeContext &aRC ) { maStrips.push_back( aRC ); }
95 virtual void doWork() override
97 std::vector< ScaleRangeContext >::iterator it;
98 for (it = maStrips.begin(); it != maStrips.end(); ++it)
99 mpFn( *(it->mrCtx), it->mnStartY, it->mnEndY );
103 void scalePallete8bit(ScaleContext &rCtx, long nStartY, long nEndY)
105 const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
107 for( long nY = nStartY; nY <= nEndY; nY++ )
109 long nTempY = rCtx.mpMapIY[ nY ];
110 long nTempFY = rCtx.mpMapFY[ nY ];
111 Scanline pLine0 = rCtx.mpSrc->GetScanline( nTempY );
112 Scanline pLine1 = rCtx.mpSrc->GetScanline( ++nTempY );
114 for(long nX = nStartX, nXDst = 0; nX <= nEndX; nX++ )
116 long nTempX = rCtx.mpMapIX[ nX ];
117 long nTempFX = rCtx.mpMapFX[ nX ];
119 const BitmapColor& rCol0 = rCtx.mpSrc->GetPaletteColor( pLine0[ nTempX ] );
120 const BitmapColor& rCol2 = rCtx.mpSrc->GetPaletteColor( pLine1[ nTempX ] );
121 const BitmapColor& rCol1 = rCtx.mpSrc->GetPaletteColor( pLine0[ ++nTempX ] );
122 const BitmapColor& rCol3 = rCtx.mpSrc->GetPaletteColor( pLine1[ nTempX ] );
124 sal_uInt8 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTempFX );
125 sal_uInt8 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTempFX );
126 sal_uInt8 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTempFX );
128 sal_uInt8 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTempFX );
129 sal_uInt8 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTempFX );
130 sal_uInt8 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTempFX );
132 BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
133 MAP( cG0, cG1, nTempFY ),
134 MAP( cB0, cB1, nTempFY ) );
135 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
140 void scalePalleteGeneral(ScaleContext &rCtx, long nStartY, long nEndY)
142 const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
144 for( long nY = nStartY; nY <= nEndY; nY++ )
146 long nTempY = rCtx.mpMapIY[ nY ];
147 long nTempFY = rCtx.mpMapFY[ nY ];
149 for( long nX = nStartX, nXDst = 0; nX <= nEndX; nX++ )
151 long nTempX = rCtx.mpMapIX[ nX ];
152 long nTempFX = rCtx.mpMapFX[ nX ];
154 BitmapColor aCol0 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( nTempY, nTempX ) );
155 BitmapColor aCol1 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( nTempY, ++nTempX ) );
156 sal_uInt8 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
157 sal_uInt8 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
158 sal_uInt8 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
160 aCol1 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( ++nTempY, nTempX ) );
161 aCol0 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( nTempY--, --nTempX ) );
162 sal_uInt8 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
163 sal_uInt8 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
164 sal_uInt8 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
166 BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
167 MAP( cG0, cG1, nTempFY ),
168 MAP( cB0, cB1, nTempFY ) );
169 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
174 void scale24bitBGR(ScaleContext &rCtx, long nStartY, long nEndY)
176 const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
178 for( long nY = nStartY; nY <= nEndY; nY++ )
180 long nTempY = rCtx.mpMapIY[ nY ];
181 long nTempFY = rCtx.mpMapFY[ nY ];
182 Scanline pLine0 = rCtx.mpSrc->GetScanline( nTempY );
183 Scanline pLine1 = rCtx.mpSrc->GetScanline( ++nTempY );
185 for( long nX = nStartX, nXDst = 0; nX <= nEndX; nX++ )
187 long nOff = 3 * rCtx.mpMapIX[ nX ];
188 long nTempFX = rCtx.mpMapFX[ nX ];
190 Scanline pTmp0 = pLine0 + nOff ;
191 Scanline pTmp1 = pTmp0 + 3;
192 sal_uInt8 cB0 = MAP( *pTmp0, *pTmp1, nTempFX );
193 pTmp0++; pTmp1++;
194 sal_uInt8 cG0 = MAP( *pTmp0, *pTmp1, nTempFX );
195 pTmp0++; pTmp1++;
196 sal_uInt8 cR0 = MAP( *pTmp0, *pTmp1, nTempFX );
198 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3;
199 sal_uInt8 cB1 = MAP( *pTmp0, *pTmp1, nTempFX );
200 pTmp0++; pTmp1++;
201 sal_uInt8 cG1 = MAP( *pTmp0, *pTmp1, nTempFX );
202 pTmp0++; pTmp1++;
203 sal_uInt8 cR1 = MAP( *pTmp0, *pTmp1, nTempFX );
205 BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
206 MAP( cG0, cG1, nTempFY ),
207 MAP( cB0, cB1, nTempFY ) );
208 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
213 void scale24bitRGB(ScaleContext &rCtx, long nStartY, long nEndY)
215 const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
217 for( long nY = nStartY; nY <= nEndY; nY++ )
219 long nTempY = rCtx.mpMapIY[ nY ];
220 long nTempFY = rCtx.mpMapFY[ nY ];
221 Scanline pLine0 = rCtx.mpSrc->GetScanline( nTempY );
222 Scanline pLine1 = rCtx.mpSrc->GetScanline( ++nTempY );
224 for( long nX = nStartX, nXDst = 0; nX <= nEndX; nX++ )
226 long nOff = 3 * rCtx.mpMapIX[ nX ];
227 long nTempFX = rCtx.mpMapFX[ nX ];
229 Scanline pTmp0 = pLine0 + nOff;
230 Scanline pTmp1 = pTmp0 + 3;
231 sal_uInt8 cR0 = MAP( *pTmp0, *pTmp1, nTempFX );
232 pTmp0++; pTmp1++;
233 sal_uInt8 cG0 = MAP( *pTmp0, *pTmp1, nTempFX );
234 pTmp0++; pTmp1++;
235 sal_uInt8 cB0 = MAP( *pTmp0, *pTmp1, nTempFX );
237 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3;
238 sal_uInt8 cR1 = MAP( *pTmp0, *pTmp1, nTempFX );
239 pTmp0++; pTmp1++;
240 sal_uInt8 cG1 = MAP( *pTmp0, *pTmp1, nTempFX );
241 pTmp0++; pTmp1++;
242 sal_uInt8 cB1 = MAP( *pTmp0, *pTmp1, nTempFX );
244 BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
245 MAP( cG0, cG1, nTempFY ),
246 MAP( cB0, cB1, nTempFY ) );
247 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
252 void scaleNonPalleteGeneral(ScaleContext &rCtx, long nStartY, long nEndY)
254 const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
256 for( long nY = nStartY; nY <= nEndY; nY++ )
258 long nTempY = rCtx.mpMapIY[ nY ];
259 long nTempFY = rCtx.mpMapFY[ nY ];
261 for( long nX = nStartX, nXDst = 0; nX <= nEndX; nX++ )
263 long nTempX = rCtx.mpMapIX[ nX ];
264 long nTempFX = rCtx.mpMapFX[ nX ];
266 BitmapColor aCol0 = rCtx.mpSrc->GetPixel( nTempY, nTempX );
267 BitmapColor aCol1 = rCtx.mpSrc->GetPixel( nTempY, ++nTempX );
268 sal_uInt8 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
269 sal_uInt8 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
270 sal_uInt8 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
272 aCol1 = rCtx.mpSrc->GetPixel( ++nTempY, nTempX );
273 aCol0 = rCtx.mpSrc->GetPixel( nTempY--, --nTempX );
274 sal_uInt8 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
275 sal_uInt8 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
276 sal_uInt8 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
278 BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
279 MAP( cG0, cG1, nTempFY ),
280 MAP( cB0, cB1, nTempFY ) );
281 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
286 void scalePallete8bit2(ScaleContext &rCtx, long nStartY, long nEndY)
288 const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
289 const long nMax = 1 << 7;
291 for( long nY = nStartY; nY <= nEndY; nY++ )
293 long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
294 long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
296 long nLineStart, nLineRange;
297 if( nY == nEndY )
299 nLineStart = rCtx.mpMapIY[ nY ];
300 nLineRange = 0;
302 else
304 nLineStart = rCtx.mpMapIY[ nTop ] ;
305 nLineRange = ( rCtx.mpMapIY[ nBottom ] == rCtx.mpMapIY[ nTop ] ) ? 1 :( rCtx.mpMapIY[ nBottom ] - rCtx.mpMapIY[ nTop ] );
308 for( long nX = nStartX , nXDst = 0; nX <= nEndX; nX++ )
310 long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
311 long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
313 long nRowStart;
314 long nRowRange;
315 if( nX == nEndX )
317 nRowStart = rCtx.mpMapIX[ nX ];
318 nRowRange = 0;
320 else
322 nRowStart = rCtx.mpMapIX[ nLeft ];
323 nRowRange = ( rCtx.mpMapIX[ nRight ] == rCtx.mpMapIX[ nLeft ] )? 1 : ( rCtx.mpMapIX[ nRight ] - rCtx.mpMapIX[ nLeft ] );
326 long nSumR = 0;
327 long nSumG = 0;
328 long nSumB = 0;
329 long nTotalWeightY = 0;
331 for(long i = 0; i<= nLineRange; i++)
333 Scanline pTmpY = rCtx.mpSrc->GetScanline( nLineStart + i );
334 long nSumRowR = 0;
335 long nSumRowG = 0;
336 long nSumRowB = 0;
337 long nTotalWeightX = 0;
339 for(long j = 0; j <= nRowRange; j++)
341 const BitmapColor& rCol = rCtx.mpSrc->GetPaletteColor( pTmpY[ nRowStart + j ] );
343 if(nX == nEndX )
345 nSumRowB += rCol.GetBlue() << 7;
346 nSumRowG += rCol.GetGreen() << 7;
347 nSumRowR += rCol.GetRed() << 7;
348 nTotalWeightX += 1 << 7;
350 else if( j == 0 )
352 long nWeightX = (nMax- rCtx.mpMapFX[ nLeft ]) ;
353 nSumRowB += ( nWeightX *rCol.GetBlue()) ;
354 nSumRowG += ( nWeightX *rCol.GetGreen()) ;
355 nSumRowR += ( nWeightX *rCol.GetRed()) ;
356 nTotalWeightX += nWeightX;
358 else if ( nRowRange == j )
360 long nWeightX = rCtx.mpMapFX[ nRight ] ;
361 nSumRowB += ( nWeightX *rCol.GetBlue() );
362 nSumRowG += ( nWeightX *rCol.GetGreen() );
363 nSumRowR += ( nWeightX *rCol.GetRed() );
364 nTotalWeightX += nWeightX;
366 else
368 nSumRowB += rCol.GetBlue() << 7;
369 nSumRowG += rCol.GetGreen() << 7;
370 nSumRowR += rCol.GetRed() << 7;
371 nTotalWeightX += 1 << 7;
375 long nWeightY = nMax;
376 if( nY == nEndY )
377 nWeightY = nMax;
378 else if( i == 0 )
379 nWeightY = nMax - rCtx.mpMapFY[ nTop ];
380 else if( nLineRange == 1 )
381 nWeightY = rCtx.mpMapFY[ nTop ];
382 else if ( nLineRange == i )
383 nWeightY = rCtx.mpMapFY[ nBottom ];
385 if (nTotalWeightX)
387 nSumRowB /= nTotalWeightX;
388 nSumRowG /= nTotalWeightX;
389 nSumRowR /= nTotalWeightX;
392 nSumB += nWeightY * nSumRowB;
393 nSumG += nWeightY * nSumRowG;
394 nSumR += nWeightY * nSumRowR;
395 nTotalWeightY += nWeightY;
398 if (nTotalWeightY)
400 nSumR /= nTotalWeightY;
401 nSumG /= nTotalWeightY;
402 nSumB /= nTotalWeightY;
405 BitmapColor aColRes((sal_uInt8)nSumR, (sal_uInt8)nSumG, (sal_uInt8)nSumB);
406 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
411 void scalePalleteGeneral2(ScaleContext &rCtx, long nStartY, long nEndY)
413 const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
414 const long nMax = 1 << 7;
416 for( long nY = nStartY; nY <= nEndY; nY++ )
418 long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
419 long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
421 long nLineStart, nLineRange;
422 if( nY ==nEndY )
424 nLineStart = rCtx.mpMapIY[ nY ];
425 nLineRange = 0;
427 else
429 nLineStart = rCtx.mpMapIY[ nTop ] ;
430 nLineRange = ( rCtx.mpMapIY[ nBottom ] == rCtx.mpMapIY[ nTop ] ) ? 1 :( rCtx.mpMapIY[ nBottom ] - rCtx.mpMapIY[ nTop ] );
433 for( long nX = nStartX , nXDst = 0; nX <= nEndX; nX++ )
435 long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
436 long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
438 long nRowStart, nRowRange;
439 if( nX == nEndX )
441 nRowStart = rCtx.mpMapIX[ nX ];
442 nRowRange = 0;
444 else
446 nRowStart = rCtx.mpMapIX[ nLeft ];
447 nRowRange = ( rCtx.mpMapIX[ nRight ] == rCtx.mpMapIX[ nLeft ] )? 1 : ( rCtx.mpMapIX[ nRight ] - rCtx.mpMapIX[ nLeft ] );
450 long nSumR = 0;
451 long nSumG = 0;
452 long nSumB = 0;
453 long nTotalWeightY = 0;
455 for(long i = 0; i<= nLineRange; i++)
457 long nSumRowR = 0;
458 long nSumRowG = 0;
459 long nSumRowB = 0;
460 long nTotalWeightX = 0;
462 for(long j = 0; j <= nRowRange; j++)
464 BitmapColor aCol0 = rCtx.mpSrc->GetPaletteColor ( rCtx.mpSrc->GetPixelIndex( nLineStart + i, nRowStart + j ) );
466 if(nX == nEndX )
469 nSumRowB += aCol0.GetBlue() << 7;
470 nSumRowG += aCol0.GetGreen() << 7;
471 nSumRowR += aCol0.GetRed() << 7;
472 nTotalWeightX += 1 << 7;
474 else if( j == 0 )
477 long nWeightX = (nMax- rCtx.mpMapFX[ nLeft ]) ;
478 nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
479 nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
480 nSumRowR += ( nWeightX *aCol0.GetRed()) ;
481 nTotalWeightX += nWeightX;
483 else if ( nRowRange == j )
486 long nWeightX = rCtx.mpMapFX[ nRight ] ;
487 nSumRowB += ( nWeightX *aCol0.GetBlue() );
488 nSumRowG += ( nWeightX *aCol0.GetGreen() );
489 nSumRowR += ( nWeightX *aCol0.GetRed() );
490 nTotalWeightX += nWeightX;
492 else
495 nSumRowB += aCol0.GetBlue() << 7;
496 nSumRowG += aCol0.GetGreen() << 7;
497 nSumRowR += aCol0.GetRed() << 7;
498 nTotalWeightX += 1 << 7;
502 long nWeightY = nMax;
503 if( nY == nEndY )
504 nWeightY = nMax;
505 else if( i == 0 )
506 nWeightY = nMax - rCtx.mpMapFY[ nTop ];
507 else if( nLineRange == 1 )
508 nWeightY = rCtx.mpMapFY[ nTop ];
509 else if ( nLineRange == i )
510 nWeightY = rCtx.mpMapFY[ nBottom ];
512 if (nTotalWeightX)
514 nSumRowB /= nTotalWeightX;
515 nSumRowG /= nTotalWeightX;
516 nSumRowR /= nTotalWeightX;
519 nSumB += nWeightY * nSumRowB;
520 nSumG += nWeightY * nSumRowG;
521 nSumR += nWeightY * nSumRowR;
522 nTotalWeightY += nWeightY;
525 if (nTotalWeightY)
527 nSumR /= nTotalWeightY;
528 nSumG /= nTotalWeightY;
529 nSumB /= nTotalWeightY;
532 BitmapColor aColRes((sal_uInt8)nSumR, (sal_uInt8)nSumG, (sal_uInt8)nSumB);
533 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
538 void scale24bitBGR2(ScaleContext &rCtx, long nStartY, long nEndY)
540 const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
541 const long nMax = 1 << 7;
543 for( long nY = nStartY; nY <= nEndY; nY++ )
545 long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
546 long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
548 long nLineStart;
549 long nLineRange;
550 if( nY ==nEndY )
552 nLineStart = rCtx.mpMapIY[ nY ];
553 nLineRange = 0;
555 else
557 nLineStart = rCtx.mpMapIY[ nTop ] ;
558 nLineRange = ( rCtx.mpMapIY[ nBottom ] == rCtx.mpMapIY[ nTop ] ) ? 1 :( rCtx.mpMapIY[ nBottom ] - rCtx.mpMapIY[ nTop ] );
561 for( long nX = nStartX , nXDst = 0; nX <= nEndX; nX++ )
563 long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
564 long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
566 long nRowStart;
567 long nRowRange;
568 if( nX == nEndX )
570 nRowStart = rCtx.mpMapIX[ nX ];
571 nRowRange = 0;
573 else
575 nRowStart = rCtx.mpMapIX[ nLeft ];
576 nRowRange = ( rCtx.mpMapIX[ nRight ] == rCtx.mpMapIX[ nLeft ] )? 1 : ( rCtx.mpMapIX[ nRight ] - rCtx.mpMapIX[ nLeft ] );
579 long nSumR = 0;
580 long nSumG = 0;
581 long nSumB = 0;
582 long nTotalWeightY = 0;
584 for(long i = 0; i<= nLineRange; i++)
586 Scanline pTmpY = rCtx.mpSrc->GetScanline( nLineStart + i );
587 Scanline pTmpX = pTmpY + 3 * nRowStart;
588 long nSumRowR = 0;
589 long nSumRowG = 0;
590 long nSumRowB = 0;
591 long nTotalWeightX = 0;
593 for(long j = 0; j <= nRowRange; j++)
595 if(nX == nEndX )
597 nSumRowB += ( *pTmpX ) << 7;pTmpX++;
598 nSumRowG += ( *pTmpX ) << 7;pTmpX++;
599 nSumRowR += ( *pTmpX ) << 7;pTmpX++;
600 nTotalWeightX += 1 << 7;
602 else if( j == 0 )
604 long nWeightX = (nMax- rCtx.mpMapFX[ nLeft ]) ;
605 nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++;
606 nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++;
607 nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++;
608 nTotalWeightX += nWeightX;
610 else if ( nRowRange == j )
612 long nWeightX = rCtx.mpMapFX[ nRight ] ;
613 nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++;
614 nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++;
615 nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++;
616 nTotalWeightX += nWeightX;
618 else
620 nSumRowB += ( *pTmpX ) << 7;pTmpX++;
621 nSumRowG += ( *pTmpX ) << 7;pTmpX++;
622 nSumRowR += ( *pTmpX ) << 7;pTmpX++;
623 nTotalWeightX += 1 << 7;
627 long nWeightY = nMax;
628 if( nY == nEndY )
629 nWeightY = nMax;
630 else if( i == 0 )
631 nWeightY = nMax - rCtx.mpMapFY[ nTop ];
632 else if( nLineRange == 1 )
633 nWeightY = rCtx.mpMapFY[ nTop ];
634 else if ( nLineRange == i )
635 nWeightY = rCtx.mpMapFY[ nBottom ];
637 if (nTotalWeightX)
639 nSumRowB /= nTotalWeightX;
640 nSumRowG /= nTotalWeightX;
641 nSumRowR /= nTotalWeightX;
643 nSumB += nWeightY * nSumRowB;
644 nSumG += nWeightY * nSumRowG;
645 nSumR += nWeightY * nSumRowR;
646 nTotalWeightY += nWeightY;
649 if (nTotalWeightY)
651 nSumR /= nTotalWeightY;
652 nSumG /= nTotalWeightY;
653 nSumB /= nTotalWeightY;
655 BitmapColor aColRes((sal_uInt8)nSumR, (sal_uInt8)nSumG, (sal_uInt8)nSumB);
656 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
661 void scale24bitRGB2(ScaleContext &rCtx, long nStartY, long nEndY)
663 const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
664 const long nMax = 1 << 7;
666 for( long nY = nStartY; nY <= nEndY; nY++ )
668 long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
669 long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
671 long nLineStart, nLineRange;
672 if( nY ==nEndY )
674 nLineStart = rCtx.mpMapIY[ nY ];
675 nLineRange = 0;
677 else
679 nLineStart = rCtx.mpMapIY[ nTop ] ;
680 nLineRange = ( rCtx.mpMapIY[ nBottom ] == rCtx.mpMapIY[ nTop ] ) ? 1 :( rCtx.mpMapIY[ nBottom ] - rCtx.mpMapIY[ nTop ] );
683 for( long nX = nStartX , nXDst = 0; nX <= nEndX; nX++ )
685 long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
686 long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
688 long nRowStart, nRowRange;
689 if( nX == nEndX )
691 nRowStart = rCtx.mpMapIX[ nX ];
692 nRowRange = 0;
694 else
696 nRowStart = rCtx.mpMapIX[ nLeft ];
697 nRowRange = ( rCtx.mpMapIX[ nRight ] == rCtx.mpMapIX[ nLeft ] )? 1 : ( rCtx.mpMapIX[ nRight ] - rCtx.mpMapIX[ nLeft ] );
700 long nSumR = 0;
701 long nSumG = 0;
702 long nSumB = 0;
703 long nTotalWeightY = 0;
705 for(long i = 0; i<= nLineRange; i++)
707 Scanline pTmpY = rCtx.mpSrc->GetScanline( nLineStart + i );
708 Scanline pTmpX = pTmpY + 3 * nRowStart;
709 long nSumRowR = 0;
710 long nSumRowG = 0;
711 long nSumRowB = 0;
712 long nTotalWeightX = 0;
714 for(long j = 0; j <= nRowRange; j++)
716 if(nX == nEndX )
718 nSumRowR += ( *pTmpX ) << 7;pTmpX++;
719 nSumRowG += ( *pTmpX ) << 7;pTmpX++;
720 nSumRowB += ( *pTmpX ) << 7;pTmpX++;
721 nTotalWeightX += 1 << 7;
723 else if( j == 0 )
725 long nWeightX = (nMax- rCtx.mpMapFX[ nLeft ]) ;
726 nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++;
727 nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++;
728 nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++;
729 nTotalWeightX += nWeightX;
731 else if ( nRowRange == j )
733 long nWeightX = rCtx.mpMapFX[ nRight ] ;
734 nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++;
735 nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++;
736 nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++;
737 nTotalWeightX += nWeightX;
739 else
741 nSumRowR += ( *pTmpX ) << 7;pTmpX++;
742 nSumRowG += ( *pTmpX ) << 7;pTmpX++;
743 nSumRowB += ( *pTmpX ) << 7;pTmpX++;
744 nTotalWeightX += 1 << 7;
748 long nWeightY = nMax;
749 if( nY == nEndY )
750 nWeightY = nMax;
751 else if( i == 0 )
752 nWeightY = nMax - rCtx.mpMapFY[ nTop ];
753 else if( nLineRange == 1 )
754 nWeightY = rCtx.mpMapFY[ nTop ];
755 else if ( nLineRange == i )
756 nWeightY = rCtx.mpMapFY[ nBottom ];
758 if (nTotalWeightX)
760 nSumRowB /= nTotalWeightX;
761 nSumRowG /= nTotalWeightX;
762 nSumRowR /= nTotalWeightX;
764 nSumB += nWeightY * nSumRowB;
765 nSumG += nWeightY * nSumRowG;
766 nSumR += nWeightY * nSumRowR;
767 nTotalWeightY += nWeightY;
770 if (nTotalWeightY)
772 nSumR /= nTotalWeightY;
773 nSumG /= nTotalWeightY;
774 nSumB /= nTotalWeightY;
776 BitmapColor aColRes((sal_uInt8)nSumR, (sal_uInt8)nSumG, (sal_uInt8)nSumB);
777 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
782 void scaleNonPalleteGeneral2(ScaleContext &rCtx, long nStartY, long nEndY)
784 const long nStartX = 0, nEndX = rCtx.mnDestW - 1;
785 const long nMax = 1 << 7;
787 for( long nY = nStartY; nY <= nEndY; nY++ )
789 long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
790 long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
792 long nLineStart, nLineRange;
793 if( nY ==nEndY )
795 nLineStart = rCtx.mpMapIY[ nY ];
796 nLineRange = 0;
798 else
800 nLineStart = rCtx.mpMapIY[ nTop ] ;
801 nLineRange = ( rCtx.mpMapIY[ nBottom ] == rCtx.mpMapIY[ nTop ] ) ? 1 :( rCtx.mpMapIY[ nBottom ] - rCtx.mpMapIY[ nTop ] );
804 for( long nX = nStartX , nXDst = 0; nX <= nEndX; nX++ )
806 long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
807 long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
809 long nRowStart, nRowRange;
810 if( nX == nEndX )
812 nRowStart = rCtx.mpMapIX[ nX ];
813 nRowRange = 0;
815 else
817 nRowStart = rCtx.mpMapIX[ nLeft ];
818 nRowRange = ( rCtx.mpMapIX[ nRight ] == rCtx.mpMapIX[ nLeft ] )? 1 : ( rCtx.mpMapIX[ nRight ] - rCtx.mpMapIX[ nLeft ] );
821 long nSumR = 0;
822 long nSumG = 0;
823 long nSumB = 0;
824 long nTotalWeightY = 0;
826 for(long i = 0; i<= nLineRange; i++)
828 long nSumRowR = 0;
829 long nSumRowG = 0;
830 long nSumRowB = 0;
831 long nTotalWeightX = 0;
833 for(long j = 0; j <= nRowRange; j++)
835 BitmapColor aCol0 = rCtx.mpSrc->GetPixel( nLineStart + i, nRowStart + j );
837 if(nX == nEndX )
840 nSumRowB += aCol0.GetBlue() << 7;
841 nSumRowG += aCol0.GetGreen() << 7;
842 nSumRowR += aCol0.GetRed() << 7;
843 nTotalWeightX += 1 << 7;
845 else if( j == 0 )
848 long nWeightX = (nMax- rCtx.mpMapFX[ nLeft ]) ;
849 nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
850 nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
851 nSumRowR += ( nWeightX *aCol0.GetRed()) ;
852 nTotalWeightX += nWeightX;
854 else if ( nRowRange == j )
857 long nWeightX = rCtx.mpMapFX[ nRight ] ;
858 nSumRowB += ( nWeightX *aCol0.GetBlue() );
859 nSumRowG += ( nWeightX *aCol0.GetGreen() );
860 nSumRowR += ( nWeightX *aCol0.GetRed() );
861 nTotalWeightX += nWeightX;
863 else
865 nSumRowB += aCol0.GetBlue() << 7;
866 nSumRowG += aCol0.GetGreen() << 7;
867 nSumRowR += aCol0.GetRed() << 7;
868 nTotalWeightX += 1 << 7;
872 long nWeightY = nMax;
873 if( nY == nEndY )
874 nWeightY = nMax;
875 else if( i == 0 )
876 nWeightY = nMax - rCtx.mpMapFY[ nTop ];
877 else if( nLineRange == 1 )
878 nWeightY = rCtx.mpMapFY[ nTop ];
879 else if ( nLineRange == i )
880 nWeightY = rCtx.mpMapFY[ nBottom ];
882 if (nTotalWeightX)
884 nSumRowB /= nTotalWeightX;
885 nSumRowG /= nTotalWeightX;
886 nSumRowR /= nTotalWeightX;
889 nSumB += nWeightY * nSumRowB;
890 nSumG += nWeightY * nSumRowG;
891 nSumR += nWeightY * nSumRowR;
892 nTotalWeightY += nWeightY;
895 if (nTotalWeightY)
897 nSumR /= nTotalWeightY;
898 nSumG /= nTotalWeightY;
899 nSumB /= nTotalWeightY;
902 BitmapColor aColRes((sal_uInt8)nSumR, (sal_uInt8)nSumG, (sal_uInt8)nSumB);
903 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
908 } // end anonymous namespace
910 BitmapScaleSuper::BitmapScaleSuper(const double& rScaleX, const double& rScaleY) :
911 mrScaleX(rScaleX),
912 mrScaleY(rScaleY)
915 BitmapScaleSuper::~BitmapScaleSuper()
918 bool BitmapScaleSuper::filter(Bitmap& rBitmap)
920 bool bRet = false;
922 const Size aSizePix(rBitmap.GetSizePixel());
924 bool bHMirr = mrScaleX < 0;
925 bool bVMirr = mrScaleY < 0;
927 double fScaleX = std::fabs(mrScaleX);
928 double fScaleY = std::fabs(mrScaleY);
930 const long nDstW = FRound(aSizePix.Width() * fScaleX);
931 const long nDstH = FRound(aSizePix.Height() * fScaleY);
933 const double fScaleThresh = 0.6;
935 if (nDstW <= 1 || nDstH <= 1)
936 return false;
938 Bitmap::ScopedReadAccess pReadAccess(rBitmap);
940 Bitmap aOutBmp(Size(nDstW, nDstH), 24);
941 Bitmap::ScopedWriteAccess pWriteAccess(aOutBmp);
943 const long nStartY = 0;
944 const long nEndY = nDstH - 1;
946 if (pReadAccess && pWriteAccess)
948 ScaleRangeFn pScaleRangeFn;
949 ScaleContext aContext( pReadAccess.get(),
950 pWriteAccess.get(),
951 pReadAccess->Width(),
952 pWriteAccess->Width(),
953 pReadAccess->Height(),
954 pWriteAccess->Height(),
955 bVMirr, bHMirr );
957 bool bScaleUp = fScaleX >= fScaleThresh && fScaleY >= fScaleThresh;
958 if( pReadAccess->HasPalette() )
960 switch( pReadAccess->GetScanlineFormat() )
962 case ScanlineFormat::N8BitPal:
963 pScaleRangeFn = bScaleUp ? scalePallete8bit : scalePallete8bit2;
964 break;
965 default:
966 pScaleRangeFn = bScaleUp ? scalePalleteGeneral
967 : scalePalleteGeneral2;
968 break;
971 else
973 switch( pReadAccess->GetScanlineFormat() )
975 case ScanlineFormat::N24BitTcBgr:
976 pScaleRangeFn = bScaleUp ? scale24bitBGR : scale24bitBGR2;
977 break;
978 case ScanlineFormat::N24BitTcRgb:
979 pScaleRangeFn = bScaleUp ? scale24bitRGB : scale24bitRGB2;
980 break;
981 default:
982 pScaleRangeFn = bScaleUp ? scaleNonPalleteGeneral
983 : scaleNonPalleteGeneral2;
984 break;
988 // We want to thread - only if there is a lot of work to do:
989 // We work hard when there is a large destination image, or
990 // A large source image.
991 bool bHorizontalWork = pReadAccess->Width() > 512 || pWriteAccess->Width() > 512;
993 static bool bDisableThreadedScaling = getenv ("VCL_NO_THREAD_SCALE");
994 if ( bDisableThreadedScaling || !bHorizontalWork ||
995 nEndY - nStartY < SCALE_THREAD_STRIP )
997 SAL_INFO("vcl.gdi", "Scale in main thread");
998 pScaleRangeFn( aContext, nStartY, nEndY );
1000 else
1002 // partition and queue work
1003 comphelper::ThreadPool &rShared = comphelper::ThreadPool::getSharedOptimalPool();
1004 std::shared_ptr<comphelper::ThreadTaskTag> pTag = comphelper::ThreadPool::createThreadTaskTag();
1005 sal_uInt32 nThreads = rShared.getWorkerCount();
1006 assert( nThreads > 0 );
1007 sal_uInt32 nStrips = ((nEndY - nStartY) + SCALE_THREAD_STRIP - 1) / SCALE_THREAD_STRIP;
1008 sal_uInt32 nStripsPerThread = nStrips / nThreads;
1009 SAL_INFO("vcl.gdi", "Scale in " << nStrips << " strips " << nStripsPerThread << " per thread we have " << nThreads << " CPU threads ");
1010 long nStripY = nStartY;
1011 for ( sal_uInt32 t = 0; t < nThreads - 1; t++ )
1013 ScaleTask *pTask = new ScaleTask( pTag, pScaleRangeFn );
1014 for ( sal_uInt32 j = 0; j < nStripsPerThread; j++ )
1016 ScaleRangeContext aRC( &aContext, nStripY );
1017 pTask->push( aRC );
1018 nStripY += SCALE_THREAD_STRIP;
1020 rShared.pushTask( pTask );
1022 // finish any remaining bits here
1023 pScaleRangeFn( aContext, nStripY, nEndY );
1025 rShared.waitUntilDone(pTag);
1026 SAL_INFO("vcl.gdi", "All threaded scaling tasks complete");
1029 bRet = true;
1032 if( bRet )
1034 rBitmap.AdaptBitCount(aOutBmp);
1035 rBitmap = aOutBmp;
1038 return bRet;
1041 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */