summaryrefslogtreecommitdiff
path: root/vcl/source/gdi/dibtools.cxx
diff options
context:
space:
mode:
authorArmin Le Grand <alg@apache.org>2013-01-10 16:28:40 +0000
committerCaolán McNamara <caolanm@redhat.com>2013-06-13 14:50:46 +0100
commite0cce521f1ad0cc384d30ce2f1077ea229fffe62 (patch)
treeae40b74bceb4b036d87b79e861f5eef76ec41102 /vcl/source/gdi/dibtools.cxx
parent6ed3ef87d2472bad71b719e9ec927e72acfd2850 (diff)
Resolves: #i121504# Support for alpha channel in clipboard for all systems
(cherry picked from commit ef3931ff410117e1237b3bef7bc090e8b83b9519) Conflicts: automation/source/server/statemnt.cxx basic/source/runtime/methods.cxx canvas/source/vcl/devicehelper.cxx canvas/source/vcl/spritedevicehelper.cxx drawinglayer/source/processor2d/vclhelperbufferdevice.cxx drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx drawinglayer/source/tools/converters.cxx dtrans/source/win32/dtobj/FmtFilter.cxx editeng/source/items/bulitem.cxx extensions/source/scanner/sanedlg.cxx external/gcc3_specific/makefile.mk filter/source/graphicfilter/eos2met/eos2met.cxx filter/source/graphicfilter/ios2met/ios2met.cxx filter/source/msfilter/msdffimp.cxx fpicker/source/office/iodlg.cxx framework/source/fwe/classes/addonsoptions.cxx framework/source/fwe/helper/actiontriggerhelper.cxx sc/source/filter/excel/xiescher.cxx sc/source/ui/docshell/docsh.cxx sc/source/ui/inc/viewfunc.hxx sd/source/ui/app/sdxfer.cxx sd/source/ui/unoidl/unopage.cxx sd/source/ui/view/sdview3.cxx sfx2/source/appl/fileobj.cxx sfx2/source/appl/linkmgr2.cxx sfx2/source/dialog/filedlghelper.cxx sfx2/source/dialog/intro.cxx sfx2/source/doc/docinf.cxx sot/inc/sot/formats.hxx sot/source/base/formats.cxx svtools/bmpmaker/bmpcore.cxx svtools/bmpmaker/bmpsum.cxx svtools/inc/svtools/transfer.hxx svtools/source/filter/filter.cxx svtools/source/filter/wmf/emfwr.cxx svtools/source/filter/wmf/enhwmf.cxx svtools/source/filter/wmf/winwmf.cxx svtools/source/filter/wmf/wmfwr.cxx svtools/source/graphic/graphic.cxx svtools/source/graphic/provider.cxx svtools/source/misc/transfer.cxx svx/inc/svx/xoutbmp.hxx svx/source/sdr/overlay/overlaymanagerbuffered.cxx svx/source/xoutdev/_xoutbmp.cxx sw/source/core/view/viewsh.cxx sw/source/filter/ww1/w1filter.cxx sw/source/filter/ww8/ww8par.hxx sw/source/ui/dochdl/swdtflvr.cxx toolkit/source/awt/vclxbitmap.cxx toolkit/source/helper/vclunohelper.cxx vcl/Library_vcl.mk vcl/Package_inc.mk vcl/aqua/source/dtrans/DataFlavorMapping.cxx vcl/aqua/source/dtrans/OSXTransferable.cxx vcl/aqua/source/dtrans/PictToBmpFlt.cxx vcl/aqua/source/dtrans/PictToBmpFlt.hxx vcl/inc/vcl/alpha.hxx vcl/inc/vcl/bitmap.hxx vcl/inc/vcl/bitmapex.hxx vcl/inc/vcl/pngwrite.hxx vcl/inc/vcl/salbtype.hxx vcl/inc/vcl/wall.hxx vcl/source/gdi/animate.cxx vcl/source/gdi/bitmap2.cxx vcl/source/gdi/bitmapex.cxx vcl/source/gdi/bmpconv.cxx vcl/source/gdi/cvtsvm.cxx vcl/source/gdi/impgraph.cxx vcl/source/gdi/impimagetree.cxx vcl/source/gdi/metaact.cxx vcl/source/gdi/wall.cxx Change-Id: I79938bc412c048c3d4e64f430f216e73bec16167
Diffstat (limited to 'vcl/source/gdi/dibtools.cxx')
-rw-r--r--vcl/source/gdi/dibtools.cxx1587
1 files changed, 1587 insertions, 0 deletions
diff --git a/vcl/source/gdi/dibtools.cxx b/vcl/source/gdi/dibtools.cxx
new file mode 100644
index 000000000000..c4b3bfec31fd
--- /dev/null
+++ b/vcl/source/gdi/dibtools.cxx
@@ -0,0 +1,1587 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <vcl/salbtype.hxx>
+#include <vcl/dibtools.hxx>
+#include <tools/zcodec.hxx>
+#include <tools/stream.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/outdev.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// - 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);
+}
+
+//////////////////////////////////////////////////////////////////////////////