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/bitmapaccess.hxx>
21 #include <bitmapscalesuper.hxx>
25 #include <comphelper/threadpool.hxx>
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;
37 for (long nX
= 0; 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 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
{
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 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
);
194 sal_uInt8 cG0
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
196 sal_uInt8 cR0
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
198 pTmp1
= ( pTmp0
= pLine1
+ nOff
) + 3;
199 sal_uInt8 cB1
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
201 sal_uInt8 cG1
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
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
);
233 sal_uInt8 cG0
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
235 sal_uInt8 cB0
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
237 pTmp1
= ( pTmp0
= pLine1
+ nOff
) + 3;
238 sal_uInt8 cR1
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
240 sal_uInt8 cG1
= MAP( *pTmp0
, *pTmp1
, nTempFX
);
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
;
299 nLineStart
= rCtx
.mpMapIY
[ nY
];
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 ) ;
317 nRowStart
= rCtx
.mpMapIX
[ nX
];
322 nRowStart
= rCtx
.mpMapIX
[ nLeft
];
323 nRowRange
= ( rCtx
.mpMapIX
[ nRight
] == rCtx
.mpMapIX
[ nLeft
] )? 1 : ( rCtx
.mpMapIX
[ nRight
] - rCtx
.mpMapIX
[ nLeft
] );
329 long nTotalWeightY
= 0;
331 for(long i
= 0; i
<= nLineRange
; i
++)
333 Scanline pTmpY
= rCtx
.mpSrc
->GetScanline( nLineStart
+ i
);
337 long nTotalWeightX
= 0;
339 for(long j
= 0; j
<= nRowRange
; j
++)
341 const BitmapColor
& rCol
= rCtx
.mpSrc
->GetPaletteColor( pTmpY
[ nRowStart
+ j
] );
345 nSumRowB
+= rCol
.GetBlue() << 7;
346 nSumRowG
+= rCol
.GetGreen() << 7;
347 nSumRowR
+= rCol
.GetRed() << 7;
348 nTotalWeightX
+= 1 << 7;
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
;
368 nSumRowB
+= rCol
.GetBlue() << 7;
369 nSumRowG
+= rCol
.GetGreen() << 7;
370 nSumRowR
+= rCol
.GetRed() << 7;
371 nTotalWeightX
+= 1 << 7;
375 long nWeightY
= nMax
;
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
];
387 nSumRowB
/= nTotalWeightX
;
388 nSumRowG
/= nTotalWeightX
;
389 nSumRowR
/= nTotalWeightX
;
392 nSumB
+= nWeightY
* nSumRowB
;
393 nSumG
+= nWeightY
* nSumRowG
;
394 nSumR
+= nWeightY
* nSumRowR
;
395 nTotalWeightY
+= nWeightY
;
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
;
424 nLineStart
= rCtx
.mpMapIY
[ nY
];
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
;
441 nRowStart
= rCtx
.mpMapIX
[ nX
];
446 nRowStart
= rCtx
.mpMapIX
[ nLeft
];
447 nRowRange
= ( rCtx
.mpMapIX
[ nRight
] == rCtx
.mpMapIX
[ nLeft
] )? 1 : ( rCtx
.mpMapIX
[ nRight
] - rCtx
.mpMapIX
[ nLeft
] );
453 long nTotalWeightY
= 0;
455 for(long i
= 0; i
<= nLineRange
; i
++)
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
) );
469 nSumRowB
+= aCol0
.GetBlue() << 7;
470 nSumRowG
+= aCol0
.GetGreen() << 7;
471 nSumRowR
+= aCol0
.GetRed() << 7;
472 nTotalWeightX
+= 1 << 7;
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
;
495 nSumRowB
+= aCol0
.GetBlue() << 7;
496 nSumRowG
+= aCol0
.GetGreen() << 7;
497 nSumRowR
+= aCol0
.GetRed() << 7;
498 nTotalWeightX
+= 1 << 7;
502 long nWeightY
= nMax
;
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
];
514 nSumRowB
/= nTotalWeightX
;
515 nSumRowG
/= nTotalWeightX
;
516 nSumRowR
/= nTotalWeightX
;
519 nSumB
+= nWeightY
* nSumRowB
;
520 nSumG
+= nWeightY
* nSumRowG
;
521 nSumR
+= nWeightY
* nSumRowR
;
522 nTotalWeightY
+= nWeightY
;
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 ) ;
552 nLineStart
= rCtx
.mpMapIY
[ nY
];
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 ) ;
570 nRowStart
= rCtx
.mpMapIX
[ nX
];
575 nRowStart
= rCtx
.mpMapIX
[ nLeft
];
576 nRowRange
= ( rCtx
.mpMapIX
[ nRight
] == rCtx
.mpMapIX
[ nLeft
] )? 1 : ( rCtx
.mpMapIX
[ nRight
] - rCtx
.mpMapIX
[ nLeft
] );
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
;
591 long nTotalWeightX
= 0;
593 for(long j
= 0; j
<= nRowRange
; j
++)
597 nSumRowB
+= ( *pTmpX
) << 7;pTmpX
++;
598 nSumRowG
+= ( *pTmpX
) << 7;pTmpX
++;
599 nSumRowR
+= ( *pTmpX
) << 7;pTmpX
++;
600 nTotalWeightX
+= 1 << 7;
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
;
620 nSumRowB
+= ( *pTmpX
) << 7;pTmpX
++;
621 nSumRowG
+= ( *pTmpX
) << 7;pTmpX
++;
622 nSumRowR
+= ( *pTmpX
) << 7;pTmpX
++;
623 nTotalWeightX
+= 1 << 7;
627 long nWeightY
= nMax
;
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
];
639 nSumRowB
/= nTotalWeightX
;
640 nSumRowG
/= nTotalWeightX
;
641 nSumRowR
/= nTotalWeightX
;
643 nSumB
+= nWeightY
* nSumRowB
;
644 nSumG
+= nWeightY
* nSumRowG
;
645 nSumR
+= nWeightY
* nSumRowR
;
646 nTotalWeightY
+= nWeightY
;
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
;
674 nLineStart
= rCtx
.mpMapIY
[ nY
];
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
;
691 nRowStart
= rCtx
.mpMapIX
[ nX
];
696 nRowStart
= rCtx
.mpMapIX
[ nLeft
];
697 nRowRange
= ( rCtx
.mpMapIX
[ nRight
] == rCtx
.mpMapIX
[ nLeft
] )? 1 : ( rCtx
.mpMapIX
[ nRight
] - rCtx
.mpMapIX
[ nLeft
] );
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
;
712 long nTotalWeightX
= 0;
714 for(long j
= 0; j
<= nRowRange
; j
++)
718 nSumRowR
+= ( *pTmpX
) << 7;pTmpX
++;
719 nSumRowG
+= ( *pTmpX
) << 7;pTmpX
++;
720 nSumRowB
+= ( *pTmpX
) << 7;pTmpX
++;
721 nTotalWeightX
+= 1 << 7;
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
;
741 nSumRowR
+= ( *pTmpX
) << 7;pTmpX
++;
742 nSumRowG
+= ( *pTmpX
) << 7;pTmpX
++;
743 nSumRowB
+= ( *pTmpX
) << 7;pTmpX
++;
744 nTotalWeightX
+= 1 << 7;
748 long nWeightY
= nMax
;
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
];
760 nSumRowB
/= nTotalWeightX
;
761 nSumRowG
/= nTotalWeightX
;
762 nSumRowR
/= nTotalWeightX
;
764 nSumB
+= nWeightY
* nSumRowB
;
765 nSumG
+= nWeightY
* nSumRowG
;
766 nSumR
+= nWeightY
* nSumRowR
;
767 nTotalWeightY
+= nWeightY
;
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
;
795 nLineStart
= rCtx
.mpMapIY
[ nY
];
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
;
812 nRowStart
= rCtx
.mpMapIX
[ nX
];
817 nRowStart
= rCtx
.mpMapIX
[ nLeft
];
818 nRowRange
= ( rCtx
.mpMapIX
[ nRight
] == rCtx
.mpMapIX
[ nLeft
] )? 1 : ( rCtx
.mpMapIX
[ nRight
] - rCtx
.mpMapIX
[ nLeft
] );
824 long nTotalWeightY
= 0;
826 for(long i
= 0; i
<= nLineRange
; i
++)
831 long nTotalWeightX
= 0;
833 for(long j
= 0; j
<= nRowRange
; j
++)
835 BitmapColor aCol0
= rCtx
.mpSrc
->GetPixel( nLineStart
+ i
, nRowStart
+ j
);
840 nSumRowB
+= aCol0
.GetBlue() << 7;
841 nSumRowG
+= aCol0
.GetGreen() << 7;
842 nSumRowR
+= aCol0
.GetRed() << 7;
843 nTotalWeightX
+= 1 << 7;
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
;
865 nSumRowB
+= aCol0
.GetBlue() << 7;
866 nSumRowG
+= aCol0
.GetGreen() << 7;
867 nSumRowR
+= aCol0
.GetRed() << 7;
868 nTotalWeightX
+= 1 << 7;
872 long nWeightY
= nMax
;
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
];
884 nSumRowB
/= nTotalWeightX
;
885 nSumRowG
/= nTotalWeightX
;
886 nSumRowR
/= nTotalWeightX
;
889 nSumB
+= nWeightY
* nSumRowB
;
890 nSumG
+= nWeightY
* nSumRowG
;
891 nSumR
+= nWeightY
* nSumRowR
;
892 nTotalWeightY
+= nWeightY
;
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
) :
915 BitmapScaleSuper::~BitmapScaleSuper()
918 bool BitmapScaleSuper::filter(Bitmap
& rBitmap
)
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)
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(),
951 pReadAccess
->Width(),
952 pWriteAccess
->Width(),
953 pReadAccess
->Height(),
954 pWriteAccess
->Height(),
957 bool bScaleUp
= fScaleX
>= fScaleThresh
&& fScaleY
>= fScaleThresh
;
958 if( pReadAccess
->HasPalette() )
960 switch( pReadAccess
->GetScanlineFormat() )
962 case ScanlineFormat::N8BitPal
:
963 pScaleRangeFn
= bScaleUp
? scalePallete8bit
: scalePallete8bit2
;
966 pScaleRangeFn
= bScaleUp
? scalePalleteGeneral
967 : scalePalleteGeneral2
;
973 switch( pReadAccess
->GetScanlineFormat() )
975 case ScanlineFormat::N24BitTcBgr
:
976 pScaleRangeFn
= bScaleUp
? scale24bitBGR
: scale24bitBGR2
;
978 case ScanlineFormat::N24BitTcRgb
:
979 pScaleRangeFn
= bScaleUp
? scale24bitRGB
: scale24bitRGB2
;
982 pScaleRangeFn
= bScaleUp
? scaleNonPalleteGeneral
983 : scaleNonPalleteGeneral2
;
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
);
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
);
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");
1034 rBitmap
.AdaptBitCount(aOutBmp
);
1041 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */