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/salgtype.hxx>
22 #include <bmpfast.hxx>
23 #include <o3tl/safeint.hxx>
24 #include <osl/diagnose.h>
25 #include <sal/log.hxx>
26 #include <tools/helpers.hxx>
29 #define IMPL_CASE_GET_FORMAT( Format ) \
30 case( ScanlineFormat::Format ): \
31 pFncGetPixel = BitmapReadAccess::GetPixelFor##Format; \
34 #define IMPL_CASE_SET_FORMAT( Format, BitCount ) \
35 case( ScanlineFormat::Format ): \
37 pFncSetPixel = BitmapReadAccess::SetPixelFor##Format; \
38 pDstBuffer->mnBitCount = BitCount; \
42 #define DOUBLE_SCANLINES() \
43 while( ( nActY < nHeight1 ) && ( pMapY[ nActY + 1 ] == nMapY ) ) \
45 memcpy( pDstScanMap[ nActY + 1 ], pDstScan, rDstBuffer.mnScanlineSize ); \
49 #define TC_TO_PAL_COLORS 4096
51 static long ImplIndexFromColor( const BitmapColor
& rCol
)
53 #if TC_TO_PAL_COLORS == 4096
55 return( ( ( static_cast<long>(rCol
.GetBlue()) >> 4) << 8 ) |
56 ( ( static_cast<long>(rCol
.GetGreen()) >> 4 ) << 4 ) |
57 ( static_cast<long>(rCol
.GetRed()) >> 4 ) );
59 #elif TC_TO_PAL_COLORS == 32768
61 return( ( ( (long) rCol
.GetBlue() >> 3) << 10 ) |
62 ( ( (long) rCol
.GetGreen() >> 3 ) << 5 ) |
63 ( (long) rCol
.GetRed() >> 3 ) );
68 static void ImplPALToPAL( const BitmapBuffer
& rSrcBuffer
, BitmapBuffer
& rDstBuffer
,
69 FncGetPixel pFncGetPixel
, FncSetPixel pFncSetPixel
,
70 Scanline
* pSrcScanMap
, Scanline
* pDstScanMap
, long const * pMapX
, const long* pMapY
)
72 const long nHeight1
= rDstBuffer
.mnHeight
- 1;
73 const ColorMask
& rSrcMask
= rSrcBuffer
.maColorMask
;
74 const ColorMask
& rDstMask
= rDstBuffer
.maColorMask
;
75 BitmapPalette
aColMap( rSrcBuffer
.maPalette
.GetEntryCount() );
76 BitmapColor
* pColMapBuf
= aColMap
.ImplGetColorBuffer();
77 BitmapColor
aIndex( 0 );
79 for( sal_uInt16 i
= 0, nSrcCount
= aColMap
.GetEntryCount(), nDstCount
= rDstBuffer
.maPalette
.GetEntryCount(); i
< nSrcCount
; i
++ )
81 if( ( i
< nDstCount
) && ( rSrcBuffer
.maPalette
[ i
] == rDstBuffer
.maPalette
[ i
] ) )
82 aIndex
.SetIndex( sal::static_int_cast
<sal_uInt8
>(i
) );
84 aIndex
.SetIndex( sal::static_int_cast
<sal_uInt8
>(rDstBuffer
.maPalette
.GetBestIndex( rSrcBuffer
.maPalette
[ i
] )) );
86 pColMapBuf
[ i
] = aIndex
;
89 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
91 long nMapY
= pMapY
[nActY
];
92 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
94 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
; ++nX
)
95 pFncSetPixel( pDstScan
, nX
, pColMapBuf
[ pFncGetPixel( pSrcScan
, pMapX
[ nX
], rSrcMask
).GetIndex() ], rDstMask
);
101 static void ImplPALToTC( const BitmapBuffer
& rSrcBuffer
, BitmapBuffer
const & rDstBuffer
,
102 FncGetPixel pFncGetPixel
, FncSetPixel pFncSetPixel
,
103 Scanline
* pSrcScanMap
, Scanline
* pDstScanMap
, long const * pMapX
, const long* pMapY
)
105 const long nHeight1
= rDstBuffer
.mnHeight
- 1;
106 const ColorMask
& rSrcMask
= rSrcBuffer
.maColorMask
;
107 const ColorMask
& rDstMask
= rDstBuffer
.maColorMask
;
108 const BitmapColor
* pColBuf
= rSrcBuffer
.maPalette
.ImplGetColorBuffer();
110 if( RemoveScanline( rSrcBuffer
.mnFormat
) == ScanlineFormat::N1BitMsbPal
)
112 const BitmapColor
aCol0( pColBuf
[ 0 ] );
113 const BitmapColor
aCol1( pColBuf
[ 1 ] );
116 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
118 long nMapY
= pMapY
[nActY
];
119 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
121 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
;)
124 pFncSetPixel( pDstScan
, nX
++,
125 pSrcScan
[ nMapX
>> 3 ] & ( 1 << ( 7 - ( nMapX
& 7 ) ) ) ? aCol1
: aCol0
,
132 else if( RemoveScanline( rSrcBuffer
.mnFormat
) == ScanlineFormat::N4BitMsnPal
)
136 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
138 long nMapY
= pMapY
[nActY
];
139 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
141 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
;)
144 pFncSetPixel( pDstScan
, nX
++,
145 pColBuf
[ ( pSrcScan
[ nMapX
>> 1 ] >> ( nMapX
& 1 ? 0 : 4 ) ) & 0x0f ],
152 else if( RemoveScanline( rSrcBuffer
.mnFormat
) == ScanlineFormat::N8BitPal
)
154 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
156 long nMapY
= pMapY
[nActY
];
157 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
159 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
; ++nX
)
160 pFncSetPixel( pDstScan
, nX
, pColBuf
[ pSrcScan
[ pMapX
[ nX
] ] ], rDstMask
);
167 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
169 long nMapY
= pMapY
[nActY
];
170 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
172 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
; ++nX
)
173 pFncSetPixel( pDstScan
, nX
, pColBuf
[ pFncGetPixel( pSrcScan
, pMapX
[ nX
], rSrcMask
).GetIndex() ], rDstMask
);
180 static void ImplTCToTC( const BitmapBuffer
& rSrcBuffer
, BitmapBuffer
const & rDstBuffer
,
181 FncGetPixel pFncGetPixel
, FncSetPixel pFncSetPixel
,
182 Scanline
* pSrcScanMap
, Scanline
* pDstScanMap
, long const * pMapX
, const long* pMapY
)
184 const long nHeight1
= rDstBuffer
.mnHeight
- 1;
185 const ColorMask
& rSrcMask
= rSrcBuffer
.maColorMask
;
186 const ColorMask
& rDstMask
= rDstBuffer
.maColorMask
;
188 if( RemoveScanline( rSrcBuffer
.mnFormat
) == ScanlineFormat::N24BitTcBgr
)
191 sal_uInt8
* pPixel
= nullptr;
193 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
195 long nMapY
= pMapY
[nActY
];
196 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
198 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
; ++nX
)
200 pPixel
= pSrcScan
+ pMapX
[ nX
] * 3;
201 aCol
.SetBlue( *pPixel
++ );
202 aCol
.SetGreen( *pPixel
++ );
203 aCol
.SetRed( *pPixel
);
204 pFncSetPixel( pDstScan
, nX
, aCol
, rDstMask
);
212 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
214 long nMapY
= pMapY
[nActY
];
215 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
217 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
; ++nX
)
218 pFncSetPixel( pDstScan
, nX
, pFncGetPixel( pSrcScan
, pMapX
[ nX
], rSrcMask
), rDstMask
);
225 static void ImplTCToPAL( const BitmapBuffer
& rSrcBuffer
, BitmapBuffer
const & rDstBuffer
,
226 FncGetPixel pFncGetPixel
, FncSetPixel pFncSetPixel
,
227 Scanline
* pSrcScanMap
, Scanline
* pDstScanMap
, long const * pMapX
, const long* pMapY
)
229 const long nHeight1
= rDstBuffer
.mnHeight
- 1;
230 const ColorMask
& rSrcMask
= rSrcBuffer
.maColorMask
;
231 const ColorMask
& rDstMask
= rDstBuffer
.maColorMask
;
232 BitmapPalette
aColMap( rSrcBuffer
.maPalette
.GetEntryCount() );
233 std::unique_ptr
<sal_uInt8
[]> pColToPalMap(new sal_uInt8
[ TC_TO_PAL_COLORS
]);
234 BitmapColor
aIndex( 0 );
236 for( long nR
= 0; nR
< 16; nR
++ )
238 for( long nG
= 0; nG
< 16; nG
++ )
240 for( long nB
= 0; nB
< 16; nB
++ )
242 BitmapColor
aCol( sal::static_int_cast
<sal_uInt8
>(nR
<< 4),
243 sal::static_int_cast
<sal_uInt8
>(nG
<< 4),
244 sal::static_int_cast
<sal_uInt8
>(nB
<< 4) );
245 pColToPalMap
[ ImplIndexFromColor( aCol
) ] = static_cast<sal_uInt8
>(rDstBuffer
.maPalette
.GetBestIndex( aCol
));
250 for (long nActY
= 0; nActY
< rDstBuffer
.mnHeight
; ++nActY
)
252 long nMapY
= pMapY
[nActY
];
253 Scanline
pSrcScan(pSrcScanMap
[nMapY
]), pDstScan(pDstScanMap
[nActY
]);
255 for (long nX
= 0; nX
< rDstBuffer
.mnWidth
; ++nX
)
257 aIndex
.SetIndex( pColToPalMap
[ ImplIndexFromColor( pFncGetPixel( pSrcScan
, pMapX
[ nX
], rSrcMask
) ) ] );
258 pFncSetPixel( pDstScan
, nX
, aIndex
, rDstMask
);
265 std::unique_ptr
<BitmapBuffer
> StretchAndConvert(
266 const BitmapBuffer
& rSrcBuffer
, const SalTwoRect
& rTwoRect
,
267 ScanlineFormat nDstBitmapFormat
, const BitmapPalette
* pDstPal
, const ColorMask
* pDstMask
)
269 FncGetPixel pFncGetPixel
;
270 FncSetPixel pFncSetPixel
;
271 std::unique_ptr
<BitmapBuffer
> pDstBuffer(new BitmapBuffer
);
273 // set function for getting pixels
274 switch( RemoveScanline( rSrcBuffer
.mnFormat
) )
276 IMPL_CASE_GET_FORMAT( N1BitMsbPal
);
277 IMPL_CASE_GET_FORMAT( N1BitLsbPal
);
278 IMPL_CASE_GET_FORMAT( N4BitMsnPal
);
279 IMPL_CASE_GET_FORMAT( N4BitLsnPal
);
280 IMPL_CASE_GET_FORMAT( N8BitPal
);
281 IMPL_CASE_GET_FORMAT( N8BitTcMask
);
282 IMPL_CASE_GET_FORMAT( N24BitTcBgr
);
283 IMPL_CASE_GET_FORMAT( N24BitTcRgb
);
284 IMPL_CASE_GET_FORMAT( N32BitTcAbgr
);
285 IMPL_CASE_GET_FORMAT( N32BitTcArgb
);
286 IMPL_CASE_GET_FORMAT( N32BitTcBgra
);
287 IMPL_CASE_GET_FORMAT( N32BitTcRgba
);
288 IMPL_CASE_GET_FORMAT( N32BitTcMask
);
291 // should never come here
292 // initialize pFncGetPixel to something valid that is
293 // least likely to crash
294 pFncGetPixel
= BitmapReadAccess::GetPixelForN1BitMsbPal
;
295 OSL_FAIL( "unknown read format" );
299 // set function for setting pixels
300 const ScanlineFormat nDstScanlineFormat
= RemoveScanline( nDstBitmapFormat
);
301 switch( nDstScanlineFormat
)
303 IMPL_CASE_SET_FORMAT( N1BitMsbPal
, 1 );
304 IMPL_CASE_SET_FORMAT( N1BitLsbPal
, 1 );
305 IMPL_CASE_SET_FORMAT( N4BitMsnPal
, 1 );
306 IMPL_CASE_SET_FORMAT( N4BitLsnPal
, 4 );
307 IMPL_CASE_SET_FORMAT( N8BitPal
, 8 );
308 IMPL_CASE_SET_FORMAT( N8BitTcMask
, 8 );
309 IMPL_CASE_SET_FORMAT( N24BitTcBgr
, 24 );
310 IMPL_CASE_SET_FORMAT( N24BitTcRgb
, 24 );
311 IMPL_CASE_SET_FORMAT( N32BitTcAbgr
, 32 );
312 IMPL_CASE_SET_FORMAT( N32BitTcArgb
, 32 );
313 IMPL_CASE_SET_FORMAT( N32BitTcBgra
, 32 );
314 IMPL_CASE_SET_FORMAT( N32BitTcRgba
, 32 );
315 IMPL_CASE_SET_FORMAT( N32BitTcMask
, 32 );
318 // should never come here
319 // initialize pFncSetPixel to something valid that is
320 // least likely to crash
321 pFncSetPixel
= BitmapReadAccess::SetPixelForN1BitMsbPal
;
322 pDstBuffer
->mnBitCount
= 1;
323 OSL_FAIL( "unknown write format" );
327 // fill destination buffer
328 pDstBuffer
->mnFormat
= nDstBitmapFormat
;
329 pDstBuffer
->mnWidth
= rTwoRect
.mnDestWidth
;
330 pDstBuffer
->mnHeight
= rTwoRect
.mnDestHeight
;
332 bool bFail
= o3tl::checked_multiply
<long>(pDstBuffer
->mnBitCount
, pDstBuffer
->mnWidth
, nScanlineBase
);
335 SAL_WARN("vcl.gdi", "checked multiply failed");
336 pDstBuffer
->mpBits
= nullptr;
339 pDstBuffer
->mnScanlineSize
= AlignedWidth4Bytes(nScanlineBase
);
340 if (pDstBuffer
->mnScanlineSize
< nScanlineBase
/8)
342 SAL_WARN("vcl.gdi", "scanline calculation wraparound");
343 pDstBuffer
->mpBits
= nullptr;
348 pDstBuffer
->mpBits
= new sal_uInt8
[ pDstBuffer
->mnScanlineSize
* pDstBuffer
->mnHeight
];
350 catch( const std::bad_alloc
& )
352 // memory exception, clean up
353 pDstBuffer
->mpBits
= nullptr;
357 // do we need a destination palette or color mask?
358 if( ( nDstScanlineFormat
== ScanlineFormat::N1BitMsbPal
) ||
359 ( nDstScanlineFormat
== ScanlineFormat::N1BitLsbPal
) ||
360 ( nDstScanlineFormat
== ScanlineFormat::N4BitMsnPal
) ||
361 ( nDstScanlineFormat
== ScanlineFormat::N4BitLsnPal
) ||
362 ( nDstScanlineFormat
== ScanlineFormat::N8BitPal
) )
364 assert(pDstPal
&& "destination buffer requires palette");
369 pDstBuffer
->maPalette
= *pDstPal
;
371 else if( ( nDstScanlineFormat
== ScanlineFormat::N8BitTcMask
) ||
372 ( nDstScanlineFormat
== ScanlineFormat::N32BitTcMask
) )
374 assert(pDstMask
&& "destination buffer requires color mask");
379 pDstBuffer
->maColorMask
= *pDstMask
;
382 // short circuit the most important conversions
383 bool bFastConvert
= ImplFastBitmapConversion( *pDstBuffer
, rSrcBuffer
, rTwoRect
);
387 std::unique_ptr
<Scanline
[]> pSrcScan
;
388 std::unique_ptr
<Scanline
[]> pDstScan
;
389 std::unique_ptr
<long[]> pMapX
;
390 std::unique_ptr
<long[]> pMapY
;
394 pSrcScan
.reset(new Scanline
[rSrcBuffer
.mnHeight
]);
395 pDstScan
.reset(new Scanline
[pDstBuffer
->mnHeight
]);
396 pMapX
.reset(new long[pDstBuffer
->mnWidth
]);
397 pMapY
.reset(new long[pDstBuffer
->mnHeight
]);
399 catch( const std::bad_alloc
& )
401 // memory exception, clean up
402 // remark: the buffer ptr causing the exception
403 // is still NULL here
407 // horizontal mapping table
408 if( (pDstBuffer
->mnWidth
!= rTwoRect
.mnSrcWidth
) && (pDstBuffer
->mnWidth
!= 0) )
410 const double fFactorX
= static_cast<double>(rTwoRect
.mnSrcWidth
) / pDstBuffer
->mnWidth
;
412 for (long i
= 0; i
< pDstBuffer
->mnWidth
; ++i
)
413 pMapX
[ i
] = rTwoRect
.mnSrcX
+ static_cast<int>( i
* fFactorX
);
417 for (long i
= 0, nTmp
= rTwoRect
.mnSrcX
; i
< pDstBuffer
->mnWidth
; ++i
)
421 // vertical mapping table
422 if( (pDstBuffer
->mnHeight
!= rTwoRect
.mnSrcHeight
) && (pDstBuffer
->mnHeight
!= 0) )
424 const double fFactorY
= static_cast<double>(rTwoRect
.mnSrcHeight
) / pDstBuffer
->mnHeight
;
426 for (long i
= 0; i
< pDstBuffer
->mnHeight
; ++i
)
427 pMapY
[ i
] = rTwoRect
.mnSrcY
+ static_cast<int>( i
* fFactorY
);
431 for (long i
= 0, nTmp
= rTwoRect
.mnSrcY
; i
< pDstBuffer
->mnHeight
; ++i
)
435 // source scanline buffer
438 if( rSrcBuffer
.mnFormat
& ScanlineFormat::TopDown
)
440 pTmpScan
= rSrcBuffer
.mpBits
;
441 nOffset
= rSrcBuffer
.mnScanlineSize
;
445 pTmpScan
= rSrcBuffer
.mpBits
+ ( rSrcBuffer
.mnHeight
- 1 ) * rSrcBuffer
.mnScanlineSize
;
446 nOffset
= -rSrcBuffer
.mnScanlineSize
;
449 for (long i
= 0; i
< rSrcBuffer
.mnHeight
; i
++, pTmpScan
+= nOffset
)
450 pSrcScan
[ i
] = pTmpScan
;
452 // destination scanline buffer
453 if( pDstBuffer
->mnFormat
& ScanlineFormat::TopDown
)
455 pTmpScan
= pDstBuffer
->mpBits
;
456 nOffset
= pDstBuffer
->mnScanlineSize
;
460 pTmpScan
= pDstBuffer
->mpBits
+ ( pDstBuffer
->mnHeight
- 1 ) * pDstBuffer
->mnScanlineSize
;
461 nOffset
= -pDstBuffer
->mnScanlineSize
;
464 for (long i
= 0; i
< pDstBuffer
->mnHeight
; i
++, pTmpScan
+= nOffset
)
465 pDstScan
[ i
] = pTmpScan
;
467 // do buffer scaling and conversion
468 if( rSrcBuffer
.mnBitCount
<= 8 && pDstBuffer
->mnBitCount
<= 8 )
470 ImplPALToPAL( rSrcBuffer
, *pDstBuffer
, pFncGetPixel
, pFncSetPixel
,
471 pSrcScan
.get(), pDstScan
.get(), pMapX
.get(), pMapY
.get() );
473 else if( rSrcBuffer
.mnBitCount
<= 8 && pDstBuffer
->mnBitCount
> 8 )
475 ImplPALToTC( rSrcBuffer
, *pDstBuffer
, pFncGetPixel
, pFncSetPixel
,
476 pSrcScan
.get(), pDstScan
.get(), pMapX
.get(), pMapY
.get() );
478 else if( rSrcBuffer
.mnBitCount
> 8 && pDstBuffer
->mnBitCount
> 8 )
480 ImplTCToTC( rSrcBuffer
, *pDstBuffer
, pFncGetPixel
, pFncSetPixel
,
481 pSrcScan
.get(), pDstScan
.get(), pMapX
.get(), pMapY
.get() );
485 ImplTCToPAL( rSrcBuffer
, *pDstBuffer
, pFncGetPixel
, pFncSetPixel
,
486 pSrcScan
.get(), pDstScan
.get(), pMapX
.get(), pMapY
.get() );
492 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */