diff options
author | sj <sj@openoffice.org> | 2009-12-03 16:31:03 +0100 |
---|---|---|
committer | sj <sj@openoffice.org> | 2009-12-03 16:31:03 +0100 |
commit | 11c7cf17c5b96e2201cfaf43f5b4aa6cf2c34906 (patch) | |
tree | dc938f48be13dceb985d5946203cc54f202bd1c1 /svtools | |
parent | c0f197f920974f3fdaf8278dad16dc5ecb994d52 (diff) |
impress181: #i107292#: Applied patch, wmf filter is now supporting embedded EMF data from the META_ESCAPE action.
Diffstat (limited to 'svtools')
-rw-r--r-- | svtools/source/filter.vcl/wmf/winmtf.cxx | 5 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/winmtf.hxx | 15 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/winwmf.cxx | 216 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/wmfwr.cxx | 80 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/wmfwr.hxx | 9 |
5 files changed, 264 insertions, 61 deletions
diff --git a/svtools/source/filter.vcl/wmf/winmtf.cxx b/svtools/source/filter.vcl/wmf/winmtf.cxx index 6f1caae18750..3db3e6957e41 100644 --- a/svtools/source/filter.vcl/wmf/winmtf.cxx +++ b/svtools/source/filter.vcl/wmf/winmtf.cxx @@ -2195,3 +2195,8 @@ void WinMtfOutput::Pop() } } +void WinMtfOutput::AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile ) +{ + rGDIMetaFile.Play( *mpGDIMetaFile, 0xFFFFFFFF ); +} + diff --git a/svtools/source/filter.vcl/wmf/winmtf.hxx b/svtools/source/filter.vcl/wmf/winmtf.hxx index ada590a19675..f3b2482f63bc 100644 --- a/svtools/source/filter.vcl/wmf/winmtf.hxx +++ b/svtools/source/filter.vcl/wmf/winmtf.hxx @@ -672,6 +672,7 @@ class WinMtfOutput void MoveClipRegion( const Size& rSize ); void SetClipPath( const PolyPolygon& rPolyPoly, sal_Int32 nClippingMode, sal_Bool bIsMapped ); void UpdateClipRegion(); + void AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile ); WinMtfOutput( GDIMetaFile& rGDIMetaFile ); virtual ~WinMtfOutput(); @@ -734,6 +735,18 @@ private: UINT16 nUnitsPerInch; sal_uInt32 nRecSize; + // embedded EMF data + SvMemoryStream* pEMFStream; + + // total number of comment records containing EMF data + sal_uInt32 nEMFRecCount; + + // number of EMF records read + sal_uInt32 nEMFRec; + + // total size of embedded EMF data + sal_uInt32 nEMFSize; + sal_uInt32 nSkipActions; sal_uInt32 nCurrentAction; sal_uInt32 nUnicodeEscapeAction; @@ -755,6 +768,8 @@ public: WMFReader( SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile, FilterConfigItem* pConfigItem = NULL ) : WinMtf( new WinMtfOutput( rGDIMetaFile ), rStreamWMF, pConfigItem ) {}; + ~WMFReader(); + // Liesst aus dem Stream eine WMF-Datei und fuellt das GDIMetaFile void ReadWMF(); }; diff --git a/svtools/source/filter.vcl/wmf/winwmf.cxx b/svtools/source/filter.vcl/wmf/winwmf.cxx index 0930b0ece8a8..54629383a4f8 100644 --- a/svtools/source/filter.vcl/wmf/winwmf.cxx +++ b/svtools/source/filter.vcl/wmf/winwmf.cxx @@ -32,6 +32,7 @@ #include "precompiled_svtools.hxx" #include "winmtf.hxx" +#include <vcl/gdimtf.hxx> #include <rtl/crc.h> #include <rtl/tencinfo.h> #include <osl/endian.h> @@ -831,81 +832,136 @@ void WMFReader::ReadRecordParams( USHORT nFunc ) pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); break; } - if ( nRecSize >= 12 ) // minimal escape lenght + if ( nRecSize >= 4 ) // minimal escape lenght { - sal_uInt16 nMode, nLen, OO; - sal_uInt32 Magic, nCheck,nEsc; + sal_uInt16 nMode, nLen; *pWMF >> nMode - >> nLen - >> OO - >> Magic - >> nCheck - >> nEsc; - if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 14 ) && ( OO == 0x4f4f ) && ( Magic == 0xa2c2a ) ) + >> nLen; + if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 4 ) ) { - sal_uInt32 nEscLen = nLen - 14; - if ( nEscLen <= ( nRecSize * 2 ) ) + sal_uInt32 nNewMagic; // we have to read int32 for + *pWMF >> nNewMagic; // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier + + if( nNewMagic == 0x2c2a4f4f && nLen >= 14 ) { + sal_uInt16 nMagic2; + *pWMF >> nMagic2; + if( nMagic2 == 0x0a ) // 2nd half of magic + { // continue with private escape + sal_uInt32 nCheck, nEsc; + *pWMF >> nCheck + >> nEsc; + + sal_uInt32 nEscLen = nLen - 14; + if ( nEscLen <= ( nRecSize * 2 ) ) + { #ifdef OSL_BIGENDIAN - sal_uInt32 nTmp = SWAPLONG( nEsc ); - sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 ); + sal_uInt32 nTmp = SWAPLONG( nEsc ); + sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 ); #else - sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 ); + sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 ); #endif - sal_Int8* pData = NULL; + sal_Int8* pData = NULL; - if ( ( static_cast< sal_uInt64 >( nEscLen ) + pWMF->Tell() ) > nMetaRecEndPos ) - { - pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); - break; - } - if ( nEscLen > 0 ) - { - pData = new sal_Int8[ nEscLen ]; - pWMF->Read( pData, nEscLen ); - nCheckSum = rtl_crc32( nCheckSum, pData, nEscLen ); - } - if ( nCheck == nCheckSum ) - { - switch( nEsc ) - { - case PRIVATE_ESCAPE_UNICODE : - { // we will use text instead of polygons only if we have the correct font - if ( aVDev.IsFontAvailable( pOut->GetFont().GetName() ) ) + if ( ( static_cast< sal_uInt64 >( nEscLen ) + pWMF->Tell() ) > nMetaRecEndPos ) + { + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + break; + } + if ( nEscLen > 0 ) + { + pData = new sal_Int8[ nEscLen ]; + pWMF->Read( pData, nEscLen ); + nCheckSum = rtl_crc32( nCheckSum, pData, nEscLen ); + } + if ( nCheck == nCheckSum ) + { + switch( nEsc ) { - Point aPt; - String aString; - sal_uInt32 i, nStringLen, nDXCount; - sal_Int32* pDXAry = NULL; - SvMemoryStream aMemoryStream( nEscLen ); - aMemoryStream.Write( pData, nEscLen ); - aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN ); - aMemoryStream >> aPt.X() - >> aPt.Y() - >> nStringLen; - - if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) ) - { - sal_Unicode* pBuf = aString.AllocBuffer( (xub_StrLen)nStringLen ); - for ( i = 0; i < nStringLen; i++ ) - aMemoryStream >> pBuf[ i ]; - aMemoryStream >> nDXCount; - if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) ) - nDXCount = 0; - if ( nDXCount ) - pDXAry = new sal_Int32[ nDXCount ]; - for ( i = 0; i < nDXCount; i++ ) - aMemoryStream >> pDXAry[ i ]; - aMemoryStream >> nSkipActions; - pOut->DrawText( aPt, aString, pDXAry ); - delete[] pDXAry; + case PRIVATE_ESCAPE_UNICODE : + { // we will use text instead of polygons only if we have the correct font + if ( aVDev.IsFontAvailable( pOut->GetFont().GetName() ) ) + { + Point aPt; + String aString; + sal_uInt32 i, nStringLen, nDXCount; + sal_Int32* pDXAry = NULL; + SvMemoryStream aMemoryStream( nEscLen ); + aMemoryStream.Write( pData, nEscLen ); + aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN ); + aMemoryStream >> aPt.X() + >> aPt.Y() + >> nStringLen; + + if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) ) + { + sal_Unicode* pBuf = aString.AllocBuffer( (xub_StrLen)nStringLen ); + for ( i = 0; i < nStringLen; i++ ) + aMemoryStream >> pBuf[ i ]; + aMemoryStream >> nDXCount; + if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) ) + nDXCount = 0; + if ( nDXCount ) + pDXAry = new sal_Int32[ nDXCount ]; + for ( i = 0; i < nDXCount; i++ ) + aMemoryStream >> pDXAry[ i ]; + aMemoryStream >> nSkipActions; + pOut->DrawText( aPt, aString, pDXAry ); + delete[] pDXAry; + } + } } + break; } } - break; + delete[] pData; + } + } + } + else if ( nNewMagic == 0x43464D57 && nLen >= 34 && ( nLen + 10 <= nRecSize * 2 )) + { + sal_uInt32 nComType, nVersion, nFlags, nComRecCount, + nCurRecSize, nRemainingSize, nEMFTotalSize; + sal_uInt16 nCheck; + + *pWMF >> nComType >> nVersion >> nCheck >> nFlags + >> nComRecCount >> nCurRecSize + >> nRemainingSize >> nEMFTotalSize; // the nRemainingSize is not mentioned in MSDN documentation + // but it seems to be required to read in data produced by OLE + + if( nComType == 0x01 && nVersion == 0x10000 && nComRecCount ) + { + if( !nEMFRec ) + { // first EMF comment + nEMFRecCount = nComRecCount; + nEMFSize = nEMFTotalSize; + pEMFStream = new SvMemoryStream( nEMFSize ); + } + else if( ( nEMFRecCount != nComRecCount ) || ( nEMFSize != nEMFTotalSize ) ) // add additional checks here + { + // total records should be the same as in previous comments + nEMFRecCount = 0xFFFFFFFF; + delete pEMFStream; + pEMFStream = NULL; + } + nEMFRec++; + + if( pEMFStream && nCurRecSize + 34 > nLen ) + { + nEMFRecCount = 0xFFFFFFFF; + delete pEMFStream; + pEMFStream = NULL; + } + + if( pEMFStream ) + { + sal_Int8* pBuf = new sal_Int8[ nCurRecSize ]; + sal_uInt32 nCount = pWMF->Read( pBuf, nCurRecSize ); + if( nCount == nCurRecSize ) + pEMFStream->Write( pBuf, nCount ); + delete[] pBuf; } } - delete[] pData; } } } @@ -1023,6 +1079,11 @@ void WMFReader::ReadWMF() nCurrentAction = 0; nUnicodeEscapeAction = 0; + pEMFStream = NULL; + nEMFRecCount = 0; + nEMFRec = 0; + nEMFSize = 0; + pOut->SetMapMode( MM_ANISOTROPIC ); pOut->SetWinOrg( Point() ); pOut->SetWinExt( Size( 1, 1 ) ); @@ -1070,6 +1131,33 @@ void WMFReader::ReadWMF() ReadRecordParams( nFunction ); else nSkipActions--; + + if( pEMFStream && nEMFRecCount == nEMFRec ) + { + GDIMetaFile aMeta; + pEMFStream->Seek( 0 ); + EnhWMFReader* pEMFReader = new EnhWMFReader ( *pEMFStream, aMeta ); + BOOL bRead = pEMFReader->ReadEnhWMF(); + delete pEMFReader; // destroy first!!! + + if( bRead ) + { + pOut->AddFromGDIMetaFile( aMeta ); + pOut->SetrclFrame( Rectangle(0, 0, aMeta.GetPrefSize().Width(), aMeta.GetPrefSize().Height() )); + // we have successfully read the embedded EMF data + // no need to process WMF data further + break; + } + else + { + // something went wrong + // continue with WMF, don't try this again + delete pEMFStream; + pEMFStream = NULL; + } + + } + nPos += nRecSize * 2; if ( nPos <= nEndPos ) pWMF->Seek( nPos ); @@ -1333,3 +1421,9 @@ sal_Bool WMFReader::GetPlaceableBound( Rectangle& rPlaceableBound, SvStream* pSt return bRet; } +WMFReader::~WMFReader() +{ + if( pEMFStream ) + delete pEMFStream; +} + diff --git a/svtools/source/filter.vcl/wmf/wmfwr.cxx b/svtools/source/filter.vcl/wmf/wmfwr.cxx index ee3a71c51f9d..f6ff58426a6a 100644 --- a/svtools/source/filter.vcl/wmf/wmfwr.cxx +++ b/svtools/source/filter.vcl/wmf/wmfwr.cxx @@ -33,6 +33,7 @@ #include <vcl/salbtype.hxx> #include "wmfwr.hxx" +#include "emfwr.hxx" #include <vcl/fontcvt.hxx> #include <rtl/crc.h> #include <rtl/tencinfo.h> @@ -1807,6 +1808,7 @@ BOOL WMFWriter::WriteWMF( const GDIMetaFile& rMTF, SvStream& rTargetStream, { WMFWriterAttrStackMember * pAt; + bEmbedEMF = TRUE; bStatus=TRUE; pConvert = 0; pVirDev = new VirtualDevice; @@ -1870,6 +1872,8 @@ BOOL WMFWriter::WriteWMF( const GDIMetaFile& rMTF, SvStream& rTargetStream, CountActionsAndBitmaps(rMTF); WriteHeader(rMTF,bPlaceable); + if( bEmbedEMF ) + WriteEmbeddedEMF( rMTF ); WMFRecord_SetWindowOrg(Point(0,0)); WMFRecord_SetWindowExt(rMTF.GetPrefSize()); WMFRecord_SetBkMode( TRUE ); @@ -1948,3 +1952,79 @@ USHORT WMFWriter::CalcSaveTargetMapMode(MapMode& rMapMode, return nDivisor; } + +// ------------------------------------------------------------------------ + +void WMFWriter::WriteEmbeddedEMF( const GDIMetaFile& rMTF ) +{ + EMFWriter aEMFWriter; + SvMemoryStream aStream; + if( aEMFWriter.WriteEMF( rMTF, aStream ) ) + { + aStream.Seek( 0 ); + sal_Size nTotalSize = aStream.GetSize(); + if( nTotalSize > SAL_MAX_UINT32 ) + return; + sal_uInt32 nRemainingSize = static_cast< sal_uInt32 >( nTotalSize ); + sal_uInt32 nRecCounts = ( (nTotalSize - 1) / 0x2000 ) + 1; + sal_uInt16 nCheckSum = 0, nWord; + + sal_uInt32 nPos = 0; + + while( nPos + 1 < nTotalSize ) + { + aStream >> nWord; + nCheckSum ^= nWord; + nPos += 2; + } + + nCheckSum = static_cast< sal_uInt16 >( nCheckSum * -1 ); + + aStream.Seek( 0 ); + while( nRemainingSize > 0 ) + { + sal_uInt32 nCurSize; + if( nRemainingSize > 0x2000 ) + { + nCurSize = 0x2000; + nRemainingSize -= 0x2000; + } + else + { + nCurSize = nRemainingSize; + nRemainingSize = 0; + } + WriteEMFRecord( aStream, + nCurSize, + nRemainingSize, + nTotalSize, + nRecCounts, + nCheckSum ); + nCheckSum = 0; + } + } +} + +// ------------------------------------------------------------------------ + +void WMFWriter::WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize, sal_uInt32 nRemainingSize, + sal_uInt32 nTotalSize, sal_uInt32 nRecCounts, sal_uInt16 nCheckSum ) +{ + // according to http://msdn.microsoft.com/en-us/library/dd366152%28PROT.13%29.aspx + WriteRecordHeader( 0, W_META_ESCAPE ); + *pWMF << (sal_uInt16)W_MFCOMMENT // same as META_ESCAPE_ENHANCED_METAFILE + << (sal_uInt16)( nCurSize + 34 ) // we will always have a 34 byte escape header: + << (sal_uInt32) 0x43464D57 // WMFC + << (sal_uInt32) 0x00000001 // Comment type + << (sal_uInt32) 0x00010000 // version + << nCheckSum // check sum + << (sal_uInt32) 0 // flags = 0 + << nRecCounts // total number of records + << nCurSize // size of this record's data + << nRemainingSize // remaining size of data in following records, missing in MSDN documentation + << nTotalSize; // total size of EMF stream + + pWMF->Write( static_cast< const sal_Char* >( rStream.GetData() ) + rStream.Tell(), nCurSize ); + rStream.SeekRel( nCurSize ); + UpdateRecordHeader(); +} diff --git a/svtools/source/filter.vcl/wmf/wmfwr.hxx b/svtools/source/filter.vcl/wmf/wmfwr.hxx index 48986a280404..a98b496a17e2 100644 --- a/svtools/source/filter.vcl/wmf/wmfwr.hxx +++ b/svtools/source/filter.vcl/wmf/wmfwr.hxx @@ -128,6 +128,8 @@ private: ULONG nWrittenBitmaps; // Anzahl der bereits geschriebenen Bitmaps ULONG nActBitmapPercent; // Wieviel Prozent die naechste Bitmap schon geschrieben ist. + BOOL bEmbedEMF; // optionally embedd EMF data into WMF + void MayCallback(); // Berechnet anhand der obigen 5 Parameter eine Prozentzahl // und macht dann ggf. einen Callback. Setzt bStatus auf FALSE wenn User abbrechen @@ -207,6 +209,13 @@ private: void WriteHeader(const GDIMetaFile & rMTF, BOOL bPlaceable); void UpdateHeader(); + void WriteEmbeddedEMF( const GDIMetaFile& rMTF ); + void WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize, + sal_uInt32 nRemainingSize, + sal_uInt32 nTotalSize, + sal_uInt32 nRecCounts, + sal_uInt16 nCheckSum ); + USHORT CalcSaveTargetMapMode(MapMode& rMapMode, const Size& rPrefSize); public: |