/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////// // - Defines - #define DIBCOREHEADERSIZE ( 12UL ) #define DIBINFOHEADERSIZE ( sizeof(DIBInfoHeader) ) #define DIBV5HEADERSIZE ( sizeof(DIBV5Header) ) ////////////////////////////////////////////////////////////////////////////// // - Compression defines #define COMPRESS_OWN ('S'|('D'<<8UL)) #define COMPRESS_NONE ( 0UL ) #define RLE_8 ( 1UL ) #define RLE_4 ( 2UL ) #define BITFIELDS ( 3UL ) #define ZCOMPRESS ( COMPRESS_OWN | 0x01000000UL ) /* == 'SD01' (binary) */ ////////////////////////////////////////////////////////////////////////////// // - DIBInfoHeader and DIBV5Header typedef sal_Int32 FXPT2DOT30; struct CIEXYZ { FXPT2DOT30 aXyzX; FXPT2DOT30 aXyzY; FXPT2DOT30 aXyzZ; CIEXYZ() : aXyzX(0L), aXyzY(0L), aXyzZ(0L) {} ~CIEXYZ() {} }; struct CIEXYZTriple { CIEXYZ aXyzRed; CIEXYZ aXyzGreen; CIEXYZ aXyzBlue; CIEXYZTriple() : aXyzRed(), aXyzGreen(), aXyzBlue() {} ~CIEXYZTriple() {} }; struct DIBInfoHeader { sal_uInt32 nSize; sal_Int32 nWidth; sal_Int32 nHeight; sal_uInt16 nPlanes; sal_uInt16 nBitCount; sal_uInt32 nCompression; sal_uInt32 nSizeImage; sal_Int32 nXPelsPerMeter; sal_Int32 nYPelsPerMeter; sal_uInt32 nColsUsed; sal_uInt32 nColsImportant; DIBInfoHeader() : nSize(0UL), nWidth(0UL), nHeight(0UL), nPlanes(0), nBitCount(0), nCompression(0), nSizeImage(0), nXPelsPerMeter(0UL), nYPelsPerMeter(0UL), nColsUsed(0UL), nColsImportant(0UL) {} ~DIBInfoHeader() {} }; struct DIBV5Header : public DIBInfoHeader { sal_uInt32 nV5RedMask; sal_uInt32 nV5GreenMask; sal_uInt32 nV5BlueMask; sal_uInt32 nV5AlphaMask; sal_uInt32 nV5CSType; CIEXYZTriple aV5Endpoints; sal_uInt32 nV5GammaRed; sal_uInt32 nV5GammaGreen; sal_uInt32 nV5GammaBlue; sal_uInt32 nV5Intent; sal_uInt32 nV5ProfileData; sal_uInt32 nV5ProfileSize; sal_uInt32 nV5Reserved; DIBV5Header() : DIBInfoHeader(), nV5RedMask(0UL), nV5GreenMask(0UL), nV5BlueMask(0UL), nV5AlphaMask(0UL), nV5CSType(0UL), aV5Endpoints(), nV5GammaRed(0UL), nV5GammaGreen(0UL), nV5GammaBlue(0UL), nV5Intent(0UL), nV5ProfileData(0UL), nV5ProfileSize(0UL), nV5Reserved(0UL) {} ~DIBV5Header() {} }; ////////////////////////////////////////////////////////////////////////////// namespace { inline sal_uInt16 discretizeBitcount( sal_uInt16 nInputCount ) { return ( nInputCount <= 1 ) ? 1 : ( nInputCount <= 4 ) ? 4 : ( nInputCount <= 8 ) ? 8 : 24; } inline bool isBitfieldCompression( sal_uLong nScanlineFormat ) { return (BMP_FORMAT_16BIT_TC_LSB_MASK == nScanlineFormat) || (BMP_FORMAT_32BIT_TC_MASK == nScanlineFormat); } } ////////////////////////////////////////////////////////////////////////////// bool ImplReadDIBInfoHeader(SvStream& rIStm, DIBV5Header& rHeader, bool& bTopDown) { // BITMAPINFOHEADER or BITMAPCOREHEADER or BITMAPV5HEADER const sal_Size aStartPos(rIStm.Tell()); rIStm >> rHeader.nSize; // BITMAPCOREHEADER if ( rHeader.nSize == DIBCOREHEADERSIZE ) { sal_Int16 nTmp16; rIStm >> nTmp16; rHeader.nWidth = nTmp16; rIStm >> nTmp16; rHeader.nHeight = nTmp16; rIStm >> rHeader.nPlanes; rIStm >> rHeader.nBitCount; } else { // BITMAPCOREHEADER, BITMAPV5HEADER or unknown. Read as far as possible sal_Size nUsed(sizeof(rHeader.nSize)); // read DIBInfoHeader entries if(nUsed < rHeader.nSize) { rIStm >> rHeader.nWidth; nUsed += sizeof(rHeader.nWidth); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nHeight; nUsed += sizeof(rHeader.nHeight); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nPlanes; nUsed += sizeof(rHeader.nPlanes); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nBitCount; nUsed += sizeof(rHeader.nBitCount); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nCompression; nUsed += sizeof(rHeader.nCompression); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nSizeImage; nUsed += sizeof(rHeader.nSizeImage); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nXPelsPerMeter; nUsed += sizeof(rHeader.nXPelsPerMeter); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nYPelsPerMeter; nUsed += sizeof(rHeader.nYPelsPerMeter); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nColsUsed; nUsed += sizeof(rHeader.nColsUsed); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nColsImportant; nUsed += sizeof(rHeader.nColsImportant); } // read DIBV5HEADER members if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5RedMask; nUsed += sizeof(rHeader.nV5RedMask); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5GreenMask; nUsed += sizeof(rHeader.nV5GreenMask); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5BlueMask; nUsed += sizeof(rHeader.nV5BlueMask); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5AlphaMask; nUsed += sizeof(rHeader.nV5AlphaMask); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5CSType; nUsed += sizeof(rHeader.nV5CSType); } // read contained CIEXYZTriple's if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzRed.aXyzX; nUsed += sizeof(rHeader.aV5Endpoints.aXyzRed.aXyzX); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzRed.aXyzY; nUsed += sizeof(rHeader.aV5Endpoints.aXyzRed.aXyzY); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzRed.aXyzZ; nUsed += sizeof(rHeader.aV5Endpoints.aXyzRed.aXyzZ); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzGreen.aXyzX; nUsed += sizeof(rHeader.aV5Endpoints.aXyzGreen.aXyzX); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzGreen.aXyzY; nUsed += sizeof(rHeader.aV5Endpoints.aXyzGreen.aXyzY); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzGreen.aXyzZ; nUsed += sizeof(rHeader.aV5Endpoints.aXyzGreen.aXyzZ); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzBlue.aXyzX; nUsed += sizeof(rHeader.aV5Endpoints.aXyzBlue.aXyzX); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzBlue.aXyzY; nUsed += sizeof(rHeader.aV5Endpoints.aXyzBlue.aXyzY); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzBlue.aXyzZ; nUsed += sizeof(rHeader.aV5Endpoints.aXyzBlue.aXyzZ); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5GammaRed; nUsed += sizeof(rHeader.nV5GammaRed); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5GammaGreen; nUsed += sizeof(rHeader.nV5GammaGreen); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5GammaBlue; nUsed += sizeof(rHeader.nV5GammaBlue); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5Intent; nUsed += sizeof(rHeader.nV5Intent); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5ProfileData; nUsed += sizeof(rHeader.nV5ProfileData); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5ProfileSize; nUsed += sizeof(rHeader.nV5ProfileSize); } if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5Reserved; nUsed += sizeof(rHeader.nV5Reserved); } // seek to EndPos rIStm.Seek(aStartPos + rHeader.nSize); } if ( rHeader.nHeight < 0 ) { bTopDown = true; rHeader.nHeight *= -1; } else { bTopDown = false; } if ( rHeader.nWidth < 0 ) { rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR ); } // #144105# protect a little against damaged files if( rHeader.nSizeImage > ( 16 * static_cast< sal_uInt32 >( rHeader.nWidth * rHeader.nHeight ) ) ) { rHeader.nSizeImage = 0; } return( ( rHeader.nPlanes == 1 ) && ( rIStm.GetError() == 0UL ) ); } bool ImplReadDIBPalette( SvStream& rIStm, BitmapWriteAccess& rAcc, bool bQuad ) { const sal_uInt16 nColors = rAcc.GetPaletteEntryCount(); const sal_uLong nPalSize = nColors * ( bQuad ? 4UL : 3UL ); BitmapColor aPalColor; sal_uInt8* pEntries = new sal_uInt8[ nPalSize ]; rIStm.Read( pEntries, nPalSize ); sal_uInt8* pTmpEntry = pEntries; for( sal_uInt16 i = 0; i < nColors; i++ ) { aPalColor.SetBlue( *pTmpEntry++ ); aPalColor.SetGreen( *pTmpEntry++ ); aPalColor.SetRed( *pTmpEntry++ ); if( bQuad ) pTmpEntry++; rAcc.SetPaletteColor( i, aPalColor ); } delete[] pEntries; return( rIStm.GetError() == 0UL ); } void ImplDecodeRLE( sal_uInt8* pBuffer, DIBV5Header& rHeader, BitmapWriteAccess& rAcc, bool bRLE4 ) { Scanline pRLE = pBuffer; long nY = rHeader.nHeight - 1L; const sal_uLong nWidth = rAcc.Width(); sal_uLong nCountByte; sal_uLong nRunByte; sal_uLong nX = 0UL; sal_uInt8 cTmp; bool bEndDecoding = false; do { if( ( nCountByte = *pRLE++ ) == 0 ) { nRunByte = *pRLE++; if( nRunByte > 2 ) { if( bRLE4 ) { nCountByte = nRunByte >> 1; for( sal_uLong i = 0UL; i < nCountByte; i++ ) { cTmp = *pRLE++; if( nX < nWidth ) rAcc.SetPixelIndex( nY, nX++, cTmp >> 4 ); if( nX < nWidth ) rAcc.SetPixelIndex( nY, nX++, cTmp & 0x0f ); } if( nRunByte & 1 ) { if( nX < nWidth ) rAcc.SetPixelIndex( nY, nX++, *pRLE >> 4 ); pRLE++; } if( ( ( nRunByte + 1 ) >> 1 ) & 1 ) pRLE++; } else { for( sal_uLong i = 0UL; i < nRunByte; i++ ) { if( nX < nWidth ) rAcc.SetPixelIndex( nY, nX++, *pRLE ); pRLE++; } if( nRunByte & 1 ) pRLE++; } } else if( !nRunByte ) { nY--; nX = 0UL; } else if( nRunByte == 1 ) bEndDecoding = true; else { nX += *pRLE++; nY -= *pRLE++; } } else { cTmp = *pRLE++; if( bRLE4 ) { nRunByte = nCountByte >> 1; for( sal_uLong i = 0UL; i < nRunByte; i++ ) { if( nX < nWidth ) rAcc.SetPixelIndex( nY, nX++, cTmp >> 4 ); if( nX < nWidth ) rAcc.SetPixelIndex( nY, nX++, cTmp & 0x0f ); } if( ( nCountByte & 1 ) && ( nX < nWidth ) ) rAcc.SetPixelIndex( nY, nX++, cTmp >> 4 ); } else { for( sal_uLong i = 0UL; ( i < nCountByte ) && ( nX < nWidth ); i++ ) rAcc.SetPixelIndex( nY, nX++, cTmp ); } } } while ( !bEndDecoding && ( nY >= 0L ) ); } bool ImplReadDIBBits(SvStream& rIStm, DIBV5Header& rHeader, BitmapWriteAccess& rAcc, BitmapWriteAccess* pAccAlpha, bool bTopDown) { const sal_uLong nAlignedWidth = AlignedWidth4Bytes(rHeader.nWidth * rHeader.nBitCount); sal_uInt32 nRMask(0); sal_uInt32 nGMask(0); sal_uInt32 nBMask(0); bool bNative(false); bool bTCMask(!pAccAlpha && ((16 == rHeader.nBitCount) || (32 == rHeader.nBitCount))); bool bRLE((RLE_8 == rHeader.nCompression && 8 == rHeader.nBitCount) || (RLE_4 == rHeader.nCompression && 4 == rHeader.nBitCount)); // Is native format? switch(rAcc.GetScanlineFormat()) { case( BMP_FORMAT_1BIT_MSB_PAL ): case( BMP_FORMAT_4BIT_MSN_PAL ): case( BMP_FORMAT_8BIT_PAL ): case( BMP_FORMAT_24BIT_TC_BGR ): { bNative = ( ( static_cast< bool >(rAcc.IsBottomUp()) != bTopDown ) && !bRLE && !bTCMask && ( rAcc.GetScanlineSize() == nAlignedWidth ) ); break; } default: { break; } } // Read data if(bNative) { // true color DIB's can have a (optimization) palette if(rHeader.nColsUsed && 8 < rHeader.nBitCount) { rIStm.SeekRel(rHeader.nColsUsed * ((rHeader.nSize != DIBCOREHEADERSIZE ) ? 4 : 3)); } rIStm.Read(rAcc.GetBuffer(), rHeader.nHeight * nAlignedWidth); } else { // Read color mask if(bTCMask) { if(BITFIELDS == rHeader.nCompression) { rIStm.SeekRel( -12L ); rIStm >> nRMask; rIStm >> nGMask; rIStm >> nBMask; } else { nRMask = ( rHeader.nBitCount == 16 ) ? 0x00007c00UL : 0x00ff0000UL; nGMask = ( rHeader.nBitCount == 16 ) ? 0x000003e0UL : 0x0000ff00UL; nBMask = ( rHeader.nBitCount == 16 ) ? 0x0000001fUL : 0x000000ffUL; } } if(bRLE) { if(!rHeader.nSizeImage) { const sal_uLong nOldPos(rIStm.Tell()); rIStm.Seek(STREAM_SEEK_TO_END); rHeader.nSizeImage = rIStm.Tell() - nOldPos; rIStm.Seek(nOldPos); } sal_uInt8* pBuffer = (sal_uInt8*)rtl_allocateMemory(rHeader.nSizeImage); rIStm.Read((char*)pBuffer, rHeader.nSizeImage); ImplDecodeRLE(pBuffer, rHeader, rAcc, RLE_4 == rHeader.nCompression); rtl_freeMemory(pBuffer); } else { const long nWidth(rHeader.nWidth); const long nHeight(rHeader.nHeight); sal_uInt8* pBuf = new sal_uInt8[nAlignedWidth]; // true color DIB's can have a (optimization) palette if(rHeader.nColsUsed && 8 < rHeader.nBitCount) { rIStm.SeekRel(rHeader.nColsUsed * ((rHeader.nSize != DIBCOREHEADERSIZE ) ? 4 : 3)); } const long nI(bTopDown ? 1 : -1); long nY(bTopDown ? 0 : nHeight - 1); long nCount(nHeight); switch(rHeader.nBitCount) { case( 1 ): { sal_uInt8* pTmp; sal_uInt8 cTmp; for( ; nCount--; nY += nI ) { rIStm.Read( pTmp = pBuf, nAlignedWidth ); cTmp = *pTmp++; for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ ) { if( !nShift ) { nShift = 8L, cTmp = *pTmp++; } rAcc.SetPixelIndex( nY, nX, (cTmp >> --nShift) & 1); } } } break; case( 4 ): { sal_uInt8* pTmp; sal_uInt8 cTmp; for( ; nCount--; nY += nI ) { rIStm.Read( pTmp = pBuf, nAlignedWidth ); cTmp = *pTmp++; for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ ) { if( !nShift ) { nShift = 2UL, cTmp = *pTmp++; } rAcc.SetPixelIndex( nY, nX, (cTmp >> ( --nShift << 2UL ) ) & 0x0f); } } } break; case( 8 ): { sal_uInt8* pTmp; for( ; nCount--; nY += nI ) { rIStm.Read( pTmp = pBuf, nAlignedWidth ); for( long nX = 0L; nX < nWidth; nX++ ) rAcc.SetPixelIndex( nY, nX, *pTmp++ ); } } break; case( 16 ): { ColorMask aMask( nRMask, nGMask, nBMask ); BitmapColor aColor; sal_uInt16* pTmp16; for( ; nCount--; nY += nI ) { rIStm.Read( (char*)( pTmp16 = (sal_uInt16*) pBuf ), nAlignedWidth ); for( long nX = 0L; nX < nWidth; nX++ ) { aMask.GetColorFor16BitLSB( aColor, (sal_uInt8*) pTmp16++ ); rAcc.SetPixel( nY, nX, aColor ); } } } break; case( 24 ): { BitmapColor aPixelColor; sal_uInt8* pTmp; for( ; nCount--; nY += nI ) { rIStm.Read( pTmp = pBuf, nAlignedWidth ); for( long nX = 0L; nX < nWidth; nX++ ) { aPixelColor.SetBlue( *pTmp++ ); aPixelColor.SetGreen( *pTmp++ ); aPixelColor.SetRed( *pTmp++ ); rAcc.SetPixel( nY, nX, aPixelColor ); } } } break; case( 32 ): { ColorMask aMask(nRMask, nGMask, nBMask); BitmapColor aColor; sal_uInt32* pTmp32; if(pAccAlpha) { sal_uInt8 aAlpha; for( ; nCount--; nY += nI ) { rIStm.Read( (char*)( pTmp32 = (sal_uInt32*) pBuf ), nAlignedWidth ); for( long nX = 0L; nX < nWidth; nX++ ) { aMask.GetColorAndAlphaFor32Bit( aColor, aAlpha, (sal_uInt8*) pTmp32++ ); rAcc.SetPixel( nY, nX, aColor ); pAccAlpha->SetPixelIndex(nY, nX, sal_uInt8(0xff) - aAlpha); } } } else { for( ; nCount--; nY += nI ) { rIStm.Read( (char*)( pTmp32 = (sal_uInt32*) pBuf ), nAlignedWidth ); for( long nX = 0L; nX < nWidth; nX++ ) { aMask.GetColorFor32Bit( aColor, (sal_uInt8*) pTmp32++ ); rAcc.SetPixel( nY, nX, aColor ); } } } } } delete[] pBuf; } } return( rIStm.GetError() == 0UL ); } bool ImplReadDIBBody( SvStream& rIStm, Bitmap& rBmp, Bitmap* pBmpAlpha, sal_uLong nOffset ) { DIBV5Header aHeader; const sal_uLong nStmPos = rIStm.Tell(); bool bRet(false); bool bTopDown(false); if(ImplReadDIBInfoHeader(rIStm, aHeader, bTopDown) && aHeader.nWidth && aHeader.nHeight && aHeader.nBitCount) { const sal_uInt16 nBitCount(discretizeBitcount(aHeader.nBitCount)); const Size aSizePixel(aHeader.nWidth, aHeader.nHeight); BitmapPalette aDummyPal; Bitmap aNewBmp(aSizePixel, nBitCount, &aDummyPal); Bitmap aNewBmpAlpha; BitmapWriteAccess* pAcc = aNewBmp.AcquireWriteAccess(); BitmapWriteAccess* pAccAlpha = 0; bool bAlphaPossible(pBmpAlpha && aHeader.nBitCount == 32); if(bAlphaPossible) { const bool bRedSet(0 != aHeader.nV5RedMask); const bool bGreenSet(0 != aHeader.nV5GreenMask); const bool bBlueSet(0 != aHeader.nV5BlueMask); // some clipboard entries have alpha mask on zero to say that there is // no alpha; do only use this when the other masks are set. The MS docu // says that that masks are only to be set when bV5Compression is set to // BI_BITFIELDS, but there seem to exist a wild variety of usages... if((bRedSet || bGreenSet || bBlueSet) && (0 == aHeader.nV5AlphaMask)) { bAlphaPossible = false; } } if(bAlphaPossible) { aNewBmpAlpha = Bitmap(aSizePixel, 8); pAccAlpha = aNewBmpAlpha.AcquireWriteAccess(); } if(pAcc) { sal_uInt16 nColors(0); SvStream* pIStm; SvMemoryStream* pMemStm = NULL; sal_uInt8* pData = NULL; if(nBitCount <= 8) { if(aHeader.nColsUsed) { nColors = (sal_uInt16)aHeader.nColsUsed; } else { nColors = ( 1 << aHeader.nBitCount ); } } if(ZCOMPRESS == aHeader.nCompression) { ZCodec aCodec; sal_uInt32 nCodedSize(0); sal_uInt32 nUncodedSize(0); sal_uLong nCodedPos(0); // read coding information rIStm >> nCodedSize >> nUncodedSize >> aHeader.nCompression; pData = (sal_uInt8*) rtl_allocateMemory( nUncodedSize ); // decode buffer nCodedPos = rIStm.Tell(); aCodec.BeginCompression(); aCodec.Read( rIStm, pData, nUncodedSize ); aCodec.EndCompression(); // skip unread bytes from coded buffer rIStm.SeekRel( nCodedSize - ( rIStm.Tell() - nCodedPos ) ); // set decoded bytes to memory stream, // from which we will read the bitmap data pIStm = pMemStm = new SvMemoryStream; pMemStm->SetBuffer( (char*) pData, nUncodedSize, false, nUncodedSize ); nOffset = 0; } else { pIStm = &rIStm; } // read palette if(nColors) { pAcc->SetPaletteEntryCount(nColors); ImplReadDIBPalette(*pIStm, *pAcc, aHeader.nSize != DIBCOREHEADERSIZE); } // read bits if(!pIStm->GetError()) { if(nOffset) { pIStm->SeekRel(nOffset - (pIStm->Tell() - nStmPos)); } bRet = ImplReadDIBBits(*pIStm, aHeader, *pAcc, pAccAlpha, bTopDown); if(bRet && aHeader.nXPelsPerMeter && aHeader.nYPelsPerMeter) { MapMode aMapMode( MAP_MM, Point(), Fraction(1000, aHeader.nXPelsPerMeter), Fraction(1000, aHeader.nYPelsPerMeter)); aNewBmp.SetPrefMapMode(aMapMode); aNewBmp.SetPrefSize(Size(aHeader.nWidth, aHeader.nHeight)); } } if( pData ) { rtl_freeMemory(pData); } delete pMemStm; aNewBmp.ReleaseAccess(pAcc); if(bAlphaPossible) { aNewBmpAlpha.ReleaseAccess(pAccAlpha); } if(bRet) { rBmp = aNewBmp; if(bAlphaPossible) { *pBmpAlpha = aNewBmpAlpha; } } } } return bRet; } bool ImplReadDIBFileHeader( SvStream& rIStm, sal_uLong& rOffset ) { sal_uInt32 nTmp32; sal_uInt16 nTmp16 = 0; bool bRet = false; rIStm >> nTmp16; if ( ( 0x4D42 == nTmp16 ) || ( 0x4142 == nTmp16 ) ) { if ( 0x4142 == nTmp16 ) { rIStm.SeekRel( 12L ); rIStm >> nTmp16; rIStm.SeekRel( 8L ); rIStm >> nTmp32; rOffset = nTmp32 - 28UL; bRet = ( 0x4D42 == nTmp16 ); } else // 0x4D42 == nTmp16, 'MB' from BITMAPFILEHEADER { rIStm.SeekRel( 8L ); // we are on bfSize member of BITMAPFILEHEADER, forward to bfOffBits rIStm >> nTmp32; // read bfOffBits rOffset = nTmp32 - 14UL; // adapt offset by sizeof(BITMAPFILEHEADER) bRet = ( rIStm.GetError() == 0UL ); } } else rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR ); return bRet; } bool ImplWriteDIBPalette( SvStream& rOStm, BitmapReadAccess& rAcc ) { const sal_uInt16 nColors = rAcc.GetPaletteEntryCount(); const sal_uLong nPalSize = nColors * 4UL; sal_uInt8* pEntries = new sal_uInt8[ nPalSize ]; sal_uInt8* pTmpEntry = pEntries; BitmapColor aPalColor; for( sal_uInt16 i = 0; i < nColors; i++ ) { const BitmapColor& rPalColor = rAcc.GetPaletteColor( i ); *pTmpEntry++ = rPalColor.GetBlue(); *pTmpEntry++ = rPalColor.GetGreen(); *pTmpEntry++ = rPalColor.GetRed(); *pTmpEntry++ = 0; } rOStm.Write( pEntries, nPalSize ); delete[] pEntries; return( rOStm.GetError() == 0UL ); } bool ImplWriteRLE( SvStream& rOStm, BitmapReadAccess& rAcc, bool bRLE4 ) { const sal_uLong nWidth = rAcc.Width(); const sal_uLong nHeight = rAcc.Height(); sal_uLong nX; sal_uLong nSaveIndex; sal_uLong nCount; sal_uLong nBufCount; sal_uInt8* pBuf = new sal_uInt8[ ( nWidth << 1 ) + 2 ]; sal_uInt8* pTmp; sal_uInt8 cPix; sal_uInt8 cLast; bool bFound; for ( long nY = nHeight - 1L; nY >= 0L; nY-- ) { pTmp = pBuf; nX = nBufCount = 0UL; while( nX < nWidth ) { nCount = 1L; cPix = rAcc.GetPixelIndex( nY, nX++ ); while( ( nX < nWidth ) && ( nCount < 255L ) && ( cPix == rAcc.GetPixelIndex( nY, nX ) ) ) { nX++; nCount++; } if ( nCount > 1 ) { *pTmp++ = (sal_uInt8) nCount; *pTmp++ = ( bRLE4 ? ( ( cPix << 4 ) | cPix ) : cPix ); nBufCount += 2; } else { cLast = cPix; nSaveIndex = nX - 1UL; bFound = false; while( ( nX < nWidth ) && ( nCount < 256L ) && ( cPix = rAcc.GetPixelIndex( nY, nX ) ) != cLast ) { nX++; nCount++; cLast = cPix; bFound = true; } if ( bFound ) nX--; if ( nCount > 3 ) { *pTmp++ = 0; *pTmp++ = (sal_uInt8) --nCount; if( bRLE4 ) { for ( sal_uLong i = 0; i < nCount; i++, pTmp++ ) { *pTmp = rAcc.GetPixelIndex( nY, nSaveIndex++ ) << 4; if ( ++i < nCount ) *pTmp |= rAcc.GetPixelIndex( nY, nSaveIndex++ ); } nCount = ( nCount + 1 ) >> 1; } else { for( sal_uLong i = 0UL; i < nCount; i++ ) *pTmp++ = rAcc.GetPixelIndex( nY, nSaveIndex++ ); } if ( nCount & 1 ) { *pTmp++ = 0; nBufCount += ( nCount + 3 ); } else nBufCount += ( nCount + 2 ); } else { *pTmp++ = 1; *pTmp++ = rAcc.GetPixelIndex( nY, nSaveIndex ) << (bRLE4 ? 4 : 0); if ( nCount == 3 ) { *pTmp++ = 1; *pTmp++ = rAcc.GetPixelIndex( nY, ++nSaveIndex ) << ( bRLE4 ? 4 : 0 ); nBufCount += 4; } else nBufCount += 2; } } } pBuf[ nBufCount++ ] = 0; pBuf[ nBufCount++ ] = 0; rOStm.Write( pBuf, nBufCount ); } rOStm << (sal_uInt8) 0; rOStm << (sal_uInt8) 1; delete[] pBuf; return( rOStm.GetError() == 0UL ); } bool ImplWriteDIBBits(SvStream& rOStm, BitmapReadAccess& rAcc, BitmapReadAccess* pAccAlpha, sal_uLong nCompression, sal_uInt32& rImageSize) { if(!pAccAlpha && BITFIELDS == nCompression) { const ColorMask& rMask = rAcc.GetColorMask(); SVBT32 aVal32; UInt32ToSVBT32( rMask.GetRedMask(), aVal32 ); rOStm.Write( (sal_uInt8*) aVal32, 4UL ); UInt32ToSVBT32( rMask.GetGreenMask(), aVal32 ); rOStm.Write( (sal_uInt8*) aVal32, 4UL ); UInt32ToSVBT32( rMask.GetBlueMask(), aVal32 ); rOStm.Write( (sal_uInt8*) aVal32, 4UL ); rImageSize = rOStm.Tell(); if( rAcc.IsBottomUp() ) rOStm.Write( rAcc.GetBuffer(), rAcc.Height() * rAcc.GetScanlineSize() ); else { for( long nY = rAcc.Height() - 1, nScanlineSize = rAcc.GetScanlineSize(); nY >= 0L; nY-- ) rOStm.Write( rAcc.GetScanline( nY ), nScanlineSize ); } } else if(!pAccAlpha && ((RLE_4 == nCompression) || (RLE_8 == nCompression))) { rImageSize = rOStm.Tell(); ImplWriteRLE( rOStm, rAcc, RLE_4 == nCompression ); } else if(!nCompression) { // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are not // handled properly below (would have to set color masks, and // nCompression=BITFIELDS - but color mask is not set for // formats != *_TC_*). Note that this very problem might cause // trouble at other places - the introduction of 32 bit RGBA // bitmaps is relatively recent. // #i59239# discretize bitcount for aligned width to 1,4,8,24 // (other cases are not written below) const sal_uInt16 nBitCount(pAccAlpha ? 32 : discretizeBitcount(static_cast< sal_uInt16 >(rAcc.GetBitCount()))); const sal_uLong nAlignedWidth(AlignedWidth4Bytes(rAcc.Width() * nBitCount)); bool bNative(false); switch(rAcc.GetScanlineFormat()) { case( BMP_FORMAT_1BIT_MSB_PAL ): case( BMP_FORMAT_4BIT_MSN_PAL ): case( BMP_FORMAT_8BIT_PAL ): case( BMP_FORMAT_24BIT_TC_BGR ): { if(!pAccAlpha && rAcc.IsBottomUp() && (rAcc.GetScanlineSize() == nAlignedWidth)) { bNative = true; } break; } default: { break; } } rImageSize = rOStm.Tell(); if(bNative) { rOStm.Write(rAcc.GetBuffer(), nAlignedWidth * rAcc.Height()); } else { const long nWidth(rAcc.Width()); const long nHeight(rAcc.Height()); sal_uInt8* pBuf = new sal_uInt8[ nAlignedWidth ]; sal_uInt8* pTmp(0); sal_uInt8 cTmp(0); switch( nBitCount ) { case( 1 ): { for( long nY = nHeight - 1; nY >= 0L; nY-- ) { pTmp = pBuf; cTmp = 0; for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ ) { if( !nShift ) { nShift = 8L; *pTmp++ = cTmp; cTmp = 0; } cTmp |= rAcc.GetPixelIndex( nY, nX ) << --nShift; } *pTmp = cTmp; rOStm.Write( pBuf, nAlignedWidth ); } } break; case( 4 ): { for( long nY = nHeight - 1; nY >= 0L; nY-- ) { pTmp = pBuf; cTmp = 0; for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ ) { if( !nShift ) { nShift = 2L; *pTmp++ = cTmp; cTmp = 0; } cTmp |= rAcc.GetPixelIndex( nY, nX ) << ( --nShift << 2L ); } *pTmp = cTmp; rOStm.Write( pBuf, nAlignedWidth ); } } break; case( 8 ): { for( long nY = nHeight - 1; nY >= 0L; nY-- ) { pTmp = pBuf; for( long nX = 0L; nX < nWidth; nX++ ) *pTmp++ = rAcc.GetPixelIndex( nY, nX ); rOStm.Write( pBuf, nAlignedWidth ); } } break; // #i59239# fallback to 24 bit format, if bitcount is non-default default: // FALLTHROUGH intended case( 24 ): { BitmapColor aPixelColor; const bool bWriteAlpha(32 == nBitCount && pAccAlpha); for( long nY = nHeight - 1; nY >= 0L; nY-- ) { pTmp = pBuf; for( long nX = 0L; nX < nWidth; nX++ ) { // when alpha is used, this may be non-24bit main bitmap, so use GetColor // instead of GetPixel to ensure RGB value aPixelColor = rAcc.GetColor( nY, nX ); *pTmp++ = aPixelColor.GetBlue(); *pTmp++ = aPixelColor.GetGreen(); *pTmp++ = aPixelColor.GetRed(); if(bWriteAlpha) { if(pAccAlpha) { *pTmp++ = (sal_uInt8)0xff - (sal_uInt8)pAccAlpha->GetPixelIndex( nY, nX ); } else { *pTmp++ = (sal_uInt8)0xff; } } } rOStm.Write( pBuf, nAlignedWidth ); } } break; } delete[] pBuf; } } rImageSize = rOStm.Tell() - rImageSize; return (!rOStm.GetError()); } bool ImplWriteDIBBody(const Bitmap& rBitmap, SvStream& rOStm, BitmapReadAccess& rAcc, BitmapReadAccess* pAccAlpha, bool bCompressed) { const MapMode aMapPixel(MAP_PIXEL); DIBV5Header aHeader; sal_uLong nImageSizePos(0); sal_uLong nEndPos(0); sal_uInt32 nCompression(COMPRESS_NONE); bool bRet(false); aHeader.nSize = pAccAlpha ? DIBV5HEADERSIZE : DIBINFOHEADERSIZE; // size dependent on CF_DIB type to use aHeader.nWidth = rAcc.Width(); aHeader.nHeight = rAcc.Height(); aHeader.nPlanes = 1; if(!pAccAlpha && isBitfieldCompression(rAcc.GetScanlineFormat())) { aHeader.nBitCount = (BMP_FORMAT_16BIT_TC_LSB_MASK == rAcc.GetScanlineFormat()) ? 16 : 32; aHeader.nSizeImage = rAcc.Height() * rAcc.GetScanlineSize(); nCompression = BITFIELDS; } else { // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are // not handled properly below (would have to set color // masks, and nCompression=BITFIELDS - but color mask is // not set for formats != *_TC_*). Note that this very // problem might cause trouble at other places - the // introduction of 32 bit RGBA bitmaps is relatively // recent. // #i59239# discretize bitcount to 1,4,8,24 (other cases // are not written below) const sal_uInt16 nBitCount(pAccAlpha ? 32 : discretizeBitcount(static_cast< sal_uInt16 >(rAcc.GetBitCount()))); aHeader.nBitCount = nBitCount; aHeader.nSizeImage = rAcc.Height() * AlignedWidth4Bytes(rAcc.Width() * aHeader.nBitCount); if(bCompressed) { if(4 == nBitCount) { nCompression = RLE_4; } else if(8 == nBitCount) { nCompression = RLE_8; } } } if((rOStm.GetCompressMode() & COMPRESSMODE_ZBITMAP) && (rOStm.GetVersion() >= SOFFICE_FILEFORMAT_40)) { aHeader.nCompression = ZCOMPRESS; } else { aHeader.nCompression = nCompression; } if(rBitmap.GetPrefSize().Width() && rBitmap.GetPrefSize().Height() && (rBitmap.GetPrefMapMode() != aMapPixel)) { // #i48108# Try to recover xpels/ypels as previously stored on // disk. The problem with just converting maPrefSize to 100th // mm and then relating that to the bitmap pixel size is that // MapMode is integer-based, and suffers from roundoffs, // especially if maPrefSize is small. Trying to circumvent // that by performing part of the math in floating point. const Size aScale100000(OutputDevice::LogicToLogic(Size(100000L, 100000L), MAP_100TH_MM, rBitmap.GetPrefMapMode())); const double fBmpWidthM((double)rBitmap.GetPrefSize().Width() / aScale100000.Width()); const double fBmpHeightM((double)rBitmap.GetPrefSize().Height() / aScale100000.Height()); if(!basegfx::fTools::equalZero(fBmpWidthM) && !basegfx::fTools::equalZero(fBmpHeightM)) { aHeader.nXPelsPerMeter = basegfx::fround(rAcc.Width() / fabs(fBmpWidthM)); aHeader.nYPelsPerMeter = basegfx::fround(rAcc.Height() / fabs(fBmpHeightM)); } } aHeader.nColsUsed = ((!pAccAlpha && aHeader.nBitCount <= 8) ? rAcc.GetPaletteEntryCount() : 0); aHeader.nColsImportant = 0; rOStm << aHeader.nSize; rOStm << aHeader.nWidth; rOStm << aHeader.nHeight; rOStm << aHeader.nPlanes; rOStm << aHeader.nBitCount; rOStm << aHeader.nCompression; nImageSizePos = rOStm.Tell(); rOStm.SeekRel( sizeof( aHeader.nSizeImage ) ); rOStm << aHeader.nXPelsPerMeter; rOStm << aHeader.nYPelsPerMeter; rOStm << aHeader.nColsUsed; rOStm << aHeader.nColsImportant; if(pAccAlpha) // only write DIBV5 when asked to do so { aHeader.nV5CSType = 0x57696E20; // LCS_WINDOWS_COLOR_SPACE aHeader.nV5Intent = 0x00000008; // LCS_GM_ABS_COLORIMETRIC rOStm << aHeader.nV5RedMask; rOStm << aHeader.nV5GreenMask; rOStm << aHeader.nV5BlueMask; rOStm << aHeader.nV5AlphaMask; rOStm << aHeader.nV5CSType; rOStm << aHeader.aV5Endpoints.aXyzRed.aXyzX; rOStm << aHeader.aV5Endpoints.aXyzRed.aXyzY; rOStm << aHeader.aV5Endpoints.aXyzRed.aXyzZ; rOStm << aHeader.aV5Endpoints.aXyzGreen.aXyzX; rOStm << aHeader.aV5Endpoints.aXyzGreen.aXyzY; rOStm << aHeader.aV5Endpoints.aXyzGreen.aXyzZ; rOStm << aHeader.aV5Endpoints.aXyzBlue.aXyzX; rOStm << aHeader.aV5Endpoints.aXyzBlue.aXyzY; rOStm << aHeader.aV5Endpoints.aXyzBlue.aXyzZ; rOStm << aHeader.nV5GammaRed; rOStm << aHeader.nV5GammaGreen; rOStm << aHeader.nV5GammaBlue; rOStm << aHeader.nV5Intent; rOStm << aHeader.nV5ProfileData; rOStm << aHeader.nV5ProfileSize; rOStm << aHeader.nV5Reserved; } if(ZCOMPRESS == aHeader.nCompression) { ZCodec aCodec; SvMemoryStream aMemStm(aHeader.nSizeImage + 4096, 65535); sal_uLong nCodedPos(rOStm.Tell()); sal_uLong nLastPos(0); sal_uInt32 nCodedSize(0); sal_uInt32 nUncodedSize(0); // write uncoded data palette if(aHeader.nColsUsed) { ImplWriteDIBPalette(aMemStm, rAcc); } // write uncoded bits bRet = ImplWriteDIBBits(aMemStm, rAcc, pAccAlpha, nCompression, aHeader.nSizeImage); // get uncoded size nUncodedSize = aMemStm.Tell(); // seek over compress info rOStm.SeekRel(12); // write compressed data aCodec.BeginCompression(3); aCodec.Write(rOStm, (sal_uInt8*)aMemStm.GetData(), nUncodedSize); aCodec.EndCompression(); // update compress info ( coded size, uncoded size, uncoded compression ) nLastPos = rOStm.Tell(); nCodedSize = nLastPos - nCodedPos - 12; rOStm.Seek(nCodedPos); rOStm << nCodedSize << nUncodedSize << nCompression; rOStm.Seek(nLastPos); if(bRet) { bRet = (ERRCODE_NONE == rOStm.GetError()); } } else { if(aHeader.nColsUsed) { ImplWriteDIBPalette(rOStm, rAcc); } bRet = ImplWriteDIBBits(rOStm, rAcc, pAccAlpha, aHeader.nCompression, aHeader.nSizeImage); } nEndPos = rOStm.Tell(); rOStm.Seek(nImageSizePos); rOStm << aHeader.nSizeImage; rOStm.Seek(nEndPos); return bRet; } bool ImplWriteDIBFileHeader(SvStream& rOStm, BitmapReadAccess& rAcc, bool bUseDIBV5) { const sal_uInt32 nPalCount((rAcc.HasPalette() ? rAcc.GetPaletteEntryCount() : isBitfieldCompression(rAcc.GetScanlineFormat()) ? 3UL : 0UL)); const sal_uInt32 nOffset(14 + (bUseDIBV5 ? DIBV5HEADERSIZE : DIBINFOHEADERSIZE) + nPalCount * 4UL); rOStm << (sal_uInt16)0x4D42; // 'MB' from BITMAPFILEHEADER rOStm << (sal_uInt32)(nOffset + (rAcc.Height() * rAcc.GetScanlineSize())); rOStm << (sal_uInt16)0; rOStm << (sal_uInt16)0; rOStm << nOffset; return( rOStm.GetError() == 0UL ); } ////////////////////////////////////////////////////////////////////////////// bool ImplReadDIB( Bitmap& rTarget, Bitmap* pTargetAlpha, SvStream& rIStm, bool bFileHeader) { const sal_uInt16 nOldFormat(rIStm.GetNumberFormatInt()); const sal_uLong nOldPos(rIStm.Tell()); sal_uLong nOffset(0UL); bool bRet(false); rIStm.SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN); if(bFileHeader) { if(ImplReadDIBFileHeader(rIStm, nOffset)) { bRet = ImplReadDIBBody(rIStm, rTarget, nOffset >= DIBV5HEADERSIZE ? pTargetAlpha : 0, nOffset); } } else { bRet = ImplReadDIBBody(rIStm, rTarget, 0, nOffset); } if(!bRet) { if(!rIStm.GetError()) { rIStm.SetError(SVSTREAM_GENERALERROR); } rIStm.Seek(nOldPos); } rIStm.SetNumberFormatInt(nOldFormat); return bRet; } bool ImplWriteDIB( const Bitmap& rSource, const Bitmap* pSourceAlpha, SvStream& rOStm, bool bCompressed, bool bFileHeader) { const Size aSizePix(rSource.GetSizePixel()); bool bRet(false); if(aSizePix.Width() && aSizePix.Height()) { BitmapReadAccess* pAcc = const_cast< Bitmap& >(rSource).AcquireReadAccess(); BitmapReadAccess* pAccAlpha = 0; const sal_uInt16 nOldFormat(rOStm.GetNumberFormatInt()); const sal_uLong nOldPos(rOStm.Tell()); if(pSourceAlpha) { const Size aSizePixAlpha(pSourceAlpha->GetSizePixel()); if(aSizePixAlpha == aSizePix) { pAccAlpha = const_cast< Bitmap* >(pSourceAlpha)->AcquireReadAccess(); } else { OSL_ENSURE(false, "WriteDIB got an alpha channel, but it's pixel size differs from the base bitmap (!)"); } } rOStm.SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN); if(pAcc) { if(bFileHeader) { if(ImplWriteDIBFileHeader(rOStm, *pAcc, 0 != pSourceAlpha)) { bRet = ImplWriteDIBBody(rSource, rOStm, *pAcc, pAccAlpha, bCompressed); } } else { bRet = ImplWriteDIBBody(rSource, rOStm, *pAcc, pAccAlpha, bCompressed); } const_cast< Bitmap& >(rSource).ReleaseAccess(pAcc); if(pAccAlpha) { const_cast< Bitmap* >(pSourceAlpha)->ReleaseAccess(pAccAlpha); } } if(!bRet) { rOStm.SetError(SVSTREAM_GENERALERROR); rOStm.Seek(nOldPos); } rOStm.SetNumberFormatInt(nOldFormat); } return bRet; } ////////////////////////////////////////////////////////////////////////////// bool ReadDIB( Bitmap& rTarget, SvStream& rIStm, bool bFileHeader) { return ImplReadDIB(rTarget, 0, rIStm, bFileHeader); } bool ReadDIBBitmapEx( BitmapEx& rTarget, SvStream& rIStm) { Bitmap aBmp; bool bRetval(ImplReadDIB(aBmp, 0, rIStm, true) && !rIStm.GetError()); if(bRetval) { // base bitmap was read, set as return value and try to read alpha extra-data const sal_uLong nStmPos(rIStm.Tell()); sal_uInt32 nMagic1(0); sal_uInt32 nMagic2(0); rTarget = BitmapEx(aBmp); rIStm >> nMagic1 >> nMagic2; bRetval = (0x25091962 == nMagic1) && (0xACB20201 == nMagic2) && !rIStm.GetError(); if(bRetval) { sal_uInt8 bTransparent(false); rIStm >> bTransparent; bRetval = !rIStm.GetError(); if(bRetval) { if((sal_uInt8)TRANSPARENT_BITMAP == bTransparent) { Bitmap aMask; bRetval = ImplReadDIB(aMask, 0, rIStm, true); if(bRetval) { if(!!aMask) { // do we have an alpha mask? if((8 == aMask.GetBitCount()) && aMask.HasGreyPalette()) { AlphaMask aAlpha; // create alpha mask quickly (without greyscale conversion) aAlpha.ImplSetBitmap(aMask); rTarget = BitmapEx(aBmp, aAlpha); } else { rTarget = BitmapEx(aBmp, aMask); } } } } else if((sal_uInt8)TRANSPARENT_COLOR == bTransparent) { Color aTransparentColor; rIStm >> aTransparentColor; bRetval = !rIStm.GetError(); if(bRetval) { rTarget = BitmapEx(aBmp, aTransparentColor); } } } } if(!bRetval) { // alpha extra data could not be read; reset, but use base bitmap as result rIStm.ResetError(); rIStm.Seek(nStmPos); bRetval = true; } } return bRetval; } bool ReadDIBV5( Bitmap& rTarget, Bitmap& rTargetAlpha, SvStream& rIStm) { return ImplReadDIB(rTarget, &rTargetAlpha, rIStm, true); } ////////////////////////////////////////////////////////////////////////////// bool WriteDIB( const Bitmap& rSource, SvStream& rOStm, bool bCompressed, bool bFileHeader) { return ImplWriteDIB(rSource, 0, rOStm, bCompressed, bFileHeader); } bool WriteDIBBitmapEx( const BitmapEx& rSource, SvStream& rOStm) { if(ImplWriteDIB(rSource.GetBitmap(), 0, rOStm, true, true)) { rOStm << (sal_uInt32)0x25091962; rOStm << (sal_uInt32)0xACB20201; rOStm << (sal_uInt8)rSource.eTransparent; if(TRANSPARENT_BITMAP == rSource.eTransparent) { return ImplWriteDIB(rSource.aMask, 0, rOStm, true, true); } else if(TRANSPARENT_COLOR == rSource.eTransparent) { rOStm << rSource.aTransparentColor; return true; } } return false; } bool WriteDIBV5( const Bitmap& rSource, const Bitmap& rSourceAlpha, SvStream& rOStm) { return ImplWriteDIB(rSource, &rSourceAlpha, rOStm, false, true); } ////////////////////////////////////////////////////////////////////////////// // eof