Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / source / bitmap / bitmapscalesuper.cxx
blob116b23355afd90e7f25843b36273e6a9177d080c
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/bmpacc.hxx>
21 #include <vcl/bitmapscalesuper.hxx>
23 #include <algorithm>
24 #include <boost/scoped_array.hpp>
25 #include <comphelper/threadpool.hxx>
27 namespace {
29 #define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<7L)+nFrac*((long)(cVal1)-(cVal0)))>>7L))
31 void generateMap(long nW, long nDstW, bool bHMirr, long* pMapIX, long* pMapFX)
33 const double fRevScaleX = (nDstW > 1L) ? (double) (nW - 1) / (nDstW - 1) : 0.0;
35 long nTemp = nW - 2L;
36 long nTempX = nW - 1L;
37 for (long nX = 0L; 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 boost::scoped_array<long> mpMapIX;
54 boost::scoped_array<long> mpMapIY;
55 boost::scoped_array<long> mpMapFX;
56 boost::scoped_array<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 ScaleTask( ScaleRangeFn pFn ) : mpFn( pFn ) {}
93 void push( ScaleRangeContext &aRC ) { maStrips.push_back( aRC ); }
94 virtual void doWork() SAL_OVERRIDE
96 std::vector< ScaleRangeContext >::iterator it;
97 for (it = maStrips.begin(); it != maStrips.end(); ++it)
98 mpFn( *(it->mrCtx), it->mnStartY, it->mnEndY );
102 void scalePallete8bit(ScaleContext &rCtx, long nStartY, long nEndY)
104 const long nStartX = 0, nEndX = rCtx.mnDestW - 1L;
106 for( long nY = nStartY; nY <= nEndY; nY++ )
108 long nTempY = rCtx.mpMapIY[ nY ];
109 long nTempFY = rCtx.mpMapFY[ nY ];
110 Scanline pLine0 = rCtx.mpSrc->GetScanline( nTempY );
111 Scanline pLine1 = rCtx.mpSrc->GetScanline( ++nTempY );
113 for(long nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
115 long nTempX = rCtx.mpMapIX[ nX ];
116 long nTempFX = rCtx.mpMapFX[ nX ];
118 const BitmapColor& rCol0 = rCtx.mpSrc->GetPaletteColor( pLine0[ nTempX ] );
119 const BitmapColor& rCol2 = rCtx.mpSrc->GetPaletteColor( pLine1[ nTempX ] );
120 const BitmapColor& rCol1 = rCtx.mpSrc->GetPaletteColor( pLine0[ ++nTempX ] );
121 const BitmapColor& rCol3 = rCtx.mpSrc->GetPaletteColor( pLine1[ nTempX ] );
123 sal_uInt8 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTempFX );
124 sal_uInt8 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTempFX );
125 sal_uInt8 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTempFX );
127 sal_uInt8 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTempFX );
128 sal_uInt8 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTempFX );
129 sal_uInt8 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTempFX );
131 BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
132 MAP( cG0, cG1, nTempFY ),
133 MAP( cB0, cB1, nTempFY ) );
134 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
139 void scalePalleteGeneral(ScaleContext &rCtx, long nStartY, long nEndY)
141 const long nStartX = 0, nEndX = rCtx.mnDestW - 1L;
143 for( long nY = nStartY; nY <= nEndY; nY++ )
145 long nTempY = rCtx.mpMapIY[ nY ];
146 long nTempFY = rCtx.mpMapFY[ nY ];
148 for( long nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
150 long nTempX = rCtx.mpMapIX[ nX ];
151 long nTempFX = rCtx.mpMapFX[ nX ];
153 BitmapColor aCol0 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( nTempY, nTempX ) );
154 BitmapColor aCol1 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( nTempY, ++nTempX ) );
155 sal_uInt8 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
156 sal_uInt8 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
157 sal_uInt8 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
159 aCol1 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( ++nTempY, nTempX ) );
160 aCol0 = rCtx.mpSrc->GetPaletteColor( rCtx.mpSrc->GetPixelIndex( nTempY--, --nTempX ) );
161 sal_uInt8 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
162 sal_uInt8 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
163 sal_uInt8 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
165 BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
166 MAP( cG0, cG1, nTempFY ),
167 MAP( cB0, cB1, nTempFY ) );
168 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
173 void scale24bitBGR(ScaleContext &rCtx, long nStartY, long nEndY)
175 const long nStartX = 0, nEndX = rCtx.mnDestW - 1L;
177 for( long nY = nStartY; nY <= nEndY; nY++ )
179 long nTempY = rCtx.mpMapIY[ nY ];
180 long nTempFY = rCtx.mpMapFY[ nY ];
181 Scanline pLine0 = rCtx.mpSrc->GetScanline( nTempY );
182 Scanline pLine1 = rCtx.mpSrc->GetScanline( ++nTempY );
184 for( long nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
186 long nOff = 3L * rCtx.mpMapIX[ nX ];
187 long nTempFX = rCtx.mpMapFX[ nX ];
189 Scanline pTmp0 = pLine0 + nOff ;
190 Scanline pTmp1 = pTmp0 + 3L;
191 sal_uInt8 cB0 = MAP( *pTmp0, *pTmp1, nTempFX );
192 pTmp0++; pTmp1++;
193 sal_uInt8 cG0 = MAP( *pTmp0, *pTmp1, nTempFX );
194 pTmp0++; pTmp1++;
195 sal_uInt8 cR0 = MAP( *pTmp0, *pTmp1, nTempFX );
197 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
198 sal_uInt8 cB1 = MAP( *pTmp0, *pTmp1, nTempFX );
199 pTmp0++; pTmp1++;
200 sal_uInt8 cG1 = MAP( *pTmp0, *pTmp1, nTempFX );
201 pTmp0++; pTmp1++;
202 sal_uInt8 cR1 = MAP( *pTmp0, *pTmp1, nTempFX );
204 BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
205 MAP( cG0, cG1, nTempFY ),
206 MAP( cB0, cB1, nTempFY ) );
207 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
212 void scale24bitRGB(ScaleContext &rCtx, long nStartY, long nEndY)
214 const long nStartX = 0, nEndX = rCtx.mnDestW - 1L;
216 for( long nY = nStartY; nY <= nEndY; nY++ )
218 long nTempY = rCtx.mpMapIY[ nY ];
219 long nTempFY = rCtx.mpMapFY[ nY ];
220 Scanline pLine0 = rCtx.mpSrc->GetScanline( nTempY );
221 Scanline pLine1 = rCtx.mpSrc->GetScanline( ++nTempY );
223 for( long nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
225 long nOff = 3L * rCtx.mpMapIX[ nX ];
226 long nTempFX = rCtx.mpMapFX[ nX ];
228 Scanline pTmp0 = pLine0 + nOff;
229 Scanline pTmp1 = pTmp0 + 3L;
230 sal_uInt8 cR0 = MAP( *pTmp0, *pTmp1, nTempFX );
231 pTmp0++; pTmp1++;
232 sal_uInt8 cG0 = MAP( *pTmp0, *pTmp1, nTempFX );
233 pTmp0++; pTmp1++;
234 sal_uInt8 cB0 = MAP( *pTmp0, *pTmp1, nTempFX );
236 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
237 sal_uInt8 cR1 = MAP( *pTmp0, *pTmp1, nTempFX );
238 pTmp0++; pTmp1++;
239 sal_uInt8 cG1 = MAP( *pTmp0, *pTmp1, nTempFX );
240 pTmp0++; pTmp1++;
241 sal_uInt8 cB1 = MAP( *pTmp0, *pTmp1, nTempFX );
243 BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
244 MAP( cG0, cG1, nTempFY ),
245 MAP( cB0, cB1, nTempFY ) );
246 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
251 void scaleNonPalleteGeneral(ScaleContext &rCtx, long nStartY, long nEndY)
253 const long nStartX = 0, nEndX = rCtx.mnDestW - 1L;
255 for( long nY = nStartY; nY <= nEndY; nY++ )
257 long nTempY = rCtx.mpMapIY[ nY ];
258 long nTempFY = rCtx.mpMapFY[ nY ];
260 for( long nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
262 long nTempX = rCtx.mpMapIX[ nX ];
263 long nTempFX = rCtx.mpMapFX[ nX ];
265 BitmapColor aCol0 = rCtx.mpSrc->GetPixel( nTempY, nTempX );
266 BitmapColor aCol1 = rCtx.mpSrc->GetPixel( nTempY, ++nTempX );
267 sal_uInt8 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
268 sal_uInt8 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
269 sal_uInt8 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
271 aCol1 = rCtx.mpSrc->GetPixel( ++nTempY, nTempX );
272 aCol0 = rCtx.mpSrc->GetPixel( nTempY--, --nTempX );
273 sal_uInt8 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
274 sal_uInt8 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
275 sal_uInt8 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
277 BitmapColor aColRes( MAP( cR0, cR1, nTempFY ),
278 MAP( cG0, cG1, nTempFY ),
279 MAP( cB0, cB1, nTempFY ) );
280 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
285 void scalePallete8bit2(ScaleContext &rCtx, long nStartY, long nEndY)
287 const long nStartX = 0, nEndX = rCtx.mnDestW - 1L;
288 const long nMax = 1 << 7L;
290 for( long nY = nStartY; nY <= nEndY; nY++ )
292 long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
293 long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
295 long nLineStart, nLineRange;
296 if( nY == nEndY )
298 nLineStart = rCtx.mpMapIY[ nY ];
299 nLineRange = 0;
301 else
303 nLineStart = rCtx.mpMapIY[ nTop ] ;
304 nLineRange = ( rCtx.mpMapIY[ nBottom ] == rCtx.mpMapIY[ nTop ] ) ? 1 :( rCtx.mpMapIY[ nBottom ] - rCtx.mpMapIY[ nTop ] );
307 for( long nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
309 long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
310 long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
312 long nRowStart;
313 long nRowRange;
314 if( nX == nEndX )
316 nRowStart = rCtx.mpMapIX[ nX ];
317 nRowRange = 0;
319 else
321 nRowStart = rCtx.mpMapIX[ nLeft ];
322 nRowRange = ( rCtx.mpMapIX[ nRight ] == rCtx.mpMapIX[ nLeft ] )? 1 : ( rCtx.mpMapIX[ nRight ] - rCtx.mpMapIX[ nLeft ] );
325 long nSumR = 0;
326 long nSumG = 0;
327 long nSumB = 0;
328 long nTotalWeightY = 0;
330 for(int i = 0; i<= nLineRange; i++)
332 Scanline pTmpY = rCtx.mpSrc->GetScanline( nLineStart + i );
333 long nSumRowR = 0;
334 long nSumRowG = 0;
335 long nSumRowB = 0;
336 long nTotalWeightX = 0;
338 for(int j = 0; j <= nRowRange; j++)
340 const BitmapColor& rCol = rCtx.mpSrc->GetPaletteColor( pTmpY[ nRowStart + j ] );
342 if(nX == nEndX )
344 nSumRowB += rCol.GetBlue() << 7L;
345 nSumRowG += rCol.GetGreen() << 7L;
346 nSumRowR += rCol.GetRed() << 7L;
347 nTotalWeightX += 1 << 7L;
349 else if( j == 0 )
351 long nWeightX = (nMax- rCtx.mpMapFX[ nLeft ]) ;
352 nSumRowB += ( nWeightX *rCol.GetBlue()) ;
353 nSumRowG += ( nWeightX *rCol.GetGreen()) ;
354 nSumRowR += ( nWeightX *rCol.GetRed()) ;
355 nTotalWeightX += nWeightX;
357 else if ( nRowRange == j )
359 long nWeightX = rCtx.mpMapFX[ nRight ] ;
360 nSumRowB += ( nWeightX *rCol.GetBlue() );
361 nSumRowG += ( nWeightX *rCol.GetGreen() );
362 nSumRowR += ( nWeightX *rCol.GetRed() );
363 nTotalWeightX += nWeightX;
365 else
367 nSumRowB += rCol.GetBlue() << 7L;
368 nSumRowG += rCol.GetGreen() << 7L;
369 nSumRowR += rCol.GetRed() << 7L;
370 nTotalWeightX += 1 << 7L;
374 long nWeightY = nMax;
375 if( nY == nEndY )
376 nWeightY = nMax;
377 else if( i == 0 )
378 nWeightY = nMax - rCtx.mpMapFY[ nTop ];
379 else if( nLineRange == 1 )
380 nWeightY = rCtx.mpMapFY[ nTop ];
381 else if ( nLineRange == i )
382 nWeightY = rCtx.mpMapFY[ nBottom ];
384 if (nTotalWeightX)
386 nSumRowB /= nTotalWeightX;
387 nSumRowG /= nTotalWeightX;
388 nSumRowR /= nTotalWeightX;
391 nSumB += nWeightY * nSumRowB;
392 nSumG += nWeightY * nSumRowG;
393 nSumR += nWeightY * nSumRowR;
394 nTotalWeightY += nWeightY;
397 if (nTotalWeightY)
399 nSumR /= nTotalWeightY;
400 nSumG /= nTotalWeightY;
401 nSumB /= nTotalWeightY;
404 BitmapColor aColRes((sal_uInt8)nSumR, (sal_uInt8)nSumG, (sal_uInt8)nSumB);
405 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
410 void scalePalleteGeneral2(ScaleContext &rCtx, long nStartY, long nEndY)
412 const long nStartX = 0, nEndX = rCtx.mnDestW - 1L;
413 const long nMax = 1 << 7L;
415 for( long nY = nStartY; nY <= nEndY; nY++ )
417 long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
418 long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
420 long nLineStart, nLineRange;
421 if( nY ==nEndY )
423 nLineStart = rCtx.mpMapIY[ nY ];
424 nLineRange = 0;
426 else
428 nLineStart = rCtx.mpMapIY[ nTop ] ;
429 nLineRange = ( rCtx.mpMapIY[ nBottom ] == rCtx.mpMapIY[ nTop ] ) ? 1 :( rCtx.mpMapIY[ nBottom ] - rCtx.mpMapIY[ nTop ] );
432 for( long nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
434 long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
435 long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
437 long nRowStart, nRowRange;
438 if( nX == nEndX )
440 nRowStart = rCtx.mpMapIX[ nX ];
441 nRowRange = 0;
443 else
445 nRowStart = rCtx.mpMapIX[ nLeft ];
446 nRowRange = ( rCtx.mpMapIX[ nRight ] == rCtx.mpMapIX[ nLeft ] )? 1 : ( rCtx.mpMapIX[ nRight ] - rCtx.mpMapIX[ nLeft ] );
449 long nSumR = 0;
450 long nSumG = 0;
451 long nSumB = 0;
452 long nTotalWeightY = 0;
454 for(int i = 0; i<= nLineRange; i++)
456 long nSumRowR = 0;
457 long nSumRowG = 0;
458 long nSumRowB = 0;
459 long nTotalWeightX = 0;
461 for(int j = 0; j <= nRowRange; j++)
463 BitmapColor aCol0 = rCtx.mpSrc->GetPaletteColor ( rCtx.mpSrc->GetPixelIndex( nLineStart + i, nRowStart + j ) );
465 if(nX == nEndX )
468 nSumRowB += aCol0.GetBlue() << 7L;
469 nSumRowG += aCol0.GetGreen() << 7L;
470 nSumRowR += aCol0.GetRed() << 7L;
471 nTotalWeightX += 1 << 7L;
473 else if( j == 0 )
476 long nWeightX = (nMax- rCtx.mpMapFX[ nLeft ]) ;
477 nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
478 nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
479 nSumRowR += ( nWeightX *aCol0.GetRed()) ;
480 nTotalWeightX += nWeightX;
482 else if ( nRowRange == j )
485 long nWeightX = rCtx.mpMapFX[ nRight ] ;
486 nSumRowB += ( nWeightX *aCol0.GetBlue() );
487 nSumRowG += ( nWeightX *aCol0.GetGreen() );
488 nSumRowR += ( nWeightX *aCol0.GetRed() );
489 nTotalWeightX += nWeightX;
491 else
494 nSumRowB += aCol0.GetBlue() << 7L;
495 nSumRowG += aCol0.GetGreen() << 7L;
496 nSumRowR += aCol0.GetRed() << 7L;
497 nTotalWeightX += 1 << 7L;
501 long nWeightY = nMax;
502 if( nY == nEndY )
503 nWeightY = nMax;
504 else if( i == 0 )
505 nWeightY = nMax - rCtx.mpMapFY[ nTop ];
506 else if( nLineRange == 1 )
507 nWeightY = rCtx.mpMapFY[ nTop ];
508 else if ( nLineRange == i )
509 nWeightY = rCtx.mpMapFY[ nBottom ];
511 if (nTotalWeightX)
513 nSumRowB /= nTotalWeightX;
514 nSumRowG /= nTotalWeightX;
515 nSumRowR /= nTotalWeightX;
518 nSumB += nWeightY * nSumRowB;
519 nSumG += nWeightY * nSumRowG;
520 nSumR += nWeightY * nSumRowR;
521 nTotalWeightY += nWeightY;
524 if (nTotalWeightY)
526 nSumR /= nTotalWeightY;
527 nSumG /= nTotalWeightY;
528 nSumB /= nTotalWeightY;
531 BitmapColor aColRes((sal_uInt8)nSumR, (sal_uInt8)nSumG, (sal_uInt8)nSumB);
532 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
537 void scale24bitBGR2(ScaleContext &rCtx, long nStartY, long nEndY)
539 const long nStartX = 0, nEndX = rCtx.mnDestW - 1L;
540 const long nMax = 1 << 7L;
542 for( long nY = nStartY; nY <= nEndY; nY++ )
544 long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
545 long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
547 long nLineStart;
548 long nLineRange;
549 if( nY ==nEndY )
551 nLineStart = rCtx.mpMapIY[ nY ];
552 nLineRange = 0;
554 else
556 nLineStart = rCtx.mpMapIY[ nTop ] ;
557 nLineRange = ( rCtx.mpMapIY[ nBottom ] == rCtx.mpMapIY[ nTop ] ) ? 1 :( rCtx.mpMapIY[ nBottom ] - rCtx.mpMapIY[ nTop ] );
560 for( long nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
562 long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
563 long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
565 long nRowStart;
566 long nRowRange;
567 if( nX == nEndX )
569 nRowStart = rCtx.mpMapIX[ nX ];
570 nRowRange = 0;
572 else
574 nRowStart = rCtx.mpMapIX[ nLeft ];
575 nRowRange = ( rCtx.mpMapIX[ nRight ] == rCtx.mpMapIX[ nLeft ] )? 1 : ( rCtx.mpMapIX[ nRight ] - rCtx.mpMapIX[ nLeft ] );
578 long nSumR = 0;
579 long nSumG = 0;
580 long nSumB = 0;
581 long nTotalWeightY = 0;
583 for(int i = 0; i<= nLineRange; i++)
585 Scanline pTmpY = rCtx.mpSrc->GetScanline( nLineStart + i );
586 Scanline pTmpX = pTmpY + 3L * nRowStart;
587 long nSumRowR = 0;
588 long nSumRowG = 0;
589 long nSumRowB = 0;
590 long nTotalWeightX = 0;
592 for(int j = 0; j <= nRowRange; j++)
594 if(nX == nEndX )
596 nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
597 nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
598 nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
599 nTotalWeightX += 1 << 7L;
601 else if( j == 0 )
603 long nWeightX = (nMax- rCtx.mpMapFX[ nLeft ]) ;
604 nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++;
605 nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++;
606 nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++;
607 nTotalWeightX += nWeightX;
609 else if ( nRowRange == j )
611 long nWeightX = rCtx.mpMapFX[ nRight ] ;
612 nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++;
613 nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++;
614 nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++;
615 nTotalWeightX += nWeightX;
617 else
619 nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
620 nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
621 nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
622 nTotalWeightX += 1 << 7L;
626 long nWeightY = nMax;
627 if( nY == nEndY )
628 nWeightY = nMax;
629 else if( i == 0 )
630 nWeightY = nMax - rCtx.mpMapFY[ nTop ];
631 else if( nLineRange == 1 )
632 nWeightY = rCtx.mpMapFY[ nTop ];
633 else if ( nLineRange == i )
634 nWeightY = rCtx.mpMapFY[ nBottom ];
636 if (nTotalWeightX)
638 nSumRowB /= nTotalWeightX;
639 nSumRowG /= nTotalWeightX;
640 nSumRowR /= nTotalWeightX;
642 nSumB += nWeightY * nSumRowB;
643 nSumG += nWeightY * nSumRowG;
644 nSumR += nWeightY * nSumRowR;
645 nTotalWeightY += nWeightY;
648 if (nTotalWeightY)
650 nSumR /= nTotalWeightY;
651 nSumG /= nTotalWeightY;
652 nSumB /= nTotalWeightY;
654 BitmapColor aColRes((sal_uInt8)nSumR, (sal_uInt8)nSumG, (sal_uInt8)nSumB);
655 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
660 void scale24bitRGB2(ScaleContext &rCtx, long nStartY, long nEndY)
662 const long nStartX = 0, nEndX = rCtx.mnDestW - 1L;
663 const long nMax = 1 << 7L;
665 for( long nY = nStartY; nY <= nEndY; nY++ )
667 long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
668 long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
670 long nLineStart, nLineRange;
671 if( nY ==nEndY )
673 nLineStart = rCtx.mpMapIY[ nY ];
674 nLineRange = 0;
676 else
678 nLineStart = rCtx.mpMapIY[ nTop ] ;
679 nLineRange = ( rCtx.mpMapIY[ nBottom ] == rCtx.mpMapIY[ nTop ] ) ? 1 :( rCtx.mpMapIY[ nBottom ] - rCtx.mpMapIY[ nTop ] );
682 for( long nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
684 long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
685 long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
687 long nRowStart, nRowRange;
688 if( nX == nEndX )
690 nRowStart = rCtx.mpMapIX[ nX ];
691 nRowRange = 0;
693 else
695 nRowStart = rCtx.mpMapIX[ nLeft ];
696 nRowRange = ( rCtx.mpMapIX[ nRight ] == rCtx.mpMapIX[ nLeft ] )? 1 : ( rCtx.mpMapIX[ nRight ] - rCtx.mpMapIX[ nLeft ] );
699 long nSumR = 0;
700 long nSumG = 0;
701 long nSumB = 0;
702 long nTotalWeightY = 0;
704 for(int i = 0; i<= nLineRange; i++)
706 Scanline pTmpY = rCtx.mpSrc->GetScanline( nLineStart + i );
707 Scanline pTmpX = pTmpY + 3L * nRowStart;
708 long nSumRowR = 0;
709 long nSumRowG = 0;
710 long nSumRowB = 0;
711 long nTotalWeightX = 0;
713 for(int j = 0; j <= nRowRange; j++)
715 if(nX == nEndX )
717 nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
718 nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
719 nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
720 nTotalWeightX += 1 << 7L;
722 else if( j == 0 )
724 long nWeightX = (nMax- rCtx.mpMapFX[ nLeft ]) ;
725 nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++;
726 nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++;
727 nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++;
728 nTotalWeightX += nWeightX;
730 else if ( nRowRange == j )
732 long nWeightX = rCtx.mpMapFX[ nRight ] ;
733 nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++;
734 nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++;
735 nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++;
736 nTotalWeightX += nWeightX;
738 else
740 nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
741 nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
742 nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
743 nTotalWeightX += 1 << 7L;
747 long nWeightY = nMax;
748 if( nY == nEndY )
749 nWeightY = nMax;
750 else if( i == 0 )
751 nWeightY = nMax - rCtx.mpMapFY[ nTop ];
752 else if( nLineRange == 1 )
753 nWeightY = rCtx.mpMapFY[ nTop ];
754 else if ( nLineRange == i )
755 nWeightY = rCtx.mpMapFY[ nBottom ];
757 if (nTotalWeightX)
759 nSumRowB /= nTotalWeightX;
760 nSumRowG /= nTotalWeightX;
761 nSumRowR /= nTotalWeightX;
763 nSumB += nWeightY * nSumRowB;
764 nSumG += nWeightY * nSumRowG;
765 nSumR += nWeightY * nSumRowR;
766 nTotalWeightY += nWeightY;
769 if (nTotalWeightY)
771 nSumR /= nTotalWeightY;
772 nSumG /= nTotalWeightY;
773 nSumB /= nTotalWeightY;
775 BitmapColor aColRes((sal_uInt8)nSumR, (sal_uInt8)nSumG, (sal_uInt8)nSumB);
776 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
781 void scaleNonPalleteGeneral2(ScaleContext &rCtx, long nStartY, long nEndY)
783 const long nStartX = 0, nEndX = rCtx.mnDestW - 1L;
784 const long nMax = 1 << 7L;
786 for( long nY = nStartY; nY <= nEndY; nY++ )
788 long nTop = rCtx.mbVMirr ? ( nY + 1 ) : nY;
789 long nBottom = rCtx.mbVMirr ? nY : ( nY + 1 ) ;
791 long nLineStart, nLineRange;
792 if( nY ==nEndY )
794 nLineStart = rCtx.mpMapIY[ nY ];
795 nLineRange = 0;
797 else
799 nLineStart = rCtx.mpMapIY[ nTop ] ;
800 nLineRange = ( rCtx.mpMapIY[ nBottom ] == rCtx.mpMapIY[ nTop ] ) ? 1 :( rCtx.mpMapIY[ nBottom ] - rCtx.mpMapIY[ nTop ] );
803 for( long nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
805 long nLeft = rCtx.mbHMirr ? ( nX + 1 ) : nX;
806 long nRight = rCtx.mbHMirr ? nX : ( nX + 1 ) ;
808 long nRowStart, nRowRange;
809 if( nX == nEndX )
811 nRowStart = rCtx.mpMapIX[ nX ];
812 nRowRange = 0;
814 else
816 nRowStart = rCtx.mpMapIX[ nLeft ];
817 nRowRange = ( rCtx.mpMapIX[ nRight ] == rCtx.mpMapIX[ nLeft ] )? 1 : ( rCtx.mpMapIX[ nRight ] - rCtx.mpMapIX[ nLeft ] );
820 long nSumR = 0;
821 long nSumG = 0;
822 long nSumB = 0;
823 long nTotalWeightY = 0;
825 for(int i = 0; i<= nLineRange; i++)
827 long nSumRowR = 0;
828 long nSumRowG = 0;
829 long nSumRowB = 0;
830 long nTotalWeightX = 0;
832 for(int j = 0; j <= nRowRange; j++)
834 BitmapColor aCol0 = rCtx.mpSrc->GetPixel( nLineStart + i, nRowStart + j );
836 if(nX == nEndX )
839 nSumRowB += aCol0.GetBlue() << 7L;
840 nSumRowG += aCol0.GetGreen() << 7L;
841 nSumRowR += aCol0.GetRed() << 7L;
842 nTotalWeightX += 1 << 7L;
844 else if( j == 0 )
847 long nWeightX = (nMax- rCtx.mpMapFX[ nLeft ]) ;
848 nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
849 nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
850 nSumRowR += ( nWeightX *aCol0.GetRed()) ;
851 nTotalWeightX += nWeightX;
853 else if ( nRowRange == j )
856 long nWeightX = rCtx.mpMapFX[ nRight ] ;
857 nSumRowB += ( nWeightX *aCol0.GetBlue() );
858 nSumRowG += ( nWeightX *aCol0.GetGreen() );
859 nSumRowR += ( nWeightX *aCol0.GetRed() );
860 nTotalWeightX += nWeightX;
862 else
864 nSumRowB += aCol0.GetBlue() << 7L;
865 nSumRowG += aCol0.GetGreen() << 7L;
866 nSumRowR += aCol0.GetRed() << 7L;
867 nTotalWeightX += 1 << 7L;
871 long nWeightY = nMax;
872 if( nY == nEndY )
873 nWeightY = nMax;
874 else if( i == 0 )
875 nWeightY = nMax - rCtx.mpMapFY[ nTop ];
876 else if( nLineRange == 1 )
877 nWeightY = rCtx.mpMapFY[ nTop ];
878 else if ( nLineRange == i )
879 nWeightY = rCtx.mpMapFY[ nBottom ];
881 if (nTotalWeightX)
883 nSumRowB /= nTotalWeightX;
884 nSumRowG /= nTotalWeightX;
885 nSumRowR /= nTotalWeightX;
888 nSumB += nWeightY * nSumRowB;
889 nSumG += nWeightY * nSumRowG;
890 nSumR += nWeightY * nSumRowR;
891 nTotalWeightY += nWeightY;
894 if (nTotalWeightY)
896 nSumR /= nTotalWeightY;
897 nSumG /= nTotalWeightY;
898 nSumB /= nTotalWeightY;
901 BitmapColor aColRes((sal_uInt8)nSumR, (sal_uInt8)nSumG, (sal_uInt8)nSumB);
902 rCtx.mpDest->SetPixel( nY, nXDst++, aColRes );
907 } // end anonymous namespace
909 BitmapScaleSuper::BitmapScaleSuper(const double& rScaleX, const double& rScaleY) :
910 mrScaleX(rScaleX),
911 mrScaleY(rScaleY)
914 BitmapScaleSuper::~BitmapScaleSuper()
917 bool BitmapScaleSuper::filter(Bitmap& rBitmap)
919 bool bRet = false;
921 const Size aSizePix(rBitmap.GetSizePixel());
923 bool bHMirr = mrScaleX < 0;
924 bool bVMirr = mrScaleY < 0;
926 double fScaleX = std::fabs(mrScaleX);
927 double fScaleY = std::fabs(mrScaleY);
929 const long nDstW = FRound(aSizePix.Width() * fScaleX);
930 const long nDstH = FRound(aSizePix.Height() * fScaleY);
932 const double fScaleThresh = 0.6;
934 if (nDstW <= 1L || nDstH <= 1L)
935 return false;
937 Bitmap::ScopedReadAccess pReadAccess(rBitmap);
939 Bitmap aOutBmp(Size(nDstW, nDstH), 24);
940 Bitmap::ScopedWriteAccess pWriteAccess(aOutBmp);
942 const long nStartY = 0;
943 const long nEndY = nDstH - 1L;
945 if (pReadAccess && pWriteAccess)
947 ScaleRangeFn pScaleRangeFn;
948 ScaleContext aContext( pReadAccess.get(),
949 pWriteAccess.get(),
950 pReadAccess->Width(),
951 pWriteAccess->Width(),
952 pReadAccess->Height(),
953 pWriteAccess->Height(),
954 bVMirr, bHMirr );
956 bool bScaleUp = fScaleX >= fScaleThresh && fScaleY >= fScaleThresh;
957 if( pReadAccess->HasPalette() )
959 switch( pReadAccess->GetScanlineFormat() )
961 case BMP_FORMAT_8BIT_PAL:
962 pScaleRangeFn = bScaleUp ? scalePallete8bit : scalePallete8bit2;
963 break;
964 default:
965 pScaleRangeFn = bScaleUp ? scalePalleteGeneral
966 : scalePalleteGeneral2;
967 break;
970 else
972 switch( pReadAccess->GetScanlineFormat() )
974 case BMP_FORMAT_24BIT_TC_BGR:
975 pScaleRangeFn = bScaleUp ? scale24bitBGR : scale24bitBGR2;
976 break;
977 case BMP_FORMAT_24BIT_TC_RGB:
978 pScaleRangeFn = bScaleUp ? scale24bitRGB : scale24bitRGB2;
979 break;
980 default:
981 pScaleRangeFn = bScaleUp ? scaleNonPalleteGeneral
982 : scaleNonPalleteGeneral2;
983 break;
987 // We want to thread - only if there is a lot of work to do:
988 // We work hard when there is a large destination image, or
989 // A large source image.
990 bool bHorizontalWork = pReadAccess->Width() > 512 || pWriteAccess->Width() > 512;
992 static bool bDisableThreadedScaling = getenv ("VCL_NO_THREAD_SCALE");
993 if ( bDisableThreadedScaling || !bHorizontalWork ||
994 nEndY - nStartY < SCALE_THREAD_STRIP )
996 SAL_INFO("vcl.gdi", "Scale in main thread");
997 pScaleRangeFn( aContext, nStartY, nEndY );
999 else
1001 // partition and queue work
1002 comphelper::ThreadPool &rShared = comphelper::ThreadPool::getSharedOptimalPool();
1003 sal_uInt32 nThreads = rShared.getWorkerCount();
1004 assert( nThreads > 0 );
1005 sal_uInt32 nStrips = ((nEndY - nStartY) + SCALE_THREAD_STRIP - 1) / SCALE_THREAD_STRIP;
1006 sal_uInt32 nStripsPerThread = nStrips / nThreads;
1007 SAL_INFO("vcl.gdi", "Scale in " << nStrips << " strips " << nStripsPerThread << " per thread we have " << nThreads << " CPU threads ");
1008 long nStripY = nStartY;
1009 for ( sal_uInt32 t = 0; t < nThreads - 1; t++ )
1011 ScaleTask *pTask = new ScaleTask( pScaleRangeFn );
1012 for ( sal_uInt32 j = 0; j < nStripsPerThread; j++ )
1014 ScaleRangeContext aRC( &aContext, nStripY );
1015 pTask->push( aRC );
1016 nStripY += SCALE_THREAD_STRIP;
1018 rShared.pushTask( pTask );
1020 // finish any remaining bits here
1021 pScaleRangeFn( aContext, nStripY, nEndY );
1023 rShared.waitUntilEmpty();
1024 SAL_INFO("vcl.gdi", "All threaded scaling tasks complete");
1027 bRet = true;
1030 if( bRet )
1032 rBitmap.AdaptBitCount(aOutBmp);
1033 rBitmap = aOutBmp;
1036 return bRet;
1039 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */