blob: a7c69e6a22ea9fa1016b953d063774efcacc88f9 [file] [log] [blame]
/**************************************************************
*
* 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_filter.hxx"
#include <svtools/fltcall.hxx>
#include <math.h>
#include <tools/stream.hxx>
#include <tools/bigint.hxx>
#include <vcl/metaact.hxx>
#include <vcl/salbtype.hxx>
#include <tools/poly.hxx>
#include <vcl/graph.hxx>
#include <vcl/gradient.hxx>
#include <vcl/hatch.hxx>
#include <vcl/metric.hxx>
#include <vcl/font.hxx>
#include <vcl/virdev.hxx>
#include <vcl/svapp.hxx>
#include <vcl/msgbox.hxx>
#include <svl/solar.hrc>
#include <vcl/gdimetafiletools.hxx>
#include <vcl/dibtools.hxx>
// -----------------------------Feld-Typen-------------------------------
#define BegDocumnMagic 0xA8A8 /* Begin Document */
#define EndDocumnMagic 0xA8A9 /* End Document */
#define BegResGrpMagic 0xC6A8 /* Begin Resource Group */
#define EndResGrpMagic 0xC6A9 /* End Resource Group */
#define BegColAtrMagic 0x77A8 /* Begin Color Attribute Table */
#define EndColAtrMagic 0x77A9 /* End Color Attribute Table */
#define BlkColAtrMagic 0x77B0 /* Color Attribute Table */
#define MapColAtrMagic 0x77AB /* Map Color Attribute Table */
#define BegImgObjMagic 0xFBA8 /* Begin Image Object */
#define EndImgObjMagic 0xFBA9 /* End Image Object */
#define DscImgObjMagic 0xFBA6 /* Image Data Descriptor */
#define DatImgObjMagic 0xFBEE /* Image Picture Data */
#define BegObjEnvMagic 0xC7A8 /* Begin Object Environment Group */
#define EndObjEnvMagic 0xC7A9 /* End Object Environment Group */
#define BegGrfObjMagic 0xBBA8 /* Begin Graphics Object */
#define EndGrfObjMagic 0xBBA9 /* End Graphics Object */
#define DscGrfObjMagic 0xBBA6 /* Graphics Data Descritor */
#define DatGrfObjMagic 0xBBEE /* Graphics Data */
#define MapCodFntMagic 0x8AAB /* Map Coded Font */
#define MapDatResMagic 0xC3AB /* Map Data Resource */
// Struktur des Metafiles
// BegDocumn
// BegResGrp
// BegColAtr
// BlkColAtr
// EndColAtr
// BegImgObj[0..n]
// BegResGrp[]
// BegColAtr[]
// BlkColAtr
// EndColAtr
// EndResGrp
// BegObjEnv[]
// MapColAtr
// EndObjEnv
// DscImgObj
// DatImgOb1
// DatImgOb2[1..n]
// EndImgObj
// BegGrfObj
// BegObjEnv[]
// MapColAtr
// MapCodFnt1
// MapCodFnt2[0..n]
// MapDatRes[0..n]
// EndObjEnv
// DscGrfObj
// DatGrfObj[0..n]
// EndGrfObj
// EndResGrp
// EndDocumn
//============================== METWriter ===================================
struct METChrSet
{
struct METChrSet * pSucc;
sal_uInt8 nSet;
String aName;
FontWeight eWeight;
};
struct METGDIStackMember
{
struct METGDIStackMember * pSucc;
Color aLineColor;
Color aFillColor;
RasterOp eRasterOp;
Font aFont;
MapMode aMapMode;
Rectangle aClipRect;
};
class METWriter
{
private:
sal_Bool bStatus;
sal_uLong nLastPercent; // Mit welcher Zahl pCallback zuletzt aufgerufen wurde.
SvStream* pMET;
Rectangle aPictureRect;
MapMode aPictureMapMode;
MapMode aTargetMapMode;
sal_uLong nActualFieldStartPos; // Anfangs-Position des aktuellen 'Field'
sal_uLong nNumberOfDataFields; // Anzahl der angefangenen 'Graphcis Data Fields'
Color aGDILineColor;
Color aGDIFillColor;
RasterOp eGDIRasterOp;
Font aGDIFont;
MapMode aGDIMapMode; // derzeit unbenutzt!
Rectangle aGDIClipRect; // derzeit unbenutzt!
METGDIStackMember* pGDIStack;
Color aMETColor;
Color aMETBackgroundColor;
Color aMETPatternSymbol;
RasterOp eMETMix ;
long nMETStrokeLineWidth;
Size aMETChrCellSize;
short nMETChrAngle;
sal_uInt8 nMETChrSet;
METChrSet* pChrSetList; // Liste der Character-Sets
sal_uInt8 nNextChrSetId; // die erste unbenutzte ChrSet-Id
sal_uLong nActBitmapId; // Field-Id der naechsten Bitmap
sal_uLong nNumberOfActions; // Anzahl der Actions im GDIMetafile
sal_uLong nNumberOfBitmaps; // Anzahl der Bitmaps
sal_uLong nWrittenActions; // Anzahl der bereits verarbeiteten Actions beim Schreiben der Orders
sal_uLong nWrittenBitmaps; // Anzahl der bereits geschriebenen Bitmaps
sal_uLong nActBitmapPercent; // Wieviel Prozent die naechste Bitmap schon geschrieben ist.
::std::auto_ptr< VirtualDevice > apDummyVDev;
OutputDevice* pCompDev;
com::sun::star::uno::Reference< com::sun::star::task::XStatusIndicator > xStatusIndicator;
void MayCallback();
// Berechnet anhand der obigen 5 Parameter eine Prozentzahl
// und macht dann ggf. einen Callback. Setzt bStatus auf sal_False wenn User abbrechen
// moechte.
void CountActionsAndBitmaps(const GDIMetaFile * pMTF);
// Zaehlt die Bitmaps und Actions (nNumberOfActions und nNumberOfBitmaps muessen
// zu Anfang auf 0 gesetzt werden, weil diese Methode rekursiv ist)
void WriteBigEndianShort(sal_uInt16 nWord);
void WriteBigEndianLong(sal_uLong nLong);
void WritePoint(Point aPt);
void WriteClipRect( const Rectangle& rRect );
void WriteFieldIntroducer(sal_uInt16 nFieldSize, sal_uInt16 nFieldType,
sal_uInt8 nFlags, sal_uInt16 nSegSeqNum);
void UpdateFieldSize();
void WriteFieldId(sal_uLong nId);
void CreateChrSets(const GDIMetaFile * pMTF);
void CreateChrSet(const Font & rFont);
void WriteChrSets();
sal_uInt8 FindChrSet(const Font & rFont);
void WriteColorAttributeTable(sal_uLong nFieldId=4, BitmapPalette* pPalette=NULL,
sal_uInt8 nBasePartFlags=0x40, sal_uInt8 nBasePartLCTID=0);
void WriteImageObject(const Bitmap & rBitmap);
void WriteImageObjects(const GDIMetaFile * pMTF);
void WriteDataDescriptor(const GDIMetaFile * pMTF);
void WillWriteOrder(sal_uLong nNextOrderMaximumLength);
void METSetAndPushLineInfo( const LineInfo& rLineInfo );
void METPopLineInfo( const LineInfo& rLineInfo );
void METBitBlt(Point aPt, Size aSize, const Size& rSizePixel);
void METBeginArea(sal_Bool bBoundaryLine);
void METEndArea();
void METBeginPath(sal_uInt32 nPathId);
void METEndPath();
void METFillPath(sal_uInt32 nPathId);
void METOutlinePath(sal_uInt32 nPathId);
void METCloseFigure();
void METMove(Point aPt);
void METLine(Point aPt1, Point aPt2);
void METLine(const Polygon & rPolygon);
void METLine(const PolyPolygon & rPolyPolygon);
void METLineAtCurPos(Point aPt);
void METBox(sal_Bool bFill, sal_Bool bBoundary,
Rectangle aRect, sal_uInt32 nHAxis, sal_uInt32 nVAxis);
void METFullArc(Point aCenter, double fMultiplier);
void METPartialArcAtCurPos(Point aCenter, double fMultiplier,
double fStartAngle, double fSweepAngle);
void METChrStr(Point aPt, String aStr);
void METSetArcParams(long nP, long nQ, long nR, long nS);
void METSetColor(Color aColor);
void METSetBackgroundColor(Color aColor);
void METSetMix(RasterOp eROP);
void METSetChrCellSize(Size aSize);
void METSetChrAngle(short nAngle);
void METSetChrSet(sal_uInt8 nSet);
void WriteOrders(const GDIMetaFile * pMTF);
void WriteObjectEnvironmentGroup(const GDIMetaFile * pMTF);
void WriteGraphicsObject(const GDIMetaFile * pMTF);
void WriteResourceGroup(const GDIMetaFile * pMTF);
void WriteDocument(const GDIMetaFile * pMTF);
public:
METWriter() :
pCompDev( NULL )
{
#ifndef NO_GETAPPWINDOW
pCompDev = reinterpret_cast< OutputDevice* >( Application::GetAppWindow() );
#endif
if( !pCompDev )
{
apDummyVDev.reset( new VirtualDevice );
pCompDev = apDummyVDev.get();
}
}
sal_Bool WriteMET( const GDIMetaFile & rMTF, SvStream & rTargetStream,
FilterConfigItem* pConfigItem );
};
//========================== Methoden von METWriter ==========================
void METWriter::MayCallback()
{
if ( xStatusIndicator.is() )
{
sal_uLong nPercent;
nPercent=((nWrittenBitmaps<<14)+(nActBitmapPercent<<14)/100+nWrittenActions)
*100/((nNumberOfBitmaps<<14)+nNumberOfActions);
if (nPercent>=nLastPercent+3)
{
nLastPercent = nPercent;
if ( nPercent <= 100 )
xStatusIndicator->setValue( nPercent );
}
}
}
void METWriter::WriteClipRect( const Rectangle& rRect )
{
aGDIClipRect = rRect;
sal_uInt32 nPathId = ( rRect.IsEmpty() ) ? 0 : 1;
if ( nPathId )
{
Polygon aPoly( rRect );
METBeginPath( nPathId );
METLine( aPoly );
METEndPath();
}
WillWriteOrder(8);
*pMET << (sal_uInt8)0xb4 << (sal_uInt8)6
<< (sal_uInt8)0x00 << (sal_uInt8)0 << nPathId;
}
void METWriter::CountActionsAndBitmaps(const GDIMetaFile * pMTF)
{
const MetaAction* pMA;
for( sal_uLong nAction = 0, nActionCount=pMTF->GetActionCount(); nAction < nActionCount; nAction++ )
{
pMA = pMTF->GetAction(nAction);
switch (pMA->GetType())
{
case META_EPS_ACTION :
{
const GDIMetaFile aGDIMetaFile( ((const MetaEPSAction*)pMA)->GetSubstitute() );
sal_Int32 nCount = aGDIMetaFile.GetActionCount();
sal_Int32 i;
for ( i = 0; i < nCount; i++ )
if ( ((const MetaAction*)aGDIMetaFile.GetAction( i ))->GetType() == META_BMPSCALE_ACTION )
break;
if ( i == nCount)
break;
}
case META_BMP_ACTION:
case META_BMPSCALE_ACTION:
case META_BMPSCALEPART_ACTION:
case META_BMPEX_ACTION:
case META_BMPEXSCALE_ACTION:
case META_BMPEXSCALEPART_ACTION:
nNumberOfBitmaps++;
break;
}
nNumberOfActions++;
}
}
void METWriter::WriteBigEndianShort(sal_uInt16 nWord)
{
*pMET << ((sal_uInt8)(nWord>>8)) << ((sal_uInt8)(nWord&0x00ff));
}
void METWriter::WriteBigEndianLong(sal_uLong nLong)
{
WriteBigEndianShort((sal_uInt16)(nLong>>16));
WriteBigEndianShort((sal_uInt16)(nLong&0x0000ffff));
}
void METWriter::WritePoint(Point aPt)
{
Point aNewPt = pCompDev->LogicToLogic( aPt, aPictureMapMode, aTargetMapMode );
*pMET << (long) ( aNewPt.X() - aPictureRect.Left() )
<< (long) ( aPictureRect.Bottom() - aNewPt.Y() );
}
void METWriter::WriteFieldIntroducer(sal_uInt16 nFieldSize, sal_uInt16 nFieldType,
sal_uInt8 nFlags, sal_uInt16 nSegSeqNum)
{
nActualFieldStartPos=pMET->Tell();
WriteBigEndianShort(nFieldSize);
*pMET << (sal_uInt8)0xd3 << nFieldType << nFlags << nSegSeqNum;
}
void METWriter::UpdateFieldSize()
{
sal_uLong nPos;
nPos=pMET->Tell();
pMET->Seek(nActualFieldStartPos);
WriteBigEndianShort((sal_uInt16)(nPos-nActualFieldStartPos));
pMET->Seek(nPos);
}
void METWriter::WriteFieldId(sal_uLong nId)
{
sal_uInt8 nbyte;
short i;
for (i=1; i<=8; i++) {
nbyte= '0' + (sal_uInt8)((nId >> (32-i*4)) & 0x0f);
*pMET << nbyte;
}
}
void METWriter::CreateChrSets(const GDIMetaFile * pMTF)
{
sal_uLong nAction, nActionCount;
const MetaAction * pMA;
if (bStatus==sal_False)
return;
nActionCount=pMTF->GetActionCount();
for (nAction=0; nAction<nActionCount; nAction++)
{
pMA = pMTF->GetAction(nAction);
switch (pMA->GetType())
{
case META_FONT_ACTION:
{
const MetaFontAction* pA = (const MetaFontAction*) pMA;
CreateChrSet( pA->GetFont() );
}
break;
}
}
}
void METWriter::CreateChrSet(const Font & rFont)
{
METChrSet * pCS;
if ( FindChrSet( rFont ) == 0 )
{
pCS = new METChrSet;
pCS->pSucc = pChrSetList; pChrSetList=pCS;
pCS->nSet = nNextChrSetId++;
pCS->aName = rFont.GetName();
pCS->eWeight = rFont.GetWeight();
}
}
sal_uInt8 METWriter::FindChrSet(const Font & rFont)
{
METChrSet* pCS;
for (pCS=pChrSetList; pCS!=NULL; pCS=pCS->pSucc)
{
if (pCS->aName==rFont.GetName() && pCS->eWeight==rFont.GetWeight() )
return pCS->nSet;
}
return 0;
}
void METWriter::WriteChrSets()
{
sal_uInt16 i;
char c = 0;
METChrSet * pCS;
sal_uInt8 nbyte;
for (pCS=pChrSetList; pCS!=NULL; pCS=pCS->pSucc)
{
WriteFieldIntroducer(0x58,MapCodFntMagic,0,0);
WriteBigEndianShort(0x0050);
*pMET << (sal_uInt8)0x0c << (sal_uInt8)0x02 << (sal_uInt8)0x84 << (sal_uInt8)0x00;
*pMET << (sal_uInt8)0xa4 << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x01;
*pMET << (sal_uInt8)0x01 << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00;
*pMET << (sal_uInt8)0x04 << (sal_uInt8)0x24 << (sal_uInt8)0x05 << (sal_uInt8)pCS->nSet;
*pMET << (sal_uInt8)0x14 << (sal_uInt8)0x1f;
switch (pCS->eWeight)
{
case WEIGHT_THIN: nbyte=1; break;
case WEIGHT_ULTRALIGHT: nbyte=2; break;
case WEIGHT_LIGHT: nbyte=3; break;
case WEIGHT_SEMILIGHT: nbyte=4; break;
case WEIGHT_NORMAL: nbyte=5; break;
case WEIGHT_SEMIBOLD: nbyte=6; break;
case WEIGHT_BOLD: nbyte=7; break;
case WEIGHT_ULTRABOLD: nbyte=8; break;
case WEIGHT_BLACK: nbyte=9; break;
default: nbyte=5;
}
*pMET << nbyte;
*pMET << (sal_uInt8)0x05;
*pMET << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00;
*pMET << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00;
*pMET << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00;
*pMET << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x0c;
*pMET << (sal_uInt8)0x06 << (sal_uInt8)0x20 << (sal_uInt8)0x03 << (sal_uInt8)0xd4;
*pMET << (sal_uInt8)0x03 << (sal_uInt8)0x52;
*pMET << (sal_uInt8)0x24 << (sal_uInt8)0x02 << (sal_uInt8)0x08 << (sal_uInt8)0x00;
ByteString n(pCS->aName, gsl_getSystemTextEncoding());
for (i=0; i<32; i++)
{
if ( i == 0 || c != 0 )
c = n.GetChar( i );
*pMET << c;
}
}
}
void METWriter::WriteColorAttributeTable(sal_uLong nFieldId, BitmapPalette* pPalette, sal_uInt8 nBasePartFlags, sal_uInt8 nBasePartLCTID)
{
sal_uInt16 nIndex,nNumI,i;
if (bStatus==sal_False) return;
//--- Das Feld 'Begin Color Attribute Table':
WriteFieldIntroducer(16,BegColAtrMagic,0,0);
WriteFieldId(nFieldId);
//--- Das Feld 'Color Attribute Table':
WriteFieldIntroducer(0,BlkColAtrMagic,0,0);
*pMET << nBasePartFlags << (sal_uInt8)0x00 << nBasePartLCTID; // 'Base Part'
if (pPalette!=NULL)
{
nIndex=0;
while (nIndex<pPalette->GetEntryCount())
{
nNumI=pPalette->GetEntryCount()-nIndex;
if (nNumI>81) nNumI=81;
*pMET << (sal_uInt8)(11+nNumI*3); // Laenge des Parameters
*pMET << (sal_uInt8)1 << (sal_uInt8)0 << (sal_uInt8)1; // typ: element list, Reserved, Format: RGB
*pMET << (sal_uInt8)0; WriteBigEndianShort(nIndex); // Start-Index (3 Bytes)
*pMET << (sal_uInt8)8 << (sal_uInt8)8 << (sal_uInt8)8; // Bits je Komponente R,G,B
*pMET << (sal_uInt8)3; // Anzahl Bytes je Eintrag
for (i=0; i<nNumI; i++)
{
const BitmapColor& rCol = (*pPalette)[ nIndex ];
*pMET << (sal_uInt8) rCol.GetRed();
*pMET << (sal_uInt8) rCol.GetGreen();
*pMET << (sal_uInt8) rCol.GetBlue();
nIndex++;
}
}
}
else
{
// 'Trible Generating'
*pMET << (sal_uInt8)0x0a << (sal_uInt8)0x02 << (sal_uInt8)0x00 << (sal_uInt8)0x01 << (sal_uInt8)0x00;
*pMET << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x08 << (sal_uInt8)0x08 << (sal_uInt8)0x08;
}
UpdateFieldSize();
//--- Das Feld 'End Color Attribute Table':
WriteFieldIntroducer(16,EndColAtrMagic,0,0);
WriteFieldId(nFieldId);
if (pMET->GetError())
bStatus=sal_False;
}
void METWriter::WriteImageObject(const Bitmap & rBitmap)
{
SvMemoryStream aTemp(0x00010000,0x00010000);
sal_uInt32 nWidth,nHeight,nResX,nResY;
sal_uLong nBytesPerLine,i,j,nNumColors,ny,nLines;
sal_uLong nActColMapId;
sal_uInt16 nBitsPerPixel;
sal_uInt8 nbyte, * pBuf;
if (bStatus==sal_False)
return;
nActColMapId=((nActBitmapId>>24)&0x000000ff) | ((nActBitmapId>> 8)&0x0000ff00) |
((nActBitmapId<< 8)&0x00ff0000) | ((nActBitmapId<<24)&0xff000000);
//--- Das Feld 'Begin Image Object':
WriteFieldIntroducer(16,BegImgObjMagic,0,0);
WriteFieldId(nActBitmapId);
// Windows-BMP-Datei erzeugen:
WriteDIB(rBitmap, aTemp, false, true);
// Header der Windows-BMP-Datei einlesen:
aTemp.SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
aTemp.Seek(18);
aTemp >> nWidth >> nHeight;
aTemp.SeekRel(2);
aTemp >> nBitsPerPixel;
aTemp.SeekRel(8);
aTemp >> nResX >> nResY;
aTemp.SeekRel(8);
nNumColors=1<<nBitsPerPixel;
nBytesPerLine=((nWidth*nBitsPerPixel+0x0000001f) & 0xffffffe0 ) >> 3;
// ggf. Farbpalette einlesen und in die MET-Datei schreiben:
if (nBitsPerPixel<=8)
{
BitmapPalette aPal( (sal_uInt16) nNumColors );
sal_uInt8 nr,ng,nb;
for (i=0; i<nNumColors; i++)
{
aTemp >> nb >> ng >> nr; aTemp.SeekRel(1);
aPal[ (sal_uInt16) i ] = BitmapColor( nr, ng, nb );
}
//--- Das Feld 'Begin Resource Group':
WriteFieldIntroducer(16,BegResGrpMagic,0,0);
WriteFieldId(nActColMapId);
//--- Farbtabelle schreiben:
WriteColorAttributeTable(nActColMapId,&aPal,0,1);
//--- Das Feld 'End Resource Group':
WriteFieldIntroducer(16,EndResGrpMagic,0,0);
WriteFieldId(nActColMapId);
//--- Das Feld 'Begin Object Environment Group':
WriteFieldIntroducer(16,BegObjEnvMagic,0,0);
WriteFieldId(nActBitmapId);
//--- Das Feld 'Map Color Attribute Table':
WriteFieldIntroducer(26,MapColAtrMagic,0,0);
WriteBigEndianShort(0x0012);
*pMET << (sal_uInt8)0x0c << (sal_uInt8)0x02 << (sal_uInt8)0x84 << (sal_uInt8)0x00;
WriteFieldId(nActColMapId);
*pMET << (sal_uInt8)0x04 << (sal_uInt8)0x24 << (sal_uInt8)0x07 << (sal_uInt8)0x01;
//--- Das Feld 'End Object Environment Group':
WriteFieldIntroducer(16,EndObjEnvMagic,0,0);
WriteFieldId(nActBitmapId);
}
//--- Das Feld 'Image Data Descriptor':
WriteFieldIntroducer(17,DscImgObjMagic,0,0);
*pMET << (sal_uInt8)0x01; // Unit of measure: tens of centimeters
WriteBigEndianShort((sal_uInt16)nResX);
WriteBigEndianShort((sal_uInt16)nResY);
WriteBigEndianShort((sal_uInt16)nWidth);
WriteBigEndianShort((sal_uInt16)nHeight);
//--- Das erste Feld 'Image Picture Data':
WriteFieldIntroducer(0,DatImgObjMagic,0,0);
// Begin Segment:
*pMET << (sal_uInt8)0x70 << (sal_uInt8)0x00;
// Begin Image Content:
*pMET << (sal_uInt8)0x91 << (sal_uInt8)0x01 << (sal_uInt8)0xff;
// Image Size:
*pMET << (sal_uInt8)0x94 << (sal_uInt8)0x09 << (sal_uInt8)0x02;
*pMET << (sal_uInt16) 0 << (sal_uInt16) 0;
WriteBigEndianShort((sal_uInt16)nHeight);
WriteBigEndianShort((sal_uInt16)nWidth);
// Image Encoding:
*pMET << (sal_uInt8)0x95 << (sal_uInt8)0x02 << (sal_uInt8)0x03 << (sal_uInt8)0x03;
// Image IDE-Size:
*pMET << (sal_uInt8)0x96 << (sal_uInt8)0x01 << (sal_uInt8)nBitsPerPixel;
if (nBitsPerPixel<=8) {
// Image LUT-ID
*pMET << (sal_uInt8)0x97 << (sal_uInt8)0x01 << (sal_uInt8)0x01;
}
else {
// IDE Structure
*pMET << (sal_uInt8)0x9b << (sal_uInt8)0x08 << (sal_uInt8)0x00 << (sal_uInt8)0x01;
*pMET << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x08;
*pMET << (sal_uInt8)0x08 << (sal_uInt8)0x08;
}
pBuf=new sal_uInt8[nBytesPerLine];
ny=0;
while (ny<nHeight) {
// Abschliessen des vorherigen Feldes 'Image Picture Data':
UpdateFieldSize();
// Und ein neues Feld 'Image Picture Data' anfangen:
WriteFieldIntroducer(0,DatImgObjMagic,0,0);
// Einige Scanlines lesen und schreiben:
nLines=nHeight-ny;
if (nLines*nBytesPerLine>30000) nLines=30000/nBytesPerLine;
if (nLines<1) nLines=1;
WriteBigEndianShort(0xfe92);
WriteBigEndianShort((sal_uInt16)(nLines*nBytesPerLine));
for (i=0; i<nLines; i++) {
aTemp.Read(pBuf,nBytesPerLine);
if (nBitsPerPixel==24) {
for (j=2; j<nBytesPerLine; j+=3) {
nbyte=pBuf[j]; pBuf[j]=pBuf[j-2]; pBuf[j-2]=nbyte;
}
}
pMET->Write(pBuf,nBytesPerLine);
ny++;
}
if (aTemp.GetError() || pMET->GetError()) bStatus=sal_False;
nActBitmapPercent=(ny+1)*100/nHeight;
MayCallback();
if (bStatus==sal_False) { delete[] pBuf; return; }
}
delete[] pBuf;
// End Image Content:
*pMET << (sal_uInt8)0x93 << (sal_uInt8)0x00;
// End Segment:
*pMET << (sal_uInt8)0x71 << (sal_uInt8)0x00;
// Abschliessen des letzten Feldes 'Image Picture Data':
UpdateFieldSize();
//--- Das Feld 'End Image Object':
WriteFieldIntroducer(16,EndImgObjMagic,0,0);
WriteFieldId(nActBitmapId);
// Ids erhoehen:
nActBitmapId++;
// Bitmaps zaehlen:
nWrittenBitmaps++;
nActBitmapPercent=0;
if (pMET->GetError()) bStatus=sal_False;
}
void METWriter::WriteImageObjects(const GDIMetaFile * pMTF)
{
const MetaAction* pMA;
if (bStatus==sal_False)
return;
for ( sal_uLong nAction = 0, nActionCount = pMTF->GetActionCount(); nAction < nActionCount; nAction++)
{
pMA = pMTF->GetAction(nAction);
switch (pMA->GetType())
{
case META_BMP_ACTION:
{
METSetMix( eGDIRasterOp );
WriteImageObject( ( (MetaBmpAction*) pMA )->GetBitmap() );
}
break;
case META_BMPSCALE_ACTION:
{
METSetMix( eGDIRasterOp );
WriteImageObject( ( (MetaBmpScaleAction*) pMA )->GetBitmap() );
}
break;
case META_BMPSCALEPART_ACTION:
{
METSetMix( eGDIRasterOp );
WriteImageObject( ( (MetaBmpScalePartAction*) pMA )->GetBitmap() );
}
break;
case META_BMPEX_ACTION:
{
METSetMix( eGDIRasterOp );
WriteImageObject( Graphic( ( (MetaBmpExAction*) pMA )->GetBitmapEx() ).GetBitmap() );
}
break;
case META_BMPEXSCALE_ACTION:
{
METSetMix( eGDIRasterOp );
WriteImageObject( Graphic( ( (MetaBmpExScaleAction*) pMA )->GetBitmapEx() ).GetBitmap() );
}
break;
case META_BMPEXSCALEPART_ACTION:
{
METSetMix( eGDIRasterOp );
WriteImageObject( Graphic( ( (MetaBmpExScalePartAction*) pMA )->GetBitmapEx() ).GetBitmap() );
}
break;
case META_EPS_ACTION :
{
const MetaEPSAction* pA = (const MetaEPSAction*)pMA;
const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() );
sal_Int32 nCount = aGDIMetaFile.GetActionCount();
for ( sal_Int32 i = 0; i < nCount; i++ )
{
const MetaAction* pMetaAct = aGDIMetaFile.GetAction( i );
if ( pMetaAct->GetType() == META_BMPSCALE_ACTION )
{
const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*)pMetaAct;
METSetMix( eGDIRasterOp );
WriteImageObject( pBmpScaleAction->GetBitmap() );
break;
}
}
}
break;
}
if (bStatus==sal_False)
break;
}
if (pMET->GetError())
bStatus=sal_False;
}
void METWriter::WriteDataDescriptor(const GDIMetaFile *)
{
if (bStatus==sal_False)
return;
WriteFieldIntroducer(0,DscGrfObjMagic,0,0);
//------------------------------------------------------------------------------
// Im Folgenden die OS2-Orginal-Dokumentation und die Implementation dazu (uff)
//------------------------------------------------------------------------------
// Parameters (all required and in this order)
// 0 0xF7 Specify GVM Subset
// 1 Length of following data 0x07
// 2 0xB0 drawing order subset
// 3-4 0x0000
// 5 0x23 Level 3.2
// 6 0x01 Version 1
// 7 Length of following field 0x01
// 8 Coordinate types in data
// 0x04Intel16
// 0x05Intel32
*pMET << (sal_uInt8)0xf7 << (sal_uInt8)0x07 << (sal_uInt8)0xb0 << (sal_uInt8)0x00
<< (sal_uInt8)0x00 << (sal_uInt8)0x23 << (sal_uInt8)0x01 << (sal_uInt8)0x01
<< (sal_uInt8)0x05;
// 0 0xF6 Set Picture Descriptor
// 1 Length of following data
// 2 Flags
// 0 B'0' Picture in 2D
// 1 Picture Dimensions
// B'0' Not absolute (PU_ARBITRARY PS)
// B'1' Absolute (example: PU_TWIPS PS)
// 2 Picture Elements
// B'0' Not pels
// B'1' Pels (PU_PELS PS)
// (Bit 1 must also be set)
// 3-7 B'00000'
// 3 0x00 Reserved
// 4 Picture frame size coordinate type
// 0x04 Intel16
// 0x05 Intel32
// 5 UnitsOfMeasure
// 0x00 Ten inches
// 0x01 Decimeter
// 6-11 or 6-17(2 or 4 bytes) Resolution.
// GPS Units / UOM on x axis
// GPS Units / UOM on y axis
// GPS Units / UOM on z axis
// 12-23 or 18-41(2 or 4 bytes) Window Size.
// GPS X left, X right
// GPS Y bottom, Y top
// GPS Z near, Z far
Size aUnitsPerDecimeter=OutputDevice::LogicToLogic(Size(10,10),MapMode(MAP_CM),aPictureMapMode);
*pMET << (sal_uInt8)0xf6 << (sal_uInt8)0x28 << (sal_uInt8)0x40 << (sal_uInt8)0x00
<< (sal_uInt8)0x05 << (sal_uInt8)0x01
<< (sal_uInt32)(aUnitsPerDecimeter.Width())
<< (sal_uInt32)(aUnitsPerDecimeter.Height())
<< (sal_uInt32)0
<< (sal_uInt32)0 << (sal_uInt32)aPictureRect.GetWidth()
<< (sal_uInt32)0 << (sal_uInt32)aPictureRect.GetHeight()
<< (sal_uInt32)0 << (sal_uInt32)0;
// 0 0x21 Set Current Defaults
// 1 Length of following data
// 2 Set Default Parameter Format 0x08
// 3-4 Mask 0xE000
// 5 Names 0x8F
// 6 Coordinates
// 0x00 Picture in 2D
// 7 Transforms
// 0x04 Intel16
// 0x05 Intel32
// 8 Geometrics
// 0x04 Intel16
// 0x05 Intel32
*pMET << (sal_uInt8)0x21 << (sal_uInt8)0x07 << (sal_uInt8)0x08 << (sal_uInt8)0xe0
<< (sal_uInt8)0x00 << (sal_uInt8)0x8f << (sal_uInt8)0x00 << (sal_uInt8)0x05
<< (sal_uInt8)0x05;
// 0 0x21 Set Current Defaults
// 1 Length of following data
// 2 Set default viewing transform 0x07
// 3-4 Mask 0xCC0C
// 5 Names 0x8F
// 6-n M11, M12, M21, M22, M41, M42 Matrix elements
*pMET << (sal_uInt8)0x21 << (sal_uInt8)0x1c << (sal_uInt8)0x07 << (sal_uInt8)0xcc
<< (sal_uInt8)0x0c << (sal_uInt8)0x8f
<< (sal_uInt32)0x00010000 << (sal_uInt32)0x00000000 << (sal_uInt32)0x00000000
<< (sal_uInt32)0x00010000 << (sal_uInt32)0x00000000 << (sal_uInt32)0x00000000;
// 0 0x21 Set Current Defaults
// 1 Length of following data
// 2 Set default line attributes 0x01
// 3-4 Mask - OR of as many of the following bits as are required:
// 0x8000 Line type
// 0x4000 Line width
// 0x2000 Line end
// 0x1000 Line join
// 0x0800 Stroke width
// 0x0008 Line color
// 0x0002 Line mix
// 5 Flags
//
// 0x0F Set indicated default attributes to initial values. (Data field is not present in this
// instance).
// 0x8F Set indicated default attributes to specified values.
// 6-n Data - data values as required, in the following order if present.
// No space is reserved for attributes for which the corresponding mask flag was not
// set.
//
// (1 byte) - Line type
// (1 byte) - Line width
// (1 byte) - Line end
// (1 byte) - Line join
// (G bytes) - Stroke width
// (4 bytes) - Line color
// (1 byte) - Line mix (G=2 or 4 depending on the Geometrics parameter of Set Default
// Parameter Format)
// Nanu! witziger-weise fehlt obiger Abschnitt in den Metadateien. Also lassen wir ihn auch weg
// 0 0x21 Set Current Defaults
// 1 Length of following data
// 2 Set Default Character Attributes 0x02
// 3-4 Mask - OR of as many of the following bits as are required:
//
// 0x8000 Character angle
// 0x4000 Character box
// 0x2000 Character direction
// 0x1000 Character precision
// 0x0800 Character set
// 0x0400 Character shear
// 0x0040 Character break extra
// 0x0020 Character extra
// 0x0008 Character color
// 0x0004 Character background color
// 0x0002 Character mix
// 0x0001 Character background mix
// 5 Flags
// 0x0FSet indicated default attributes to initial values. (Data field is not present in this
// case).
// 0x8FSet indicated default attributes to specified values.
// 6-n Data - data values as required, in the following order if present.
// No space is reserved for attributes for which the corresponding Mask flag was not
// set.
// (2*G bytes) - Character angle
// (2*G + 4 bytes)- Character box
// (1 byte) - Character direction
// (1 byte) - Character precision
// (1 byte) - Character set
// (2*G bytes) - Character shear
// (4 bytes) - Character break extra
// (4 bytes) - Character extra
// (4 bytes) - Character color
// (4 bytes) - Character background color
// (1 byte) - Character mix
// (1 byte) - Character background mix (G=2 or 4 depending on the Geometrics
// parameter of Set Default Parameter Format)
*pMET << (sal_uInt8)0x21 << (sal_uInt8)0x10 << (sal_uInt8)0x02 << (sal_uInt8)0x40
<< (sal_uInt8)0x00 << (sal_uInt8)0x8f
<< (sal_uInt8)0xaa << (sal_uInt8)0x02 << (sal_uInt8)0x00 << (sal_uInt8)0x00
<< (sal_uInt8)0x44 << (sal_uInt8)0x04 << (sal_uInt8)0x00 << (sal_uInt8)0x00
<< (sal_uInt8)0xa8 << (sal_uInt8)0xaa << (sal_uInt8)0x40 << (sal_uInt8)0x44;
// 0 0x21 Set Current Defaults
// 1 Length of following data
// 2 Set Default Marker Attributes 0x03
// 3-4 Mask - OR of as many of the following bits as are required:
// 0x4000 Marker box
// 0x1000 Marker precision
// 0x0800 Marker set
// 0x0100 Marker symbol
// 0x0008 Marker color
// 0x0004 Marker background color
// 0x0002 Marker mix
// 0x0001 Marker background mix
// 5 Flags
// 0x0F Set indicated default attributes to initial values.
// (Data field is not present in this instance)
// 0x8F Set indicated default attributes to specified values.
// 6-n Data - data values as required, in this order if present.
// No space is reserved for attributes for which the corresponding Mask flag was not
// set.
// (2*G bytes) - Marker box
// (1 byte) - Marker precision
// (1 byte) - Marker set
// (1 byte) - Marker symbol
// (4 bytes) - Marker color
// (4 bytes) - Marker background color
// (1 byte) - Marker mix
// (1 byte) - Marker background mix (G=2 or 4 depending on the Geometrics
// parameter of Set Default Parameter Format)
*pMET << (sal_uInt8)0x21 << (sal_uInt8)0x0c << (sal_uInt8)0x03 << (sal_uInt8)0x40
<< (sal_uInt8)0x00 << (sal_uInt8)0x8f
<< (sal_uInt8)0x66 << (sal_uInt8)0x02 << (sal_uInt8)0x00 << (sal_uInt8)0x00
<< (sal_uInt8)0x66 << (sal_uInt8)0x02 << (sal_uInt8)0x00 << (sal_uInt8)0x00;
// 0 0x21 Set Current Defaults
// 1 Length of following data
// 2 Set Default Pattern Attributes 0x04
// 3-4 Mask - OR of as many of the following bits as are required:
// 0x0800 Pattern set
// 0x0100 Pattern symbol
// 0x0080 Pattern reference point
// 0x0008 Pattern color
// 0x0004 Pattern background color
// 0x0002 Pattern mix
// 0x0001 Pattern background mix
// 5 Flags
//
// 0x0F Set indicated default attributes to initial values.
// (Data field is not present in this instance)
// 0x8F Set indicated default attributes to specified values.
// 6-n Data - data values as required, in this order if present.
// No space is reserved for attributes for which the corresponding Mask flag was
// not set.
//
// (1 byte) - Pattern set
// (1 byte) - Pattern symbol
// (2*G bytes) - Pattern reference point
// (4 bytes) - Pattern color
// (4 bytes) - Pattern background color
// (1 byte) - Pattern mix
// (1 byte) - Pattern background mix (G=2 or 4 depending on the Geometrics
// parameter of Set Default Parameter Format)
// 0 0x21 Set Current Defaults
// 1 Length of following data
// 2 Set Default Image Attributes 0x06
// 3-4 Mask - OR of as many of these bits as are required:
// 0x0008 Image color
// 0x0004 Image background color
// 0x0002 Image mix
// 0x0001 Image background mix
// 5 Flags
// 0x0F Set indicated default attributes to initial values. (Data field is not present in
// this instance)
// 0x8F Set indicated default attributes to specified values.
// 6-n Data - data values as required, in this order if present.
// No space is reserved for attributes for which the corresponding Mask flag was
// not set.
// (4 bytes) - Image color
// (4 bytes) - Image background color
// (1 byte) - Image mix
// (1 byte) - Image background mix
// 0 0x21 Set Current Defaults
// 1 Length of following data
// 2 Set Default Viewing Window 0x05
// 3-4 Mask - OR of as many of the following bits as are required:
// 0x8000 x left limit
// 0x4000 x right limit
// 0x2000 y bottom limit
// 0x1000 y top limit
// 5 Flags
// 0x0F Set indicated default attributes to initial values.
// (Data field is not present in this case).
// 0x8F Set indicated default attributes to specified values.
// 6-n Data - data values as required, in the following order if present.
// No space is reserved for attributes for which the corresponding Mask flag was
// not set.
// (2*G bytes) - x left limit
// (2*G bytes) - x right limit
// (2*G bytes) - y bottom limit
// (2*G bytes) - y top limit (G=2 or 4 depending on the Geometrics parameter of Set
// Default Parameter Format)
// 0 0x21 Set Current Defaults
// 1 Length of following data
// 2 Set Default Arc Parameters 0x0B
// 3-4 Mask - OR of as many of the following bits as are required:
// 0x8000 P value
// 0x4000 Q value
// 0x2000 R value
// 0x1000 S value
// 5 Flags
// 0x0F Set indicated default attributes to initial values.
// (Data field is not present in this case).
// 0x8F Set indicated default attributes to specified values.
// 6-n Data - data values as required, in the following order if present.
// No space is reserved for attributes for which the corresponding Mask flag was
// not set.
// (G bytes) - P value
// (G bytes) - Q value
// (G bytes) - R value
// (G bytes) - S value (G=2 or 4 depending on the Geometrics parameter of Set
// Default Parameter Format)
// 0 0x21 Set Current Defaults
// 1 Length of following data
// 2 Set Default Pick Identifier 0x0C
// 3-4 Mask - OR of as many of the following bits as are required:
// 0x8000 Pick identifier
// 5 Flags
// 0x0F Set indicated default attributes to initial values.
// (Data field is not present in this case).
// 0x8F Set indicated default attributes to specified values.
// 6-n Data - data values as required, in the following order if present.
// No space is reserved for attributes for which the corresponding Mask flag was
// not set.
// (4 bytes) - Pick identifier
// 0 0xE7 Set Bit-map Identifier
// 1 Length of following data 0x07
// 2-3 Usage Flags 0x8000
// 4-7 Bit-map handle
// 8 Lcid
if (nNumberOfBitmaps>0) {
*pMET << (sal_uInt8)0xe7 << (sal_uInt8)0x07 << (sal_uInt8)0x80 << (sal_uInt8)0x00;
WriteBigEndianLong(nActBitmapId);
*pMET << (sal_uInt8)0xfe;
}
UpdateFieldSize();
if (pMET->GetError()) bStatus=sal_False;
}
void METWriter::WillWriteOrder(sal_uLong nNextOrderMaximumLength)
{
// Die Parameter eines 'Graphics Data Fields' duerfen (laut OS2-Doku)
// hoechstens 32759 Bytes umfassen. Gemeint ist die Laenge des Feldes minus
// dem 'Structured Field Introducer' (groesse: 8). Also darf die Groesse
// des ganzen Fields hoechstens 8+32759=32767=0x7fff sein.
// Zur Sicherheit nehmen wir lieber 30000 als Grenze.
if (pMET->Tell()-nActualFieldStartPos+nNextOrderMaximumLength>30000)
{
UpdateFieldSize();
WriteFieldIntroducer(0,DatGrfObjMagic,0,0);
nNumberOfDataFields++;
}
}
void METWriter::METBitBlt(Point aPt, Size aSize, const Size& rBmpSizePixel)
{
WillWriteOrder(46);
*pMET << (sal_uInt8)0xd6 << (sal_uInt8)44 << (sal_uInt16)0 << (sal_uInt16) 0x00cc;
WriteBigEndianLong(nActBitmapId++);
*pMET << (sal_uInt8)0x02 << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00;
WritePoint(Point(aPt.X(),aPt.Y()+aSize.Height()));
WritePoint(Point(aPt.X()+aSize.Width(),aPt.Y()));
*pMET << (sal_uInt32)0 << (sal_uInt32)0
<< (sal_uInt32)(rBmpSizePixel.Width())
<< (sal_uInt32)(rBmpSizePixel.Height());
}
void METWriter::METSetAndPushLineInfo( const LineInfo& rLineInfo )
{
sal_Int32 nWidth = pCompDev->LogicToLogic( Size( rLineInfo.GetWidth(),0 ), aPictureMapMode, aTargetMapMode ).Width();
WillWriteOrder( 8 ); // set stroke linewidth
*pMET << (sal_uInt8)0x15
<< (sal_uInt8)6
<< (sal_uInt8)0 // Flags
<< (sal_uInt8)0
<< nWidth;
if ( rLineInfo.GetStyle() != LINE_SOLID )
{
sal_uInt8 nStyle = 0; // LineDefault;
switch ( rLineInfo.GetStyle() )
{
case LINE_NONE :
nStyle = 8;
break;
case LINE_DASH :
{
if ( rLineInfo.GetDotCount() )
{
if ( !rLineInfo.GetDashCount() )
nStyle = 1; // LINE_DOT
else
nStyle = 3; // LINE_DASH_DOT
}
else
nStyle = 2; // LINE_DASH
}
break;
case LineStyle_SOLID:
case LineStyle_FORCE_EQUAL_SIZE:
break; // not handled -Wall
}
WillWriteOrder( 2 );
*pMET << (sal_uInt8)0x18 << nStyle; // set LineType
}
}
void METWriter::METPopLineInfo( const LineInfo& rLineInfo )
{
WillWriteOrder( 8 ); // set stroke linewidth
*pMET << (sal_uInt8)0x15
<< (sal_uInt8)6
<< (sal_uInt8)0 // Flags
<< (sal_uInt8)0
<< (sal_uInt32)1;
if ( rLineInfo.GetStyle() != LINE_SOLID )
{
WillWriteOrder( 2 );
*pMET << (sal_uInt8)0x18 << (sal_uInt8)0; // set LineType
}
}
void METWriter::METBeginArea(sal_Bool bBoundaryLine)
{
WillWriteOrder(2);
*pMET << (sal_uInt8)0x68;
if (bBoundaryLine) *pMET << (sal_uInt8)0xc0;
else *pMET << (sal_uInt8)0x80;
}
void METWriter::METEndArea()
{
WillWriteOrder(2);
*pMET << (sal_uInt8)0x60 << (sal_uInt8)0;
}
void METWriter::METBeginPath(sal_uInt32 nPathId)
{
WillWriteOrder(8);
*pMET << (sal_uInt8)0xd0 << (sal_uInt8)6 << (sal_uInt16) 0 << nPathId;
}
void METWriter::METEndPath()
{
WillWriteOrder(2);
*pMET << (sal_uInt8)0x7f << (sal_uInt8)0;
}
void METWriter::METFillPath(sal_uInt32 nPathId)
{
WillWriteOrder(8);
*pMET << (sal_uInt8)0xd7 << (sal_uInt8)6
<< (sal_uInt8)0x00 << (sal_uInt8)0 << nPathId;
}
void METWriter::METOutlinePath(sal_uInt32 nPathId)
{
WillWriteOrder(8);
*pMET << (sal_uInt8)0xd4 << (sal_uInt8)6
<< (sal_uInt8)0 << (sal_uInt8)0 << nPathId;
}
void METWriter::METCloseFigure()
{
WillWriteOrder(2);
*pMET << (sal_uInt8)0x7d << (sal_uInt8)0;
}
void METWriter::METMove(Point aPt)
{
WillWriteOrder(10);
*pMET << (sal_uInt8)0x21 << (sal_uInt8)8;
WritePoint(aPt);
}
void METWriter::METLine(Point aPt1, Point aPt2)
{
WillWriteOrder(18);
*pMET << (sal_uInt8)0xc1 << (sal_uInt8)16;
WritePoint(aPt1); WritePoint(aPt2);
}
void METWriter::METLine(const Polygon & rPolygon)
{
sal_uInt16 nNumPoints,i,j,nOrderPoints;
sal_Bool bFirstOrder;
bFirstOrder=sal_True;
i=0; nNumPoints=rPolygon.GetSize();
while (i<nNumPoints) {
nOrderPoints=nNumPoints-i;
if (nOrderPoints>30) nOrderPoints=30;
WillWriteOrder(nOrderPoints*8+2);
if (bFirstOrder==sal_True) {
*pMET << (sal_uInt8)0xc1; // Line at given pos
bFirstOrder=sal_False;
}
else {
*pMET << (sal_uInt8)0x81; // Line at current pos
}
*pMET << (sal_uInt8)(nOrderPoints*8);
for (j=0; j<nOrderPoints; j++) WritePoint(rPolygon.GetPoint(i++));
}
}
void METWriter::METLine(const PolyPolygon & rPolyPolygon)
{
sal_uInt16 i,nCount;
nCount=rPolyPolygon.Count();
for (i=0; i<nCount; i++) {
METLine(rPolyPolygon.GetObject(i));
METCloseFigure();
}
}
void METWriter::METLineAtCurPos(Point aPt)
{
WillWriteOrder(10);
*pMET << (sal_uInt8)0x81 << (sal_uInt8)8;
WritePoint(aPt);
}
void METWriter::METBox(sal_Bool bFill, sal_Bool bBoundary,
Rectangle aRect, sal_uInt32 nHAxis, sal_uInt32 nVAxis)
{
sal_uInt8 nFlags=0;
if (bFill) nFlags|=0x40;
if (bBoundary) nFlags|=0x20;
WillWriteOrder(28);
*pMET << (sal_uInt8)0xc0 << (sal_uInt8)26 << nFlags << (sal_uInt8)0;
WritePoint(aRect.BottomLeft());
WritePoint(aRect.TopRight());
*pMET << nHAxis << nVAxis;
}
void METWriter::METFullArc(Point aCenter, double fMultiplier)
{
WillWriteOrder(14);
*pMET << (sal_uInt8)0xc7 << (sal_uInt8)12;
WritePoint(aCenter);
*pMET << (long)(fMultiplier*65536.0+0.5);
}
void METWriter::METPartialArcAtCurPos(Point aCenter, double fMultiplier,
double fStartAngle, double fSweepAngle)
{
fStartAngle*=180.0/3.14159265359;
while (fStartAngle>360.0) fStartAngle-=360.0;
while (fStartAngle<0.0) fStartAngle+=360.0;
fSweepAngle*=180.0/3.14159265359;
while (fSweepAngle>360.0) fSweepAngle-=360.0;
while (fSweepAngle<.00) fSweepAngle+=360.0;
WillWriteOrder(22);
*pMET << (sal_uInt8)0xa3 << (sal_uInt8)20;
WritePoint(aCenter);
*pMET << (long)(fMultiplier*65536.0+0.5);
*pMET << (long)(fStartAngle*65536.0+0.5);
*pMET << (long)(fSweepAngle*65536.0+0.5);
}
void METWriter::METChrStr( Point aPt, String aUniStr )
{
sal_uInt16 nLen,i;
ByteString aStr( aUniStr, gsl_getSystemTextEncoding() );
nLen = aStr.Len();
WillWriteOrder( 11 + nLen );
*pMET << (sal_uInt8)0xc3 << (sal_uInt8)( 9 + nLen );
WritePoint(aPt);
for ( i = 0; i < nLen; i++ )
*pMET << aStr.GetChar( i );
*pMET << (sal_uInt8)0;
}
void METWriter::METSetArcParams(long nP, long nQ, long nR, long nS)
{
WillWriteOrder(18);
*pMET << (sal_uInt8)0x22 << (sal_uInt8)16 << nP << nQ << nR << nS;
}
void METWriter::METSetColor(Color aColor)
{
if (aColor==aMETColor) return;
aMETColor=aColor;
WillWriteOrder(6);
*pMET << (sal_uInt8)0xa6 << (sal_uInt8)4 << (sal_uInt8)0
<< (sal_uInt8)(aColor.GetBlue())
<< (sal_uInt8)(aColor.GetGreen())
<< (sal_uInt8)(aColor.GetRed());
}
void METWriter::METSetBackgroundColor(Color aColor)
{
if (aColor==aMETBackgroundColor) return;
aMETBackgroundColor=aColor;
WillWriteOrder(6);
*pMET << (sal_uInt8)0xa7 << (sal_uInt8)4 << (sal_uInt8)0
<< (sal_uInt8)(aColor.GetBlue())
<< (sal_uInt8)(aColor.GetGreen())
<< (sal_uInt8)(aColor.GetRed());
}
void METWriter::METSetMix(RasterOp eROP)
{
sal_uInt8 nMix;
if (eMETMix==eROP)
return;
eMETMix=eROP;
switch (eROP)
{
case ROP_INVERT: nMix=0x0c; break;
case ROP_XOR: nMix=0x04; break;
default: nMix=0x02;
}
WillWriteOrder(2);
*pMET << (sal_uInt8)0x0c << nMix;
}
void METWriter::METSetChrCellSize(Size aSize)
{
if (aMETChrCellSize==aSize)
return;
aMETChrCellSize=aSize;
WillWriteOrder(10);
if (aSize.Width()==0) aSize.Width()=aSize.Height();
*pMET << (sal_uInt8)0x33 << (sal_uInt8)8 << (long)aSize.Width() << (long)aSize.Height();
}
void METWriter::METSetChrAngle(short nAngle)
{
double fa;
long nax,nay;
if (nMETChrAngle==nAngle) return;
nMETChrAngle=nAngle;
if (nAngle==0)
{
nax=256;
nay=0;
}
else
{
fa=((double)nAngle)/1800.0*3.14159265359;
nax=(long)(256.0*cos(fa)+0.5);
nay=(long)(256.0*sin(fa)+0.5);
}
WillWriteOrder(10);
*pMET << (sal_uInt8)0x34 << (sal_uInt8)8 << nax << nay;
}
void METWriter::METSetChrSet(sal_uInt8 nSet)
{
if (nMETChrSet==nSet)
return;
nMETChrSet=nSet;
WillWriteOrder(2);
*pMET << (sal_uInt8)0x38 << nSet;
}
void METWriter::WriteOrders( const GDIMetaFile* pMTF )
{
if(bStatus==sal_False)
return;
for( sal_uLong nA = 0, nACount = pMTF->GetActionCount(); nA < nACount; nA++ )
{
const MetaAction* pMA = pMTF->GetAction( nA );
switch (pMA->GetType())
{
case META_PIXEL_ACTION:
{
const MetaPixelAction* pA = (const MetaPixelAction*) pMA;
METSetMix( eGDIRasterOp );
METSetColor( pA->GetColor() );
METLine( pA->GetPoint(),pA->GetPoint() );
}
break;
case META_POINT_ACTION:
{
const MetaPointAction* pA = (const MetaPointAction*) pMA;
METSetArcParams(1,1,0,0);
METSetMix(eGDIRasterOp);
METSetColor(aGDILineColor);
METBeginArea(sal_False);
METFullArc(pA->GetPoint(),0.5);
METEndArea();
}
break;
case META_LINE_ACTION:
{
const MetaLineAction* pA = (const MetaLineAction*) pMA;
if( aGDILineColor != Color( COL_TRANSPARENT ) )
{
LineInfo aLineInfo( pA->GetLineInfo() );
if ( ! ( aLineInfo.IsDefault() ) )
METSetAndPushLineInfo( aLineInfo );
METSetMix( eGDIRasterOp );
METSetColor(aGDILineColor);
METBeginPath( 1 );
METLine( pA->GetStartPoint(), pA->GetEndPoint() );
METEndPath();
METOutlinePath( 1 );
if ( ! ( aLineInfo.IsDefault() ) )
METPopLineInfo( aLineInfo );
}
}
break;
case META_RECT_ACTION:
{
const MetaRectAction* pA = (const MetaRectAction*) pMA;
if( aGDIFillColor != Color( COL_TRANSPARENT ) )
{
METSetMix( eGDIRasterOp );
METSetColor( aGDIFillColor );
METSetBackgroundColor( aGDIFillColor );
METBox( sal_True, sal_False, pA->GetRect(), 0, 0 );
}
if( aGDILineColor != Color( COL_TRANSPARENT ) )
{
METSetMix( eGDIRasterOp );
METSetColor( aGDILineColor );
METBox( sal_False, sal_True, pA->GetRect(), 0, 0 );
}
}
break;
case META_ROUNDRECT_ACTION:
{
const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pMA;
if( aGDIFillColor != Color( COL_TRANSPARENT ) )
{
METSetMix( eGDIRasterOp );
METSetColor( aGDIFillColor );
METSetBackgroundColor( aGDIFillColor );
METBox( sal_True, sal_False, pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
}
if( aGDILineColor != Color( COL_TRANSPARENT ) )
{
METSetMix( eGDIRasterOp );
METSetColor( aGDILineColor );
METBox( sal_False, sal_True, pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
}
}
break;
case META_ELLIPSE_ACTION:
{
const MetaEllipseAction* pA = (const MetaEllipseAction*) pMA;
Point aCenter;
aCenter.X()=(pA->GetRect().Left()+pA->GetRect().Right())/2;
aCenter.Y()=(pA->GetRect().Top()+pA->GetRect().Bottom())/2;
METSetArcParams(pA->GetRect().GetWidth(), pA->GetRect().GetHeight(),0,0);
if( aGDIFillColor != Color( COL_TRANSPARENT ) )
{
METSetMix( eGDIRasterOp );
METSetColor( aGDIFillColor );
METSetBackgroundColor( aGDIFillColor );
METBeginArea(sal_False);
METFullArc(aCenter,0.5);
METEndArea();
}
if( aGDILineColor != Color( COL_TRANSPARENT ) )
{
METSetMix( eGDIRasterOp );
METSetColor( aGDILineColor );
METFullArc( aCenter,0.5 );
}
}
break;
case META_ARC_ACTION:
{
const MetaArcAction* pA = (const MetaArcAction*) pMA;
Point aStartPos,aCenter;
double fdx,fdy,fa1,fa2;
aCenter.X()=(pA->GetRect().Left()+pA->GetRect().Right())/2;
aCenter.Y()=(pA->GetRect().Top()+pA->GetRect().Bottom())/2;
fdx=(double)(pA->GetStartPoint().X()-aCenter.X());
fdy=(double)(pA->GetStartPoint().Y()-aCenter.Y());
fdx*=(double)pA->GetRect().GetHeight();
fdy*=(double)pA->GetRect().GetWidth();
if (fdx==0.0 && fdy==0.0) fdx=1.0;
fa1=atan2(-fdy,fdx);
fdx=(double)(pA->GetEndPoint().X()-aCenter.X());
fdy=(double)(pA->GetEndPoint().Y()-aCenter.Y());
fdx*=(double)pA->GetRect().GetHeight();
fdy*=(double)pA->GetRect().GetWidth();
if (fdx==0.0 && fdy==0.0) fdx=1.0;
fa2=atan2(-fdy,fdx);
aStartPos.X()=aCenter.X()+(long)(((double)pA->GetRect().GetWidth())*cos(fa1)/2.0+0.5);
aStartPos.Y()=aCenter.Y()-(long)(((double)pA->GetRect().GetHeight())*sin(fa1)/2.0+0.5);
if( aGDILineColor != Color( COL_TRANSPARENT ) )
{
METSetMix( eGDIRasterOp );
METSetColor( aGDILineColor );
METSetArcParams(pA->GetRect().GetWidth(), pA->GetRect().GetHeight(),0,0);
METBeginPath(1);
METMove(aStartPos);
METPartialArcAtCurPos(aCenter,0.5,fa1,fa2-fa1);
METEndPath();
METOutlinePath(1);
}
}
break;
case META_PIE_ACTION:
{
const MetaPieAction* pA = (const MetaPieAction*) pMA;
Point aCenter;
double fdx,fdy,fa1,fa2;
aCenter.X()=(pA->GetRect().Left()+pA->GetRect().Right())/2;
aCenter.Y()=(pA->GetRect().Top()+pA->GetRect().Bottom())/2;
fdx=(double)(pA->GetStartPoint().X()-aCenter.X());
fdy=(double)(pA->GetStartPoint().Y()-aCenter.Y());
fdx*=(double)pA->GetRect().GetHeight();
fdy*=(double)pA->GetRect().GetWidth();
if (fdx==0.0 && fdy==0.0) fdx=1.0;
fa1=atan2(-fdy,fdx);
fdx=(double)(pA->GetEndPoint().X()-aCenter.X());
fdy=(double)(pA->GetEndPoint().Y()-aCenter.Y());
fdx*=(double)pA->GetRect().GetHeight();
fdy*=(double)pA->GetRect().GetWidth();
if (fdx==0.0 && fdy==0.0) fdx=1.0;
fa2=atan2(-fdy,fdx);
METSetArcParams(pA->GetRect().GetWidth(), pA->GetRect().GetHeight(),0,0);
if( aGDIFillColor != Color( COL_TRANSPARENT ) )
{
METSetMix( eGDIRasterOp );
METSetColor( aGDIFillColor );
METSetBackgroundColor( aGDIFillColor );
METBeginPath(1);
METMove(aCenter);
METPartialArcAtCurPos(aCenter,0.5,fa1,fa2-fa1);
METLineAtCurPos(aCenter);
METEndPath();
METFillPath(1);
}
if( aGDILineColor != Color( COL_TRANSPARENT ) )
{
METSetMix( eGDIRasterOp );
METSetColor( aGDILineColor );
METBeginPath(1);
METMove(aCenter);
METPartialArcAtCurPos(aCenter,0.5,fa1,fa2-fa1);
METLineAtCurPos(aCenter);
METEndPath();
METOutlinePath(1);
}
}
break;
case META_CHORD_ACTION:
{
const MetaChordAction* pA = (const MetaChordAction*) pMA;
Point aStartPos,aCenter;
double fdx,fdy,fa1,fa2;
aCenter.X()=(pA->GetRect().Left()+pA->GetRect().Right())/2;
aCenter.Y()=(pA->GetRect().Top()+pA->GetRect().Bottom())/2;
fdx=(double)(pA->GetStartPoint().X()-aCenter.X());
fdy=(double)(pA->GetStartPoint().Y()-aCenter.Y());
fdx*=(double)pA->GetRect().GetHeight();
fdy*=(double)pA->GetRect().GetWidth();
if (fdx==0.0 && fdy==0.0) fdx=1.0;
fa1=atan2(-fdy,fdx);
fdx=(double)(pA->GetEndPoint().X()-aCenter.X());
fdy=(double)(pA->GetEndPoint().Y()-aCenter.Y());
fdx*=(double)pA->GetRect().GetHeight();
fdy*=(double)pA->GetRect().GetWidth();
if (fdx==0.0 && fdy==0.0) fdx=1.0;
fa2=atan2(-fdy,fdx);
aStartPos.X()=aCenter.X()+(long)(((double)pA->GetRect().GetWidth())*cos(fa1)/2.0+0.5);
aStartPos.Y()=aCenter.Y()-(long)(((double)pA->GetRect().GetHeight())*sin(fa1)/2.0+0.5);
if( aGDIFillColor != Color( COL_TRANSPARENT ) )
{
METSetMix( eGDIRasterOp );
METSetColor( aGDIFillColor );
METSetBackgroundColor( aGDIFillColor );
METBeginPath(1);
METMove(aStartPos);
METPartialArcAtCurPos(aCenter,0.5,fa1,fa2-fa1);
METLineAtCurPos(aStartPos);
METEndPath();
METFillPath(1);
}
if( aGDILineColor != Color( COL_TRANSPARENT ) )
{
METSetMix( eGDIRasterOp );
METSetColor( aGDILineColor );
METBeginPath(1);
METMove(aStartPos);
METPartialArcAtCurPos(aCenter,0.5,fa1,fa2-fa1);
METLineAtCurPos(aStartPos);
METEndPath();
METOutlinePath(1);
}
}
break;
case META_POLYLINE_ACTION:
{
const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pMA;
if( aGDILineColor != Color( COL_TRANSPARENT ) )
{
LineInfo aLineInfo( pA->GetLineInfo() );
if ( ! ( aLineInfo.IsDefault() ) )
METSetAndPushLineInfo( aLineInfo );
METSetMix(eGDIRasterOp);
METSetColor(aGDILineColor);
METBeginPath(1);
Polygon aSimplePoly;
const Polygon& rPoly = pA->GetPolygon();
if ( rPoly.HasFlags() )
rPoly.AdaptiveSubdivide( aSimplePoly );
else
aSimplePoly = rPoly;
METLine( aSimplePoly );
METEndPath();
METOutlinePath(1);
if ( ! ( aLineInfo.IsDefault() ) )
METPopLineInfo( aLineInfo );
}
}
break;
case META_POLYGON_ACTION:
{
const MetaPolygonAction* pA = (const MetaPolygonAction*) pMA;
Polygon aSimplePoly;
const Polygon& rPoly = pA->GetPolygon();
if ( rPoly.HasFlags() )
rPoly.AdaptiveSubdivide( aSimplePoly );
else
aSimplePoly = rPoly;
if( aGDIFillColor != Color( COL_TRANSPARENT ) )
{
METSetMix(eGDIRasterOp);
METSetColor(aGDIFillColor );
METSetBackgroundColor(aGDIFillColor );
METBeginPath(1);
METLine( aSimplePoly );
METEndPath();
METFillPath(1);
}
if( aGDILineColor != Color( COL_TRANSPARENT ) )
{
METSetMix(eGDIRasterOp);
METSetColor(aGDILineColor );
METBeginPath(1);
METLine( aSimplePoly );
METEndPath();
METOutlinePath(1);
}
}
break;
case META_POLYPOLYGON_ACTION:
{
const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*) pMA;
PolyPolygon aSimplePolyPoly( pA->GetPolyPolygon() );
sal_uInt16 i, nCount = aSimplePolyPoly.Count();
for ( i = 0; i < nCount; i++ )
{
if ( aSimplePolyPoly[ i ].HasFlags() )
{
Polygon aSimplePoly;
aSimplePolyPoly[ i ].AdaptiveSubdivide( aSimplePoly );
aSimplePolyPoly[ i ] = aSimplePoly;
}
}
if( aGDIFillColor != Color( COL_TRANSPARENT ) )
{
METSetMix(eGDIRasterOp);
METSetColor(aGDIFillColor);
METSetBackgroundColor(aGDIFillColor);
METBeginPath(1);
METLine( aSimplePolyPoly );
METEndPath();
METFillPath(1);
}
if( aGDILineColor != Color( COL_TRANSPARENT ) )
{
METSetMix(eGDIRasterOp);
METSetColor(aGDILineColor);
METBeginPath(1);
METLine( aSimplePolyPoly );
METEndPath();
METOutlinePath(1);
}
}
break;
case META_TEXT_ACTION:
{
const MetaTextAction* pA = (const MetaTextAction*) pMA;
Point aPt( pA->GetPoint() );
if( aGDIFont.GetAlign() != ALIGN_BASELINE)
{
VirtualDevice aVDev;
if( aGDIFont.GetAlign()==ALIGN_TOP )
aPt.Y()+=(long)aVDev.GetFontMetric( aGDIFont ).GetAscent();
else
aPt.Y()-=(long)aVDev.GetFontMetric( aGDIFont ).GetDescent();
}
METSetMix(eGDIRasterOp);
METSetColor(aGDIFont.GetColor());
METSetBackgroundColor(aGDIFont.GetFillColor());
METSetChrCellSize(aGDIFont.GetSize());
METSetChrAngle(aGDIFont.GetOrientation());
METSetChrSet(FindChrSet(aGDIFont));
METChrStr(aPt, String(pA->GetText(),pA->GetIndex(),pA->GetLen()));
}
break;
case META_TEXTARRAY_ACTION:
{
const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pMA;
sal_uInt16 i;
String aStr;
Polygon aPolyDummy(1);
short nOrientation;
Point aPt( pA->GetPoint() );
if( aGDIFont.GetAlign() != ALIGN_BASELINE )
{
VirtualDevice aVDev;
if( aGDIFont.GetAlign() == ALIGN_TOP )
aPt.Y()+=(long)aVDev.GetFontMetric(aGDIFont).GetAscent();
else
aPt.Y()-=(long)aVDev.GetFontMetric(aGDIFont).GetDescent();
}
METSetMix(eGDIRasterOp);
METSetColor(aGDIFont.GetColor());
METSetBackgroundColor(aGDIFont.GetFillColor());
METSetChrCellSize(aGDIFont.GetSize());
METSetChrAngle( nOrientation = aGDIFont.GetOrientation() );
METSetChrSet(FindChrSet(aGDIFont));
aStr=String(pA->GetText(),pA->GetIndex(),pA->GetLen());
if( pA->GetDXArray()!=NULL )
{
Point aPt2;
for( i=0; i < aStr.Len(); i++ )
{
aPt2 = aPt;
if ( i > 0 )
{
aPt2.X() += pA->GetDXArray()[i-1];
if ( nOrientation )
{
aPolyDummy.SetPoint( aPt2, 0 );
aPolyDummy.Rotate( aPt, nOrientation );
aPt2 = aPolyDummy.GetPoint( 0 );
}
}
METChrStr( aPt2, String( aStr.GetChar( i ) ) );
}
}
else
METChrStr( aPt, aStr );
}
break;
case META_STRETCHTEXT_ACTION:
{
const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pMA;
VirtualDevice aVDev;
sal_uInt16 i;
sal_Int32* pDXAry;
sal_Int32 nNormSize;
String aStr;
Polygon aPolyDummy(1);
short nOrientation;
Point aPt( pA->GetPoint() );
Point aPt2;
aVDev.SetFont( aGDIFont );
if( aGDIFont.GetAlign() != ALIGN_BASELINE)
{
if( aGDIFont.GetAlign() == ALIGN_TOP )
aPt.Y()+=(long)aVDev.GetFontMetric().GetAscent();
else
aPt.Y()-=(long)aVDev.GetFontMetric().GetDescent();
}
METSetMix(eGDIRasterOp);
METSetColor(aGDIFont.GetColor());
METSetBackgroundColor(aGDIFont.GetFillColor());
METSetChrCellSize(aGDIFont.GetSize());
METSetChrAngle( nOrientation = aGDIFont.GetOrientation() );
METSetChrSet(FindChrSet(aGDIFont));
aStr=String(pA->GetText(),pA->GetIndex(),pA->GetLen());
pDXAry=new sal_Int32[aStr.Len()];
nNormSize = aVDev.GetTextArray( aStr, pDXAry );
for ( i = 0; i < aStr.Len(); i++ )
{
aPt2 = aPt;
if ( i > 0 )
{
aPt2.X() += pDXAry[i-1]*((long)pA->GetWidth())/ nNormSize;
if ( nOrientation )
{
aPolyDummy.SetPoint( aPt2, 0 );
aPolyDummy.Rotate( aPt, nOrientation );
aPt2 = aPolyDummy.GetPoint( 0 );
}
}
METChrStr( aPt2, String( aStr.GetChar( i ) ) );
}
delete[] pDXAry;
}
break;
case META_TEXTRECT_ACTION:
{
// DBG_ERROR( "Unsupported MET-Action: META_TEXTRECT_ACTION!" );
}
break;
case META_BMP_ACTION:
{
const MetaBmpAction* pA = (const MetaBmpAction*) pMA;
const Size aSizePixel( pA->GetBitmap().GetSizePixel() );
METSetMix(eGDIRasterOp);
METBitBlt( pA->GetPoint(), pCompDev->PixelToLogic( aSizePixel, aPictureMapMode ), aSizePixel );
}
break;
case META_BMPSCALE_ACTION:
{
const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pMA;
METSetMix(eGDIRasterOp);
METBitBlt( pA->GetPoint(), pA->GetSize(), pA->GetBitmap().GetSizePixel() );
}
break;
case META_BMPSCALEPART_ACTION:
{
const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pMA;
Bitmap aTmp( pA->GetBitmap() );
aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
METSetMix( eGDIRasterOp );
METBitBlt( pA->GetDestPoint(), pA->GetDestSize(), pA->GetBitmap().GetSizePixel() );
}
break;
case META_BMPEX_ACTION:
{
const MetaBmpExAction* pA = (const MetaBmpExAction*) pMA;
const Size aSizePixel( pA->GetBitmapEx().GetSizePixel() );
METSetMix( eGDIRasterOp );
METBitBlt( pA->GetPoint(), pCompDev->PixelToLogic( aSizePixel, aPictureMapMode ), aSizePixel );
}
break;
case META_BMPEXSCALE_ACTION:
{
const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pMA;
const Size aSizePixel( pA->GetBitmapEx().GetSizePixel() );
METSetMix( eGDIRasterOp );
METBitBlt( pA->GetPoint(), pA->GetSize(), aSizePixel );
}
break;
case META_BMPEXSCALEPART_ACTION:
{
const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pMA;
Bitmap aTmp( Graphic( pA->GetBitmapEx() ).GetBitmap() );
aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
METSetMix( eGDIRasterOp );
METBitBlt( pA->GetDestPoint(), pA->GetDestSize(), aTmp.GetSizePixel() );
}
break;
case META_EPS_ACTION :
{
const MetaEPSAction* pA = (const MetaEPSAction*)pMA;
const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() );
sal_Int32 nCount = aGDIMetaFile.GetActionCount();
for ( sal_Int32 i = 0; i < nCount; i++ )
{
const MetaAction* pMetaAct = aGDIMetaFile.GetAction( i );
if ( pMetaAct->GetType() == META_BMPSCALE_ACTION )
{
const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*)pMetaAct;
METSetMix(eGDIRasterOp);
METBitBlt( pA->GetPoint(), pA->GetSize(), pBmpScaleAction->GetBitmap().GetSizePixel() );
break;
}
}
}
break;
case META_MASK_ACTION:
{
// DBG_ERROR( "Unsupported MET-Action: META_MASK_ACTION!" );
}
break;
case META_MASKSCALE_ACTION:
{
// DBG_ERROR( "Unsupported MET-Action: META_MASKSCALE_ACTION!" );
}
break;
case META_MASKSCALEPART_ACTION:
{
// DBG_ERROR( "Unsupported MET-Action: META_MASKSCALEPART_ACTION!" );
}
break;
case META_GRADIENT_ACTION:
{
VirtualDevice aVDev;
GDIMetaFile aTmpMtf;
const MetaGradientAction* pA = (const MetaGradientAction*) pMA;
aVDev.SetMapMode( aTargetMapMode );
aVDev.AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf );
WriteOrders( &aTmpMtf );
}
break;
case META_HATCH_ACTION:
{
VirtualDevice aVDev;
GDIMetaFile aTmpMtf;
const MetaHatchAction* pA = (const MetaHatchAction*) pMA;
aVDev.SetMapMode( aTargetMapMode );
aVDev.AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
WriteOrders( &aTmpMtf );
}
break;
case META_WALLPAPER_ACTION:
{
// DBG_ERROR( "Unsupported MET-Action: META_WALLPAPER_ACTION!" );
}
break;
case META_CLIPREGION_ACTION:
{
// DBG_ERROR( "Unsupported MET-Action: META_CLIPREGION_ACTION!" );
}
break;
case META_ISECTRECTCLIPREGION_ACTION:
{
const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*) pMA;
WriteClipRect( pA->GetRect() );
}
break;
case META_ISECTREGIONCLIPREGION_ACTION:
{
// DBG_ERROR( "Unsupported MET-Action: META_ISECTREGIONCLIPREGION_ACTION!" );
}
break;
case META_MOVECLIPREGION_ACTION:
{
// DBG_ERROR( "Unsupported MET-Action: META_MOVECLIPREGION_ACTION!" );
}
break;
case META_LINECOLOR_ACTION:
{
const MetaLineColorAction* pA = (const MetaLineColorAction*) pMA;
if( pA->IsSetting() )
aGDILineColor = pA->GetColor();
else
aGDILineColor = Color( COL_TRANSPARENT );
}
break;
case META_FILLCOLOR_ACTION:
{
const MetaFillColorAction* pA = (const MetaFillColorAction*) pMA;
if( pA->IsSetting() )
aGDIFillColor = pA->GetColor();
else
aGDIFillColor = Color( COL_TRANSPARENT );
}
break;
case META_TEXTCOLOR_ACTION:
{
const MetaTextColorAction* pA = (const MetaTextColorAction*) pMA;
aGDIFont.SetColor( pA->GetColor() );
}
break;
case META_TEXTFILLCOLOR_ACTION:
{
const MetaTextFillColorAction* pA = (const MetaTextFillColorAction*) pMA;
if( pA->IsSetting() )
aGDIFont.SetFillColor( pA->GetColor() );
else
aGDIFont.SetFillColor( Color( COL_TRANSPARENT ) );
}
break;
case META_TEXTALIGN_ACTION:
{
// DBG_ERROR( "Unsupported MET-Action: META_TEXTALIGN_ACTION!" );
}
break;
case META_MAPMODE_ACTION:
{
const MetaMapModeAction* pA = (const MetaMapModeAction*) pMA;
if( aPictureMapMode != pA->GetMapMode() )
{
if ( pA->GetMapMode().GetMapUnit() == MAP_RELATIVE )
{
MapMode aMM = pA->GetMapMode();
Fraction aScaleX = aMM.GetScaleX();
Fraction aScaleY = aMM.GetScaleY();
Point aOrigin = aPictureMapMode.GetOrigin();
BigInt aX( aOrigin.X() );
aX *= BigInt( aScaleX.GetDenominator() );
if( aOrigin.X() >= 0 )
{
if( aScaleX.GetNumerator() >= 0 )
aX += BigInt( aScaleX.GetNumerator()/2 );
else
aX -= BigInt( (aScaleX.GetNumerator()+1)/2 );
}
else
{
if( aScaleX.GetNumerator() >= 0 )
aX -= BigInt( (aScaleX.GetNumerator()-1)/2 );
else
aX += BigInt( aScaleX.GetNumerator()/2 );
}
aX /= BigInt( aScaleX.GetNumerator() );
aOrigin.X() = (long) aX + aMM.GetOrigin().X();
BigInt aY( aOrigin.Y() );
aY *= BigInt( aScaleY.GetDenominator() );
if( aOrigin.Y() >= 0 )
{
if( aScaleY.GetNumerator() >= 0 )
aY += BigInt( aScaleY.GetNumerator()/2 );
else
aY -= BigInt( (aScaleY.GetNumerator()+1)/2 );
}
else
{
if( aScaleY.GetNumerator() >= 0 )
aY -= BigInt( (aScaleY.GetNumerator()-1)/2 );
else
aY += BigInt( aScaleY.GetNumerator()/2 );
}
aY /= BigInt( aScaleY.GetNumerator() );
aOrigin.Y() = (long)aY + aMM.GetOrigin().Y();
aPictureMapMode.SetOrigin( aOrigin );
aScaleX *= aPictureMapMode.GetScaleX();
aScaleY *= aPictureMapMode.GetScaleY();
aPictureMapMode.SetScaleX( aScaleX );
aPictureMapMode.SetScaleY( aScaleY );
}
else
aPictureMapMode=pA->GetMapMode();
}
}
break;
case META_FONT_ACTION:
{
aGDIFont = ( (const MetaFontAction*) pMA )->GetFont();
}
break;
case META_PUSH_ACTION:
{
METGDIStackMember* pGS = new METGDIStackMember;
pGS->pSucc=pGDIStack; pGDIStack=pGS;
pGS->aLineColor=aGDILineColor;
pGS->aFillColor=aGDIFillColor;
pGS->eRasterOp=eGDIRasterOp;
pGS->aFont=aGDIFont;
pGS->aMapMode=aPictureMapMode;
pGS->aClipRect=aGDIClipRect;
}
break;
case META_POP_ACTION:
{
METGDIStackMember* pGS;
if( pGDIStack )
{
pGS=pGDIStack; pGDIStack=pGS->pSucc;
aGDILineColor=pGS->aLineColor;
aGDIFillColor=pGS->aFillColor;
eGDIRasterOp=pGS->eRasterOp;
aGDIFont=pGS->aFont;
if ( pGS->aClipRect != aGDIClipRect )
WriteClipRect( pGS->aClipRect );
aPictureMapMode=pGS->aMapMode;
delete pGS;
}
}
break;
case META_RASTEROP_ACTION:
{
eGDIRasterOp = ( (const MetaRasterOpAction*) pMA )->GetRasterOp();
}
break;
case META_TRANSPARENT_ACTION:
{
if( aGDIFillColor != Color( COL_TRANSPARENT ) )
{
METSetMix(eGDIRasterOp);
METSetColor(aGDIFillColor);
METSetBackgroundColor(aGDIFillColor);
METBeginPath(1);
METLine(( (const MetaTransparentAction*) pMA )->GetPolyPolygon());
METEndPath();
METFillPath(1);
}
if( aGDILineColor != Color( COL_TRANSPARENT ) )
{
METSetMix(eGDIRasterOp);
METSetColor(aGDILineColor);
METBeginPath(1);
METLine(( (const MetaTransparentAction*) pMA )->GetPolyPolygon());
METEndPath();
METOutlinePath(1);
}
}
break;
case META_FLOATTRANSPARENT_ACTION:
{
const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pMA;
GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
const Size aSrcSize( aTmpMtf.GetPrefSize() );
const Point aDestPt( pA->GetPoint() );
const Size aDestSize( pA->GetSize() );
const double fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
const double fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
long nMoveX, nMoveY;
if( fScaleX != 1.0 || fScaleY != 1.0 )
{
aTmpMtf.Scale( fScaleX, fScaleY );
aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
}
nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y();
if( nMoveX || nMoveY )
aTmpMtf.Move( nMoveX, nMoveY );
WriteOrders( &aTmpMtf );
}
break;
}
nWrittenActions++;
MayCallback();
if( pMET->GetError() )
bStatus=sal_False;
if( bStatus == sal_False )
break;
}
}
void METWriter::WriteObjectEnvironmentGroup(const GDIMetaFile * pMTF)
{
sal_uLong i, nId;
//--- Das Feld 'Begin Object Environment Group':
WriteFieldIntroducer(16,BegObjEnvMagic,0,0);
WriteFieldId(7);
//--- Das Feld 'Map Color Attribute Table':
WriteFieldIntroducer(22,MapColAtrMagic,0,0);
WriteBigEndianShort(0x000e);
*pMET << (sal_uInt8)0x0c << (sal_uInt8)0x02 << (sal_uInt8)0x84 << (sal_uInt8)0x00;
WriteFieldId(4);
//--- Das erste Feld 'Map Coded Font':
WriteFieldIntroducer(32,MapCodFntMagic,0,0);
WriteBigEndianShort(0x0018);
*pMET << (sal_uInt8)0x0c << (sal_uInt8)0x02 << (sal_uInt8)0x84 << (sal_uInt8)0x00;
*pMET << (sal_uInt8)0xff << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00;
*pMET << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00 << (sal_uInt8)0x00;
*pMET << (sal_uInt8)0x04 << (sal_uInt8)0x24 << (sal_uInt8)0x05 << (sal_uInt8)0x00;
*pMET << (sal_uInt8)0x06 << (sal_uInt8)0x20;
*pMET << (sal_uInt8)0x03 << (sal_uInt8)0x97 << (sal_uInt8)0x01 << (sal_uInt8)0xb5;
//--- Die weiteren Felder 'Map Coded Font':
CreateChrSets(pMTF);
WriteChrSets();
//--- Die Felder 'Map Data Resource':
nId=nActBitmapId;
for (i=0; i<nNumberOfBitmaps; i++)
{
WriteFieldIntroducer(29,MapDatResMagic,0,0);
WriteBigEndianShort(0x0015);
*pMET << (sal_uInt8)0x0c << (sal_uInt8)0x02 << (sal_uInt8)0x84 << (sal_uInt8)0x00;
WriteFieldId(nId);
*pMET << (sal_uInt8)0x07 << (sal_uInt8)0x22 << (sal_uInt8)0x10;
*pMET << (sal_uInt32)nId;
nId++;
}
//--- Das Feld 'End Object Environment Group':
WriteFieldIntroducer(16,EndObjEnvMagic,0,0);
WriteFieldId(7);
}
void METWriter::WriteGraphicsObject(const GDIMetaFile * pMTF)
{
sal_uLong nSegmentSize,nPos,nDataFieldsStartPos;
if( bStatus==sal_False )
return;
//--- Das Feld 'Begin Graphics Object':
WriteFieldIntroducer(16,BegGrfObjMagic,0,0);
WriteFieldId(7);
// Map Color Attribute Table, Fonts und anderes:
WriteObjectEnvironmentGroup(pMTF);
//--- Das Feld 'Graphics Data Descriptor':
WriteDataDescriptor(pMTF);
// Zaehler fuer Data Fields initialisieren:
nNumberOfDataFields=0;
// Und Position des ersten Data Fields merken:
nDataFieldsStartPos=pMET->Tell();
//--- Anfang des ersten Feldes 'Graphics Data'
WriteFieldIntroducer(0,DatGrfObjMagic,0,0);
nNumberOfDataFields++;
// Nun schreiben wir zunaechst den Kopf des Segments:
*pMET << (sal_uInt8)0x70 << (sal_uInt8)0x0e << (sal_uInt32)0;
*pMET << (sal_uInt8)0x70 << (sal_uInt8)0x10; // Flags
*pMET << (sal_uInt16)0; // Lo-Wort der Laenge der Segementdaten (Big Endian)
*pMET << (sal_uInt32)0; // Reserved
*pMET << (sal_uInt16)0; // Hi-Wort der Laenge der Segementdaten (Big Endian) (Ohh Ohh OS2)
// Anmerkung: die richtige Daten-Laenge schreiben wir weiter unten nochmal
// Jetzt werden alle Orders rausgeschrieben:
// (wobei die Sache ggf. in mehrere 'Graphics Data Fields' aufgeteilt
// wird, per Methode WillWriteOrder(..))
WriteOrders(pMTF);
//--- Das letzte Feld 'Graphic Data' beenden:
UpdateFieldSize();
//--- Und schliesslich die Segmentgroesse richtigstellen:
nPos=pMET->Tell();
nSegmentSize=nPos-nDataFieldsStartPos;
nSegmentSize-=nNumberOfDataFields*8; // Structured Field Introducers zaehlen nicht mit
pMET->Seek(nDataFieldsStartPos+16); // Zum Lo-Wort der Segmentgroesse seeken
WriteBigEndianShort((sal_uInt16)(nSegmentSize&0x0000ffff)); // Und schreiben
pMET->Seek(nDataFieldsStartPos+22); // Zum Hi-Wort der Segmentgroesse seeken
WriteBigEndianShort((sal_uInt16)(nSegmentSize>>16)); // Und schreiben
pMET->Seek(nPos); // Zurueck zur Tagesordnung
//--- Das Feld 'End Graphic Objects':
WriteFieldIntroducer(16,EndGrfObjMagic,0,0);
WriteFieldId(7);
if( pMET->GetError() )
bStatus=sal_False;
}
void METWriter::WriteResourceGroup(const GDIMetaFile * pMTF)
{
if( bStatus==sal_False )
return;
//--- Das Feld 'Begin Resource Group':
WriteFieldIntroducer(16,BegResGrpMagic,0,0);
WriteFieldId(2);
//--- Der Inhalt:
WriteColorAttributeTable();
nActBitmapId=0x77777700;
WriteImageObjects(pMTF);
nActBitmapId=0x77777700;
WriteGraphicsObject(pMTF);
//--- Das Feld 'End Resource Group':
WriteFieldIntroducer(16,EndResGrpMagic,0,0);
WriteFieldId(2);
if( pMET->GetError() )
bStatus=sal_False;
}
void METWriter::WriteDocument(const GDIMetaFile * pMTF)
{
if( bStatus==sal_False )
return;
//--- Das Feld 'Begin Document':
WriteFieldIntroducer(0,BegDocumnMagic,0,0);
WriteFieldId(1);
*pMET << (sal_uInt8)0x00 << (sal_uInt8)0x00;
*pMET << (sal_uInt8)0x05 << (sal_uInt8)0x18 << (sal_uInt8)0x03 << (sal_uInt8)0x0c << (sal_uInt8)0x00;
*pMET << (sal_uInt8)0x06 << (sal_uInt8)0x01 << (sal_uInt8)0x03 << (sal_uInt8)0xd4 << (sal_uInt8)0x03 << (sal_uInt8)0x52;
*pMET << (sal_uInt8)0x03 << (sal_uInt8)0x65 << (sal_uInt8)0x00;
UpdateFieldSize();
//--- Der Inhalt:
WriteResourceGroup(pMTF);
//--- Das Feld 'End Document':
WriteFieldIntroducer(16,EndDocumnMagic,0,0);
WriteFieldId(1);
if( pMET->GetError() )
bStatus=sal_False;
}
sal_Bool METWriter::WriteMET( const GDIMetaFile& rMTF, SvStream& rTargetStream, FilterConfigItem* pFilterConfigItem )
{
if ( pFilterConfigItem )
{
xStatusIndicator = pFilterConfigItem->GetStatusIndicator();
if ( xStatusIndicator.is() )
{
rtl::OUString aMsg;
xStatusIndicator->start( aMsg, 100 );
}
}
METChrSet* pCS;
METGDIStackMember* pGS;
bStatus=sal_True;
nLastPercent=0;
pMET=&rTargetStream;
pMET->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
aPictureRect = Rectangle( Point(), rMTF.GetPrefSize() );
aTargetMapMode = aPictureMapMode = rMTF.GetPrefMapMode();
aGDILineColor=Color( COL_BLACK );
aGDIFillColor=Color( COL_WHITE );
eGDIRasterOp=ROP_OVERPAINT;
aGDIFont=Font();
aGDIMapMode=MapMode();
aGDIClipRect=Rectangle();
pGDIStack=NULL;
aMETColor=Color(COL_BLACK);
aMETBackgroundColor=Color(COL_WHITE);
eMETMix=ROP_OVERPAINT;
nMETStrokeLineWidth=1;
aMETChrCellSize=Size(0,0);
nMETChrAngle=0;
nMETChrSet=0x00;
pChrSetList=NULL;
nNextChrSetId=1;
nNumberOfActions=0;
nNumberOfBitmaps=0;
nWrittenActions=0;
nWrittenBitmaps=0;
nActBitmapPercent=0;
CountActionsAndBitmaps(&rMTF);
WriteDocument(&rMTF);
while( pChrSetList )
{
pCS=pChrSetList;
pChrSetList=pCS->pSucc;
delete pCS;
}
while( pGDIStack )
{
pGS=pGDIStack;
pGDIStack=pGS->pSucc;
delete pGS;
}
if ( xStatusIndicator.is() )
xStatusIndicator->end();
return bStatus;
}
//================== GraphicExport - die exportierte Funktion ================
extern "C" sal_Bool __LOADONCALLAPI GraphicExport( SvStream & rStream, Graphic & rGraphic, FilterConfigItem* pFilterConfigItem, sal_Bool )
{
METWriter aMETWriter;
// #119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
GDIMetaFile aMetafile(rGraphic.GetGDIMetaFile());
if(usesClipActions(aMetafile))
{
// #121267# It is necessary to prepare the metafile since the export does *not* support
// clip regions. This tooling method clips the geometry content of the metafile internally
// against it's own clip regions, so that the export is safe to ignore clip regions
clipMetafileContentAgainstOwnRegions(aMetafile);
}
// #119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
return aMETWriter.WriteMET( aMetafile, rStream, pFilterConfigItem );
}