1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
24 #include <boost/scoped_array.hpp>
25 #include <comphelper/threadpool.hxx>
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;
36 long nTempX
= nW
- 1L;
37 for (long nX
= 0L; nX
< nDstW
; nX
++)
39 double fTemp
= nX
* fRevScaleX
;
41 fTemp
= nTempX
- fTemp
;
42 pMapIX
[nX
] = MinMax((long) fTemp
, 0, nTemp
);
43 pMapFX
[nX
] = (long) ((fTemp
- pMapIX
[nX
]) * 128.0);
48 BitmapReadAccess
*mpSrc
;
49 BitmapWriteAccess
*mpDest
;
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
{
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
90 std::vector
< ScaleRangeContext
> maStrips
;
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
);
193 sal_uInt8 cG0
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
195 sal_uInt8 cR0
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
197 pTmp1
= ( pTmp0
= pLine1
+ nOff
) + 3L;
198 sal_uInt8 cB1
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
200 sal_uInt8 cG1
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
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
);
232 sal_uInt8 cG0
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
234 sal_uInt8 cB0
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
236 pTmp1
= ( pTmp0
= pLine1
+ nOff
) + 3L;
237 sal_uInt8 cR1
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
239 sal_uInt8 cG1
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
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
;
298 nLineStart
= rCtx
.mpMapIY
[ nY
];
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 ) ;
316 nRowStart
= rCtx
.mpMapIX
[ nX
];
321 nRowStart
= rCtx
.mpMapIX
[ nLeft
];
322 nRowRange
= ( rCtx
.mpMapIX
[ nRight
] == rCtx
.mpMapIX
[ nLeft
] )? 1 : ( rCtx
.mpMapIX
[ nRight
] - rCtx
.mpMapIX
[ nLeft
] );
328 long nTotalWeightY
= 0;
330 for(int i
= 0; i
<= nLineRange
; i
++)
332 Scanline pTmpY
= rCtx
.mpSrc
->GetScanline( nLineStart
+ i
);
336 long nTotalWeightX
= 0;
338 for(int j
= 0; j
<= nRowRange
; j
++)
340 const BitmapColor
& rCol
= rCtx
.mpSrc
->GetPaletteColor( pTmpY
[ nRowStart
+ j
] );
344 nSumRowB
+= rCol
.GetBlue() << 7L;
345 nSumRowG
+= rCol
.GetGreen() << 7L;
346 nSumRowR
+= rCol
.GetRed() << 7L;
347 nTotalWeightX
+= 1 << 7L;
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
;
367 nSumRowB
+= rCol
.GetBlue() << 7L;
368 nSumRowG
+= rCol
.GetGreen() << 7L;
369 nSumRowR
+= rCol
.GetRed() << 7L;
370 nTotalWeightX
+= 1 << 7L;
374 long nWeightY
= nMax
;
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
];
386 nSumRowB
/= nTotalWeightX
;
387 nSumRowG
/= nTotalWeightX
;
388 nSumRowR
/= nTotalWeightX
;
391 nSumB
+= nWeightY
* nSumRowB
;
392 nSumG
+= nWeightY
* nSumRowG
;
393 nSumR
+= nWeightY
* nSumRowR
;
394 nTotalWeightY
+= nWeightY
;
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
;
423 nLineStart
= rCtx
.mpMapIY
[ nY
];
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
;
440 nRowStart
= rCtx
.mpMapIX
[ nX
];
445 nRowStart
= rCtx
.mpMapIX
[ nLeft
];
446 nRowRange
= ( rCtx
.mpMapIX
[ nRight
] == rCtx
.mpMapIX
[ nLeft
] )? 1 : ( rCtx
.mpMapIX
[ nRight
] - rCtx
.mpMapIX
[ nLeft
] );
452 long nTotalWeightY
= 0;
454 for(int i
= 0; i
<= nLineRange
; i
++)
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
) );
468 nSumRowB
+= aCol0
.GetBlue() << 7L;
469 nSumRowG
+= aCol0
.GetGreen() << 7L;
470 nSumRowR
+= aCol0
.GetRed() << 7L;
471 nTotalWeightX
+= 1 << 7L;
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
;
494 nSumRowB
+= aCol0
.GetBlue() << 7L;
495 nSumRowG
+= aCol0
.GetGreen() << 7L;
496 nSumRowR
+= aCol0
.GetRed() << 7L;
497 nTotalWeightX
+= 1 << 7L;
501 long nWeightY
= nMax
;
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
];
513 nSumRowB
/= nTotalWeightX
;
514 nSumRowG
/= nTotalWeightX
;
515 nSumRowR
/= nTotalWeightX
;
518 nSumB
+= nWeightY
* nSumRowB
;
519 nSumG
+= nWeightY
* nSumRowG
;
520 nSumR
+= nWeightY
* nSumRowR
;
521 nTotalWeightY
+= nWeightY
;
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 ) ;
551 nLineStart
= rCtx
.mpMapIY
[ nY
];
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 ) ;
569 nRowStart
= rCtx
.mpMapIX
[ nX
];
574 nRowStart
= rCtx
.mpMapIX
[ nLeft
];
575 nRowRange
= ( rCtx
.mpMapIX
[ nRight
] == rCtx
.mpMapIX
[ nLeft
] )? 1 : ( rCtx
.mpMapIX
[ nRight
] - rCtx
.mpMapIX
[ nLeft
] );
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
;
590 long nTotalWeightX
= 0;
592 for(int j
= 0; j
<= nRowRange
; j
++)
596 nSumRowB
+= ( *pTmpX
) << 7L;pTmpX
++;
597 nSumRowG
+= ( *pTmpX
) << 7L;pTmpX
++;
598 nSumRowR
+= ( *pTmpX
) << 7L;pTmpX
++;
599 nTotalWeightX
+= 1 << 7L;
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
;
619 nSumRowB
+= ( *pTmpX
) << 7L;pTmpX
++;
620 nSumRowG
+= ( *pTmpX
) << 7L;pTmpX
++;
621 nSumRowR
+= ( *pTmpX
) << 7L;pTmpX
++;
622 nTotalWeightX
+= 1 << 7L;
626 long nWeightY
= nMax
;
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
];
638 nSumRowB
/= nTotalWeightX
;
639 nSumRowG
/= nTotalWeightX
;
640 nSumRowR
/= nTotalWeightX
;
642 nSumB
+= nWeightY
* nSumRowB
;
643 nSumG
+= nWeightY
* nSumRowG
;
644 nSumR
+= nWeightY
* nSumRowR
;
645 nTotalWeightY
+= nWeightY
;
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
;
673 nLineStart
= rCtx
.mpMapIY
[ nY
];
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
;
690 nRowStart
= rCtx
.mpMapIX
[ nX
];
695 nRowStart
= rCtx
.mpMapIX
[ nLeft
];
696 nRowRange
= ( rCtx
.mpMapIX
[ nRight
] == rCtx
.mpMapIX
[ nLeft
] )? 1 : ( rCtx
.mpMapIX
[ nRight
] - rCtx
.mpMapIX
[ nLeft
] );
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
;
711 long nTotalWeightX
= 0;
713 for(int j
= 0; j
<= nRowRange
; j
++)
717 nSumRowR
+= ( *pTmpX
) << 7L;pTmpX
++;
718 nSumRowG
+= ( *pTmpX
) << 7L;pTmpX
++;
719 nSumRowB
+= ( *pTmpX
) << 7L;pTmpX
++;
720 nTotalWeightX
+= 1 << 7L;
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
;
740 nSumRowR
+= ( *pTmpX
) << 7L;pTmpX
++;
741 nSumRowG
+= ( *pTmpX
) << 7L;pTmpX
++;
742 nSumRowB
+= ( *pTmpX
) << 7L;pTmpX
++;
743 nTotalWeightX
+= 1 << 7L;
747 long nWeightY
= nMax
;
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
];
759 nSumRowB
/= nTotalWeightX
;
760 nSumRowG
/= nTotalWeightX
;
761 nSumRowR
/= nTotalWeightX
;
763 nSumB
+= nWeightY
* nSumRowB
;
764 nSumG
+= nWeightY
* nSumRowG
;
765 nSumR
+= nWeightY
* nSumRowR
;
766 nTotalWeightY
+= nWeightY
;
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
;
794 nLineStart
= rCtx
.mpMapIY
[ nY
];
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
;
811 nRowStart
= rCtx
.mpMapIX
[ nX
];
816 nRowStart
= rCtx
.mpMapIX
[ nLeft
];
817 nRowRange
= ( rCtx
.mpMapIX
[ nRight
] == rCtx
.mpMapIX
[ nLeft
] )? 1 : ( rCtx
.mpMapIX
[ nRight
] - rCtx
.mpMapIX
[ nLeft
] );
823 long nTotalWeightY
= 0;
825 for(int i
= 0; i
<= nLineRange
; i
++)
830 long nTotalWeightX
= 0;
832 for(int j
= 0; j
<= nRowRange
; j
++)
834 BitmapColor aCol0
= rCtx
.mpSrc
->GetPixel( nLineStart
+ i
, nRowStart
+ j
);
839 nSumRowB
+= aCol0
.GetBlue() << 7L;
840 nSumRowG
+= aCol0
.GetGreen() << 7L;
841 nSumRowR
+= aCol0
.GetRed() << 7L;
842 nTotalWeightX
+= 1 << 7L;
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
;
864 nSumRowB
+= aCol0
.GetBlue() << 7L;
865 nSumRowG
+= aCol0
.GetGreen() << 7L;
866 nSumRowR
+= aCol0
.GetRed() << 7L;
867 nTotalWeightX
+= 1 << 7L;
871 long nWeightY
= nMax
;
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
];
883 nSumRowB
/= nTotalWeightX
;
884 nSumRowG
/= nTotalWeightX
;
885 nSumRowR
/= nTotalWeightX
;
888 nSumB
+= nWeightY
* nSumRowB
;
889 nSumG
+= nWeightY
* nSumRowG
;
890 nSumR
+= nWeightY
* nSumRowR
;
891 nTotalWeightY
+= nWeightY
;
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
) :
914 BitmapScaleSuper::~BitmapScaleSuper()
917 bool BitmapScaleSuper::filter(Bitmap
& rBitmap
)
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)
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(),
950 pReadAccess
->Width(),
951 pWriteAccess
->Width(),
952 pReadAccess
->Height(),
953 pWriteAccess
->Height(),
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
;
965 pScaleRangeFn
= bScaleUp
? scalePalleteGeneral
966 : scalePalleteGeneral2
;
972 switch( pReadAccess
->GetScanlineFormat() )
974 case BMP_FORMAT_24BIT_TC_BGR
:
975 pScaleRangeFn
= bScaleUp
? scale24bitBGR
: scale24bitBGR2
;
977 case BMP_FORMAT_24BIT_TC_RGB
:
978 pScaleRangeFn
= bScaleUp
? scale24bitRGB
: scale24bitRGB2
;
981 pScaleRangeFn
= bScaleUp
? scaleNonPalleteGeneral
982 : scaleNonPalleteGeneral2
;
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
);
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
);
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");
1032 rBitmap
.AdaptBitCount(aOutBmp
);
1039 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */