1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: salmisc.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
33 #include <rtl/memory.h>
34 #include <vcl/bmpacc.hxx>
35 #include <vcl/salbtype.hxx>
36 #include <vcl/bmpfast.hxx>
42 #define IMPL_CASE_GET_FORMAT( Format ) \
43 case( BMP_FORMAT##Format ): \
44 pFncGetPixel = BitmapReadAccess::GetPixelFor##Format; \
47 // -----------------------------------------------------------------------------
49 #define IMPL_CASE_SET_FORMAT( Format, BitCount ) \
50 case( BMP_FORMAT##Format ): \
52 pFncSetPixel = BitmapReadAccess::SetPixelFor##Format; \
53 pDstBuffer->mnBitCount = BitCount; \
57 // -----------------------------------------------------------------------------
59 #define DOUBLE_SCANLINES() \
60 while( ( nActY < nHeight1 ) && ( pMapY[ nActY + 1 ] == nMapY ) ) \
62 memcpy( pDstScanMap[ nActY + 1L ], pDstScan, rDstBuffer.mnScanlineSize ); \
70 #define TC_TO_PAL_COLORS 4096
72 static long ImplIndexFromColor( const BitmapColor
& rCol
)
74 #if TC_TO_PAL_COLORS == 4096
76 return( ( ( (long) rCol
.GetBlue() >> 4L) << 8L ) |
77 ( ( (long) rCol
.GetGreen() >> 4L ) << 4L ) |
78 ( (long) rCol
.GetRed() >> 4L ) );
80 #elif TC_TO_PAL_COLORS == 32768
82 return( ( ( (long) rCol
.GetBlue() >> 3L) << 10L ) |
83 ( ( (long) rCol
.GetGreen() >> 3L ) << 5L ) |
84 ( (long) rCol
.GetRed() >> 3L ) );
90 #define COLOR_TO_INDEX( _def_rCol )
92 // ------------------------
93 // - conversion functions -
94 // ------------------------
96 static void ImplPALToPAL( const BitmapBuffer
& rSrcBuffer
, BitmapBuffer
& rDstBuffer
,
97 FncGetPixel pFncGetPixel
, FncSetPixel pFncSetPixel
,
98 Scanline
* pSrcScanMap
, Scanline
* pDstScanMap
, long* pMapX
, long* pMapY
)
100 const long nWidth
= rDstBuffer
.mnWidth
, nHeight
= rDstBuffer
.mnHeight
, nHeight1
= nHeight
- 1;
101 const ColorMask
& rSrcMask
= rSrcBuffer
.maColorMask
;
102 const ColorMask
& rDstMask
= rDstBuffer
.maColorMask
;
103 BitmapPalette
aColMap( rSrcBuffer
.maPalette
.GetEntryCount() );
104 BitmapColor
* pColMapBuf
= aColMap
.ImplGetColorBuffer();
105 BitmapColor
aIndex( 0 );
107 for( USHORT i
= 0, nSrcCount
= aColMap
.GetEntryCount(), nDstCount
= rDstBuffer
.maPalette
.GetEntryCount(); i
< nSrcCount
; i
++ )
109 if( ( i
< nDstCount
) && ( rSrcBuffer
.maPalette
[ i
] == rDstBuffer
.maPalette
[ i
] ) )
110 aIndex
.SetIndex( sal::static_int_cast
<BYTE
>(i
) );
112 aIndex
.SetIndex( sal::static_int_cast
<BYTE
>(rDstBuffer
.maPalette
.GetBestIndex( rSrcBuffer
.maPalette
[ i
] )) );
114 pColMapBuf
[ i
] = aIndex
;
117 for( long nActY
= 0, nMapY
; nActY
< nHeight
; nActY
++ )
119 Scanline
pSrcScan( pSrcScanMap
[ nMapY
= pMapY
[ nActY
] ] ), pDstScan( pDstScanMap
[ nActY
] );
121 for( long nX
= 0L; nX
< nWidth
; nX
++ )
122 pFncSetPixel( pDstScan
, nX
, pColMapBuf
[ pFncGetPixel( pSrcScan
, pMapX
[ nX
], rSrcMask
).GetIndex() ], rDstMask
);
128 // -----------------------------------------------------------------------------
130 static void ImplPALToTC( const BitmapBuffer
& rSrcBuffer
, BitmapBuffer
& rDstBuffer
,
131 FncGetPixel pFncGetPixel
, FncSetPixel pFncSetPixel
,
132 Scanline
* pSrcScanMap
, Scanline
* pDstScanMap
, long* pMapX
, long* pMapY
)
134 const long nWidth
= rDstBuffer
.mnWidth
, nHeight
= rDstBuffer
.mnHeight
, nHeight1
= nHeight
- 1;
135 const ColorMask
& rSrcMask
= rSrcBuffer
.maColorMask
;
136 const ColorMask
& rDstMask
= rDstBuffer
.maColorMask
;
137 const BitmapColor
* pColBuf
= rSrcBuffer
.maPalette
.ImplGetColorBuffer();
139 if( BMP_SCANLINE_FORMAT( rSrcBuffer
.mnFormat
) == BMP_FORMAT_1BIT_MSB_PAL
)
141 const BitmapColor
aCol0( pColBuf
[ 0 ] );
142 const BitmapColor
aCol1( pColBuf
[ 1 ] );
145 for( long nActY
= 0, nMapY
; nActY
< nHeight
; nActY
++ )
147 Scanline
pSrcScan( pSrcScanMap
[ nMapY
= pMapY
[ nActY
] ] ), pDstScan( pDstScanMap
[ nActY
] );
149 for( long nX
= 0L; nX
< nWidth
; )
152 pFncSetPixel( pDstScan
, nX
++,
153 pSrcScan
[ nMapX
>> 3 ] & ( 1 << ( 7 - ( nMapX
& 7 ) ) ) ? aCol1
: aCol0
,
160 else if( BMP_SCANLINE_FORMAT( rSrcBuffer
.mnFormat
) == BMP_FORMAT_4BIT_MSN_PAL
)
164 for( long nActY
= 0, nMapY
; nActY
< nHeight
; nActY
++ )
166 Scanline
pSrcScan( pSrcScanMap
[ nMapY
= pMapY
[ nActY
] ] ), pDstScan( pDstScanMap
[ nActY
] );
168 for( long nX
= 0L; nX
< nWidth
; )
171 pFncSetPixel( pDstScan
, nX
++,
172 pColBuf
[ ( pSrcScan
[ nMapX
>> 1 ] >> ( nMapX
& 1 ? 0 : 4 ) ) & 0x0f ],
179 else if( BMP_SCANLINE_FORMAT( rSrcBuffer
.mnFormat
) == BMP_FORMAT_8BIT_PAL
)
181 for( long nActY
= 0, nMapY
; nActY
< nHeight
; nActY
++ )
183 Scanline
pSrcScan( pSrcScanMap
[ nMapY
= pMapY
[ nActY
] ] ), pDstScan( pDstScanMap
[ nActY
] );
185 for( long nX
= 0L; nX
< nWidth
; nX
++ )
186 pFncSetPixel( pDstScan
, nX
, pColBuf
[ pSrcScan
[ pMapX
[ nX
] ] ], rDstMask
);
193 for( long nActY
= 0, nMapY
; nActY
< nHeight
; nActY
++ )
195 Scanline
pSrcScan( pSrcScanMap
[ nMapY
= pMapY
[ nActY
] ] ), pDstScan( pDstScanMap
[ nActY
] );
197 for( long nX
= 0L; nX
< nWidth
; nX
++ )
198 pFncSetPixel( pDstScan
, nX
, pColBuf
[ pFncGetPixel( pSrcScan
, pMapX
[ nX
], rSrcMask
).GetIndex() ], rDstMask
);
205 // -----------------------------------------------------------------------------
207 static void ImplTCToTC( const BitmapBuffer
& rSrcBuffer
, BitmapBuffer
& rDstBuffer
,
208 FncGetPixel pFncGetPixel
, FncSetPixel pFncSetPixel
,
209 Scanline
* pSrcScanMap
, Scanline
* pDstScanMap
, long* pMapX
, long* pMapY
)
211 const long nWidth
= rDstBuffer
.mnWidth
, nHeight
= rDstBuffer
.mnHeight
, nHeight1
= nHeight
- 1;
212 const ColorMask
& rSrcMask
= rSrcBuffer
.maColorMask
;
213 const ColorMask
& rDstMask
= rDstBuffer
.maColorMask
;
215 if( BMP_SCANLINE_FORMAT( rSrcBuffer
.mnFormat
) == BMP_FORMAT_24BIT_TC_BGR
)
220 for( long nActY
= 0, nMapY
; nActY
< nHeight
; nActY
++ )
222 Scanline
pSrcScan( pSrcScanMap
[ nMapY
= pMapY
[ nActY
] ] ), pDstScan( pDstScanMap
[ nActY
] );
224 for( long nX
= 0L; nX
< nWidth
; nX
++ )
226 aCol
.SetBlue( *( pPixel
= ( pSrcScan
+ pMapX
[ nX
] * 3 ) )++ );
227 aCol
.SetGreen( *pPixel
++ );
228 aCol
.SetRed( *pPixel
);
229 pFncSetPixel( pDstScan
, nX
, aCol
, rDstMask
);
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
++ )
242 pFncSetPixel( pDstScan
, nX
, pFncGetPixel( pSrcScan
, pMapX
[ nX
], rSrcMask
), rDstMask
);
249 // -----------------------------------------------------------------------------
251 static void ImplTCToPAL( const BitmapBuffer
& rSrcBuffer
, BitmapBuffer
& rDstBuffer
,
252 FncGetPixel pFncGetPixel
, FncSetPixel pFncSetPixel
,
253 Scanline
* pSrcScanMap
, Scanline
* pDstScanMap
, long* pMapX
, long* pMapY
)
255 const long nWidth
= rDstBuffer
.mnWidth
, nHeight
= rDstBuffer
.mnHeight
, nHeight1
= nHeight
- 1;
256 const ColorMask
& rSrcMask
= rSrcBuffer
.maColorMask
;
257 const ColorMask
& rDstMask
= rDstBuffer
.maColorMask
;
258 BitmapPalette
aColMap( rSrcBuffer
.maPalette
.GetEntryCount() );
259 BYTE
* pColToPalMap
= new BYTE
[ TC_TO_PAL_COLORS
];
260 BitmapColor
aIndex( 0 );
262 for( long nR
= 0; nR
< 16; nR
++ )
264 for( long nG
= 0; nG
< 16; nG
++ )
266 for( long nB
= 0; nB
< 16; nB
++ )
268 BitmapColor
aCol( sal::static_int_cast
<BYTE
>(nR
<< 4),
269 sal::static_int_cast
<BYTE
>(nG
<< 4),
270 sal::static_int_cast
<BYTE
>(nB
<< 4) );
271 pColToPalMap
[ ImplIndexFromColor( aCol
) ] = (BYTE
) rDstBuffer
.maPalette
.GetBestIndex( aCol
);
276 for( long nActY
= 0, nMapY
; nActY
< nHeight
; nActY
++ )
278 Scanline
pSrcScan( pSrcScanMap
[ nMapY
= pMapY
[ nActY
] ] ), pDstScan( pDstScanMap
[ nActY
] );
280 for( long nX
= 0L; nX
< nWidth
; nX
++ )
282 aIndex
.SetIndex( pColToPalMap
[ ImplIndexFromColor( pFncGetPixel( pSrcScan
, pMapX
[ nX
], rSrcMask
) ) ] );
283 pFncSetPixel( pDstScan
, nX
, aIndex
, rDstMask
);
289 delete[] pColToPalMap
;
292 // -----------------------------------------------------------------------------
294 // ---------------------
295 // - StretchAndConvert -
296 // ---------------------
298 BitmapBuffer
* StretchAndConvert( const BitmapBuffer
& rSrcBuffer
, const SalTwoRect
& rTwoRect
,
299 ULONG nDstBitmapFormat
, BitmapPalette
* pDstPal
, ColorMask
* pDstMask
)
301 FncGetPixel pFncGetPixel
;
302 FncSetPixel pFncSetPixel
;
303 BitmapBuffer
* pDstBuffer
= new BitmapBuffer
;
306 // set function for getting pixels
307 switch( BMP_SCANLINE_FORMAT( rSrcBuffer
.mnFormat
) )
309 IMPL_CASE_GET_FORMAT( _1BIT_MSB_PAL
);
310 IMPL_CASE_GET_FORMAT( _1BIT_LSB_PAL
);
311 IMPL_CASE_GET_FORMAT( _4BIT_MSN_PAL
);
312 IMPL_CASE_GET_FORMAT( _4BIT_LSN_PAL
);
313 IMPL_CASE_GET_FORMAT( _8BIT_PAL
);
314 IMPL_CASE_GET_FORMAT( _8BIT_TC_MASK
);
315 IMPL_CASE_GET_FORMAT( _16BIT_TC_MSB_MASK
);
316 IMPL_CASE_GET_FORMAT( _16BIT_TC_LSB_MASK
);
317 IMPL_CASE_GET_FORMAT( _24BIT_TC_BGR
);
318 IMPL_CASE_GET_FORMAT( _24BIT_TC_RGB
);
319 IMPL_CASE_GET_FORMAT( _24BIT_TC_MASK
);
320 IMPL_CASE_GET_FORMAT( _32BIT_TC_ABGR
);
321 IMPL_CASE_GET_FORMAT( _32BIT_TC_ARGB
);
322 IMPL_CASE_GET_FORMAT( _32BIT_TC_BGRA
);
323 IMPL_CASE_GET_FORMAT( _32BIT_TC_RGBA
);
324 IMPL_CASE_GET_FORMAT( _32BIT_TC_MASK
);
327 // should never come here
328 // initialize pFncGetPixel to something valid that is
329 // least likely to crash
330 pFncGetPixel
= BitmapReadAccess::GetPixelFor_1BIT_MSB_PAL
;
331 DBG_ERROR( "unknown read format" );
335 // set function for setting pixels
336 const ULONG nDstScanlineFormat
= BMP_SCANLINE_FORMAT( nDstBitmapFormat
);
337 switch( nDstScanlineFormat
)
339 IMPL_CASE_SET_FORMAT( _1BIT_MSB_PAL
, 1 );
340 IMPL_CASE_SET_FORMAT( _1BIT_LSB_PAL
, 1 );
341 IMPL_CASE_SET_FORMAT( _4BIT_MSN_PAL
, 1 );
342 IMPL_CASE_SET_FORMAT( _4BIT_LSN_PAL
, 4 );
343 IMPL_CASE_SET_FORMAT( _8BIT_PAL
, 8 );
344 IMPL_CASE_SET_FORMAT( _8BIT_TC_MASK
, 8 );
345 IMPL_CASE_SET_FORMAT( _16BIT_TC_MSB_MASK
, 16 );
346 IMPL_CASE_SET_FORMAT( _16BIT_TC_LSB_MASK
, 16 );
347 IMPL_CASE_SET_FORMAT( _24BIT_TC_BGR
, 24 );
348 IMPL_CASE_SET_FORMAT( _24BIT_TC_RGB
, 24 );
349 IMPL_CASE_SET_FORMAT( _24BIT_TC_MASK
, 24 );
350 IMPL_CASE_SET_FORMAT( _32BIT_TC_ABGR
, 32 );
351 IMPL_CASE_SET_FORMAT( _32BIT_TC_ARGB
, 32 );
352 IMPL_CASE_SET_FORMAT( _32BIT_TC_BGRA
, 32 );
353 IMPL_CASE_SET_FORMAT( _32BIT_TC_RGBA
, 32 );
354 IMPL_CASE_SET_FORMAT( _32BIT_TC_MASK
, 32 );
357 // should never come here
358 // initialize pFncSetPixel to something valid that is
359 // least likely to crash
360 pFncSetPixel
= BitmapReadAccess::SetPixelFor_1BIT_MSB_PAL
;
361 pDstBuffer
->mnBitCount
= 1;
362 DBG_ERROR( "unknown write format" );
366 // fill destination buffer
367 pDstBuffer
->mnFormat
= nDstBitmapFormat
;
368 pDstBuffer
->mnWidth
= rTwoRect
.mnDestWidth
;
369 pDstBuffer
->mnHeight
= rTwoRect
.mnDestHeight
;
370 pDstBuffer
->mnScanlineSize
= AlignedWidth4Bytes( pDstBuffer
->mnBitCount
* pDstBuffer
->mnWidth
);
373 pDstBuffer
->mpBits
= new BYTE
[ pDstBuffer
->mnScanlineSize
* pDstBuffer
->mnHeight
];
375 catch( const std::bad_alloc
& )
377 // memory exception, clean up
378 pDstBuffer
->mpBits
= NULL
;
383 // do we need a destination palette or color mask?
384 if( ( nDstScanlineFormat
== BMP_FORMAT_1BIT_MSB_PAL
) ||
385 ( nDstScanlineFormat
== BMP_FORMAT_1BIT_LSB_PAL
) ||
386 ( nDstScanlineFormat
== BMP_FORMAT_4BIT_MSN_PAL
) ||
387 ( nDstScanlineFormat
== BMP_FORMAT_4BIT_LSN_PAL
) ||
388 ( nDstScanlineFormat
== BMP_FORMAT_8BIT_PAL
) )
390 DBG_ASSERT( pDstPal
, "destination buffer requires palette" );
391 pDstBuffer
->maPalette
= *pDstPal
;
393 else if( ( nDstScanlineFormat
== BMP_FORMAT_8BIT_TC_MASK
) ||
394 ( nDstScanlineFormat
== BMP_FORMAT_16BIT_TC_MSB_MASK
) ||
395 ( nDstScanlineFormat
== BMP_FORMAT_16BIT_TC_LSB_MASK
) ||
396 ( nDstScanlineFormat
== BMP_FORMAT_24BIT_TC_MASK
) ||
397 ( nDstScanlineFormat
== BMP_FORMAT_32BIT_TC_MASK
) )
399 DBG_ASSERT( pDstMask
, "destination buffer requires color mask" );
400 pDstBuffer
->maColorMask
= *pDstMask
;
403 // short circuit the most important conversions
404 bool bFastConvert
= ImplFastBitmapConversion( *pDstBuffer
, rSrcBuffer
, rTwoRect
);
408 const long nSrcX
= rTwoRect
.mnSrcX
, nSrcY
= rTwoRect
.mnSrcY
;
409 const long nSrcDX
= rTwoRect
.mnSrcWidth
, nSrcDY
= rTwoRect
.mnSrcHeight
;
410 const long nDstDX
= rTwoRect
.mnDestWidth
, nDstDY
= rTwoRect
.mnDestHeight
;
411 Scanline
* pSrcScan
= NULL
;
412 Scanline
* pDstScan
= NULL
;
419 pSrcScan
= new Scanline
[ rSrcBuffer
.mnHeight
];
420 pDstScan
= new Scanline
[ nDstDY
];
421 pMapX
= new long[ nDstDX
];
422 pMapY
= new long[ nDstDY
];
424 catch( const std::bad_alloc
& )
426 // memory exception, clean up
427 // remark: the buffer ptr causing the exception
428 // is still NULL here
437 // horizontal mapping table
438 if( nDstDX
!= nSrcDX
)
440 const double fFactorX
= ( nDstDX
> 1 ) ? (double) ( nSrcDX
- 1 ) / ( nDstDX
- 1 ) : 0.0;
442 for( i
= 0L; i
< nDstDX
; i
++ )
443 pMapX
[ i
] = nSrcX
+ FRound( i
* fFactorX
);
447 for( i
= 0L, nTmp
= nSrcX
; i
< nDstDX
; i
++ )
451 // vertical mapping table
452 if( nDstDY
!= nSrcDY
)
454 const double fFactorY
= ( nDstDY
> 1 ) ? (double) ( nSrcDY
- 1 ) / ( nDstDY
- 1 ) : 0.0;
456 for( i
= 0L; i
< nDstDY
; i
++ )
457 pMapY
[ i
] = nSrcY
+ FRound( i
* fFactorY
);
461 for( i
= 0L, nTmp
= nSrcY
; i
< nDstDY
; i
++ )
465 // source scanline buffer
467 if( BMP_SCANLINE_ADJUSTMENT( rSrcBuffer
.mnFormat
) == BMP_FORMAT_TOP_DOWN
)
468 pTmpScan
= rSrcBuffer
.mpBits
, nOffset
= rSrcBuffer
.mnScanlineSize
;
471 pTmpScan
= rSrcBuffer
.mpBits
+ ( rSrcBuffer
.mnHeight
- 1 ) * rSrcBuffer
.mnScanlineSize
;
472 nOffset
= -rSrcBuffer
.mnScanlineSize
;
475 for( i
= 0L; i
< rSrcBuffer
.mnHeight
; i
++, pTmpScan
+= nOffset
)
476 pSrcScan
[ i
] = pTmpScan
;
478 // destination scanline buffer
479 if( BMP_SCANLINE_ADJUSTMENT( pDstBuffer
->mnFormat
) == BMP_FORMAT_TOP_DOWN
)
480 pTmpScan
= pDstBuffer
->mpBits
, nOffset
= pDstBuffer
->mnScanlineSize
;
483 pTmpScan
= pDstBuffer
->mpBits
+ ( nDstDY
- 1 ) * pDstBuffer
->mnScanlineSize
;
484 nOffset
= -pDstBuffer
->mnScanlineSize
;
487 for( i
= 0L; i
< nDstDY
; i
++, pTmpScan
+= nOffset
)
488 pDstScan
[ i
] = pTmpScan
;
490 // do buffer scaling and conversion
491 if( rSrcBuffer
.mnBitCount
<= 8 && pDstBuffer
->mnBitCount
<= 8 )
493 ImplPALToPAL( rSrcBuffer
, *pDstBuffer
, pFncGetPixel
, pFncSetPixel
,
494 pSrcScan
, pDstScan
, pMapX
, pMapY
);
496 else if( rSrcBuffer
.mnBitCount
<= 8 && pDstBuffer
->mnBitCount
> 8 )
498 ImplPALToTC( rSrcBuffer
, *pDstBuffer
, pFncGetPixel
, pFncSetPixel
,
499 pSrcScan
, pDstScan
, pMapX
, pMapY
);
501 else if( rSrcBuffer
.mnBitCount
> 8 && pDstBuffer
->mnBitCount
> 8 )
503 ImplTCToTC( rSrcBuffer
, *pDstBuffer
, pFncGetPixel
, pFncSetPixel
,
504 pSrcScan
, pDstScan
, pMapX
, pMapY
);
508 ImplTCToPAL( rSrcBuffer
, *pDstBuffer
, pFncGetPixel
, pFncSetPixel
,
509 pSrcScan
, pDstScan
, pMapX
, pMapY
);