update credits
[LibreOffice.git] / vcl / source / gdi / salmisc.cxx
blob79e554e47fab18e054d34df126ec7113dd4bd682
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/salbtype.hxx>
22 #include <bmpfast.hxx>
24 #define IMPL_CASE_GET_FORMAT( Format ) \
25 case( BMP_FORMAT##Format ): \
26 pFncGetPixel = BitmapReadAccess::GetPixelFor##Format; \
27 break
29 #define IMPL_CASE_SET_FORMAT( Format, BitCount ) \
30 case( BMP_FORMAT##Format ): \
31 { \
32 pFncSetPixel = BitmapReadAccess::SetPixelFor##Format; \
33 pDstBuffer->mnBitCount = BitCount; \
34 } \
35 break
37 #define DOUBLE_SCANLINES() \
38 while( ( nActY < nHeight1 ) && ( pMapY[ nActY + 1 ] == nMapY ) ) \
39 { \
40 memcpy( pDstScanMap[ nActY + 1L ], pDstScan, rDstBuffer.mnScanlineSize ); \
41 nActY++; \
44 #define TC_TO_PAL_COLORS 4096
46 static long ImplIndexFromColor( const BitmapColor& rCol )
48 #if TC_TO_PAL_COLORS == 4096
50 return( ( ( (long) rCol.GetBlue() >> 4L) << 8L ) |
51 ( ( (long) rCol.GetGreen() >> 4L ) << 4L ) |
52 ( (long) rCol.GetRed() >> 4L ) );
54 #elif TC_TO_PAL_COLORS == 32768
56 return( ( ( (long) rCol.GetBlue() >> 3L) << 10L ) |
57 ( ( (long) rCol.GetGreen() >> 3L ) << 5L ) |
58 ( (long) rCol.GetRed() >> 3L ) );
60 #endif
63 static void ImplPALToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
64 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
65 Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
67 const long nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1;
68 const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
69 const ColorMask& rDstMask = rDstBuffer.maColorMask;
70 BitmapPalette aColMap( rSrcBuffer.maPalette.GetEntryCount() );
71 BitmapColor* pColMapBuf = aColMap.ImplGetColorBuffer();
72 BitmapColor aIndex( 0 );
74 for( sal_uInt16 i = 0, nSrcCount = aColMap.GetEntryCount(), nDstCount = rDstBuffer.maPalette.GetEntryCount(); i < nSrcCount; i++ )
76 if( ( i < nDstCount ) && ( rSrcBuffer.maPalette[ i ] == rDstBuffer.maPalette[ i ] ) )
77 aIndex.SetIndex( sal::static_int_cast<sal_uInt8>(i) );
78 else
79 aIndex.SetIndex( sal::static_int_cast<sal_uInt8>(rDstBuffer.maPalette.GetBestIndex( rSrcBuffer.maPalette[ i ] )) );
81 pColMapBuf[ i ] = aIndex;
84 for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
86 Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
88 for( long nX = 0L; nX < nWidth; nX++ )
89 pFncSetPixel( pDstScan, nX, pColMapBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask );
91 DOUBLE_SCANLINES();
95 static void ImplPALToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
96 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
97 Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
99 const long nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1;
100 const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
101 const ColorMask& rDstMask = rDstBuffer.maColorMask;
102 const BitmapColor* pColBuf = rSrcBuffer.maPalette.ImplGetColorBuffer();
104 if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_1BIT_MSB_PAL )
106 const BitmapColor aCol0( pColBuf[ 0 ] );
107 const BitmapColor aCol1( pColBuf[ 1 ] );
108 long nMapX;
110 for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
112 Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
114 for( long nX = 0L; nX < nWidth; )
116 nMapX = pMapX[ nX ];
117 pFncSetPixel( pDstScan, nX++,
118 pSrcScan[ nMapX >> 3 ] & ( 1 << ( 7 - ( nMapX & 7 ) ) ) ? aCol1 : aCol0,
119 rDstMask );
122 DOUBLE_SCANLINES();
125 else if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_4BIT_MSN_PAL )
127 long nMapX;
129 for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
131 Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
133 for( long nX = 0L; nX < nWidth; )
135 nMapX = pMapX[ nX ];
136 pFncSetPixel( pDstScan, nX++,
137 pColBuf[ ( pSrcScan[ nMapX >> 1 ] >> ( nMapX & 1 ? 0 : 4 ) ) & 0x0f ],
138 rDstMask );
141 DOUBLE_SCANLINES();
144 else if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_8BIT_PAL )
146 for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
148 Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
150 for( long nX = 0L; nX < nWidth; nX++ )
151 pFncSetPixel( pDstScan, nX, pColBuf[ pSrcScan[ pMapX[ nX ] ] ], rDstMask );
153 DOUBLE_SCANLINES();
156 else
158 for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
160 Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
162 for( long nX = 0L; nX < nWidth; nX++ )
163 pFncSetPixel( pDstScan, nX, pColBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask );
165 DOUBLE_SCANLINES();
170 static void ImplTCToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
171 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
172 Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
174 const long nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1;
175 const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
176 const ColorMask& rDstMask = rDstBuffer.maColorMask;
178 if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_24BIT_TC_BGR )
180 BitmapColor aCol;
181 sal_uInt8* pPixel = NULL;
183 for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
185 Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
187 for( long nX = 0L; nX < nWidth; nX++ )
189 aCol.SetBlue( *( pPixel = ( pSrcScan + pMapX[ nX ] * 3 ) )++ );
190 aCol.SetGreen( *pPixel++ );
191 aCol.SetRed( *pPixel );
192 pFncSetPixel( pDstScan, nX, aCol, rDstMask );
195 DOUBLE_SCANLINES()
198 else
200 for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
202 Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
204 for( long nX = 0L; nX < nWidth; nX++ )
205 pFncSetPixel( pDstScan, nX, pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ), rDstMask );
207 DOUBLE_SCANLINES();
212 static void ImplTCToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
213 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
214 Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
216 const long nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1;
217 const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
218 const ColorMask& rDstMask = rDstBuffer.maColorMask;
219 BitmapPalette aColMap( rSrcBuffer.maPalette.GetEntryCount() );
220 sal_uInt8* pColToPalMap = new sal_uInt8[ TC_TO_PAL_COLORS ];
221 BitmapColor aIndex( 0 );
223 for( long nR = 0; nR < 16; nR++ )
225 for( long nG = 0; nG < 16; nG++ )
227 for( long nB = 0; nB < 16; nB++ )
229 BitmapColor aCol( sal::static_int_cast<sal_uInt8>(nR << 4),
230 sal::static_int_cast<sal_uInt8>(nG << 4),
231 sal::static_int_cast<sal_uInt8>(nB << 4) );
232 pColToPalMap[ ImplIndexFromColor( aCol ) ] = (sal_uInt8) rDstBuffer.maPalette.GetBestIndex( aCol );
237 for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
239 Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
241 for( long nX = 0L; nX < nWidth; nX++ )
243 aIndex.SetIndex( pColToPalMap[ ImplIndexFromColor( pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ) ) ] );
244 pFncSetPixel( pDstScan, nX, aIndex, rDstMask );
247 DOUBLE_SCANLINES();
250 delete[] pColToPalMap;
253 BitmapBuffer* StretchAndConvert( const BitmapBuffer& rSrcBuffer, const SalTwoRect& rTwoRect,
254 sal_uLong nDstBitmapFormat, BitmapPalette* pDstPal, ColorMask* pDstMask )
256 FncGetPixel pFncGetPixel;
257 FncSetPixel pFncSetPixel;
258 BitmapBuffer* pDstBuffer = new BitmapBuffer;
259 long i;
261 // set function for getting pixels
262 switch( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) )
264 IMPL_CASE_GET_FORMAT( _1BIT_MSB_PAL );
265 IMPL_CASE_GET_FORMAT( _1BIT_LSB_PAL );
266 IMPL_CASE_GET_FORMAT( _4BIT_MSN_PAL );
267 IMPL_CASE_GET_FORMAT( _4BIT_LSN_PAL );
268 IMPL_CASE_GET_FORMAT( _8BIT_PAL );
269 IMPL_CASE_GET_FORMAT( _8BIT_TC_MASK );
270 IMPL_CASE_GET_FORMAT( _16BIT_TC_MSB_MASK );
271 IMPL_CASE_GET_FORMAT( _16BIT_TC_LSB_MASK );
272 IMPL_CASE_GET_FORMAT( _24BIT_TC_BGR );
273 IMPL_CASE_GET_FORMAT( _24BIT_TC_RGB );
274 IMPL_CASE_GET_FORMAT( _24BIT_TC_MASK );
275 IMPL_CASE_GET_FORMAT( _32BIT_TC_ABGR );
276 IMPL_CASE_GET_FORMAT( _32BIT_TC_ARGB );
277 IMPL_CASE_GET_FORMAT( _32BIT_TC_BGRA );
278 IMPL_CASE_GET_FORMAT( _32BIT_TC_RGBA );
279 IMPL_CASE_GET_FORMAT( _32BIT_TC_MASK );
281 default:
282 // should never come here
283 // initialize pFncGetPixel to something valid that is
284 // least likely to crash
285 pFncGetPixel = BitmapReadAccess::GetPixelFor_1BIT_MSB_PAL;
286 OSL_FAIL( "unknown read format" );
287 break;
290 // set function for setting pixels
291 const sal_uLong nDstScanlineFormat = BMP_SCANLINE_FORMAT( nDstBitmapFormat );
292 switch( nDstScanlineFormat )
294 IMPL_CASE_SET_FORMAT( _1BIT_MSB_PAL, 1 );
295 IMPL_CASE_SET_FORMAT( _1BIT_LSB_PAL, 1 );
296 IMPL_CASE_SET_FORMAT( _4BIT_MSN_PAL, 1 );
297 IMPL_CASE_SET_FORMAT( _4BIT_LSN_PAL, 4 );
298 IMPL_CASE_SET_FORMAT( _8BIT_PAL, 8 );
299 IMPL_CASE_SET_FORMAT( _8BIT_TC_MASK, 8 );
300 IMPL_CASE_SET_FORMAT( _16BIT_TC_MSB_MASK, 16 );
301 IMPL_CASE_SET_FORMAT( _16BIT_TC_LSB_MASK, 16 );
302 IMPL_CASE_SET_FORMAT( _24BIT_TC_BGR, 24 );
303 IMPL_CASE_SET_FORMAT( _24BIT_TC_RGB, 24 );
304 IMPL_CASE_SET_FORMAT( _24BIT_TC_MASK, 24 );
305 IMPL_CASE_SET_FORMAT( _32BIT_TC_ABGR, 32 );
306 IMPL_CASE_SET_FORMAT( _32BIT_TC_ARGB, 32 );
307 IMPL_CASE_SET_FORMAT( _32BIT_TC_BGRA, 32 );
308 IMPL_CASE_SET_FORMAT( _32BIT_TC_RGBA, 32 );
309 IMPL_CASE_SET_FORMAT( _32BIT_TC_MASK, 32 );
311 default:
312 // should never come here
313 // initialize pFncSetPixel to something valid that is
314 // least likely to crash
315 pFncSetPixel = BitmapReadAccess::SetPixelFor_1BIT_MSB_PAL;
316 pDstBuffer->mnBitCount = 1;
317 OSL_FAIL( "unknown write format" );
318 break;
321 // fill destination buffer
322 pDstBuffer->mnFormat = nDstBitmapFormat;
323 pDstBuffer->mnWidth = rTwoRect.mnDestWidth;
324 pDstBuffer->mnHeight = rTwoRect.mnDestHeight;
325 pDstBuffer->mnScanlineSize = AlignedWidth4Bytes( pDstBuffer->mnBitCount * pDstBuffer->mnWidth );
328 pDstBuffer->mpBits = new sal_uInt8[ pDstBuffer->mnScanlineSize * pDstBuffer->mnHeight ];
330 catch( const std::bad_alloc& )
332 // memory exception, clean up
333 pDstBuffer->mpBits = NULL;
334 delete pDstBuffer;
335 return NULL;
338 // do we need a destination palette or color mask?
339 if( ( nDstScanlineFormat == BMP_FORMAT_1BIT_MSB_PAL ) ||
340 ( nDstScanlineFormat == BMP_FORMAT_1BIT_LSB_PAL ) ||
341 ( nDstScanlineFormat == BMP_FORMAT_4BIT_MSN_PAL ) ||
342 ( nDstScanlineFormat == BMP_FORMAT_4BIT_LSN_PAL ) ||
343 ( nDstScanlineFormat == BMP_FORMAT_8BIT_PAL ) )
345 DBG_ASSERT( pDstPal, "destination buffer requires palette" );
346 pDstBuffer->maPalette = *pDstPal;
348 else if( ( nDstScanlineFormat == BMP_FORMAT_8BIT_TC_MASK ) ||
349 ( nDstScanlineFormat == BMP_FORMAT_16BIT_TC_MSB_MASK ) ||
350 ( nDstScanlineFormat == BMP_FORMAT_16BIT_TC_LSB_MASK ) ||
351 ( nDstScanlineFormat == BMP_FORMAT_24BIT_TC_MASK ) ||
352 ( nDstScanlineFormat == BMP_FORMAT_32BIT_TC_MASK ) )
354 DBG_ASSERT( pDstMask, "destination buffer requires color mask" );
355 pDstBuffer->maColorMask = *pDstMask;
358 // short circuit the most important conversions
359 bool bFastConvert = ImplFastBitmapConversion( *pDstBuffer, rSrcBuffer, rTwoRect );
360 if( bFastConvert )
361 return pDstBuffer;
363 const long nSrcX = rTwoRect.mnSrcX, nSrcY = rTwoRect.mnSrcY;
364 const long nSrcDX = rTwoRect.mnSrcWidth, nSrcDY = rTwoRect.mnSrcHeight;
365 const long nDstDX = rTwoRect.mnDestWidth, nDstDY = rTwoRect.mnDestHeight;
366 Scanline* pSrcScan = NULL;
367 Scanline* pDstScan = NULL;
368 long* pMapX = NULL;
369 long* pMapY = NULL;
370 long nTmp, nOffset;
374 pSrcScan = new Scanline[ rSrcBuffer.mnHeight ];
375 pDstScan = new Scanline[ nDstDY ];
376 pMapX = new long[ nDstDX ];
377 pMapY = new long[ nDstDY ];
379 catch( const std::bad_alloc& )
381 // memory exception, clean up
382 // remark: the buffer ptr causing the exception
383 // is still NULL here
384 delete[] pSrcScan;
385 delete[] pDstScan;
386 delete[] pMapX;
387 delete[] pMapY;
388 delete pDstBuffer;
389 return NULL;
392 // horizontal mapping table
393 if( nDstDX != nSrcDX )
395 const double fFactorX = ( nDstDX > 1 ) ? (double) ( nSrcDX - 1 ) / ( nDstDX - 1 ) : 0.0;
397 for( i = 0L; i < nDstDX; i++ )
398 pMapX[ i ] = nSrcX + FRound( i * fFactorX );
400 else
402 for( i = 0L, nTmp = nSrcX; i < nDstDX; i++ )
403 pMapX[ i ] = nTmp++;
406 // vertical mapping table
407 if( nDstDY != nSrcDY )
409 const double fFactorY = ( nDstDY > 1 ) ? (double) ( nSrcDY - 1 ) / ( nDstDY - 1 ) : 0.0;
411 for( i = 0L; i < nDstDY; i++ )
412 pMapY[ i ] = nSrcY + FRound( i * fFactorY );
414 else
416 for( i = 0L, nTmp = nSrcY; i < nDstDY; i++ )
417 pMapY[ i ] = nTmp++;
420 // source scanline buffer
421 Scanline pTmpScan;
422 if( BMP_SCANLINE_ADJUSTMENT( rSrcBuffer.mnFormat ) == BMP_FORMAT_TOP_DOWN )
423 pTmpScan = rSrcBuffer.mpBits, nOffset = rSrcBuffer.mnScanlineSize;
424 else
426 pTmpScan = rSrcBuffer.mpBits + ( rSrcBuffer.mnHeight - 1 ) * rSrcBuffer.mnScanlineSize;
427 nOffset = -rSrcBuffer.mnScanlineSize;
430 for( i = 0L; i < rSrcBuffer.mnHeight; i++, pTmpScan += nOffset )
431 pSrcScan[ i ] = pTmpScan;
433 // destination scanline buffer
434 if( BMP_SCANLINE_ADJUSTMENT( pDstBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
435 pTmpScan = pDstBuffer->mpBits, nOffset = pDstBuffer->mnScanlineSize;
436 else
438 pTmpScan = pDstBuffer->mpBits + ( nDstDY - 1 ) * pDstBuffer->mnScanlineSize;
439 nOffset = -pDstBuffer->mnScanlineSize;
442 for( i = 0L; i < nDstDY; i++, pTmpScan += nOffset )
443 pDstScan[ i ] = pTmpScan;
445 // do buffer scaling and conversion
446 if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount <= 8 )
448 ImplPALToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
449 pSrcScan, pDstScan, pMapX, pMapY );
451 else if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount > 8 )
453 ImplPALToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
454 pSrcScan, pDstScan, pMapX, pMapY );
456 else if( rSrcBuffer.mnBitCount > 8 && pDstBuffer->mnBitCount > 8 )
458 ImplTCToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
459 pSrcScan, pDstScan, pMapX, pMapY );
461 else
463 ImplTCToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
464 pSrcScan, pDstScan, pMapX, pMapY );
467 // cleanup
468 delete[] pSrcScan;
469 delete[] pDstScan;
470 delete[] pMapX;
471 delete[] pMapY;
473 return pDstBuffer;
476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */