/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * 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 <basegfx/polygon/b2dpolygontools.hxx> #include <basegfx/polygon/b2dpolypolygoncutter.hxx> #include <emfreader.hxx> #include <sal/log.hxx> #include <osl/diagnose.h> #include <vcl/dibtools.hxx> #include <o3tl/safeint.hxx> #include <o3tl/sprintf.hxx> #include <tools/stream.hxx> #include <memory> #include <comphelper/configuration.hxx> #include <vcl/graph.hxx> #include <vcl/pdfread.hxx> #include <rtl/bootstrap.hxx>
constchar *
record_type_name(sal_uInt32 nRecType)
{ #ifndef SAL_LOG_INFO
(void) nRecType; return""; #else switch( nRecType )
{ case EMR_HEADER: return"HEADER"; case EMR_POLYBEZIER: return"POLYBEZIER"; case EMR_POLYGON: return"POLYGON"; case EMR_POLYLINE: return"POLYLINE"; case EMR_POLYBEZIERTO: return"POLYBEZIERTO"; case EMR_POLYLINETO: return"POLYLINETO"; case EMR_POLYPOLYLINE: return"POLYPOLYLINE"; case EMR_POLYPOLYGON: return"POLYPOLYGON"; case EMR_SETWINDOWEXTEX: return"SETWINDOWEXTEX"; case EMR_SETWINDOWORGEX: return"SETWINDOWORGEX"; case EMR_SETVIEWPORTEXTEX: return"SETVIEWPORTEXTEX"; case EMR_SETVIEWPORTORGEX: return"SETVIEWPORTORGEX"; case EMR_SETBRUSHORGEX: return"SETBRUSHORGEX"; case EMR_EOF: return"EOF"; case EMR_SETPIXELV: return"SETPIXELV"; case EMR_SETMAPPERFLAGS: return"SETMAPPERFLAGS"; case EMR_SETMAPMODE: return"SETMAPMODE"; case EMR_SETBKMODE: return"SETBKMODE"; case EMR_SETPOLYFILLMODE: return"SETPOLYFILLMODE"; case EMR_SETROP2: return"SETROP2"; case EMR_SETSTRETCHBLTMODE: return"SETSTRETCHBLTMODE"; case EMR_SETTEXTALIGN: return"SETTEXTALIGN"; case EMR_SETCOLORADJUSTMENT: return"SETCOLORADJUSTMENT"; case EMR_SETTEXTCOLOR: return"SETTEXTCOLOR"; case EMR_SETBKCOLOR: return"SETBKCOLOR"; case EMR_OFFSETCLIPRGN: return"OFFSETCLIPRGN"; case EMR_MOVETOEX: return"MOVETOEX"; case EMR_SETMETARGN: return"SETMETARGN"; case EMR_EXCLUDECLIPRECT: return"EXCLUDECLIPRECT"; case EMR_INTERSECTCLIPRECT: return"INTERSECTCLIPRECT"; case EMR_SCALEVIEWPORTEXTEX: return"SCALEVIEWPORTEXTEX"; case EMR_SCALEWINDOWEXTEX: return"SCALEWINDOWEXTEX"; case EMR_SAVEDC: return"SAVEDC"; case EMR_RESTOREDC: return"RESTOREDC"; case EMR_SETWORLDTRANSFORM: return"SETWORLDTRANSFORM"; case EMR_MODIFYWORLDTRANSFORM: return"MODIFYWORLDTRANSFORM"; case EMR_SELECTOBJECT: return"SELECTOBJECT"; case EMR_CREATEPEN: return"CREATEPEN"; case EMR_CREATEBRUSHINDIRECT: return"CREATEBRUSHINDIRECT"; case EMR_DELETEOBJECT: return"DELETEOBJECT"; case EMR_ANGLEARC: return"ANGLEARC"; case EMR_ELLIPSE: return"ELLIPSE"; case EMR_RECTANGLE: return"RECTANGLE"; case EMR_ROUNDRECT: return"ROUNDRECT"; case EMR_ARC: return"ARC"; case EMR_CHORD: return"CHORD"; case EMR_PIE: return"PIE"; case EMR_SELECTPALETTE: return"SELECTPALETTE"; case EMR_CREATEPALETTE: return"CREATEPALETTE"; case EMR_SETPALETTEENTRIES: return"SETPALETTEENTRIES"; case EMR_RESIZEPALETTE: return"RESIZEPALETTE"; case EMR_REALIZEPALETTE: return"REALIZEPALETTE"; case EMR_EXTFLOODFILL: return"EXTFLOODFILL"; case EMR_LINETO: return"LINETO"; case EMR_ARCTO: return"ARCTO"; case EMR_POLYDRAW: return"POLYDRAW"; case EMR_SETARCDIRECTION: return"SETARCDIRECTION"; case EMR_SETMITERLIMIT: return"SETMITERLIMIT"; case EMR_BEGINPATH: return"BEGINPATH"; case EMR_ENDPATH: return"ENDPATH"; case EMR_CLOSEFIGURE: return"CLOSEFIGURE"; case EMR_FILLPATH: return"FILLPATH"; case EMR_STROKEANDFILLPATH: return"STROKEANDFILLPATH"; case EMR_STROKEPATH: return"STROKEPATH"; case EMR_FLATTENPATH: return"FLATTENPATH"; case EMR_WIDENPATH: return"WIDENPATH"; case EMR_SELECTCLIPPATH: return"SELECTCLIPPATH"; case EMR_ABORTPATH: return"ABORTPATH"; case EMR_COMMENT: return"COMMENT"; case EMR_FILLRGN: return"FILLRGN"; case EMR_FRAMERGN: return"FRAMERGN"; case EMR_INVERTRGN: return"INVERTRGN"; case EMR_PAINTRGN: return"PAINTRGN"; case EMR_EXTSELECTCLIPRGN: return"EXTSELECTCLIPRGN"; case EMR_BITBLT: return"BITBLT"; case EMR_STRETCHBLT: return"STRETCHBLT"; case EMR_MASKBLT: return"MASKBLT"; case EMR_PLGBLT: return"PLGBLT"; case EMR_SETDIBITSTODEVICE: return"SETDIBITSTODEVICE"; case EMR_STRETCHDIBITS: return"STRETCHDIBITS"; case EMR_EXTCREATEFONTINDIRECTW: return"EXTCREATEFONTINDIRECTW"; case EMR_EXTTEXTOUTA: return"EXTTEXTOUTA"; case EMR_EXTTEXTOUTW: return"EXTTEXTOUTW"; case EMR_POLYBEZIER16: return"POLYBEZIER16"; case EMR_POLYGON16: return"POLYGON16"; case EMR_POLYLINE16: return"POLYLINE16"; case EMR_POLYBEZIERTO16: return"POLYBEZIERTO16"; case EMR_POLYLINETO16: return"POLYLINETO16"; case EMR_POLYPOLYLINE16: return"POLYPOLYLINE16"; case EMR_POLYPOLYGON16: return"POLYPOLYGON16"; case EMR_POLYDRAW16: return"POLYDRAW16"; case EMR_CREATEMONOBRUSH: return"CREATEMONOBRUSH"; case EMR_CREATEDIBPATTERNBRUSHPT: return"CREATEDIBPATTERNBRUSHPT"; case EMR_EXTCREATEPEN: return"EXTCREATEPEN"; case EMR_POLYTEXTOUTA: return"POLYTEXTOUTA"; case EMR_POLYTEXTOUTW: return"POLYTEXTOUTW"; case EMR_SETICMMODE: return"SETICMMODE"; case EMR_CREATECOLORSPACE: return"CREATECOLORSPACE"; case EMR_SETCOLORSPACE: return"SETCOLORSPACE"; case EMR_DELETECOLORSPACE: return"DELETECOLORSPACE"; case EMR_GLSRECORD: return"GLSRECORD"; case EMR_GLSBOUNDEDRECORD: return"GLSBOUNDEDRECORD"; case EMR_PIXELFORMAT: return"PIXELFORMAT"; case EMR_DRAWESCAPE: return"DRAWESCAPE"; case EMR_EXTESCAPE: return"EXTESCAPE"; case EMR_STARTDOC: return"STARTDOC"; case EMR_SMALLTEXTOUT: return"SMALLTEXTOUT"; case EMR_FORCEUFIMAPPING: return"FORCEUFIMAPPING"; case EMR_NAMEDESCAPE: return"NAMEDESCAPE"; case EMR_COLORCORRECTPALETTE: return"COLORCORRECTPALETTE"; case EMR_SETICMPROFILEA: return"SETICMPROFILEA"; case EMR_SETICMPROFILEW: return"SETICMPROFILEW"; case EMR_ALPHABLEND: return"ALPHABLEND"; case EMR_ALPHADIBBLEND: return"ALPHADIBBLEND"; case EMR_TRANSPARENTBLT: return"TRANSPARENTBLT"; case EMR_TRANSPARENTDIB: return"TRANSPARENTDIB"; case EMR_GRADIENTFILL: return"GRADIENTFILL"; case EMR_SETLINKEDUFIS: return"SETLINKEDUFIS"; case EMR_SETTEXTJUSTIFICATION: return"SETTEXTJUSTIFICATION"; default: // Yes, return a pointer to a static buffer. This is a very // local debugging output function, so no big deal. staticchar buffer[11];
o3tl::sprintf(buffer, "0x%08" SAL_PRIxUINT32, nRecType); return buffer;
} #endif
}
sal_Int32 nLeft, nTop, nRight, nBottom; //bounds of the region
rStream.ReadInt32(nLeft);
rStream.ReadInt32(nTop);
rStream.ReadInt32(nRight);
rStream.ReadInt32(nBottom);
// aGraphic will be the only output of the EMF parser, so its size hint can be the same as // ours.
aGraphic.getVectorGraphicData()->setSizeHint(maSizeHint);
SAL_INFO("emfio", "\t\tEMF+ record type: 0x" << std::hex << type << std::dec);
// Get Device Context // TODO We should use EmfPlusRecordType::GetDC instead if( type == 0x4004 )
{
bHaveDC = true;
SAL_INFO("emfio", "\t\tEMF+ lock DC (device context)");
}
// look for the "dual mode" in header // it indicates that either EMF or EMF+ records should be processed // 0x4001 = EMF+ header // flags & 1 = dual mode active if ( type == 0x4001 && flags & 1 )
{
mbEMFPlusDualMode = true;
SAL_INFO ("emfio", "\t\tEMF+ dual mode detected");
}
// Get the length of the remaining data of this record based // on the alleged size
sal_uInt32 nRemainingRecordData = size >= nRequiredHeaderSize ?
size-nRequiredHeaderSize : 0; // clip to available size
nRemainingRecordData = std::min(nRemainingRecordData, nRemainder);
mpInputStream->SeekRel(nRemainingRecordData);
nRemainder -= nRemainingRecordData;
}
mpInputStream->SeekRel(nRemainder);
}
// these are referenced from inside the templates static SvStream& operator >> (SvStream& rStream, sal_Int16 &n)
{ return rStream.ReadInt16(n);
}
/** * Reads polygons from the stream. * The \<class T> parameter is for the type of the points (sal_uInt32 or sal_uInt16). * skipFirst: if the first point read is the 0th point or the 1st point in the array.
* */ template <class T>
tools::Polygon EmfReader::ReadPolygonWithSkip(constbool skipFirst, sal_uInt32 nNextPos)
{
sal_uInt32 nPoints(0), nStartIndex(0);
mpInputStream->SeekRel( 16 );
mpInputStream->ReadUInt32( nPoints ); if (skipFirst)
{
nPoints ++;
nStartIndex ++;
}
/** * Reads polygons from the stream. * The \<class T> parameter is for the type of the points * nStartIndex: which is the starting index in the polygon of the first point read * nPoints: number of points * mpInputStream: the stream containing the polygons
* */ template <class T>
tools::Polygon EmfReader::ReadPolygon(sal_uInt32 nStartIndex, sal_uInt32 nPoints, sal_uInt32 nNextPos)
{
SAL_INFO ("emfio", "\t\tPolygon:");
bool bRecordOk = nPoints <= SAL_MAX_UINT16;
SAL_WARN_IF(!bRecordOk, "emfio", "polygon record has more polygons than we can handle"); if (!bRecordOk || !nPoints) return tools::Polygon();
auto nRemainingSize = std::min(nNextPos - mpInputStream->Tell(), mpInputStream->remainingSize()); auto nMaxPossiblePoints = nRemainingSize / (sizeof(T) * 2); auto nPointCount = nPoints - nStartIndex; if (nPointCount > nMaxPossiblePoints)
{
SAL_WARN("emfio", "polygon claims more points than record can provide, truncating");
nPoints = nMaxPossiblePoints + nStartIndex;
}
tools::Polygon aPolygon(nPoints); for (sal_uInt32 i = nStartIndex ; i < nPoints && mpInputStream->good(); i++ )
{
T nX, nY;
*mpInputStream >> nX >> nY;
if (!mpInputStream->good())
{
SAL_WARN("emfio", "short read on polygon, truncating");
aPolygon.SetSize(i); break;
}
aPolygon[ i ] = Point( nX, nY );
}
return aPolygon;
}
/** * Reads a polyline from the WMF file and draws it * The \<class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32)
* */ template <class T> void EmfReader::ReadAndDrawPolyLine(sal_uInt32 nNextPos)
{
SAL_INFO("emfio", "\t\tPolyline: ");
mpInputStream->SeekRel( 0x10 ); // TODO Skipping Bounds. A 128-bit WMF RectL object (specifies the bounding rectangle in device units.)
sal_uInt32 nCount = 0;
mpInputStream->ReadUInt32( nCount ); // total number of points in all polylines
SAL_INFO("emfio", "\t\t\tPoints: " << nCount);
constauto nEndPos = std::min(nNextPos, mnEndPos); if (mpInputStream->Tell() >= nEndPos) return;
// taking the amount of points of each polygon, retrieving the total number of points if ( !(mpInputStream->good() &&
( nNumberOfPolylines < SAL_MAX_UINT32 / sizeof( sal_uInt16 ) ) &&
( nNumberOfPolylines * sizeof( sal_uInt16 ) ) <= ( nEndPos - mpInputStream->Tell() ))
) return;
std::unique_ptr< sal_uInt32[] > pnPolylinePointCount( new sal_uInt32[ nNumberOfPolylines ] ); for ( sal_uInt32 i = 0; i < nNumberOfPolylines && mpInputStream->good(); i++ )
{
sal_uInt32 nPoints;
mpInputStream->ReadUInt32( nPoints );
SAL_INFO("emfio", "\t\t\tPoint " << i << " of " << nNumberOfPolylines << ": " << nPoints);
pnPolylinePointCount[ i ] = nPoints;
}
// Get polyline points: for ( sal_uInt32 i = 0; ( i < nNumberOfPolylines ) && mpInputStream->good(); i++ )
{
tools::Polygon aPolygon = ReadPolygon<T>(0, pnPolylinePointCount[i], nNextPos);
DrawPolyLine(std::move(aPolygon), false, mbRecordPath);
}
}
/** * Reads a poly polygon from the WMF file and draws it. * The \<class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32)
* */ template <class T> void EmfReader::ReadAndDrawPolyPolygon(sal_uInt32 nNextPos)
{
SAL_INFO("emfio", "\t\tPolygon: ");
mpInputStream->SeekRel( 0x10 ); // RectL bounds
constauto nEndPos = std::min(nNextPos, mnEndPos); if (mpInputStream->Tell() >= nEndPos) return; if (!mpInputStream->good()) return; //check against numeric overflowing if (nGesPoints >= SAL_MAX_UINT32 / sizeof(Point)) return; if (nPoly >= SAL_MAX_UINT32 / sizeof(sal_uInt16)) return; if (nPoly * sizeof(sal_uInt16) > nEndPos - mpInputStream->Tell()) return;
// Get number of points in each polygon
std::vector<sal_uInt16> aPoints(nPoly); for (sal_uInt32 i = 0; i < nPoly && mpInputStream->good(); ++i)
{
sal_uInt32 nPoints(0);
mpInputStream->ReadUInt32( nPoints );
OUString aEMFPlusDisable;
rtl::Bootstrap::get(u"EMF_PLUS_DISABLE"_ustr, aEMFPlusDisable); bool bEnableEMFPlus = aEMFPlusDisable.isEmpty(); if (!mbEnableEMFPlus)
{ // EMF+ is enabled if neither the bootstrap variable, not the member variable disables // it.
bEnableEMFPlus = mbEnableEMFPlus;
}
case EMR_CREATEPEN:
{
mpInputStream->ReadUInt32(nIndex); if ((nIndex & ENHMETA_STOCK_OBJECT) == 0)
{
sal_uInt32 nPenStyle(0);
sal_Int32 nPenWidth(0), nIgnored;
mpInputStream->ReadUInt32(nPenStyle).ReadInt32(nPenWidth).ReadInt32(nIgnored);
SAL_INFO("emfio", "\t\tIndex: " << nIndex << " Style: 0x" << std::hex
<< nPenStyle << std::dec
<< " PenWidth: " << nPenWidth); // PS_COSMETIC width is always fixed at one logical unit // and is not affected by any geometric transformations like scaling if (nPenStyle == PS_COSMETIC)
nPenWidth = 1;
CreateObjectIndexed(nIndex, std::make_unique<WinMtfLineStyle>(ReadColor(), nPenStyle, nPenWidth));
}
} break;
case EMR_EXTCREATEPEN:
{
mpInputStream->ReadUInt32(nIndex); if ((nIndex & ENHMETA_STOCK_OBJECT) == 0)
{
sal_uInt32 offBmi, cbBmi, offBits, cbBits, nPenStyle, nWidth, nBrushStyle, elpNumEntries;
sal_Int32 elpHatch;
mpInputStream->ReadUInt32(offBmi).ReadUInt32(cbBmi).ReadUInt32(offBits).ReadUInt32(cbBits);
mpInputStream->ReadUInt32(nPenStyle).ReadUInt32(nWidth).ReadUInt32(nBrushStyle);
Color aColorRef = ReadColor();
mpInputStream->ReadInt32(elpHatch).ReadUInt32(elpNumEntries);
if (!mpInputStream->good())
bStatus = false; else
{
SAL_INFO("emfio", "\t\tStyle: 0x" << std::hex << nPenStyle << std::dec); // PS_COSMETIC width is always fixed at one logical unit // and is not affected by any geometric transformations like scaling if (nPenStyle == PS_COSMETIC)
nWidth = 1;
SAL_INFO("emfio", "\t\tWidth: " << nWidth);
CreateObjectIndexed(nIndex, std::make_unique<WinMtfLineStyle>(aColorRef, nPenStyle, nWidth));
}
}
} break;
if (!mpInputStream->good())
bStatus = false; else
{ // Convert from degrees to radians and start angle to draw from x-axis
fStartAngle = basegfx::deg2rad(fStartAngle);
fSweepAngle = basegfx::deg2rad(fSweepAngle);
if (!aPoly.GetSize())
{
SAL_WARN("emfio", "EMF file error: 0 points");
} else
{ // Before drawing the arc, AngleArc draws the line segment from the current position to the beginning of the arc
LineTo(aPoly[0], mbRecordPath);
DrawPolyLine(std::move(aPoly), true, mbRecordPath);
}
}
} break;
// This record's region data should be ignored if mode // is RGN_COPY - see EMF spec section 2.3.2.2 if (static_cast<RegionMode>(nClippingMode) == RegionMode::RGN_COPY)
{
SetDefaultClipPath();
} else
{
basegfx::B2DPolyPolygon aPolyPoly; if (cbRgnData)
ImplReadRegion(aPolyPoly, *mpInputStream, nRemainingRecSize, GetWinOrg()); const tools::PolyPolygon aPolyPolygon(aPolyPoly);
SetClipPath(aPolyPolygon, static_cast<RegionMode>(nClippingMode), false);
}
}
} break;
case EMR_ALPHABLEND:
{
sal_Int32 xDest(0), yDest(0), cxDest(0), cyDest(0);
// copy DIBInfoHeader from source (cbBmiSrc bytes)
mpInputStream->Seek( nStart + offBmiSrc ); char* pWritePos = pBuf + 14; auto nRead = mpInputStream->ReadBytes(pWritePos, cbBmiSrc); if (nRead != cbBmiSrc)
{ // zero remainder if short read
memset(pWritePos + nRead, 0, cbBmiSrc - nRead);
}
if (bReadAlpha)
{ // need to add values for all stuff that DIBV5Header is bigger // than DIBInfoHeader, all values are correctly initialized to zero, // so we can use memset here
memset(pBuf + cbBmiSrc + 14, 0, nDeltaToDIB5HeaderSize);
}
// copy bitmap data from source (offBitsSrc bytes)
mpInputStream->Seek( nStart + offBitsSrc );
pWritePos = pBuf + 14 + nDeltaToDIB5HeaderSize + cbBmiSrc;
nRead = mpInputStream->ReadBytes(pWritePos, cbBitsSrc); if (nRead != cbBitsSrc)
{ // zero remainder if short read
memset(pWritePos + nRead, 0, cbBitsSrc - nRead);
}
aTmp.Seek( 0 );
// prepare to read and fill BitmapEx
BitmapEx aBitmapEx;
sal_Unicode lfFaceName[LF_FACESIZE+1];
lfFaceName[LF_FACESIZE] = 0; for (int i = 0; i < LF_FACESIZE; ++i)
{
sal_uInt16 nChar(0);
mpInputStream->ReadUInt16(nChar);
lfFaceName[i] = nChar;
}
aLogFont.alfFaceName = OUString( lfFaceName );
// #i123216# Not used in the test case of #121382# (always identity in XForm), also // no hints in ms docu if FontSize should be scaled with WT. Using with the example // from #i123216# creates errors, so removing.
// // #i121382# Need to apply WorldTransform to FontHeight/Width; this should be completely // // changed to basegfx::B2DHomMatrix instead of 'struct XForm', but not now due to time // // constraints and dangers // const XForm& rXF = GetWorldTransform(); // const basegfx::B2DHomMatrix aWT(rXF.eM11, rXF.eM21, rXF.eDx, rXF.eM12, rXF.eM22, rXF.eDy); // const basegfx::B2DVector aTransVec(aWT * basegfx::B2DVector(aLogFont.lfWidth, aLogFont.lfHeight)); // aLogFont.lfWidth = aTransVec.getX(); // aLogFont.lfHeight = aTransVec.getY(); if (mpInputStream->good() && aLogFont.lfHeight != SAL_MIN_INT32 && aLogFont.lfWidth != SAL_MIN_INT32)
{
CreateObjectIndexed(nIndex, std::make_unique<WinMtfFontStyle>( aLogFont ));
}
}
} break;
if (!mpInputStream->good())
bStatus = false; else
{ const tools::Rectangle aRect( nLeftRect, nTopRect, nRightRect, nBottomRect ); const BackgroundMode mnBkModeBackup = mnBkMode; if ( nOptions & ETO_NO_RECT ) // Don't draw the background rectangle and text background
mnBkMode = BackgroundMode::Transparent; elseif ( nOptions & ETO_OPAQUE )
DrawRectWithBGColor( aRect );
// ETO_RTLREADING indicates that the characters are laid from right to left
vcl::text::ComplexTextLayoutFlags nTextLayoutMode = vcl::text::ComplexTextLayoutFlags::Default; if ( nOptions & ETO_RTLREADING )
nTextLayoutMode = vcl::text::ComplexTextLayoutFlags::BiDiRtl | vcl::text::ComplexTextLayoutFlags::TextOriginLeft;
SetTextLayoutMode( nTextLayoutMode );
SAL_WARN_IF( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) != 0, "emfio", "SJ: ETO_PDY || ETO_GLYPH_INDEX in EMF" );
// Reading OutputDx // ETO_PDY flag indicates that we should read twice values // compared to the number of characters in the output string. // Values are stored in an array of 32-bit unsigned integers // named OutputDx, so there will be either 8 bytes or 4 bytes // each depending on ETO_PDY is set or not. if (nOptions & ETO_PDY)
nBytesEach = 8; else
nBytesEach = 4;
case EMR_CREATECOLORSPACE :
{
sal_uInt32 nRemainingRecSize = nRecSize - 8; if (nRemainingRecSize < 5)
bStatus = false; else
{ // index of the logical color space object in the EMF object table
sal_Int32 ihCS(0);
mpInputStream->ReadInt32(ihCS);
sal_Int32 nDescChars = nRemainingRecSize - 4;
OUString aDesc; for (sal_Int32 i=0; i < nDescChars; i++)
{ unsignedchar cChar(0);
mpInputStream->ReadUChar(cChar); if (cChar == 0) break;
aDesc = aDesc + OUStringChar(static_cast<sal_Unicode>(cChar));
} // if it's the standard color space name, no need to do anything if (aDesc != "COSP")
SAL_WARN("emfio", "TODO: color space change for EMR_CREATECOLORSPACE not implemented: '" << aDesc << "' " << nDescChars);
}
} break;
case EMR_MASKBLT : case EMR_PLGBLT : case EMR_SETDIBITSTODEVICE : case EMR_FRAMERGN : case EMR_INVERTRGN : case EMR_FLATTENPATH : case EMR_WIDENPATH : case EMR_SETPALETTEENTRIES : case EMR_RESIZEPALETTE : case EMR_EXTFLOODFILL : case EMR_SETCOLORADJUSTMENT : case EMR_POLYDRAW16 : case EMR_SETCOLORSPACE : case EMR_DELETECOLORSPACE : case EMR_GLSRECORD : case EMR_GLSBOUNDEDRECORD : case EMR_PIXELFORMAT : case EMR_DRAWESCAPE : case EMR_EXTESCAPE : case EMR_STARTDOC : case EMR_SMALLTEXTOUT : case EMR_FORCEUFIMAPPING : case EMR_NAMEDESCAPE : case EMR_COLORCORRECTPALETTE : case EMR_SETICMPROFILEA : case EMR_SETICMPROFILEW : case EMR_TRANSPARENTBLT : case EMR_TRANSPARENTDIB : case EMR_GRADIENTFILL : case EMR_SETLINKEDUFIS : case EMR_SETMAPPERFLAGS : case EMR_SETICMMODE : case EMR_CREATEMONOBRUSH : case EMR_SETBRUSHORGEX : case EMR_SETMETARGN : case EMR_SETMITERLIMIT : case EMR_EXCLUDECLIPRECT : case EMR_REALIZEPALETTE : case EMR_SELECTPALETTE : case EMR_CREATEPALETTE : case EMR_ALPHADIBBLEND : case EMR_SETTEXTJUSTIFICATION :
{
SAL_WARN("emfio", "TODO: EMF record not implemented: " << record_type_name(nRecType));
} break;
case EMR_COMMENT : case EMR_HEADER : // has already been read at ReadHeader() break;
bool EmfReader::ReadHeader()
{ // Spare me the METAFILEHEADER here // Reading the METAHEADER - EMR_HEADER ([MS-EMF] section 2.3.4.2 EMR_HEADER Record Types)
sal_uInt32 nType(0), nHeaderSize(0);
mpInputStream->ReadUInt32(nType).ReadUInt32(nHeaderSize);
SAL_INFO ("emfio", "0x0-0x" << std::hex << nHeaderSize << " " << record_type_name(nType) << " size: " << std::dec << nHeaderSize); if (nType != 0x00000001)
{ // per [MS-EMF] 2.3.4.2 EMF Header Record Types, type MUST be 0x00000001
SAL_WARN("emfio", "EMF header type is not set to 0x00000001 - possibly corrupted file?"); returnfalse;
}
// Start reading the EMR_HEADER Header object
// bound size (RectL object, see [MS-WMF] section 2.2.2.19)
SAL_INFO("emfio", "\tBounding rectangle");
tools::Rectangle rclBounds = ReadRectangle(); // rectangle in logical units
// picture frame size (RectL object)
SAL_INFO("emfio", "\tPicture frame");
tools::Rectangle rclFrame = ReadRectangle(); // rectangle in device units 1/100th mm
// nSignature MUST be the ASCII characters "FME", see [WS-EMF] 2.2.9 Header Object // and 2.1.14 FormatSignature Enumeration if (nSignature != 0x464d4520)
{
SAL_WARN("emfio", "EMF\t\tSignature is not 0x464d4520 (\"FME\") - possibly corrupted file?"); returnfalse;
}
sal_uInt32 nVersion(0);
mpInputStream->ReadUInt32(nVersion); // according to [WS-EMF] 2.2.9, this SHOULD be 0x0001000, however // Microsoft note that not even Windows checks this...
SAL_INFO("emfio", "\tVersion: 0x" << std::hex << nVersion << std::dec); if (nVersion != 0x00010000)
{
SAL_WARN("emfio", "EMF\t\tThis really should be 0x00010000, though not absolutely essential...");
}
sal_uInt64 nStrmPos = mpInputStream->Tell(); // checking if mnEndPos is valid
sal_uInt64 nActualFileSize = nStrmPos + mpInputStream->remainingSize();
if ( nActualFileSize < mnEndPos )
{
SAL_WARN("emfio", "EMF\t\tEMF Header object records number of bytes as " << mnEndPos
<< ", however the file size is actually " << nActualFileSize
<< " bytes. Possible file corruption?");
mnEndPos = nActualFileSize;
}
// the next 2 bytes are reserved, but according to [MS-EMF] section 2.2.9 // it MUST be 0x000 and MUST be ignored... the thing is, having such a specific // value is actually pretty useful in checking if there is possible corruption
if ( nReserved != 0x0000 )
{
SAL_WARN("emfio", "EMF\t\tEMF Header object's reserved field is NOT 0x0000... possible " "corruption?");
}
// The next 4 bytes specifies the number of characters in the metafile description. // The 4 bytes after that specific the offset from this record that contains the // metafile description... zero means no description string. // For now, we ignore it.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.