Update ooo320-m1
[ooovba.git] / vcl / source / gdi / bitmap2.cxx
blob47a0a0f925cd3c8d350ba98eb8fb95195ae0e9e9
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: bitmap2.cxx,v $
10 * $Revision: 1.19 $
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>
37 #endif
38 #include <vcl/salbtype.hxx>
39 #include <vcl/bmpacc.hxx>
40 #include <vcl/outdev.hxx>
41 #include <vcl/bitmap.hxx>
43 #include <utility>
46 // -----------
47 // - Defines -
48 // -----------
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 )
62 #define RLE_8 ( 1UL )
63 #define RLE_4 ( 2UL )
64 #define BITFIELDS ( 3UL )
65 #define ZCOMPRESS ( COMPRESS_OWN | 0x01000000UL ) /* == 'SD01' (binary) */
67 // -----------------
68 // - DIBInfoHeader -
69 // -----------------
71 struct DIBInfoHeader
73 sal_uInt32 nSize;
74 sal_Int32 nWidth;
75 sal_Int32 nHeight;
76 sal_uInt16 nPlanes;
77 sal_uInt16 nBitCount;
78 sal_uInt32 nCompression;
79 sal_uInt32 nSizeImage;
80 sal_Int32 nXPelsPerMeter;
81 sal_Int32 nYPelsPerMeter;
82 sal_uInt32 nColsUsed;
83 sal_uInt32 nColsImportant;
85 DIBInfoHeader() :
86 nSize( 0UL ),
87 nWidth( 0UL ),
88 nHeight( 0UL ),
89 nPlanes( 0 ),
90 nBitCount( 0 ),
91 nCompression( 0 ),
92 nSizeImage( 0 ),
93 nXPelsPerMeter( 0UL ),
94 nYPelsPerMeter( 0UL ),
95 nColsUsed( 0UL ),
96 nColsImportant( 0UL ) {}
98 ~DIBInfoHeader() {}
101 namespace
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;
117 // ----------
118 // - Bitmap -
119 // ----------
121 SvStream& operator>>( SvStream& rIStm, Bitmap& rBitmap )
123 rBitmap.Read( rIStm, TRUE );
124 return rIStm;
127 // ------------------------------------------------------------------
129 SvStream& operator<<( SvStream& rOStm, const Bitmap& rBitmap )
131 rBitmap.Write( rOStm, FALSE, TRUE );
132 return rOStm;
135 // ------------------------------------------------------------------
137 BOOL Bitmap::Read( SvStream& rIStm, BOOL bFileHeader, BOOL bIsMSOFormat )
139 const USHORT nOldFormat = rIStm.GetNumberFormatInt();
140 const ULONG nOldPos = rIStm.Tell();
141 ULONG nOffset = 0UL;
142 BOOL bRet = FALSE;
144 rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
146 if( bFileHeader )
148 if( ImplReadDIBFileHeader( rIStm, nOffset ) )
149 bRet = ImplReadDIB( rIStm, *this, nOffset );
151 else
152 bRet = ImplReadDIB( rIStm, *this, nOffset, bIsMSOFormat );
154 if( !bRet )
156 if( !rIStm.GetError() )
157 rIStm.SetError( SVSTREAM_GENERALERROR );
159 rIStm.Seek( nOldPos );
162 rIStm.SetNumberFormatInt( nOldFormat );
164 return bRet;
167 // ------------------------------------------------------------------
169 BOOL Bitmap::ImplReadDIB( SvStream& rIStm, Bitmap& rBmp, ULONG nOffset, BOOL bIsMSOFormat )
171 DIBInfoHeader aHeader;
172 const ULONG nStmPos = rIStm.Tell();
173 BOOL bRet = FALSE;
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();
185 if( pAcc )
187 USHORT nColors;
188 SvStream* pIStm;
189 SvMemoryStream* pMemStm = NULL;
190 BYTE* pData = NULL;
192 if( nBitCount <= 8 )
194 if( aHeader.nColsUsed )
195 nColors = (USHORT) aHeader.nColsUsed;
196 else
197 nColors = ( 1 << aHeader.nBitCount );
199 else
200 nColors = 0;
202 if( ZCOMPRESS == aHeader.nCompression )
204 ZCodec aCodec;
205 sal_uInt32 nCodedSize, nUncodedSize;
206 ULONG nCodedPos;
208 // read coding information
209 rIStm >> nCodedSize >> nUncodedSize >> aHeader.nCompression;
210 pData = (BYTE*) rtl_allocateMemory( nUncodedSize );
212 // decode buffer
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 );
225 nOffset = 0;
227 else
228 pIStm = &rIStm;
230 // read palette
231 if( nColors )
233 pAcc->SetPaletteEntryCount( nColors );
234 ImplReadDIBPalette( *pIStm, *pAcc, aHeader.nSize != DIBCOREHEADERSIZE );
237 // read bits
238 if( !pIStm->GetError() )
240 if( nOffset )
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) ) );
256 if( pData )
257 rtl_freeMemory( pData );
259 delete pMemStm;
260 aNewBmp.ReleaseAccess( pAcc );
262 if( bRet )
263 rBmp = aNewBmp;
267 return bRet;
270 // ------------------------------------------------------------------
272 BOOL Bitmap::ImplReadDIBFileHeader( SvStream& rIStm, ULONG& rOffset )
274 UINT32 nTmp32;
275 UINT16 nTmp16 = 0;
276 BOOL bRet = FALSE;
278 rIStm >> nTmp16;
280 if ( ( 0x4D42 == nTmp16 ) || ( 0x4142 == nTmp16 ) )
282 if ( 0x4142 == nTmp16 )
284 rIStm.SeekRel( 12L );
285 rIStm >> nTmp16;
286 rIStm.SeekRel( 8L );
287 rIStm >> nTmp32;
288 rOffset = nTmp32 - 28UL;;
289 bRet = ( 0x4D42 == nTmp16 );
291 else
293 rIStm.SeekRel( 8L );
294 rIStm >> nTmp32;
295 rOffset = nTmp32 - 14UL;
296 bRet = ( rIStm.GetError() == 0UL );
299 else
300 rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
302 return bRet;
305 // ------------------------------------------------------------------
307 BOOL Bitmap::ImplReadDIBInfoHeader( SvStream& rIStm, DIBInfoHeader& rHeader, sal_Bool& bTopDown, sal_Bool bIsMSOFormat )
309 // BITMAPINFOHEADER or BITMAPCOREHEADER
310 rIStm >> rHeader.nSize;
312 // BITMAPCOREHEADER
313 sal_Int16 nTmp16 = 0;
314 sal_uInt8 nTmp8 = 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;
338 else
340 // unknown Header
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 );
386 else
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 )
406 bTopDown = sal_True;
407 rHeader.nHeight *= -1;
409 else
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++ );
440 if( bQuad )
441 pTmpEntry++;
443 rAcc.SetPaletteColor( i, aPalColor );
446 delete[] pEntries;
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 );
456 UINT32 nRMask = 0;
457 UINT32 nGMask = 0;
458 UINT32 nBMask = 0;
459 BOOL bNative;
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 );
464 // Is native format?
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 ) );
472 break;
474 default:
475 bNative = FALSE;
476 break;
478 // Read data
479 if( bNative )
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 );
487 } else {
488 for(int i=abs(rHeader.nHeight)-1;i>=0;i--) {
489 rIStm.Read( ((char*)rAcc.GetBuffer())+(nAlignedWidth*i), nAlignedWidth );
493 else
495 // Read color mask
496 if( bTCMask )
498 if( rHeader.nCompression == BITFIELDS )
500 rIStm.SeekRel( -12L );
501 rIStm >> nRMask;
502 rIStm >> nGMask;
503 rIStm >> nBMask;
505 else
507 nRMask = ( rHeader.nBitCount == 16 ) ? 0x00007c00UL : 0x00ff0000UL;
508 nGMask = ( rHeader.nBitCount == 16 ) ? 0x000003e0UL : 0x0000ff00UL;
509 nBMask = ( rHeader.nBitCount == 16 ) ? 0x0000001fUL : 0x000000ffUL;
513 if( bRLE )
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 );
531 else
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 )
547 case( 1 ):
549 BYTE* pTmp;
550 BYTE cTmp;
552 for( ; nCount--; nY += nI )
554 rIStm.Read( pTmp = pBuf, nAlignedWidth );
555 cTmp = *pTmp++;
557 for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ )
559 if( !nShift )
561 nShift = 8L,
562 cTmp = *pTmp++;
565 rAcc.SetPixel( nY, nX, sal::static_int_cast<BYTE>(( cTmp >> --nShift ) & 1) );
569 break;
571 case( 4 ):
573 BYTE* pTmp;
574 BYTE cTmp;
576 for( ; nCount--; nY += nI )
578 rIStm.Read( pTmp = pBuf, nAlignedWidth );
579 cTmp = *pTmp++;
581 for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ )
583 if( !nShift )
585 nShift = 2UL,
586 cTmp = *pTmp++;
589 rAcc.SetPixel( nY, nX, sal::static_int_cast<BYTE>(( cTmp >> ( --nShift << 2UL ) ) & 0x0f) );
593 break;
595 case( 8 ):
597 BYTE* pTmp;
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++ );
607 break;
609 case( 16 ):
611 ColorMask aMask( nRMask, nGMask, nBMask );
612 BitmapColor aColor;
613 UINT16* pTmp16;
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 );
626 break;
628 case( 24 ):
630 BitmapColor aPixelColor;
631 BYTE* pTmp;
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 );
646 break;
648 case( 32 ):
650 ColorMask aMask( nRMask, nGMask, nBMask );
651 BitmapColor aColor;
652 UINT32* pTmp32;
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 );
667 delete[] pBuf;
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() );
681 BOOL bRet = FALSE;
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 );
691 if( pAcc )
693 if( bFileHeader )
695 if( ImplWriteDIBFileHeader( rOStm, *pAcc ) )
696 bRet = ImplWriteDIB( rOStm, *pAcc, bCompressed );
698 else
699 bRet = ImplWriteDIB( rOStm, *pAcc, bCompressed );
701 ( (Bitmap*) this)->ReleaseAccess( pAcc );
704 if( !bRet )
706 rOStm.SetError( SVSTREAM_GENERALERROR );
707 rOStm.Seek( nOldPos );
710 rOStm.SetNumberFormatInt( nOldFormat );
713 return bRet;
716 // ------------------------------------------------------------------
718 BOOL Bitmap::ImplWriteDIB( SvStream& rOStm, BitmapReadAccess& rAcc, BOOL bCompressed ) const
720 const MapMode aMapPixel( MAP_PIXEL );
721 DIBInfoHeader aHeader;
722 ULONG nImageSizePos;
723 ULONG nEndPos;
724 sal_uInt32 nCompression = 0;
725 BOOL bRet = FALSE;
727 aHeader.nSize = DIBINFOHEADERSIZE;
728 aHeader.nWidth = rAcc.Width();
729 aHeader.nHeight = rAcc.Height();
730 aHeader.nPlanes = 1;
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;
739 else
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
747 // recent.
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 );
756 if( bCompressed )
758 if( 4 == nBitCount )
759 nCompression = RLE_4;
760 else if( 8 == nBitCount )
761 nCompression = RLE_8;
763 else
764 nCompression = COMPRESS_NONE;
767 if( ( rOStm.GetCompressMode() & COMPRESSMODE_ZBITMAP ) &&
768 ( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_40 ) )
770 aHeader.nCompression = ZCOMPRESS;
772 else
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,
785 100000L),
786 MAP_100TH_MM,
787 maPrefMapMode ) );
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 )
818 ZCodec aCodec;
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 );
830 // get uncoded size
831 nUncodedSize = aMemStm.Tell();
833 // seek over compress info
834 rOStm.SeekRel( 12 );
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 );
847 if( bRet )
848 bRet = ( rOStm.GetError() == ERRCODE_NONE );
850 else
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 );
863 return bRet;
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() ) );
876 rOStm << (UINT16) 0;
877 rOStm << (UINT16) 0;
878 rOStm << nOffset;
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();
900 *pTmpEntry++ = 0;
903 rOStm.Write( pEntries, nPalSize );
904 delete[] pEntries;
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();
917 SVBT32 aVal32;
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() );
932 else
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 ) )
966 bNative = TRUE;
968 break;
970 default:
971 break;
974 rImageSize = rOStm.Tell();
976 if( bNative )
977 rOStm.Write( rAcc.GetBuffer(), nAlignedWidth * rAcc.Height() );
978 else
980 const long nWidth = rAcc.Width();
981 const long nHeight = rAcc.Height();
982 BYTE* pBuf = new BYTE[ nAlignedWidth ];
983 BYTE* pTmp;
984 BYTE cTmp;
986 switch( nBitCount )
988 case( 1 ):
990 for( long nY = nHeight - 1; nY >= 0L; nY-- )
992 pTmp = pBuf;
993 cTmp = 0;
995 for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ )
997 if( !nShift )
999 nShift = 8L;
1000 *pTmp++ = cTmp;
1001 cTmp = 0;
1004 cTmp |= ( (BYTE) rAcc.GetPixel( nY, nX ) << --nShift );
1007 *pTmp = cTmp;
1008 rOStm.Write( pBuf, nAlignedWidth );
1011 break;
1013 case( 4 ):
1015 for( long nY = nHeight - 1; nY >= 0L; nY-- )
1017 pTmp = pBuf;
1018 cTmp = 0;
1020 for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ )
1022 if( !nShift )
1024 nShift = 2L;
1025 *pTmp++ = cTmp;
1026 cTmp = 0;
1029 cTmp |= ( (BYTE) rAcc.GetPixel( nY, nX ) << ( --nShift << 2L ) );
1031 *pTmp = cTmp;
1032 rOStm.Write( pBuf, nAlignedWidth );
1035 break;
1037 case( 8 ):
1039 for( long nY = nHeight - 1; nY >= 0L; nY-- )
1041 pTmp = pBuf;
1043 for( long nX = 0L; nX < nWidth; nX++ )
1044 *pTmp++ = rAcc.GetPixel( nY, nX );
1046 rOStm.Write( pBuf, nAlignedWidth );
1049 break;
1051 // #i59239# fallback to 24 bit format, if bitcount is non-default
1052 default:
1053 // FALLTHROUGH intended
1054 case( 24 ):
1056 BitmapColor aPixelColor;
1058 for( long nY = nHeight - 1; nY >= 0L; nY-- )
1060 pTmp = pBuf;
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 );
1073 break;
1076 delete[] pBuf;
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();
1093 ULONG nCountByte;
1094 ULONG nRunByte;
1095 ULONG nX = 0UL;
1096 BYTE cTmp;
1097 BOOL bEndDecoding = FALSE;
1101 if( ( nCountByte = *pRLE++ ) == 0 )
1103 nRunByte = *pRLE++;
1105 if( nRunByte > 2 )
1107 if( bRLE4 )
1109 nCountByte = nRunByte >> 1;
1111 for( ULONG i = 0UL; i < nCountByte; i++ )
1113 cTmp = *pRLE++;
1115 if( nX < nWidth )
1116 rAcc.SetPixel( nY, nX++, cTmp >> 4 );
1118 if( nX < nWidth )
1119 rAcc.SetPixel( nY, nX++, cTmp & 0x0f );
1122 if( nRunByte & 1 )
1124 if( nX < nWidth )
1125 rAcc.SetPixel( nY, nX++, *pRLE >> 4 );
1127 pRLE++;
1130 if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
1131 pRLE++;
1133 else
1135 for( ULONG i = 0UL; i < nRunByte; i++ )
1137 if( nX < nWidth )
1138 rAcc.SetPixel( nY, nX++, *pRLE );
1140 pRLE++;
1143 if( nRunByte & 1 )
1144 pRLE++;
1147 else if( !nRunByte )
1149 nY--;
1150 nX = 0UL;
1152 else if( nRunByte == 1 )
1153 bEndDecoding = TRUE;
1154 else
1156 nX += *pRLE++;
1157 nY -= *pRLE++;
1160 else
1162 cTmp = *pRLE++;
1164 if( bRLE4 )
1166 nRunByte = nCountByte >> 1;
1168 for( ULONG i = 0UL; i < nRunByte; i++ )
1170 if( nX < nWidth )
1171 rAcc.SetPixel( nY, nX++, cTmp >> 4 );
1173 if( nX < nWidth )
1174 rAcc.SetPixel( nY, nX++, cTmp & 0x0f );
1177 if( ( nCountByte & 1 ) && ( nX < nWidth ) )
1178 rAcc.SetPixel( nY, nX++, cTmp >> 4 );
1180 else
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();
1196 ULONG nX;
1197 ULONG nSaveIndex;
1198 ULONG nCount;
1199 ULONG nBufCount;
1200 BYTE* pBuf = new BYTE[ ( nWidth << 1 ) + 2 ];
1201 BYTE* pTmp;
1202 BYTE cPix;
1203 BYTE cLast;
1204 BOOL bFound;
1206 for ( long nY = nHeight - 1L; nY >= 0L; nY-- )
1208 pTmp = pBuf;
1209 nX = nBufCount = 0UL;
1211 while( nX < nWidth )
1213 nCount = 1L;
1214 cPix = rAcc.GetPixel( nY, nX++ );
1216 while( ( nX < nWidth ) && ( nCount < 255L ) && ( cPix == rAcc.GetPixel( nY, nX ) ) )
1218 nX++;
1219 nCount++;
1222 if ( nCount > 1 )
1224 *pTmp++ = (BYTE) nCount;
1225 *pTmp++ = ( bRLE4 ? ( ( cPix << 4 ) | cPix ) : cPix );
1226 nBufCount += 2;
1228 else
1230 cLast = cPix;
1231 nSaveIndex = nX - 1UL;
1232 bFound = FALSE;
1234 while( ( nX < nWidth ) && ( nCount < 256L ) && ( cPix = rAcc.GetPixel( nY, nX ) ) != cLast )
1236 nX++; nCount++;
1237 cLast = cPix;
1238 bFound = TRUE;
1241 if ( bFound )
1242 nX--;
1244 if ( nCount > 3 )
1246 *pTmp++ = 0;
1247 *pTmp++ = (BYTE) --nCount;
1249 if( bRLE4 )
1251 for ( ULONG i = 0; i < nCount; i++, pTmp++ )
1253 *pTmp = (BYTE) rAcc.GetPixel( nY, nSaveIndex++ ) << 4;
1255 if ( ++i < nCount )
1256 *pTmp |= rAcc.GetPixel( nY, nSaveIndex++ );
1259 nCount = ( nCount + 1 ) >> 1;
1261 else
1263 for( ULONG i = 0UL; i < nCount; i++ )
1264 *pTmp++ = rAcc.GetPixel( nY, nSaveIndex++ );
1267 if ( nCount & 1 )
1269 *pTmp++ = 0;
1270 nBufCount += ( nCount + 3 );
1272 else
1273 nBufCount += ( nCount + 2 );
1275 else
1277 *pTmp++ = 1;
1278 *pTmp++ = (BYTE) rAcc.GetPixel( nY, nSaveIndex ) << ( bRLE4 ? 4 : 0 );
1280 if ( nCount == 3 )
1282 *pTmp++ = 1;
1283 *pTmp++ = (BYTE) rAcc.GetPixel( nY, ++nSaveIndex ) << ( bRLE4 ? 4 : 0 );
1284 nBufCount += 4;
1286 else
1287 nBufCount += 2;
1292 pBuf[ nBufCount++ ] = 0;
1293 pBuf[ nBufCount++ ] = 0;
1295 rOStm.Write( pBuf, nBufCount );
1298 rOStm << (BYTE) 0;
1299 rOStm << (BYTE) 1;
1301 delete[] pBuf;
1303 return( rOStm.GetError() == 0UL );