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 <vcl/salbtype.hxx>
22 #include <bmpfast.hxx>
23 #include <o3tl/safeint.hxx>
24 #include <osl/diagnose.h>
27 #define IMPL_CASE_GET_FORMAT( Format ) \
28 case( ScanlineFormat::Format ): \
29 pFncGetPixel = BitmapReadAccess::GetPixelFor##Format; \
32 #define IMPL_CASE_SET_FORMAT( Format, BitCount ) \
33 case( ScanlineFormat::Format ): \
35 pFncSetPixel = BitmapReadAccess::SetPixelFor##Format; \
36 pDstBuffer->mnBitCount = BitCount; \
40 #define DOUBLE_SCANLINES() \
41 while( ( nActY < nHeight1 ) && ( pMapY[ nActY + 1 ] == nMapY ) ) \
43 memcpy( pDstScanMap[ nActY + 1 ], pDstScan, rDstBuffer.mnScanlineSize ); \
47 #define TC_TO_PAL_COLORS 4096
49 static long ImplIndexFromColor( const BitmapColor
& rCol
)
51 #if TC_TO_PAL_COLORS == 4096
53 return( ( ( (long) rCol
.GetBlue() >> 4) << 8 ) |
54 ( ( (long) rCol
.GetGreen() >> 4 ) << 4 ) |
55 ( (long) rCol
.GetRed() >> 4 ) );
57 #elif TC_TO_PAL_COLORS == 32768
59 return( ( ( (long) rCol
.GetBlue() >> 3) << 10 ) |
60 ( ( (long) rCol
.GetGreen() >> 3 ) << 5 ) |
61 ( (long) rCol
.GetRed() >> 3 ) );
66 static void ImplPALToPAL( const BitmapBuffer
& rSrcBuffer
, BitmapBuffer
& rDstBuffer
,
67 FncGetPixel pFncGetPixel
, FncSetPixel pFncSetPixel
,
68 Scanline
* pSrcScanMap
, Scanline
* pDstScanMap
, long* pMapX
, long* pMapY
)
70 const long nHeight1
= rDstBuffer
.mnHeight
- 1;
71 const ColorMask
& rSrcMask
= rSrcBuffer
.maColorMask
;
72 const ColorMask
& rDstMask
= rDstBuffer
.maColorMask
;
73 BitmapPalette
aColMap( rSrcBuffer
.maPalette
.GetEntryCount() );
74 BitmapColor
* pColMapBuf
= aColMap
.ImplGetColorBuffer();
75 BitmapColor
aIndex( 0 );
77 for( sal_uInt16 i
= 0, nSrcCount
= aColMap
.GetEntryCount(), nDstCount
= rDstBuffer
.maPalette
.GetEntryCount(); i
< nSrcCount
; i
++ )
79 if( ( i
< nDstCount
) && ( rSrcBuffer
.maPalette
[ i
] == rDstBuffer
.maPalette
[ i
] ) )
80 aIndex
.SetIndex( sal::static_int_cast
<sal_uInt8
>(i
) );
82 aIndex
.SetIndex( sal::static_int_cast
<sal_uInt8
>(rDstBuffer
.maPalette
.GetBestIndex( rSrcBuffer
.maPalette
[ i
] )) );
84 pColMapBuf
[ i
] = aIndex
;
87 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
89 long nMapY
= pMapY
[nActY
];
90 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
92 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
; ++nX
)
93 pFncSetPixel( pDstScan
, nX
, pColMapBuf
[ pFncGetPixel( pSrcScan
, pMapX
[ nX
], rSrcMask
).GetIndex() ], rDstMask
);
99 static void ImplPALToTC( const BitmapBuffer
& rSrcBuffer
, BitmapBuffer
& rDstBuffer
,
100 FncGetPixel pFncGetPixel
, FncSetPixel pFncSetPixel
,
101 Scanline
* pSrcScanMap
, Scanline
* pDstScanMap
, long* pMapX
, long* pMapY
)
103 const long nHeight1
= rDstBuffer
.mnHeight
- 1;
104 const ColorMask
& rSrcMask
= rSrcBuffer
.maColorMask
;
105 const ColorMask
& rDstMask
= rDstBuffer
.maColorMask
;
106 const BitmapColor
* pColBuf
= rSrcBuffer
.maPalette
.ImplGetColorBuffer();
108 if( RemoveScanline( rSrcBuffer
.mnFormat
) == ScanlineFormat::N1BitMsbPal
)
110 const BitmapColor
aCol0( pColBuf
[ 0 ] );
111 const BitmapColor
aCol1( pColBuf
[ 1 ] );
114 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
116 long nMapY
= pMapY
[nActY
];
117 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
119 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
;)
122 pFncSetPixel( pDstScan
, nX
++,
123 pSrcScan
[ nMapX
>> 3 ] & ( 1 << ( 7 - ( nMapX
& 7 ) ) ) ? aCol1
: aCol0
,
130 else if( RemoveScanline( rSrcBuffer
.mnFormat
) == ScanlineFormat::N4BitMsnPal
)
134 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
136 long nMapY
= pMapY
[nActY
];
137 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
139 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
;)
142 pFncSetPixel( pDstScan
, nX
++,
143 pColBuf
[ ( pSrcScan
[ nMapX
>> 1 ] >> ( nMapX
& 1 ? 0 : 4 ) ) & 0x0f ],
150 else if( RemoveScanline( rSrcBuffer
.mnFormat
) == ScanlineFormat::N8BitPal
)
152 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
154 long nMapY
= pMapY
[nActY
];
155 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
157 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
; ++nX
)
158 pFncSetPixel( pDstScan
, nX
, pColBuf
[ pSrcScan
[ pMapX
[ nX
] ] ], rDstMask
);
165 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
167 long nMapY
= pMapY
[nActY
];
168 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
170 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
; ++nX
)
171 pFncSetPixel( pDstScan
, nX
, pColBuf
[ pFncGetPixel( pSrcScan
, pMapX
[ nX
], rSrcMask
).GetIndex() ], rDstMask
);
178 static void ImplTCToTC( const BitmapBuffer
& rSrcBuffer
, BitmapBuffer
& rDstBuffer
,
179 FncGetPixel pFncGetPixel
, FncSetPixel pFncSetPixel
,
180 Scanline
* pSrcScanMap
, Scanline
* pDstScanMap
, long* pMapX
, long* pMapY
)
182 const long nHeight1
= rDstBuffer
.mnHeight
- 1;
183 const ColorMask
& rSrcMask
= rSrcBuffer
.maColorMask
;
184 const ColorMask
& rDstMask
= rDstBuffer
.maColorMask
;
186 if( RemoveScanline( rSrcBuffer
.mnFormat
) == ScanlineFormat::N24BitTcBgr
)
189 sal_uInt8
* pPixel
= nullptr;
191 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
193 long nMapY
= pMapY
[nActY
];
194 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
196 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
; ++nX
)
198 aCol
.SetBlue( *( pPixel
= ( pSrcScan
+ pMapX
[ nX
] * 3 ) )++ );
199 aCol
.SetGreen( *pPixel
++ );
200 aCol
.SetRed( *pPixel
);
201 pFncSetPixel( pDstScan
, nX
, aCol
, rDstMask
);
209 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
211 long nMapY
= pMapY
[nActY
];
212 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
214 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
; ++nX
)
215 pFncSetPixel( pDstScan
, nX
, pFncGetPixel( pSrcScan
, pMapX
[ nX
], rSrcMask
), rDstMask
);
222 static void ImplTCToPAL( const BitmapBuffer
& rSrcBuffer
, BitmapBuffer
& rDstBuffer
,
223 FncGetPixel pFncGetPixel
, FncSetPixel pFncSetPixel
,
224 Scanline
* pSrcScanMap
, Scanline
* pDstScanMap
, long* pMapX
, long* pMapY
)
226 const long nHeight1
= rDstBuffer
.mnHeight
- 1;
227 const ColorMask
& rSrcMask
= rSrcBuffer
.maColorMask
;
228 const ColorMask
& rDstMask
= rDstBuffer
.maColorMask
;
229 BitmapPalette
aColMap( rSrcBuffer
.maPalette
.GetEntryCount() );
230 std::unique_ptr
<sal_uInt8
[]> pColToPalMap(new sal_uInt8
[ TC_TO_PAL_COLORS
]);
231 BitmapColor
aIndex( 0 );
233 for( long nR
= 0; nR
< 16; nR
++ )
235 for( long nG
= 0; nG
< 16; nG
++ )
237 for( long nB
= 0; nB
< 16; nB
++ )
239 BitmapColor
aCol( sal::static_int_cast
<sal_uInt8
>(nR
<< 4),
240 sal::static_int_cast
<sal_uInt8
>(nG
<< 4),
241 sal::static_int_cast
<sal_uInt8
>(nB
<< 4) );
242 pColToPalMap
[ ImplIndexFromColor( aCol
) ] = (sal_uInt8
) rDstBuffer
.maPalette
.GetBestIndex( aCol
);
247 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
249 long nMapY
= pMapY
[nActY
];
250 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
252 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
; ++nX
)
254 aIndex
.SetIndex( pColToPalMap
[ ImplIndexFromColor( pFncGetPixel( pSrcScan
, pMapX
[ nX
], rSrcMask
) ) ] );
255 pFncSetPixel( pDstScan
, nX
, aIndex
, rDstMask
);
262 BitmapBuffer
* StretchAndConvert(
263 const BitmapBuffer
& rSrcBuffer
, const SalTwoRect
& rTwoRect
,
264 ScanlineFormat nDstBitmapFormat
, const BitmapPalette
* pDstPal
, const ColorMask
* pDstMask
)
266 FncGetPixel pFncGetPixel
;
267 FncSetPixel pFncSetPixel
;
268 BitmapBuffer
* pDstBuffer
= new BitmapBuffer
;
270 // set function for getting pixels
271 switch( RemoveScanline( rSrcBuffer
.mnFormat
) )
273 IMPL_CASE_GET_FORMAT( N1BitMsbPal
);
274 IMPL_CASE_GET_FORMAT( N1BitLsbPal
);
275 IMPL_CASE_GET_FORMAT( N4BitMsnPal
);
276 IMPL_CASE_GET_FORMAT( N4BitLsnPal
);
277 IMPL_CASE_GET_FORMAT( N8BitPal
);
278 IMPL_CASE_GET_FORMAT( N8BitTcMask
);
279 IMPL_CASE_GET_FORMAT( N16BitTcMsbMask
);
280 IMPL_CASE_GET_FORMAT( N16BitTcLsbMask
);
281 IMPL_CASE_GET_FORMAT( N24BitTcBgr
);
282 IMPL_CASE_GET_FORMAT( N24BitTcRgb
);
283 IMPL_CASE_GET_FORMAT( N32BitTcAbgr
);
284 IMPL_CASE_GET_FORMAT( N32BitTcArgb
);
285 IMPL_CASE_GET_FORMAT( N32BitTcBgra
);
286 IMPL_CASE_GET_FORMAT( N32BitTcRgba
);
287 IMPL_CASE_GET_FORMAT( N32BitTcMask
);
290 // should never come here
291 // initialize pFncGetPixel to something valid that is
292 // least likely to crash
293 pFncGetPixel
= BitmapReadAccess::GetPixelForN1BitMsbPal
;
294 OSL_FAIL( "unknown read format" );
298 // set function for setting pixels
299 const ScanlineFormat nDstScanlineFormat
= RemoveScanline( nDstBitmapFormat
);
300 switch( nDstScanlineFormat
)
302 IMPL_CASE_SET_FORMAT( N1BitMsbPal
, 1 );
303 IMPL_CASE_SET_FORMAT( N1BitLsbPal
, 1 );
304 IMPL_CASE_SET_FORMAT( N4BitMsnPal
, 1 );
305 IMPL_CASE_SET_FORMAT( N4BitLsnPal
, 4 );
306 IMPL_CASE_SET_FORMAT( N8BitPal
, 8 );
307 IMPL_CASE_SET_FORMAT( N8BitTcMask
, 8 );
308 IMPL_CASE_SET_FORMAT( N16BitTcMsbMask
, 16 );
309 IMPL_CASE_SET_FORMAT( N16BitTcLsbMask
, 16 );
310 IMPL_CASE_SET_FORMAT( N24BitTcBgr
, 24 );
311 IMPL_CASE_SET_FORMAT( N24BitTcRgb
, 24 );
312 IMPL_CASE_SET_FORMAT( N32BitTcAbgr
, 32 );
313 IMPL_CASE_SET_FORMAT( N32BitTcArgb
, 32 );
314 IMPL_CASE_SET_FORMAT( N32BitTcBgra
, 32 );
315 IMPL_CASE_SET_FORMAT( N32BitTcRgba
, 32 );
316 IMPL_CASE_SET_FORMAT( N32BitTcMask
, 32 );
319 // should never come here
320 // initialize pFncSetPixel to something valid that is
321 // least likely to crash
322 pFncSetPixel
= BitmapReadAccess::SetPixelForN1BitMsbPal
;
323 pDstBuffer
->mnBitCount
= 1;
324 OSL_FAIL( "unknown write format" );
328 // fill destination buffer
329 pDstBuffer
->mnFormat
= nDstBitmapFormat
;
330 pDstBuffer
->mnWidth
= rTwoRect
.mnDestWidth
;
331 pDstBuffer
->mnHeight
= rTwoRect
.mnDestHeight
;
333 bool bFail
= o3tl::checked_multiply
<long>(pDstBuffer
->mnBitCount
, pDstBuffer
->mnWidth
, nScanlineBase
);
336 SAL_WARN("vcl.gdi", "checked multiply failed");
337 pDstBuffer
->mpBits
= nullptr;
341 pDstBuffer
->mnScanlineSize
= AlignedWidth4Bytes(nScanlineBase
);
342 if (pDstBuffer
->mnScanlineSize
< nScanlineBase
/8)
344 SAL_WARN("vcl.gdi", "scanline calculation wraparound");
345 pDstBuffer
->mpBits
= nullptr;
351 pDstBuffer
->mpBits
= new sal_uInt8
[ pDstBuffer
->mnScanlineSize
* pDstBuffer
->mnHeight
];
353 catch( const std::bad_alloc
& )
355 // memory exception, clean up
356 pDstBuffer
->mpBits
= nullptr;
361 // do we need a destination palette or color mask?
362 if( ( nDstScanlineFormat
== ScanlineFormat::N1BitMsbPal
) ||
363 ( nDstScanlineFormat
== ScanlineFormat::N1BitLsbPal
) ||
364 ( nDstScanlineFormat
== ScanlineFormat::N4BitMsnPal
) ||
365 ( nDstScanlineFormat
== ScanlineFormat::N4BitLsnPal
) ||
366 ( nDstScanlineFormat
== ScanlineFormat::N8BitPal
) )
368 assert(pDstPal
&& "destination buffer requires palette");
374 pDstBuffer
->maPalette
= *pDstPal
;
376 else if( ( nDstScanlineFormat
== ScanlineFormat::N8BitTcMask
) ||
377 ( nDstScanlineFormat
== ScanlineFormat::N16BitTcMsbMask
) ||
378 ( nDstScanlineFormat
== ScanlineFormat::N16BitTcLsbMask
) ||
379 ( nDstScanlineFormat
== ScanlineFormat::N32BitTcMask
) )
381 assert(pDstMask
&& "destination buffer requires color mask");
387 pDstBuffer
->maColorMask
= *pDstMask
;
390 // short circuit the most important conversions
391 bool bFastConvert
= ImplFastBitmapConversion( *pDstBuffer
, rSrcBuffer
, rTwoRect
);
395 std::unique_ptr
<Scanline
[]> pSrcScan
;
396 std::unique_ptr
<Scanline
[]> pDstScan
;
397 std::unique_ptr
<long[]> pMapX
;
398 std::unique_ptr
<long[]> pMapY
;
402 pSrcScan
.reset(new Scanline
[rSrcBuffer
.mnHeight
]);
403 pDstScan
.reset(new Scanline
[pDstBuffer
->mnHeight
]);
404 pMapX
.reset(new long[pDstBuffer
->mnWidth
]);
405 pMapY
.reset(new long[pDstBuffer
->mnHeight
]);
407 catch( const std::bad_alloc
& )
409 // memory exception, clean up
410 // remark: the buffer ptr causing the exception
411 // is still NULL here
416 // horizontal mapping table
417 if( (pDstBuffer
->mnWidth
!= rTwoRect
.mnSrcWidth
) && (pDstBuffer
->mnWidth
!= 0) )
419 const double fFactorX
= (double)rTwoRect
.mnSrcWidth
/ pDstBuffer
->mnWidth
;
421 for (long i
= 0; i
< pDstBuffer
->mnWidth
; ++i
)
422 pMapX
[ i
] = rTwoRect
.mnSrcX
+ static_cast<int>( i
* fFactorX
);
426 for (long i
= 0, nTmp
= rTwoRect
.mnSrcX
; i
< pDstBuffer
->mnWidth
; ++i
)
430 // vertical mapping table
431 if( (pDstBuffer
->mnHeight
!= rTwoRect
.mnSrcHeight
) && (pDstBuffer
->mnHeight
!= 0) )
433 const double fFactorY
= (double)rTwoRect
.mnSrcHeight
/ pDstBuffer
->mnHeight
;
435 for (long i
= 0; i
< pDstBuffer
->mnHeight
; ++i
)
436 pMapY
[ i
] = rTwoRect
.mnSrcY
+ static_cast<int>( i
* fFactorY
);
440 for (long i
= 0, nTmp
= rTwoRect
.mnSrcY
; i
< pDstBuffer
->mnHeight
; ++i
)
444 // source scanline buffer
447 if( rSrcBuffer
.mnFormat
& ScanlineFormat::TopDown
)
449 pTmpScan
= rSrcBuffer
.mpBits
;
450 nOffset
= rSrcBuffer
.mnScanlineSize
;
454 pTmpScan
= rSrcBuffer
.mpBits
+ ( rSrcBuffer
.mnHeight
- 1 ) * rSrcBuffer
.mnScanlineSize
;
455 nOffset
= -rSrcBuffer
.mnScanlineSize
;
458 for (long i
= 0; i
< rSrcBuffer
.mnHeight
; i
++, pTmpScan
+= nOffset
)
459 pSrcScan
[ i
] = pTmpScan
;
461 // destination scanline buffer
462 if( pDstBuffer
->mnFormat
& ScanlineFormat::TopDown
)
464 pTmpScan
= pDstBuffer
->mpBits
;
465 nOffset
= pDstBuffer
->mnScanlineSize
;
469 pTmpScan
= pDstBuffer
->mpBits
+ ( pDstBuffer
->mnHeight
- 1 ) * pDstBuffer
->mnScanlineSize
;
470 nOffset
= -pDstBuffer
->mnScanlineSize
;
473 for (long i
= 0; i
< pDstBuffer
->mnHeight
; i
++, pTmpScan
+= nOffset
)
474 pDstScan
[ i
] = pTmpScan
;
476 // do buffer scaling and conversion
477 if( rSrcBuffer
.mnBitCount
<= 8 && pDstBuffer
->mnBitCount
<= 8 )
479 ImplPALToPAL( rSrcBuffer
, *pDstBuffer
, pFncGetPixel
, pFncSetPixel
,
480 pSrcScan
.get(), pDstScan
.get(), pMapX
.get(), pMapY
.get() );
482 else if( rSrcBuffer
.mnBitCount
<= 8 && pDstBuffer
->mnBitCount
> 8 )
484 ImplPALToTC( rSrcBuffer
, *pDstBuffer
, pFncGetPixel
, pFncSetPixel
,
485 pSrcScan
.get(), pDstScan
.get(), pMapX
.get(), pMapY
.get() );
487 else if( rSrcBuffer
.mnBitCount
> 8 && pDstBuffer
->mnBitCount
> 8 )
489 ImplTCToTC( rSrcBuffer
, *pDstBuffer
, pFncGetPixel
, pFncSetPixel
,
490 pSrcScan
.get(), pDstScan
.get(), pMapX
.get(), pMapY
.get() );
494 ImplTCToPAL( rSrcBuffer
, *pDstBuffer
, pFncGetPixel
, pFncSetPixel
,
495 pSrcScan
.get(), pDstScan
.get(), pMapX
.get(), pMapY
.get() );
501 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */