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: bitmap2.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"
34 #include <tools/zcodec.hxx>
35 #ifndef _TOOLS_STREAM_HXX
36 #include <tools/stream.hxx>
38 #include <vcl/salbtype.hxx>
39 #include <vcl/bmpacc.hxx>
40 #include <vcl/outdev.hxx>
41 #include <vcl/bitmap.hxx>
50 #define DIBCOREHEADERSIZE ( 12UL )
51 #define DIBINFOHEADERSIZE ( sizeof( DIBInfoHeader ) )
52 #define BITMAPINFOHEADER 0x28
54 #define SETPIXEL4( pBuf, nX, cChar )( (pBuf)[ (nX) >> 1 ] |= ( (nX) & 1 ) ? ( cChar ): (cChar) << 4 );
56 // ----------------------
57 // - Compression defines
58 // ----------------------
60 #define COMPRESS_OWN ('S'|('D'<<8UL))
61 #define COMPRESS_NONE ( 0UL )
64 #define BITFIELDS ( 3UL )
65 #define ZCOMPRESS ( COMPRESS_OWN | 0x01000000UL ) /* == 'SD01' (binary) */
78 sal_uInt32 nCompression
;
79 sal_uInt32 nSizeImage
;
80 sal_Int32 nXPelsPerMeter
;
81 sal_Int32 nYPelsPerMeter
;
83 sal_uInt32 nColsImportant
;
93 nXPelsPerMeter( 0UL ),
94 nYPelsPerMeter( 0UL ),
96 nColsImportant( 0UL ) {}
103 inline USHORT
discretizeBitcount( UINT16 nInputCount
)
105 return ( nInputCount
<= 1 ) ? 1 :
106 ( nInputCount
<= 4 ) ? 4 :
107 ( nInputCount
<= 8 ) ? 8 : 24;
110 inline bool isBitfieldCompression( ULONG nScanlineFormat
)
112 return nScanlineFormat
== BMP_FORMAT_16BIT_TC_LSB_MASK
||
113 nScanlineFormat
== BMP_FORMAT_32BIT_TC_MASK
;
121 SvStream
& operator>>( SvStream
& rIStm
, Bitmap
& rBitmap
)
123 rBitmap
.Read( rIStm
, TRUE
);
127 // ------------------------------------------------------------------
129 SvStream
& operator<<( SvStream
& rOStm
, const Bitmap
& rBitmap
)
131 rBitmap
.Write( rOStm
, FALSE
, TRUE
);
135 // ------------------------------------------------------------------
137 BOOL
Bitmap::Read( SvStream
& rIStm
, BOOL bFileHeader
, BOOL bIsMSOFormat
)
139 const USHORT nOldFormat
= rIStm
.GetNumberFormatInt();
140 const ULONG nOldPos
= rIStm
.Tell();
144 rIStm
.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
148 if( ImplReadDIBFileHeader( rIStm
, nOffset
) )
149 bRet
= ImplReadDIB( rIStm
, *this, nOffset
);
152 bRet
= ImplReadDIB( rIStm
, *this, nOffset
, bIsMSOFormat
);
156 if( !rIStm
.GetError() )
157 rIStm
.SetError( SVSTREAM_GENERALERROR
);
159 rIStm
.Seek( nOldPos
);
162 rIStm
.SetNumberFormatInt( nOldFormat
);
167 // ------------------------------------------------------------------
169 BOOL
Bitmap::ImplReadDIB( SvStream
& rIStm
, Bitmap
& rBmp
, ULONG nOffset
, BOOL bIsMSOFormat
)
171 DIBInfoHeader aHeader
;
172 const ULONG nStmPos
= rIStm
.Tell();
174 sal_Bool bTopDown
= sal_False
;
176 if( ImplReadDIBInfoHeader( rIStm
, aHeader
, bTopDown
, bIsMSOFormat
) && aHeader
.nWidth
&& aHeader
.nHeight
&& aHeader
.nBitCount
)
178 const USHORT
nBitCount( discretizeBitcount(aHeader
.nBitCount
) );
180 const Size
aSizePixel( aHeader
.nWidth
, abs(aHeader
.nHeight
) );
181 BitmapPalette aDummyPal
;
182 Bitmap
aNewBmp( aSizePixel
, nBitCount
, &aDummyPal
);
183 BitmapWriteAccess
* pAcc
= aNewBmp
.AcquireWriteAccess();
189 SvMemoryStream
* pMemStm
= NULL
;
194 if( aHeader
.nColsUsed
)
195 nColors
= (USHORT
) aHeader
.nColsUsed
;
197 nColors
= ( 1 << aHeader
.nBitCount
);
202 if( ZCOMPRESS
== aHeader
.nCompression
)
205 sal_uInt32 nCodedSize
, nUncodedSize
;
208 // read coding information
209 rIStm
>> nCodedSize
>> nUncodedSize
>> aHeader
.nCompression
;
210 pData
= (BYTE
*) rtl_allocateMemory( nUncodedSize
);
213 nCodedPos
= rIStm
.Tell();
214 aCodec
.BeginCompression();
215 aCodec
.Read( rIStm
, pData
, nUncodedSize
);
216 aCodec
.EndCompression();
218 // skip unread bytes from coded buffer
219 rIStm
.SeekRel( nCodedSize
- ( rIStm
.Tell() - nCodedPos
) );
221 // set decoded bytes to memory stream,
222 // from which we will read the bitmap data
223 pIStm
= pMemStm
= new SvMemoryStream
;
224 pMemStm
->SetBuffer( (char*) pData
, nUncodedSize
, FALSE
, nUncodedSize
);
233 pAcc
->SetPaletteEntryCount( nColors
);
234 ImplReadDIBPalette( *pIStm
, *pAcc
, aHeader
.nSize
!= DIBCOREHEADERSIZE
);
238 if( !pIStm
->GetError() )
241 pIStm
->SeekRel( nOffset
- ( pIStm
->Tell() - nStmPos
) );
243 bRet
= ImplReadDIBBits( *pIStm
, aHeader
, *pAcc
, bTopDown
);
245 if( bRet
&& aHeader
.nXPelsPerMeter
&& aHeader
.nYPelsPerMeter
)
247 MapMode
aMapMode( MAP_MM
, Point(),
248 Fraction( 1000, aHeader
.nXPelsPerMeter
),
249 Fraction( 1000, aHeader
.nYPelsPerMeter
) );
251 aNewBmp
.SetPrefMapMode( aMapMode
);
252 aNewBmp
.SetPrefSize( Size( aHeader
.nWidth
, abs(aHeader
.nHeight
) ) );
257 rtl_freeMemory( pData
);
260 aNewBmp
.ReleaseAccess( pAcc
);
270 // ------------------------------------------------------------------
272 BOOL
Bitmap::ImplReadDIBFileHeader( SvStream
& rIStm
, ULONG
& rOffset
)
280 if ( ( 0x4D42 == nTmp16
) || ( 0x4142 == nTmp16
) )
282 if ( 0x4142 == nTmp16
)
284 rIStm
.SeekRel( 12L );
288 rOffset
= nTmp32
- 28UL;;
289 bRet
= ( 0x4D42 == nTmp16
);
295 rOffset
= nTmp32
- 14UL;
296 bRet
= ( rIStm
.GetError() == 0UL );
300 rIStm
.SetError( SVSTREAM_FILEFORMAT_ERROR
);
305 // ------------------------------------------------------------------
307 BOOL
Bitmap::ImplReadDIBInfoHeader( SvStream
& rIStm
, DIBInfoHeader
& rHeader
, sal_Bool
& bTopDown
, sal_Bool bIsMSOFormat
)
309 // BITMAPINFOHEADER or BITMAPCOREHEADER
310 rIStm
>> rHeader
.nSize
;
313 sal_Int16 nTmp16
= 0;
315 if ( rHeader
.nSize
== DIBCOREHEADERSIZE
)
318 rIStm
>> nTmp16
; rHeader
.nWidth
= nTmp16
;
319 rIStm
>> nTmp16
; rHeader
.nHeight
= nTmp16
;
320 rIStm
>> rHeader
.nPlanes
;
321 rIStm
>> rHeader
.nBitCount
;
323 else if ( bIsMSOFormat
&& ( rHeader
.nSize
== BITMAPINFOHEADER
) )
325 rIStm
>> nTmp16
; rHeader
.nWidth
= nTmp16
;
326 rIStm
>> nTmp16
; rHeader
.nHeight
= nTmp16
;
327 rIStm
>> nTmp8
; rHeader
.nPlanes
= nTmp8
;
328 rIStm
>> nTmp8
; rHeader
.nBitCount
= nTmp8
;
329 rIStm
>> nTmp16
; rHeader
.nSizeImage
= nTmp16
;
330 rIStm
>> nTmp16
; rHeader
.nCompression
= nTmp16
;
331 if ( !rHeader
.nSizeImage
) // uncompressed?
332 rHeader
.nSizeImage
= ((rHeader
.nWidth
* rHeader
.nBitCount
+ 31) & ~31) / 8 * rHeader
.nHeight
;
333 rIStm
>> rHeader
.nXPelsPerMeter
;
334 rIStm
>> rHeader
.nYPelsPerMeter
;
335 rIStm
>> rHeader
.nColsUsed
;
336 rIStm
>> rHeader
.nColsImportant
;
341 if( rHeader
.nSize
< DIBINFOHEADERSIZE
)
343 ULONG nUnknownSize
= sizeof( rHeader
.nSize
);
345 rIStm
>> rHeader
.nWidth
; nUnknownSize
+= sizeof( rHeader
.nWidth
);
346 rIStm
>> rHeader
.nHeight
; nUnknownSize
+= sizeof( rHeader
.nHeight
);
347 rIStm
>> rHeader
.nPlanes
; nUnknownSize
+= sizeof( rHeader
.nPlanes
);
348 rIStm
>> rHeader
.nBitCount
; nUnknownSize
+= sizeof( rHeader
.nBitCount
);
350 if( nUnknownSize
< rHeader
.nSize
)
352 rIStm
>> rHeader
.nCompression
;
353 nUnknownSize
+= sizeof( rHeader
.nCompression
);
355 if( nUnknownSize
< rHeader
.nSize
)
357 rIStm
>> rHeader
.nSizeImage
;
358 nUnknownSize
+= sizeof( rHeader
.nSizeImage
);
360 if( nUnknownSize
< rHeader
.nSize
)
362 rIStm
>> rHeader
.nXPelsPerMeter
;
363 nUnknownSize
+= sizeof( rHeader
.nXPelsPerMeter
);
365 if( nUnknownSize
< rHeader
.nSize
)
367 rIStm
>> rHeader
.nYPelsPerMeter
;
368 nUnknownSize
+= sizeof( rHeader
.nYPelsPerMeter
);
371 if( nUnknownSize
< rHeader
.nSize
)
373 rIStm
>> rHeader
.nColsUsed
;
374 nUnknownSize
+= sizeof( rHeader
.nColsUsed
);
376 if( nUnknownSize
< rHeader
.nSize
)
378 rIStm
>> rHeader
.nColsImportant
;
379 nUnknownSize
+= sizeof( rHeader
.nColsImportant
);
388 rIStm
>> rHeader
.nWidth
;
389 rIStm
>> rHeader
.nHeight
; //rHeader.nHeight=abs(rHeader.nHeight);
390 rIStm
>> rHeader
.nPlanes
;
391 rIStm
>> rHeader
.nBitCount
;
392 rIStm
>> rHeader
.nCompression
;
393 rIStm
>> rHeader
.nSizeImage
;
394 rIStm
>> rHeader
.nXPelsPerMeter
;
395 rIStm
>> rHeader
.nYPelsPerMeter
;
396 rIStm
>> rHeader
.nColsUsed
;
397 rIStm
>> rHeader
.nColsImportant
;
400 // Eventuell bis zur Palette ueberlesen
401 if ( rHeader
.nSize
> DIBINFOHEADERSIZE
)
402 rIStm
.SeekRel( rHeader
.nSize
- DIBINFOHEADERSIZE
);
404 if ( rHeader
.nHeight
< 0 )
407 rHeader
.nHeight
*= -1;
410 bTopDown
= sal_False
;
412 if ( rHeader
.nWidth
< 0 )
413 rIStm
.SetError( SVSTREAM_FILEFORMAT_ERROR
);
415 // #144105# protect a little against damaged files
416 if( rHeader
.nSizeImage
> ( 16 * static_cast< sal_uInt32
>( rHeader
.nWidth
* rHeader
.nHeight
) ) )
417 rHeader
.nSizeImage
= 0;
419 return( ( rHeader
.nPlanes
== 1 ) && ( rIStm
.GetError() == 0UL ) );
422 // ------------------------------------------------------------------
424 BOOL
Bitmap::ImplReadDIBPalette( SvStream
& rIStm
, BitmapWriteAccess
& rAcc
, BOOL bQuad
)
426 const USHORT nColors
= rAcc
.GetPaletteEntryCount();
427 const ULONG nPalSize
= nColors
* ( bQuad
? 4UL : 3UL );
428 BitmapColor aPalColor
;
430 BYTE
* pEntries
= new BYTE
[ nPalSize
];
431 rIStm
.Read( pEntries
, nPalSize
);
433 BYTE
* pTmpEntry
= pEntries
;
434 for( USHORT i
= 0; i
< nColors
; i
++ )
436 aPalColor
.SetBlue( *pTmpEntry
++ );
437 aPalColor
.SetGreen( *pTmpEntry
++ );
438 aPalColor
.SetRed( *pTmpEntry
++ );
443 rAcc
.SetPaletteColor( i
, aPalColor
);
448 return( rIStm
.GetError() == 0UL );
451 // ------------------------------------------------------------------
453 BOOL
Bitmap::ImplReadDIBBits( SvStream
& rIStm
, DIBInfoHeader
& rHeader
, BitmapWriteAccess
& rAcc
, sal_Bool bTopDown
)
455 const ULONG nAlignedWidth
= AlignedWidth4Bytes( rHeader
.nWidth
* rHeader
.nBitCount
);
460 BOOL bTCMask
= ( rHeader
.nBitCount
== 16 ) || ( rHeader
.nBitCount
== 32 );
461 BOOL bRLE
= ( RLE_8
== rHeader
.nCompression
&& rHeader
.nBitCount
== 8 ) ||
462 ( RLE_4
== rHeader
.nCompression
&& rHeader
.nBitCount
== 4 );
465 switch( rAcc
.GetScanlineFormat() )
467 case( BMP_FORMAT_1BIT_MSB_PAL
):
468 case( BMP_FORMAT_4BIT_MSN_PAL
):
469 case( BMP_FORMAT_8BIT_PAL
):
470 case( BMP_FORMAT_24BIT_TC_BGR
):
471 bNative
= ( ( rAcc
.IsBottomUp() != bTopDown
) && !bRLE
&& !bTCMask
&& ( rAcc
.GetScanlineSize() == nAlignedWidth
) );
481 // true color DIB's can have a (optimization) palette
482 if( rHeader
.nColsUsed
&& rHeader
.nBitCount
> 8 )
483 rIStm
.SeekRel( rHeader
.nColsUsed
* ( ( rHeader
.nSize
!= DIBCOREHEADERSIZE
) ? 4 : 3 ) );
485 if (rHeader
.nHeight
>0) {
486 rIStm
.Read( rAcc
.GetBuffer(), rHeader
.nHeight
* nAlignedWidth
);
488 for(int i
=abs(rHeader
.nHeight
)-1;i
>=0;i
--) {
489 rIStm
.Read( ((char*)rAcc
.GetBuffer())+(nAlignedWidth
*i
), nAlignedWidth
);
498 if( rHeader
.nCompression
== BITFIELDS
)
500 rIStm
.SeekRel( -12L );
507 nRMask
= ( rHeader
.nBitCount
== 16 ) ? 0x00007c00UL
: 0x00ff0000UL
;
508 nGMask
= ( rHeader
.nBitCount
== 16 ) ? 0x000003e0UL
: 0x0000ff00UL
;
509 nBMask
= ( rHeader
.nBitCount
== 16 ) ? 0x0000001fUL
: 0x000000ffUL
;
515 if ( !rHeader
.nSizeImage
)
517 const ULONG nOldPos
= rIStm
.Tell();
519 rIStm
.Seek( STREAM_SEEK_TO_END
);
520 rHeader
.nSizeImage
= rIStm
.Tell() - nOldPos
;
521 rIStm
.Seek( nOldPos
);
524 BYTE
* pBuffer
= (BYTE
*) rtl_allocateMemory( rHeader
.nSizeImage
);
526 rIStm
.Read( (char*) pBuffer
, rHeader
.nSizeImage
);
527 ImplDecodeRLE( pBuffer
, rHeader
, rAcc
, RLE_4
== rHeader
.nCompression
);
529 rtl_freeMemory( pBuffer
);
533 const long nWidth
= rHeader
.nWidth
;
534 const long nHeight
= abs(rHeader
.nHeight
);
535 BYTE
* pBuf
= new BYTE
[ nAlignedWidth
];
537 // true color DIB's can have a (optimization) palette
538 if( rHeader
.nColsUsed
&& rHeader
.nBitCount
> 8 )
539 rIStm
.SeekRel( rHeader
.nColsUsed
* ( ( rHeader
.nSize
!= DIBCOREHEADERSIZE
) ? 4 : 3 ) );
541 const long nI
= bTopDown
? 1 : -1;
542 long nY
= bTopDown
? 0 : nHeight
- 1;
543 long nCount
= nHeight
;
545 switch( rHeader
.nBitCount
)
552 for( ; nCount
--; nY
+= nI
)
554 rIStm
.Read( pTmp
= pBuf
, nAlignedWidth
);
557 for( long nX
= 0L, nShift
= 8L; nX
< nWidth
; nX
++ )
565 rAcc
.SetPixel( nY
, nX
, sal::static_int_cast
<BYTE
>(( cTmp
>> --nShift
) & 1) );
576 for( ; nCount
--; nY
+= nI
)
578 rIStm
.Read( pTmp
= pBuf
, nAlignedWidth
);
581 for( long nX
= 0L, nShift
= 2L; nX
< nWidth
; nX
++ )
589 rAcc
.SetPixel( nY
, nX
, sal::static_int_cast
<BYTE
>(( cTmp
>> ( --nShift
<< 2UL ) ) & 0x0f) );
599 for( ; nCount
--; nY
+= nI
)
601 rIStm
.Read( pTmp
= pBuf
, nAlignedWidth
);
603 for( long nX
= 0L; nX
< nWidth
; nX
++ )
604 rAcc
.SetPixel( nY
, nX
, *pTmp
++ );
611 ColorMask
aMask( nRMask
, nGMask
, nBMask
);
615 for( ; nCount
--; nY
+= nI
)
617 rIStm
.Read( (char*)( pTmp16
= (UINT16
*) pBuf
), nAlignedWidth
);
619 for( long nX
= 0L; nX
< nWidth
; nX
++ )
621 aMask
.GetColorFor16BitLSB( aColor
, (BYTE
*) pTmp16
++ );
622 rAcc
.SetPixel( nY
, nX
, aColor
);
630 BitmapColor aPixelColor
;
633 for( ; nCount
--; nY
+= nI
)
635 rIStm
.Read( pTmp
= pBuf
, nAlignedWidth
);
637 for( long nX
= 0L; nX
< nWidth
; nX
++ )
639 aPixelColor
.SetBlue( *pTmp
++ );
640 aPixelColor
.SetGreen( *pTmp
++ );
641 aPixelColor
.SetRed( *pTmp
++ );
642 rAcc
.SetPixel( nY
, nX
, aPixelColor
);
650 ColorMask
aMask( nRMask
, nGMask
, nBMask
);
654 for( ; nCount
--; nY
+= nI
)
656 rIStm
.Read( (char*)( pTmp32
= (UINT32
*) pBuf
), nAlignedWidth
);
658 for( long nX
= 0L; nX
< nWidth
; nX
++ )
660 aMask
.GetColorFor32Bit( aColor
, (BYTE
*) pTmp32
++ );
661 rAcc
.SetPixel( nY
, nX
, aColor
);
671 return( rIStm
.GetError() == 0UL );
674 // ------------------------------------------------------------------
676 BOOL
Bitmap::Write( SvStream
& rOStm
, BOOL bCompressed
, BOOL bFileHeader
) const
678 DBG_ASSERT( mpImpBmp
, "Empty Bitmaps can't be saved" );
680 const Size
aSizePix( GetSizePixel() );
683 if( mpImpBmp
&& aSizePix
.Width() && aSizePix
.Height() )
685 BitmapReadAccess
* pAcc
= ( (Bitmap
*) this)->AcquireReadAccess();
686 const USHORT nOldFormat
= rOStm
.GetNumberFormatInt();
687 const ULONG nOldPos
= rOStm
.Tell();
689 rOStm
.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
695 if( ImplWriteDIBFileHeader( rOStm
, *pAcc
) )
696 bRet
= ImplWriteDIB( rOStm
, *pAcc
, bCompressed
);
699 bRet
= ImplWriteDIB( rOStm
, *pAcc
, bCompressed
);
701 ( (Bitmap
*) this)->ReleaseAccess( pAcc
);
706 rOStm
.SetError( SVSTREAM_GENERALERROR
);
707 rOStm
.Seek( nOldPos
);
710 rOStm
.SetNumberFormatInt( nOldFormat
);
716 // ------------------------------------------------------------------
718 BOOL
Bitmap::ImplWriteDIB( SvStream
& rOStm
, BitmapReadAccess
& rAcc
, BOOL bCompressed
) const
720 const MapMode
aMapPixel( MAP_PIXEL
);
721 DIBInfoHeader aHeader
;
724 sal_uInt32 nCompression
= 0;
727 aHeader
.nSize
= DIBINFOHEADERSIZE
;
728 aHeader
.nWidth
= rAcc
.Width();
729 aHeader
.nHeight
= rAcc
.Height();
732 if( isBitfieldCompression( rAcc
.GetScanlineFormat() ) )
734 aHeader
.nBitCount
= ( rAcc
.GetScanlineFormat() == BMP_FORMAT_16BIT_TC_LSB_MASK
) ? 16 : 32;
735 aHeader
.nSizeImage
= rAcc
.Height() * rAcc
.GetScanlineSize();
737 nCompression
= BITFIELDS
;
741 // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are
742 // not handled properly below (would have to set color
743 // masks, and nCompression=BITFIELDS - but color mask is
744 // not set for formats != *_TC_*). Note that this very
745 // problem might cause trouble at other places - the
746 // introduction of 32 bit RGBA bitmaps is relatively
748 // #i59239# discretize bitcount to 1,4,8,24 (other cases
749 // are not written below)
750 const UINT16
nBitCount( sal::static_int_cast
<UINT16
>(rAcc
.GetBitCount()) );
752 aHeader
.nBitCount
= discretizeBitcount( nBitCount
);
753 aHeader
.nSizeImage
= rAcc
.Height() *
754 AlignedWidth4Bytes( rAcc
.Width()*aHeader
.nBitCount
);
759 nCompression
= RLE_4
;
760 else if( 8 == nBitCount
)
761 nCompression
= RLE_8
;
764 nCompression
= COMPRESS_NONE
;
767 if( ( rOStm
.GetCompressMode() & COMPRESSMODE_ZBITMAP
) &&
768 ( rOStm
.GetVersion() >= SOFFICE_FILEFORMAT_40
) )
770 aHeader
.nCompression
= ZCOMPRESS
;
773 aHeader
.nCompression
= nCompression
;
775 if( maPrefSize
.Width() && maPrefSize
.Height() && ( maPrefMapMode
!= aMapPixel
) )
777 // #i48108# Try to recover xpels/ypels as previously stored on
778 // disk. The problem with just converting maPrefSize to 100th
779 // mm and then relating that to the bitmap pixel size is that
780 // MapMode is integer-based, and suffers from roundoffs,
781 // especially if maPrefSize is small. Trying to circumvent
782 // that by performing part of the math in floating point.
783 const Size
aScale100000(
784 OutputDevice::LogicToLogic( Size(100000L,
788 const double fBmpWidthM((double)maPrefSize
.Width() / aScale100000
.Width() );
789 const double fBmpHeightM((double)maPrefSize
.Height() / aScale100000
.Height() );
790 if( fabs(fBmpWidthM
) > 0.000000001 &&
791 fabs(fBmpHeightM
) > 0.000000001 )
793 aHeader
.nXPelsPerMeter
= (UINT32
)(rAcc
.Width() / fBmpWidthM
+ .5);
794 aHeader
.nYPelsPerMeter
= (UINT32
)(rAcc
.Height() / fBmpHeightM
+ .5);
798 aHeader
.nColsUsed
= ( ( aHeader
.nBitCount
<= 8 ) ? rAcc
.GetPaletteEntryCount() : 0 );
799 aHeader
.nColsImportant
= 0;
801 rOStm
<< aHeader
.nSize
;
802 rOStm
<< aHeader
.nWidth
;
803 rOStm
<< aHeader
.nHeight
;
804 rOStm
<< aHeader
.nPlanes
;
805 rOStm
<< aHeader
.nBitCount
;
806 rOStm
<< aHeader
.nCompression
;
808 nImageSizePos
= rOStm
.Tell();
809 rOStm
.SeekRel( sizeof( aHeader
.nSizeImage
) );
811 rOStm
<< aHeader
.nXPelsPerMeter
;
812 rOStm
<< aHeader
.nYPelsPerMeter
;
813 rOStm
<< aHeader
.nColsUsed
;
814 rOStm
<< aHeader
.nColsImportant
;
816 if( aHeader
.nCompression
== ZCOMPRESS
)
819 SvMemoryStream
aMemStm( aHeader
.nSizeImage
+ 4096, 65535 );
820 ULONG nCodedPos
= rOStm
.Tell(), nLastPos
;
821 sal_uInt32 nCodedSize
, nUncodedSize
;
823 // write uncoded data palette
824 if( aHeader
.nColsUsed
)
825 ImplWriteDIBPalette( aMemStm
, rAcc
);
827 // write uncoded bits
828 bRet
= ImplWriteDIBBits( aMemStm
, rAcc
, nCompression
, aHeader
.nSizeImage
);
831 nUncodedSize
= aMemStm
.Tell();
833 // seek over compress info
836 // write compressed data
837 aCodec
.BeginCompression( 3 );
838 aCodec
.Write( rOStm
, (BYTE
*) aMemStm
.GetData(), nUncodedSize
);
839 aCodec
.EndCompression();
841 // update compress info ( coded size, uncoded size, uncoded compression )
842 nCodedSize
= ( nLastPos
= rOStm
.Tell() ) - nCodedPos
- 12;
843 rOStm
.Seek( nCodedPos
);
844 rOStm
<< nCodedSize
<< nUncodedSize
<< nCompression
;
845 rOStm
.Seek( nLastPos
);
848 bRet
= ( rOStm
.GetError() == ERRCODE_NONE
);
852 if( aHeader
.nColsUsed
)
853 ImplWriteDIBPalette( rOStm
, rAcc
);
855 bRet
= ImplWriteDIBBits( rOStm
, rAcc
, aHeader
.nCompression
, aHeader
.nSizeImage
);
858 nEndPos
= rOStm
.Tell();
859 rOStm
.Seek( nImageSizePos
);
860 rOStm
<< aHeader
.nSizeImage
;
861 rOStm
.Seek( nEndPos
);
866 // ------------------------------------------------------------------
868 BOOL
Bitmap::ImplWriteDIBFileHeader( SvStream
& rOStm
, BitmapReadAccess
& rAcc
)
870 UINT32 nPalCount
= ( rAcc
.HasPalette() ? rAcc
.GetPaletteEntryCount() :
871 isBitfieldCompression( rAcc
.GetScanlineFormat() ) ? 3UL : 0UL );
872 UINT32 nOffset
= 14 + DIBINFOHEADERSIZE
+ nPalCount
* 4UL;
874 rOStm
<< (UINT16
) 0x4D42;
875 rOStm
<< (UINT32
) ( nOffset
+ ( rAcc
.Height() * rAcc
.GetScanlineSize() ) );
880 return( rOStm
.GetError() == 0UL );
883 // ------------------------------------------------------------------
885 BOOL
Bitmap::ImplWriteDIBPalette( SvStream
& rOStm
, BitmapReadAccess
& rAcc
)
887 const USHORT nColors
= rAcc
.GetPaletteEntryCount();
888 const ULONG nPalSize
= nColors
* 4UL;
889 BYTE
* pEntries
= new BYTE
[ nPalSize
];
890 BYTE
* pTmpEntry
= pEntries
;
891 BitmapColor aPalColor
;
893 for( USHORT i
= 0; i
< nColors
; i
++ )
895 const BitmapColor
& rPalColor
= rAcc
.GetPaletteColor( i
);
897 *pTmpEntry
++ = rPalColor
.GetBlue();
898 *pTmpEntry
++ = rPalColor
.GetGreen();
899 *pTmpEntry
++ = rPalColor
.GetRed();
903 rOStm
.Write( pEntries
, nPalSize
);
906 return( rOStm
.GetError() == 0UL );
909 // ------------------------------------------------------------------
911 BOOL
Bitmap::ImplWriteDIBBits( SvStream
& rOStm
, BitmapReadAccess
& rAcc
,
912 ULONG nCompression
, sal_uInt32
& rImageSize
)
914 if( BITFIELDS
== nCompression
)
916 const ColorMask
& rMask
= rAcc
.GetColorMask();
919 UInt32ToSVBT32( rMask
.GetRedMask(), aVal32
);
920 rOStm
.Write( (BYTE
*) aVal32
, 4UL );
922 UInt32ToSVBT32( rMask
.GetGreenMask(), aVal32
);
923 rOStm
.Write( (BYTE
*) aVal32
, 4UL );
925 UInt32ToSVBT32( rMask
.GetBlueMask(), aVal32
);
926 rOStm
.Write( (BYTE
*) aVal32
, 4UL );
928 rImageSize
= rOStm
.Tell();
930 if( rAcc
.IsBottomUp() )
931 rOStm
.Write( rAcc
.GetBuffer(), rAcc
.Height() * rAcc
.GetScanlineSize() );
934 for( long nY
= rAcc
.Height() - 1, nScanlineSize
= rAcc
.GetScanlineSize(); nY
>= 0L; nY
-- )
935 rOStm
.Write( rAcc
.GetScanline( nY
), nScanlineSize
);
938 else if( ( RLE_4
== nCompression
) || ( RLE_8
== nCompression
) )
940 rImageSize
= rOStm
.Tell();
941 ImplWriteRLE( rOStm
, rAcc
, RLE_4
== nCompression
);
943 else if( !nCompression
)
945 // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are not
946 // handled properly below (would have to set color masks, and
947 // nCompression=BITFIELDS - but color mask is not set for
948 // formats != *_TC_*). Note that this very problem might cause
949 // trouble at other places - the introduction of 32 bit RGBA
950 // bitmaps is relatively recent.
951 // #i59239# discretize bitcount for aligned width to 1,4,8,24
952 // (other cases are not written below)
953 const USHORT
nBitCount( sal::static_int_cast
<USHORT
>(rAcc
.GetBitCount()) );
954 const ULONG nAlignedWidth
= AlignedWidth4Bytes( rAcc
.Width() *
955 discretizeBitcount(nBitCount
));
956 BOOL bNative
= FALSE
;
958 switch( rAcc
.GetScanlineFormat() )
960 case( BMP_FORMAT_1BIT_MSB_PAL
):
961 case( BMP_FORMAT_4BIT_MSN_PAL
):
962 case( BMP_FORMAT_8BIT_PAL
):
963 case( BMP_FORMAT_24BIT_TC_BGR
):
965 if( rAcc
.IsBottomUp() && ( rAcc
.GetScanlineSize() == nAlignedWidth
) )
974 rImageSize
= rOStm
.Tell();
977 rOStm
.Write( rAcc
.GetBuffer(), nAlignedWidth
* rAcc
.Height() );
980 const long nWidth
= rAcc
.Width();
981 const long nHeight
= rAcc
.Height();
982 BYTE
* pBuf
= new BYTE
[ nAlignedWidth
];
990 for( long nY
= nHeight
- 1; nY
>= 0L; nY
-- )
995 for( long nX
= 0L, nShift
= 8L; nX
< nWidth
; nX
++ )
1004 cTmp
|= ( (BYTE
) rAcc
.GetPixel( nY
, nX
) << --nShift
);
1008 rOStm
.Write( pBuf
, nAlignedWidth
);
1015 for( long nY
= nHeight
- 1; nY
>= 0L; nY
-- )
1020 for( long nX
= 0L, nShift
= 2L; nX
< nWidth
; nX
++ )
1029 cTmp
|= ( (BYTE
) rAcc
.GetPixel( nY
, nX
) << ( --nShift
<< 2L ) );
1032 rOStm
.Write( pBuf
, nAlignedWidth
);
1039 for( long nY
= nHeight
- 1; nY
>= 0L; nY
-- )
1043 for( long nX
= 0L; nX
< nWidth
; nX
++ )
1044 *pTmp
++ = rAcc
.GetPixel( nY
, nX
);
1046 rOStm
.Write( pBuf
, nAlignedWidth
);
1051 // #i59239# fallback to 24 bit format, if bitcount is non-default
1053 // FALLTHROUGH intended
1056 BitmapColor aPixelColor
;
1058 for( long nY
= nHeight
- 1; nY
>= 0L; nY
-- )
1062 for( long nX
= 0L; nX
< nWidth
; nX
++ )
1064 aPixelColor
= rAcc
.GetPixel( nY
, nX
);
1065 *pTmp
++ = aPixelColor
.GetBlue();
1066 *pTmp
++ = aPixelColor
.GetGreen();
1067 *pTmp
++ = aPixelColor
.GetRed();
1070 rOStm
.Write( pBuf
, nAlignedWidth
);
1080 rImageSize
= rOStm
.Tell() - rImageSize
;
1082 return( rOStm
.GetError() == 0UL );
1085 // ------------------------------------------------------------------
1087 void Bitmap::ImplDecodeRLE( BYTE
* pBuffer
, DIBInfoHeader
& rHeader
,
1088 BitmapWriteAccess
& rAcc
, BOOL bRLE4
)
1090 Scanline pRLE
= pBuffer
;
1091 long nY
= abs(rHeader
.nHeight
) - 1L;
1092 const ULONG nWidth
= rAcc
.Width();
1097 BOOL bEndDecoding
= FALSE
;
1101 if( ( nCountByte
= *pRLE
++ ) == 0 )
1109 nCountByte
= nRunByte
>> 1;
1111 for( ULONG i
= 0UL; i
< nCountByte
; i
++ )
1116 rAcc
.SetPixel( nY
, nX
++, cTmp
>> 4 );
1119 rAcc
.SetPixel( nY
, nX
++, cTmp
& 0x0f );
1125 rAcc
.SetPixel( nY
, nX
++, *pRLE
>> 4 );
1130 if( ( ( nRunByte
+ 1 ) >> 1 ) & 1 )
1135 for( ULONG i
= 0UL; i
< nRunByte
; i
++ )
1138 rAcc
.SetPixel( nY
, nX
++, *pRLE
);
1147 else if( !nRunByte
)
1152 else if( nRunByte
== 1 )
1153 bEndDecoding
= TRUE
;
1166 nRunByte
= nCountByte
>> 1;
1168 for( ULONG i
= 0UL; i
< nRunByte
; i
++ )
1171 rAcc
.SetPixel( nY
, nX
++, cTmp
>> 4 );
1174 rAcc
.SetPixel( nY
, nX
++, cTmp
& 0x0f );
1177 if( ( nCountByte
& 1 ) && ( nX
< nWidth
) )
1178 rAcc
.SetPixel( nY
, nX
++, cTmp
>> 4 );
1182 for( ULONG i
= 0UL; ( i
< nCountByte
) && ( nX
< nWidth
); i
++ )
1183 rAcc
.SetPixel( nY
, nX
++, cTmp
);
1187 while ( !bEndDecoding
&& ( nY
>= 0L ) );
1190 // ------------------------------------------------------------------
1192 BOOL
Bitmap::ImplWriteRLE( SvStream
& rOStm
, BitmapReadAccess
& rAcc
, BOOL bRLE4
)
1194 const ULONG nWidth
= rAcc
.Width();
1195 const ULONG nHeight
= rAcc
.Height();
1200 BYTE
* pBuf
= new BYTE
[ ( nWidth
<< 1 ) + 2 ];
1206 for ( long nY
= nHeight
- 1L; nY
>= 0L; nY
-- )
1209 nX
= nBufCount
= 0UL;
1211 while( nX
< nWidth
)
1214 cPix
= rAcc
.GetPixel( nY
, nX
++ );
1216 while( ( nX
< nWidth
) && ( nCount
< 255L ) && ( cPix
== rAcc
.GetPixel( nY
, nX
) ) )
1224 *pTmp
++ = (BYTE
) nCount
;
1225 *pTmp
++ = ( bRLE4
? ( ( cPix
<< 4 ) | cPix
) : cPix
);
1231 nSaveIndex
= nX
- 1UL;
1234 while( ( nX
< nWidth
) && ( nCount
< 256L ) && ( cPix
= rAcc
.GetPixel( nY
, nX
) ) != cLast
)
1247 *pTmp
++ = (BYTE
) --nCount
;
1251 for ( ULONG i
= 0; i
< nCount
; i
++, pTmp
++ )
1253 *pTmp
= (BYTE
) rAcc
.GetPixel( nY
, nSaveIndex
++ ) << 4;
1256 *pTmp
|= rAcc
.GetPixel( nY
, nSaveIndex
++ );
1259 nCount
= ( nCount
+ 1 ) >> 1;
1263 for( ULONG i
= 0UL; i
< nCount
; i
++ )
1264 *pTmp
++ = rAcc
.GetPixel( nY
, nSaveIndex
++ );
1270 nBufCount
+= ( nCount
+ 3 );
1273 nBufCount
+= ( nCount
+ 2 );
1278 *pTmp
++ = (BYTE
) rAcc
.GetPixel( nY
, nSaveIndex
) << ( bRLE4
? 4 : 0 );
1283 *pTmp
++ = (BYTE
) rAcc
.GetPixel( nY
, ++nSaveIndex
) << ( bRLE4
? 4 : 0 );
1292 pBuf
[ nBufCount
++ ] = 0;
1293 pBuf
[ nBufCount
++ ] = 0;
1295 rOStm
.Write( pBuf
, nBufCount
);
1303 return( rOStm
.GetError() == 0UL );