/* -*- 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 #include #include #include #include #include #include #include #include "ipict.hxx" #include "shape.hxx" #include #include // complete FilterConfigItem for GraphicImport under -fsanitize=function namespace PictReaderInternal { //! utilitary class to store a pattern, ... class Pattern { public: //! constructor Pattern() : penStyle(PEN_SOLID), brushStyle(BRUSH_SOLID), nBitCount(64), isColor(false), isRead(false) {} //! reads black/white pattern from SvStream sal_uLong read(SvStream &stream); //! sets the color void setColor(Color col) { isColor = true; color = col; } /** returns a color which can be "used" to replace the pattern, * created from ForeColor and BackColor, ... * * note: maybe, we must also use some mode PatCopy, ... to define the color */ Color getColor(Color bkColor, Color fgColor) const { if (isColor) return color; // we create a gray pattern from nBitCount double alpha = nBitCount / 64.0; return Color(sal_uInt8(alpha*fgColor.GetRed()+(1.0-alpha)*bkColor.GetRed()), sal_uInt8(alpha*fgColor.GetGreen()+(1.0-alpha)*bkColor.GetGreen()), sal_uInt8(alpha*fgColor.GetBlue()+(1.0-alpha)*bkColor.GetBlue())); } //! returns true if this is the default pattern bool isDefault() const { return !isRead; } enum PenStyle { PEN_NULL, PEN_SOLID, PEN_DOT, PEN_DASH, PEN_DASHDOT }; enum BrushStyle { BRUSH_NULL, BRUSH_SOLID, BRUSH_HORZ, BRUSH_VERT, BRUSH_CROSS, BRUSH_DIAGCROSS, BRUSH_UPDIAG, BRUSH_DOWNDIAG, BRUSH_25, BRUSH_50, BRUSH_75 }; // Data enum PenStyle penStyle; enum BrushStyle brushStyle; short nBitCount; bool isColor; // true if it is a color pattern Color color; protected: // flag to know if the pattern came from reading the picture, or if it is the default pattern bool isRead; }; sal_uLong Pattern::read(SvStream &stream) { unsigned char nbyte[8]; sal_uLong nHiBytes, nLoBytes; isColor = false; // count the no of bits in pattern which are set to 1: nBitCount=0; for (unsigned char & ny : nbyte) { stream.ReadChar( reinterpret_cast(ny) ); for (short nx=0; nx<8; nx++) { if ( (ny & (1<(nbyte[0])<<8)| static_cast(nbyte[1]))<<8)| static_cast(nbyte[2]))<<8)| static_cast(nbyte[3]); nLoBytes=(((((static_cast(nbyte[4])<<8)| static_cast(nbyte[5]))<<8)| static_cast(nbyte[6]))<<8)| static_cast(nbyte[7]); // create a PenStyle: if (nBitCount<=0) penStyle=PEN_NULL; else if (nBitCount<=16) penStyle=PEN_DOT; else if (nBitCount<=32) penStyle=PEN_DASHDOT; else if (nBitCount<=48) penStyle=PEN_DASH; else penStyle=PEN_SOLID; // create a BrushStyle: if (nHiBytes==0xffffffff && nLoBytes==0xffffffff) brushStyle=BRUSH_SOLID; else if (nHiBytes==0xff000000 && nLoBytes==0x00000000) brushStyle=BRUSH_HORZ; else if (nHiBytes==0x80808080 && nLoBytes==0x80808080) brushStyle=BRUSH_VERT; else if (nHiBytes==0xff808080 && nLoBytes==0x80808080) brushStyle=BRUSH_CROSS; else if (nHiBytes==0x01824428 && nLoBytes==0x10284482) brushStyle=BRUSH_DIAGCROSS; else if (nHiBytes==0x80402010 && nLoBytes==0x08040201) brushStyle=BRUSH_UPDIAG; else if (nHiBytes==0x01020408 && nLoBytes==0x10204080) brushStyle=BRUSH_DOWNDIAG; else if (nBitCount<=24) brushStyle=BRUSH_25; else if (nBitCount<=40) brushStyle=BRUSH_50; else if (nBitCount<=56) brushStyle=BRUSH_75; else brushStyle=BRUSH_SOLID; isRead = true; return 8; } } //============================ PictReader ================================== enum class PictDrawingMethod { FRAME, PAINT, ERASE, INVERT, FILL, TEXT, UNDEFINED }; class PictReader { typedef class PictReaderInternal::Pattern Pattern; private: SvStream * pPict; // The Pict file to read. VclPtr pVirDev; // Here the drawing method will be called. // A recording into the GDIMetaFile will take place. sal_uLong nOrigPos; // Initial position in pPict. bool IsVersion2; // If it is a version 2 Pictfile. tools::Rectangle aBoundingRect; // Min/Max-Rectangle for the whole drawing. Point aPenPosition; Point aTextPosition; Color aActForeColor; Color aActBackColor; Pattern eActPenPattern; Pattern eActFillPattern; Pattern eActBackPattern; Size nActPenSize; // Note: Postscript mode is stored by setting eActRop to RasterOp::N1 RasterOp eActROP; PictDrawingMethod eActMethod; Size aActOvalSize; vcl::Font aActFont; Fraction aHRes; Fraction aVRes; Point ReadPoint(); Point ReadDeltaH(Point aBase); Point ReadDeltaV(Point aBase); Point ReadUnsignedDeltaH(Point aBase); Point ReadUnsignedDeltaV(Point aBase); Size ReadSize(); Color ReadColor(); Color ReadRGBColor(); void ReadRectangle(tools::Rectangle & rRect); sal_uLong ReadPolygon(tools::Polygon & rPoly); sal_uLong ReadPixPattern(Pattern &pattern); tools::Rectangle aLastRect; sal_uLong ReadAndDrawRect(PictDrawingMethod eMethod); sal_uLong ReadAndDrawSameRect(PictDrawingMethod eMethod); tools::Rectangle aLastRoundRect; sal_uLong ReadAndDrawRoundRect(PictDrawingMethod eMethod); sal_uLong ReadAndDrawSameRoundRect(PictDrawingMethod eMethod); tools::Rectangle aLastOval; sal_uLong ReadAndDrawOval(PictDrawingMethod eMethod); sal_uLong ReadAndDrawSameOval(PictDrawingMethod eMethod); tools::Polygon aLastPolygon; sal_uLong ReadAndDrawPolygon(PictDrawingMethod eMethod); sal_uLong ReadAndDrawSamePolygon(PictDrawingMethod eMethod); tools::Rectangle aLastArcRect; sal_uLong ReadAndDrawArc(PictDrawingMethod eMethod); sal_uLong ReadAndDrawSameArc(PictDrawingMethod eMethod); sal_uLong ReadAndDrawRgn(PictDrawingMethod eMethod); sal_uLong ReadAndDrawSameRgn(PictDrawingMethod eMethod); // returns true if there's no need to print the shape/text/frame bool IsInvisible( PictDrawingMethod eMethod ) const { if ( eActROP == RasterOp::N1 ) return true; if ( eMethod == PictDrawingMethod::FRAME && ( nActPenSize.Width() == 0 || nActPenSize.Height() == 0 ) ) return true; return false; } void DrawingMethod(PictDrawingMethod eMethod); sal_uLong ReadAndDrawText(); sal_uLong ReadPixMapEtc(BitmapEx & rBitmap, bool bBaseAddr, bool bColorTable, tools::Rectangle * pSrcRect, tools::Rectangle * pDestRect, bool bMode, bool bMaskRgn); void ReadHeader(); // Reads the header of the Pict file, set IsVersion and aBoundingRect sal_uLong ReadData(sal_uInt16 nOpcode); // Reads the date of anOopcode and executes the operation. // The number of data bytes belonging to the opcode will be returned // in any case. void SetLineColor( const Color& rColor ); void SetFillColor( const Color& rColor ); // OSNOLA: returns the text encoding which must be used for system id static rtl_TextEncoding GetTextEncoding (sal_uInt16 fId = 0xFFFF); public: PictReader() : pPict(nullptr) , pVirDev(nullptr) , nOrigPos(0) , IsVersion2(false) , eActROP(RasterOp::OverPaint) , eActMethod(PictDrawingMethod::UNDEFINED) { aActFont.SetCharSet(GetTextEncoding()); } void ReadPict( SvStream & rStreamPict, GDIMetaFile & rGDIMetaFile ); // reads a pict file from the stream and fills the GDIMetaFile }; static void SetByte(sal_uInt16& nx, sal_uInt16 ny, vcl::bitmap::RawBitmap& rBitmap, sal_uInt16 nPixelSize, sal_uInt8 nDat, sal_uInt16 nWidth, std::vector const & rvPalette) { switch (nPixelSize) { case 1: rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 7) & 1]); if ( nx == nWidth ) break; rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 6) & 1]); if ( nx == nWidth ) break; rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 5) & 1]); if ( nx == nWidth ) break; rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 4) & 1]); if ( nx == nWidth ) break; rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 3) & 1]); if ( nx == nWidth ) break; rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 2) & 1]); if ( nx == nWidth ) break; rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 1) & 1]); if ( nx == nWidth ) break; rBitmap.SetPixel(ny, nx++, rvPalette[nDat & 1]); break; case 2: rBitmap.SetPixel(ny, nx++, rvPalette[nDat >> 6]); if ( nx == nWidth ) break; rBitmap.SetPixel(ny, nx++, rvPalette[(nDat>>4)&3]); if ( nx == nWidth ) break; rBitmap.SetPixel(ny, nx++, rvPalette[(nDat>>2)&3]); if ( nx == nWidth ) break; rBitmap.SetPixel(ny, nx++, rvPalette[nDat & 3]); break; case 4: rBitmap.SetPixel(ny, nx++, rvPalette[nDat >> 4]); if ( nx == nWidth ) break; rBitmap.SetPixel(ny, nx++, rvPalette[nDat & 0x0f]); break; case 8: rBitmap.SetPixel(ny, nx++, rvPalette[nDat]); break; } } //=================== methods of PictReader ============================== rtl_TextEncoding PictReader::GetTextEncoding (sal_uInt16 fId) { static bool first = true; static rtl_TextEncoding enc = RTL_TEXTENCODING_APPLE_ROMAN; if (first) { rtl_TextEncoding def = osl_getThreadTextEncoding(); // we keep osl_getThreadTextEncoding only if it is a mac encoding switch(def) { case RTL_TEXTENCODING_APPLE_ROMAN: case RTL_TEXTENCODING_APPLE_ARABIC: case RTL_TEXTENCODING_APPLE_CENTEURO: case RTL_TEXTENCODING_APPLE_CROATIAN: case RTL_TEXTENCODING_APPLE_CYRILLIC: case RTL_TEXTENCODING_APPLE_DEVANAGARI: case RTL_TEXTENCODING_APPLE_FARSI: case RTL_TEXTENCODING_APPLE_GREEK: case RTL_TEXTENCODING_APPLE_GUJARATI: case RTL_TEXTENCODING_APPLE_GURMUKHI: case RTL_TEXTENCODING_APPLE_HEBREW: case RTL_TEXTENCODING_APPLE_ICELAND: case RTL_TEXTENCODING_APPLE_ROMANIAN: case RTL_TEXTENCODING_APPLE_THAI: case RTL_TEXTENCODING_APPLE_TURKISH: case RTL_TEXTENCODING_APPLE_UKRAINIAN: case RTL_TEXTENCODING_APPLE_CHINSIMP: case RTL_TEXTENCODING_APPLE_CHINTRAD: case RTL_TEXTENCODING_APPLE_JAPANESE: case RTL_TEXTENCODING_APPLE_KOREAN: enc = def; break; default: break; } first = false; } if (fId == 13) return RTL_TEXTENCODING_ADOBE_DINGBATS; // CHECKME if (fId == 23) return RTL_TEXTENCODING_ADOBE_SYMBOL; return enc; } void PictReader::SetLineColor( const Color& rColor ) { pVirDev->SetLineColor( rColor ); } void PictReader::SetFillColor( const Color& rColor ) { pVirDev->SetFillColor( rColor ); } Point PictReader::ReadPoint() { short nx,ny; pPict->ReadInt16( ny ).ReadInt16( nx ); Point aPoint( static_cast(nx) - aBoundingRect.Left(), static_cast(ny) - aBoundingRect.Top() ); SAL_INFO("filter.pict", "ReadPoint: " << aPoint); return aPoint; } Point PictReader::ReadDeltaH(Point aBase) { signed char ndh; pPict->ReadChar( reinterpret_cast(ndh) ); return Point( aBase.X() + static_cast(ndh), aBase.Y() ); } Point PictReader::ReadDeltaV(Point aBase) { signed char ndv; pPict->ReadChar( reinterpret_cast(ndv) ); return Point( aBase.X(), aBase.Y() + static_cast(ndv) ); } Point PictReader::ReadUnsignedDeltaH(Point aBase) { sal_uInt8 ndh; pPict->ReadUChar( ndh ); return Point( aBase.X() + static_cast(ndh), aBase.Y() ); } Point PictReader::ReadUnsignedDeltaV(Point aBase) { sal_uInt8 ndv; pPict->ReadUChar( ndv ); return Point( aBase.X(), aBase.Y() + static_cast(ndv) ); } Size PictReader::ReadSize() { short nx,ny; pPict->ReadInt16( ny ).ReadInt16( nx ); return Size( static_cast(nx), static_cast(ny) ); } Color PictReader::ReadColor() { sal_uInt32 nCol; Color aCol; pPict->ReadUInt32( nCol ); switch (nCol) { case 33: aCol=COL_BLACK; break; case 30: aCol=COL_WHITE; break; case 205: aCol=COL_LIGHTRED; break; case 341: aCol=COL_LIGHTGREEN; break; case 409: aCol=COL_LIGHTBLUE; break; case 273: aCol=COL_LIGHTCYAN; break; case 137: aCol=COL_LIGHTMAGENTA; break; case 69: aCol=COL_YELLOW; break; default: aCol=COL_LIGHTGRAY; } return aCol; } Color PictReader::ReadRGBColor() { sal_uInt16 nR, nG, nB; pPict->ReadUInt16( nR ).ReadUInt16( nG ).ReadUInt16( nB ); return Color( static_cast( nR >> 8 ), static_cast( nG >> 8 ), static_cast( nB >> 8 ) ); } void PictReader::ReadRectangle(tools::Rectangle & rRect) { Point aTopLeft, aBottomRight; aTopLeft=ReadPoint(); aBottomRight=ReadPoint(); rRect=tools::Rectangle(aTopLeft,aBottomRight); SAL_INFO("filter.pict", "ReadRectangle: " << rRect); } sal_uLong PictReader::ReadPolygon(tools::Polygon & rPoly) { sal_uInt16 nSize(0); pPict->ReadUInt16(nSize); pPict->SeekRel(8); sal_uLong nDataSize = static_cast(nSize); nSize=(nSize-10)/4; const size_t nMaxPossiblePoints = pPict->remainingSize() / 2 * sizeof(sal_uInt16); if (nSize > nMaxPossiblePoints) { SAL_WARN("filter.pict", "pict record claims to have: " << nSize << " points, but only " << nMaxPossiblePoints << " possible, clamping"); nSize = nMaxPossiblePoints; } rPoly.SetSize(nSize); for (sal_uInt16 i = 0; i < nSize; ++i) { rPoly.SetPoint(ReadPoint(), i); if (!pPict->good()) { rPoly.SetSize(i); break; } } return nDataSize; } sal_uLong PictReader::ReadPixPattern(PictReader::Pattern &pattern) { // Don't know if this is correct because no picture which contains PixPatterns found. // Here again the attempt to calculate the size of the date to create simple StarView-Styles // from them. Luckily a PixPattern always contains a normal pattern. sal_uLong nDataSize; sal_uInt16 nPatType; BitmapEx aBMP; pPict->ReadUInt16( nPatType ); if (nPatType==1) { pattern.read(*pPict); nDataSize=ReadPixMapEtc(aBMP,false,true,nullptr,nullptr,false,false); // CHANGEME: use average pixmap colors to update the pattern, ... if (nDataSize!=0xffffffff) nDataSize+=10; } else if (nPatType==2) { pattern.read(*pPict); // RGBColor sal_uInt16 nR, nG, nB; pPict->ReadUInt16( nR ).ReadUInt16( nG ).ReadUInt16( nB ); Color col(static_cast( nR >> 8 ), static_cast( nG >> 8 ), static_cast( nB >> 8 ) ); pattern.setColor(col); nDataSize=16; } else nDataSize=0xffffffff; return nDataSize; } sal_uLong PictReader::ReadAndDrawRect(PictDrawingMethod eMethod) { ReadRectangle(aLastRect); ReadAndDrawSameRect(eMethod); return 8; } sal_uLong PictReader::ReadAndDrawSameRect(PictDrawingMethod eMethod) { if (IsInvisible(eMethod)) return 0; DrawingMethod(eMethod); PictReaderShape::drawRectangle( pVirDev, eMethod == PictDrawingMethod::FRAME, aLastRect, nActPenSize ); return 0; } sal_uLong PictReader::ReadAndDrawRoundRect(PictDrawingMethod eMethod) { ReadRectangle(aLastRoundRect); ReadAndDrawSameRoundRect(eMethod); return 8; } sal_uLong PictReader::ReadAndDrawSameRoundRect(PictDrawingMethod eMethod) { if (IsInvisible(eMethod)) return 0; DrawingMethod(eMethod); PictReaderShape::drawRoundRectangle( pVirDev, eMethod == PictDrawingMethod::FRAME, aLastRoundRect, aActOvalSize, nActPenSize ); return 0; } sal_uLong PictReader::ReadAndDrawOval(PictDrawingMethod eMethod) { ReadRectangle(aLastOval); ReadAndDrawSameOval(eMethod); return 8; } sal_uLong PictReader::ReadAndDrawSameOval(PictDrawingMethod eMethod) { if (IsInvisible(eMethod)) return 0; DrawingMethod(eMethod); PictReaderShape::drawEllipse( pVirDev, eMethod == PictDrawingMethod::FRAME, aLastOval, nActPenSize ); return 0; } sal_uLong PictReader::ReadAndDrawPolygon(PictDrawingMethod eMethod) { sal_uLong nDataSize; nDataSize=ReadPolygon(aLastPolygon); ReadAndDrawSamePolygon(eMethod); return nDataSize; } sal_uLong PictReader::ReadAndDrawSamePolygon(PictDrawingMethod eMethod) { if (IsInvisible(eMethod)) return 0; DrawingMethod(eMethod); PictReaderShape::drawPolygon( pVirDev, eMethod == PictDrawingMethod::FRAME, aLastPolygon, nActPenSize ); return 0; } sal_uLong PictReader::ReadAndDrawArc(PictDrawingMethod eMethod) { ReadRectangle(aLastArcRect); ReadAndDrawSameArc(eMethod); return 12; } sal_uLong PictReader::ReadAndDrawSameArc(PictDrawingMethod eMethod) { short nstartAngle, narcAngle; double fAng1, fAng2; pPict->ReadInt16( nstartAngle ).ReadInt16( narcAngle ); if (IsInvisible(eMethod)) return 4; DrawingMethod(eMethod); if (narcAngle<0) { nstartAngle = nstartAngle + narcAngle; narcAngle=-narcAngle; } const double pi = 2 * acos(0.0); fAng1 = static_cast(nstartAngle) * pi / 180.0; fAng2 = static_cast(nstartAngle + narcAngle) * pi / 180.0; PictReaderShape::drawArc( pVirDev, eMethod == PictDrawingMethod::FRAME, aLastArcRect, fAng1, fAng2, nActPenSize ); return 4; } sal_uLong PictReader::ReadAndDrawRgn(PictDrawingMethod eMethod) { sal_uInt16 nSize; pPict->ReadUInt16( nSize ); // read the DATA // // a region data is a mask and is probably coded as // - the first 8 bytes: bdbox ( which can be read by ReadRectangle ) // - then a list of line modifiers: y_i, a_0, b_0, a_1, b_1, ..., a_{n_i}, b_{n_i}, 0x7fff // - 0x7fff // where y_i is the increasing sequences of line coordinates // and on each line: a0 < b0 < a1 < b1 < ... < a_{n_i} < b_{n_i} // it can be probably decoded as : // M=an empty mask: ie. (0, 0, ... ) with (left_box-right_box+1) zeroes // then for each line (y_i): // - takes M and inverts all values in [a_0,b_0-1], in [a_1,b_1-1] ... // - sets M = new y_i line mask ReadAndDrawSameRgn(eMethod); return static_cast(nSize); } sal_uLong PictReader::ReadAndDrawSameRgn(PictDrawingMethod eMethod) { if (IsInvisible(eMethod)) return 0; DrawingMethod(eMethod); // DISPLAY: ...???... return 0; } void PictReader::DrawingMethod(PictDrawingMethod eMethod) { if( eActMethod==eMethod ) return; switch (eMethod) { case PictDrawingMethod::FRAME: if (eActPenPattern.isDefault()) SetLineColor( aActForeColor ); else SetLineColor(eActPenPattern.getColor(aActBackColor, aActForeColor)); SetFillColor( COL_TRANSPARENT ); pVirDev->SetRasterOp(eActROP); break; case PictDrawingMethod::PAINT: SetLineColor( COL_TRANSPARENT ); if (eActPenPattern.isDefault()) SetFillColor( aActForeColor ); else SetFillColor(eActPenPattern.getColor(aActBackColor, aActForeColor)); pVirDev->SetRasterOp(eActROP); break; case PictDrawingMethod::ERASE: SetLineColor( COL_TRANSPARENT ); if (eActBackPattern.isDefault()) SetFillColor( aActBackColor );// Osnola: previously aActForeColor else // checkMe SetFillColor(eActBackPattern.getColor(COL_BLACK, aActBackColor)); pVirDev->SetRasterOp(RasterOp::OverPaint); break; case PictDrawingMethod::INVERT: // checkme SetLineColor( COL_TRANSPARENT); SetFillColor( COL_BLACK ); pVirDev->SetRasterOp(RasterOp::Invert); break; case PictDrawingMethod::FILL: SetLineColor( COL_TRANSPARENT ); if (eActFillPattern.isDefault()) SetFillColor( aActForeColor ); else SetFillColor(eActFillPattern.getColor(aActBackColor, aActForeColor)); pVirDev->SetRasterOp(RasterOp::OverPaint); break; case PictDrawingMethod::TEXT: aActFont.SetColor(aActForeColor); aActFont.SetFillColor(aActBackColor); aActFont.SetTransparent(true); pVirDev->SetFont(aActFont); pVirDev->SetRasterOp(RasterOp::OverPaint); break; default: break; // -Wall undefined not handled... } eActMethod=eMethod; } sal_uLong PictReader::ReadAndDrawText() { char nByteLen; sal_uInt32 nLen, nDataLen; sal_Char sText[256]; pPict->ReadChar( nByteLen ); nLen=static_cast(nByteLen)&0x000000ff; nDataLen = nLen + 1; pPict->ReadBytes(&sText, nLen); if (IsInvisible( PictDrawingMethod::TEXT )) return nDataLen; DrawingMethod( PictDrawingMethod::TEXT ); // remove annoying control characters: while ( nLen > 0 && static_cast(sText[ nLen - 1 ]) < 32 ) nLen--; sText[ nLen ] = 0; OUString aString( sText, strlen(sText), aActFont.GetCharSet()); pVirDev->DrawText( Point( aTextPosition.X(), aTextPosition.Y() ), aString ); return nDataLen; } sal_uLong PictReader::ReadPixMapEtc( BitmapEx &rBitmap, bool bBaseAddr, bool bColorTable, tools::Rectangle* pSrcRect, tools::Rectangle* pDestRect, bool bMode, bool bMaskRgn ) { std::unique_ptr pBitmap; sal_uInt16 nPackType(0), nPixelSize(0), nCmpCount(0), nCmpSize(0); sal_uInt8 nDat(0), nRed(0), nGreen(0), nBlue(0); // The calculation of nDataSize is considering the size of the whole data. size_t nDataSize = 0; // conditionally skip BaseAddr if ( bBaseAddr ) { pPict->SeekRel( 4 ); nDataSize += 4; } // Read PixMap or Bitmap structure; sal_uInt16 nRowBytes(0), nBndX(0), nBndY(0), nWidth(0), nHeight(0); pPict->ReadUInt16(nRowBytes).ReadUInt16(nBndY).ReadUInt16(nBndX).ReadUInt16(nHeight).ReadUInt16(nWidth); if (nBndY > nHeight) return 0xffffffff; nHeight = nHeight - nBndY; if (nHeight == 0) return 0xffffffff; if (nBndX > nWidth) return 0xffffffff; nWidth = nWidth - nBndX; if (nWidth == 0) return 0xffffffff; sal_uInt16 nDstBitCount = 1; std::vector aPalette; const bool bNotMonoChrome = (nRowBytes & 0x8000) != 0; if (bNotMonoChrome) { // it is a PixMap nRowBytes &= 0x3fff; sal_uInt16 nVersion; sal_uInt32 nPackSize; sal_uInt16 nPixelType; sal_uInt32 nPlaneBytes; sal_uInt32 nHRes, nVRes; pPict->ReadUInt16( nVersion ).ReadUInt16( nPackType ).ReadUInt32( nPackSize ).ReadUInt32( nHRes ).ReadUInt32( nVRes ).ReadUInt16( nPixelType ).ReadUInt16( nPixelSize ).ReadUInt16( nCmpCount ).ReadUInt16( nCmpSize ).ReadUInt32( nPlaneBytes ); pPict->SeekRel( 8 ); nDataSize += 46; nDstBitCount = nPixelSize; if ( nDstBitCount > 8 ) nDstBitCount = 24; else if ( nDstBitCount == 2 ) nDstBitCount = 4; if ( bColorTable ) { pPict->SeekRel( 6 ); sal_uInt16 nColTabSize(0); pPict->ReadUInt16(nColTabSize); if (nColTabSize > 255) return 0xffffffff; ++nColTabSize; aPalette.resize(nColTabSize); for (size_t i = 0; i < nColTabSize; ++i) { pPict->SeekRel(2); sal_uInt8 nDummy; pPict->ReadUChar( nRed ).ReadUChar( nDummy ).ReadUChar( nGreen ).ReadUChar( nDummy ).ReadUChar( nBlue ).ReadUChar( nDummy ); aPalette[i] = Color(nRed, nGreen, nBlue); } nDataSize += 8 + nColTabSize * 8; } } else { nRowBytes &= 0x3fff; nPixelSize = nCmpCount = nCmpSize = 1; nDataSize += 10; aPalette.resize(2); aPalette[0] = Color(0xff, 0xff, 0xff); aPalette[1] = Color(0, 0, 0); } // conditionally read source rectangle: if ( pSrcRect != nullptr) { sal_uInt16 nTop, nLeft, nBottom, nRight; pPict->ReadUInt16( nTop ).ReadUInt16( nLeft ).ReadUInt16( nBottom ).ReadUInt16( nRight ); *pSrcRect = tools::Rectangle( static_cast(nLeft), static_cast(nTop), static_cast(nRight), static_cast(nBottom) ); nDataSize += 8; } // conditionally read destination rectangle: if ( pDestRect != nullptr ) { Point aTL, aBR; aTL = ReadPoint(); aBR = ReadPoint(); *pDestRect = tools::Rectangle( aTL, aBR ); nDataSize += 8; } // conditionally read mode (or skip it): if ( bMode ) { pPict->SeekRel(2); nDataSize += 2; } // conditionally read region (or skip it): if ( bMaskRgn ) { sal_uInt16 nSize; pPict->ReadUInt16( nSize ); pPict->SeekRel( nSize - 2 ); nDataSize += static_cast(nSize); } // read and write Bitmap bits: if ( nPixelSize == 1 || nPixelSize == 2 || nPixelSize == 4 || nPixelSize == 8 ) { sal_uInt16 nSrcBPL, nDestBPL; size_t nCount; if ( nPixelSize == 1 ) nSrcBPL = ( nWidth + 7 ) >> 3; else if ( nPixelSize == 2 ) nSrcBPL = ( nWidth + 3 ) >> 2; else if ( nPixelSize == 4 ) nSrcBPL = ( nWidth + 1 ) >> 1; else nSrcBPL = nWidth; nDestBPL = ( nSrcBPL + 3 ) & 0xfffc; if (!nRowBytes || nRowBytes < nSrcBPL || nRowBytes > nDestBPL) return 0xffffffff; if (nRowBytes < 8 || nPackType == 1) { if (nHeight > pPict->remainingSize() / (sizeof(sal_uInt8) * nRowBytes)) return 0xffffffff; } else { size_t nByteCountSize = nRowBytes > 250 ? sizeof(sal_uInt16) : sizeof(sal_uInt8); if (nHeight > pPict->remainingSize() / nByteCountSize) return 0xffffffff; } pBitmap.reset(new vcl::bitmap::RawBitmap( Size(nWidth, nHeight), 24 )); for (sal_uInt16 ny = 0; ny < nHeight; ++ny) { sal_uInt16 nx = 0; if ( nRowBytes < 8 || nPackType == 1 ) { for (size_t i = 0; i < nRowBytes; ++i) { pPict->ReadUChar( nDat ); if ( nx < nWidth ) SetByte(nx, ny, *pBitmap, nPixelSize, nDat, nWidth, aPalette); } nDataSize += nRowBytes; } else { sal_uInt16 nByteCount(0); if ( nRowBytes > 250 ) { pPict->ReadUInt16( nByteCount ); nDataSize += 2 + static_cast(nByteCount); } else { sal_uInt8 nByteCountAsByte(0); pPict->ReadUChar( nByteCountAsByte ); nByteCount = static_cast(nByteCountAsByte) & 0x00ff; nDataSize += 1 + static_cast(nByteCount); } while (pPict->good() && nByteCount) { sal_uInt8 nFlagCounterByte(0); pPict->ReadUChar(nFlagCounterByte); if ( ( nFlagCounterByte & 0x80 ) == 0 ) { nCount = static_cast(nFlagCounterByte) + 1; for (size_t i = 0; i < nCount; ++i) { pPict->ReadUChar( nDat ); if ( nx < nWidth ) SetByte(nx, ny, *pBitmap, nPixelSize, nDat, nWidth, aPalette); } nByteCount -= 1 + nCount; } else { nCount = static_cast( 1 - sal_Int16( static_cast(nFlagCounterByte) | 0xff00 ) ); pPict->ReadUChar( nDat ); for (size_t i = 0; i < nCount; ++i) { if ( nx < nWidth ) SetByte(nx, ny, *pBitmap, nPixelSize, nDat, nWidth, aPalette); } nByteCount -= 2; } } } } } else if ( nPixelSize == 16 ) { sal_uInt8 nByteCountAsByte, nFlagCounterByte; sal_uInt16 nByteCount, nCount, nD; sal_uLong nSrcBitsPos; if (nWidth > nRowBytes / 2) return 0xffffffff; if (nRowBytes < 8 || nPackType == 1) { if (nWidth && nHeight > pPict->remainingSize() / (sizeof(sal_uInt16) * nWidth)) return 0xffffffff; } else { size_t nByteCountSize = nRowBytes > 250 ? sizeof(sal_uInt16) : sizeof(sal_uInt8); if (nHeight > pPict->remainingSize() / nByteCountSize) return 0xffffffff; } pBitmap.reset(new vcl::bitmap::RawBitmap( Size(nWidth, nHeight), 24 )); for (sal_uInt16 ny = 0; ny < nHeight; ++ny) { sal_uInt16 nx = 0; if ( nRowBytes < 8 || nPackType == 1 ) { for (size_t i = 0; i < nWidth; ++i) { pPict->ReadUInt16( nD ); nRed = static_cast( nD >> 7 ); nGreen = static_cast( nD >> 2 ); nBlue = static_cast( nD << 3 ); pBitmap->SetPixel(ny, nx++, Color(nRed, nGreen, nBlue)); } nDataSize += static_cast(nWidth) * 2; } else { nSrcBitsPos = pPict->Tell(); if ( nRowBytes > 250 ) { pPict->ReadUInt16( nByteCount ); nByteCount += 2; } else { pPict->ReadUChar( nByteCountAsByte ); nByteCount = static_cast(nByteCountAsByte) & 0x00ff; nByteCount++; } while ( nx != nWidth ) { pPict->ReadUChar( nFlagCounterByte ); if ( (nFlagCounterByte & 0x80) == 0) { nCount=static_cast(nFlagCounterByte)+1; if ( nCount + nx > nWidth) nCount = nWidth - nx; if (pPict->remainingSize() < sizeof(sal_uInt16) * nCount) return 0xffffffff; /* SJ: the RLE decoding seems not to be correct here, I don't want to change this until I have a bugdoc for this case. Have a look at 32bit, there I changed the encoding, so that it is used a straight forward array */ for (size_t i = 0; i < nCount; ++i) { pPict->ReadUInt16( nD ); nRed = static_cast( nD >> 7 ); nGreen = static_cast( nD >> 2 ); nBlue = static_cast( nD << 3 ); pBitmap->SetPixel(ny, nx++, Color(nRed, nGreen, nBlue)); } } else { if (pPict->remainingSize() < sizeof(sal_uInt16)) return 0xffffffff; nCount=(1-sal_Int16(static_cast(nFlagCounterByte)|0xff00)); if ( nCount + nx > nWidth ) nCount = nWidth - nx; pPict->ReadUInt16( nD ); nRed = static_cast( nD >> 7 ); nGreen = static_cast( nD >> 2 ); nBlue = static_cast( nD << 3 ); for (size_t i = 0; i < nCount; ++i) { pBitmap->SetPixel(ny, nx++, Color(nRed, nGreen, nBlue)); } } } nDataSize+=static_cast(nByteCount); pPict->Seek(nSrcBitsPos+static_cast(nByteCount)); } } } else if ( nPixelSize == 32 ) { sal_uInt16 nByteCount; size_t nCount; sal_uLong nSrcBitsPos; if ( nRowBytes != 4*nWidth ) return 0xffffffff; if ( nRowBytes < 8 || nPackType == 1 ) { const size_t nMaxPixels = pPict->remainingSize() / 4; const size_t nMaxRows = nWidth ? nMaxPixels / nWidth : SAL_MAX_UINT16; if (nHeight > nMaxRows) return 0xffffffff; const size_t nMaxCols = nHeight ? nMaxPixels / nHeight : SAL_MAX_UINT16; if (nWidth > nMaxCols) return 0xffffffff; pBitmap.reset(new vcl::bitmap::RawBitmap( Size(nWidth, nHeight), 24 )); for (sal_uInt16 ny = 0; ny < nHeight; ++ny) { for (sal_uInt16 nx = 0; nx < nWidth; ++nx) { sal_uInt8 nDummy; pPict->ReadUChar( nDummy ).ReadUChar( nRed ).ReadUChar( nGreen ).ReadUChar( nBlue ); pBitmap->SetPixel(ny, nx, Color(nRed, nGreen, nBlue)); } nDataSize += static_cast(nWidth) * 4; } } else if ( nPackType == 2 ) { const size_t nMaxPixels = pPict->remainingSize() / 3; const size_t nMaxRows = nWidth ? nMaxPixels / nWidth : SAL_MAX_UINT16; if (nHeight > nMaxRows) return 0xffffffff; const size_t nMaxCols = nHeight ? nMaxPixels / nHeight : SAL_MAX_UINT16; if (nWidth > nMaxCols) return 0xffffffff; pBitmap.reset(new vcl::bitmap::RawBitmap( Size(nWidth, nHeight), 24 )); for (sal_uInt16 ny = 0; ny < nHeight; ++ny) { for (sal_uInt16 nx = 0; nx < nWidth; ++nx) { pPict->ReadUChar( nRed ).ReadUChar( nGreen ).ReadUChar( nBlue ); pBitmap->SetPixel(ny, nx, Color(nRed, nGreen, nBlue)); } nDataSize += static_cast(nWidth) * 3; } } else { sal_uInt8 nByteCountAsByte; sal_uInt8 nFlagCounterByte; if ( ( nCmpCount == 3 ) || ( nCmpCount == 4 ) ) { size_t nByteCountSize = nRowBytes > 250 ? sizeof(sal_uInt16) : sizeof(sal_uInt8); if (nHeight > pPict->remainingSize() / nByteCountSize) return 0xffffffff; pBitmap.reset(new vcl::bitmap::RawBitmap( Size(nWidth, nHeight), 24 )); size_t nByteWidth = static_cast(nWidth) * nCmpCount; std::vector aScanline(nByteWidth); for (sal_uInt16 ny = 0; ny < nHeight; ++ny) { nSrcBitsPos = pPict->Tell(); if ( nRowBytes > 250 ) { pPict->ReadUInt16( nByteCount ); nByteCount += 2; } else { pPict->ReadUChar( nByteCountAsByte ); nByteCount = nByteCountAsByte; nByteCount++; } size_t i = 0; while (i < nByteWidth) { pPict->ReadUChar( nFlagCounterByte ); if ( ( nFlagCounterByte & 0x80 ) == 0) { nCount = static_cast(nFlagCounterByte) + 1; if ((i + nCount) > nByteWidth) nCount = nByteWidth - i; if (pPict->remainingSize() < nCount) return 0xffffffff; while( nCount-- ) { pPict->ReadUChar( nDat ); aScanline[ i++ ] = nDat; } } else { if (pPict->remainingSize() < 1) return 0xffffffff; nCount = ( 1 - sal_Int16( static_cast(nFlagCounterByte) | 0xff00 ) ); if (( i + nCount) > nByteWidth) nCount = nByteWidth - i; pPict->ReadUChar( nDat ); while( nCount-- ) aScanline[ i++ ] = nDat; } } sal_uInt8* pTmp = aScanline.data(); if ( nCmpCount == 4 ) pTmp += nWidth; for (sal_uInt16 nx = 0; nx < nWidth; pTmp++) pBitmap->SetPixel(ny, nx++, Color(*pTmp, pTmp[ nWidth ], pTmp[ 2 * nWidth ])); nDataSize += static_cast(nByteCount); pPict->Seek( nSrcBitsPos + static_cast(nByteCount) ); } } } } else return 0xffffffff; rBitmap = vcl::bitmap::CreateFromData(std::move(*pBitmap)); return nDataSize; } void PictReader::ReadHeader() { short y1,x1,y2,x2; sal_Char sBuf[ 2 ]; // previous code considers pPict->Tell() as the normal starting position, // can we have nStartPos != 0 ? sal_uLong nStartPos = pPict->Tell(); // Standard: // a picture file begins by 512 bytes (reserved to the application) followed by the picture data // while clipboard, pictures stored in a document often contain only the picture data. // Special cases: // - some Pict v.1 use 0x00 0x11 0x01 ( instead of 0x11 0x01) to store the version op // (we consider here this as another standard for Pict. v.1 ) // - some files seem to contain extra garbage data at the beginning // - some picture data seem to contain extra NOP opcode(0x00) between the bounding box and the version opcode // This code looks hard to find a picture header, ie. it looks at positions // - nStartPos+0, nStartPos+512 with potential extra NOP codes between bdbox and version (at most 9 extra NOP) // - 512..1024 with more strict bdbox checking and no extra NOP codes // Notes: // - if the header can begin at nStartPos+0 and at nStartPos+512, we try to choose the more // <> ( using the variable confidence) // - svtools/source/filter.vcl/filter/{filter.cxx,filter2.cxx} only check for standard Pict, // this may cause future problems int st; sal_uInt32 nOffset; int confidence[2] = { 0, 0}; for ( st = 0; st < 3 + 513; st++ ) { int actualConfid = 20; // the actual confidence pPict->ResetError(); if (st < 2) nOffset = nStartPos+st*512; else if (st == 2) { // choose nStartPos+0 or nStartPos+512 even if there are a little dubious int actPos = -1, actConf=0; if (confidence[0] > 0) { actPos = 0; actConf = confidence[0]; } if (confidence[1] > 0 && confidence[1] >= actConf) actPos = 1; if (actPos < 0) continue; nOffset = nStartPos+actPos*512; } else { nOffset = 509+st; // illogical : more logical will be nStartPos+509+st or to consider that nStartPos=0 // a small test to check if versionOp code exists after the bdbox ( with no extra NOP codes) pPict->Seek(nOffset+10); pPict->ReadBytes(sBuf, 2); if (!pPict->good()) break; if (sBuf[0] == 0x11 || (sBuf[0] == 0x00 && sBuf[1] == 0x11)) ; // maybe ok else continue; } pPict->Seek(nOffset); // 2 bytes to store size ( version 1 ) ignored pPict->SeekRel( 2 ); pPict->ReadInt16( y1 ).ReadInt16( x1 ).ReadInt16( y2 ).ReadInt16( x2 ); // frame rectangle of the picture if (x1 > x2 || y1 > y2) continue; // bad bdbox if (x1 < -2048 || x2 > 2048 || y1 < -2048 || y2 > 2048 || // origin|dest is very small|large (x1 == x2 && y1 == y2) ) // 1 pixel pict is dubious actualConfid-=3; else if (x2 < x1+8 || y2 < y1+8) // a little dubious actualConfid-=1; if (st >= 3 && actualConfid != 20) continue; aBoundingRect=tools::Rectangle( x1,y1, x2, y2 ); if (!pPict->good()) continue; // read version pPict->ReadBytes(sBuf, 2); // version 1 file if ( sBuf[ 0 ] == 0x11 && sBuf[ 1 ] == 0x01 ) { // pict v1 must be rare and we do only few tests if (st < 2) { confidence[st] = --actualConfid; continue; } IsVersion2 = false; return; } if (sBuf[0] != 0x00) continue; // unrecoverable error int numZero = 0; do { numZero++; pPict->SeekRel(-1); pPict->ReadBytes(sBuf, 2); } while ( sBuf[0] == 0x00 && numZero < 10); actualConfid -= (numZero-1); // extra nop are dubious if (!pPict->good()) continue; if (sBuf[0] != 0x11) continue; // not a version opcode // abnormal version 1 file if (sBuf[1] == 0x01 ) { // pict v1 must be rare and we do only few tests if (st < 2) { confidence[st] = --actualConfid; continue; } IsVersion2 = false; return; } if (sBuf[1] != 0x02 ) continue; // not a version 2 file IsVersion2=true; short nExtVer, nReserved; // 3 Bytes ignored : end of version arg 0x02FF (ie: 0xFF), HeaderOp : 0x0C00 pPict->SeekRel( 3 ); pPict->ReadInt16( nExtVer ).ReadInt16( nReserved ); if (!pPict->good()) continue; if ( nExtVer == -2 ) // extended version 2 picture { sal_Int32 nHResFixed, nVResFixed; pPict->ReadInt32( nHResFixed ).ReadInt32( nVResFixed ); pPict->ReadInt16( y1 ).ReadInt16( x1 ).ReadInt16( y2 ).ReadInt16( x2 ); // reading the optimal bounding rect if (x1 > x2 || y1 > y2) continue; // bad bdbox if (st < 2 && actualConfid != 20) { confidence[st] = actualConfid; continue; } double fHRes = nHResFixed; fHRes /= 65536; double fVRes = nVResFixed; fVRes /= 65536; aHRes /= fHRes; aVRes /= fVRes; aBoundingRect=tools::Rectangle( x1,y1, x2, y2 ); pPict->SeekRel( 4 ); // 4 bytes reserved return; } else if (nExtVer == -1 ) { // basic version 2 picture if (st < 2 && actualConfid != 20) { confidence[st] = actualConfid; continue; } pPict->SeekRel( 16); // bdbox(4 fixed number) pPict->SeekRel(4); // 4 bytes reserved return; } } pPict->SetError(SVSTREAM_FILEFORMAT_ERROR); } #if OSL_DEBUG_LEVEL > 0 static const char* operationName(sal_uInt16 nOpcode) { // add here whatever makes the debugging easier for you, otherwise you'll // see only the operation's opcode switch (nOpcode) { case 0x0001: return "Clip"; case 0x0003: return "TxFont"; case 0x0004: return "TxFace"; case 0x0008: return "PnMode"; case 0x0009: return "PnPat"; case 0x000d: return "TxSize"; case 0x001a: return "RGBFgCol"; case 0x001d: return "HiliteColor"; case 0x0020: return "Line"; case 0x0022: return "ShortLine"; case 0x0028: return "LongText"; case 0x0029: return "DHText"; case 0x002a: return "DVText"; case 0x002c: return "fontName"; case 0x002e: return "glyphState"; case 0x0031: return "paintRect"; case 0x0038: return "frameSameRect"; case 0x0070: return "framePoly"; case 0x0071: return "paintPoly"; case 0x00a1: return "LongComment"; default: return "?"; } } #endif sal_uLong PictReader::ReadData(sal_uInt16 nOpcode) { sal_uInt16 nUSHORT; Point aPoint; sal_uLong nDataSize=0; PictDrawingMethod shapeDMethod = PictDrawingMethod::UNDEFINED; switch (nOpcode & 7) { case 0: shapeDMethod = PictDrawingMethod::FRAME; break; case 1: shapeDMethod = PictDrawingMethod::PAINT; break; case 2: shapeDMethod = PictDrawingMethod::ERASE; break; case 3: shapeDMethod = PictDrawingMethod::INVERT; break; case 4: shapeDMethod = PictDrawingMethod::FILL; break; default: break; } #if OSL_DEBUG_LEVEL > 0 SAL_INFO("filter.pict", "Operation: 0x" << OUString::number(nOpcode, 16) << " [" << operationName(nOpcode) << "]"); #endif switch(nOpcode) { case 0x0000: // NOP nDataSize=0; break; case 0x0001: { // Clip tools::Rectangle aRect; pPict->ReadUInt16( nUSHORT ); nDataSize=nUSHORT; ReadRectangle(aRect); // checkme: do we really want to extend the rectangle here ? // I do that because the clipping is often used to clean a region, // before drawing some text and also to draw this text. // So using a too small region can lead to clip the end of the text ; // but this can be discutable... aRect.setWidth(aRect.getWidth()+1); aRect.setHeight(aRect.getHeight()+1); pVirDev->SetClipRegion( vcl::Region( aRect ) ); break; } case 0x0002: // BkPat nDataSize = eActBackPattern.read(*pPict); eActMethod = PictDrawingMethod::UNDEFINED; break; case 0x0003: // TxFont pPict->ReadUInt16( nUSHORT ); if (nUSHORT <= 1) aActFont.SetFamily(FAMILY_SWISS); else if (nUSHORT <= 12) aActFont.SetFamily(FAMILY_DECORATIVE); else if (nUSHORT <= 20) aActFont.SetFamily(FAMILY_ROMAN); else if (nUSHORT == 21) aActFont.SetFamily(FAMILY_SWISS); else if (nUSHORT == 22) aActFont.SetFamily(FAMILY_MODERN); else if (nUSHORT <= 1023) aActFont.SetFamily(FAMILY_SWISS); else aActFont.SetFamily(FAMILY_ROMAN); aActFont.SetCharSet(GetTextEncoding(nUSHORT)); eActMethod = PictDrawingMethod::UNDEFINED; nDataSize=2; break; case 0x0004: { // TxFace char nFace; pPict->ReadChar( nFace ); if ( (nFace & 0x01)!=0 ) aActFont.SetWeight(WEIGHT_BOLD); else aActFont.SetWeight(WEIGHT_NORMAL); if ( (nFace & 0x02)!=0 ) aActFont.SetItalic(ITALIC_NORMAL); else aActFont.SetItalic(ITALIC_NONE); if ( (nFace & 0x04)!=0 ) aActFont.SetUnderline(LINESTYLE_SINGLE); else aActFont.SetUnderline(LINESTYLE_NONE); if ( (nFace & 0x08)!=0 ) aActFont.SetOutline(true); else aActFont.SetOutline(false); if ( (nFace & 0x10)!=0 ) aActFont.SetShadow(true); else aActFont.SetShadow(false); eActMethod = PictDrawingMethod::UNDEFINED; nDataSize=1; break; } case 0x0005: // TxMode nDataSize=2; break; case 0x0006: // SpExtra nDataSize=4; break; case 0x0007: { // PnSize nActPenSize=ReadSize(); eActMethod = PictDrawingMethod::UNDEFINED; nDataSize=4; break; } case 0x0008: // PnMode pPict->ReadUInt16( nUSHORT ); // internal code for postscript command (Quickdraw Reference Drawing B-30,B-34) if (nUSHORT==23) eActROP = RasterOp::N1; else { switch (nUSHORT & 0x0007) { case 0: eActROP=RasterOp::OverPaint; break; // Copy case 1: eActROP=RasterOp::OverPaint; break; // Or case 2: eActROP=RasterOp::Xor; break; // Xor case 3: eActROP=RasterOp::OverPaint; break; // Bic case 4: eActROP=RasterOp::Invert; break; // notCopy case 5: eActROP=RasterOp::OverPaint; break; // notOr case 6: eActROP=RasterOp::Xor; break; // notXor case 7: eActROP=RasterOp::OverPaint; break; // notBic } } eActMethod = PictDrawingMethod::UNDEFINED; nDataSize=2; break; case 0x0009: // PnPat nDataSize=eActPenPattern.read(*pPict); eActMethod = PictDrawingMethod::UNDEFINED; break; case 0x000a: // FillPat nDataSize=eActFillPattern.read(*pPict); eActMethod = PictDrawingMethod::UNDEFINED; break; case 0x000b: // OvSize aActOvalSize=ReadSize(); nDataSize=4; break; case 0x000c: // Origin nDataSize=4; break; case 0x000d: // TxSize { pPict->ReadUInt16( nUSHORT ); aActFont.SetFontSize( Size( 0, static_cast(nUSHORT) ) ); eActMethod = PictDrawingMethod::UNDEFINED; nDataSize=2; } break; case 0x000e: // FgColor aActForeColor=ReadColor(); eActMethod = PictDrawingMethod::UNDEFINED; nDataSize=4; break; case 0x000f: // BkColor aActBackColor=ReadColor(); nDataSize=4; break; case 0x0010: // TxRatio nDataSize=8; break; case 0x0011: // VersionOp nDataSize=1; break; case 0x0012: // BkPixPat nDataSize=ReadPixPattern(eActBackPattern); eActMethod = PictDrawingMethod::UNDEFINED; break; case 0x0013: // PnPixPat nDataSize=ReadPixPattern(eActPenPattern); eActMethod = PictDrawingMethod::UNDEFINED; break; case 0x0014: // FillPixPat nDataSize=ReadPixPattern(eActFillPattern); eActMethod = PictDrawingMethod::UNDEFINED; break; case 0x0015: // PnLocHFrac nDataSize=2; break; case 0x0016: // ChExtra nDataSize=2; break; case 0x0017: // Reserved (0 Bytes) case 0x0018: // Reserved (0 Bytes) case 0x0019: // Reserved (0 Bytes) nDataSize=0; break; case 0x001a: // RGBFgCol aActForeColor=ReadRGBColor(); eActMethod = PictDrawingMethod::UNDEFINED; nDataSize=6; break; case 0x001b: // RGBBkCol aActBackColor=ReadRGBColor(); eActMethod = PictDrawingMethod::UNDEFINED; nDataSize=6; break; case 0x001c: // HiliteMode nDataSize=0; break; case 0x001d: // HiliteColor nDataSize=6; break; case 0x001e: // DefHilite nDataSize=0; break; case 0x001f: // OpColor nDataSize=6; break; case 0x0020: // Line aPoint=ReadPoint(); aPenPosition=ReadPoint(); nDataSize=8; if (IsInvisible( PictDrawingMethod::FRAME )) break; DrawingMethod( PictDrawingMethod::FRAME ); PictReaderShape::drawLine(pVirDev, aPoint,aPenPosition, nActPenSize); break; case 0x0021: // LineFrom aPoint=aPenPosition; aPenPosition=ReadPoint(); nDataSize=4; if (IsInvisible( PictDrawingMethod::FRAME )) break; DrawingMethod( PictDrawingMethod::FRAME ); PictReaderShape::drawLine(pVirDev, aPoint,aPenPosition, nActPenSize); break; case 0x0022: // ShortLine aPoint=ReadPoint(); aPenPosition=ReadDeltaH(aPoint); aPenPosition=ReadDeltaV(aPenPosition); nDataSize=6; if ( IsInvisible(PictDrawingMethod::FRAME) ) break; DrawingMethod( PictDrawingMethod::FRAME ); PictReaderShape::drawLine(pVirDev, aPoint,aPenPosition, nActPenSize); break; case 0x0023: // ShortLineFrom aPoint=aPenPosition; aPenPosition=ReadDeltaH(aPoint); aPenPosition=ReadDeltaV(aPenPosition); nDataSize=2; if (IsInvisible( PictDrawingMethod::FRAME )) break; DrawingMethod( PictDrawingMethod::FRAME ); PictReaderShape::drawLine(pVirDev, aPoint,aPenPosition, nActPenSize); break; case 0x0024: // Reserved (n Bytes) case 0x0025: // Reserved (n Bytes) case 0x0026: // Reserved (n Bytes) case 0x0027: // Reserved (n Bytes) pPict->ReadUInt16( nUSHORT ); nDataSize=2+nUSHORT; break; case 0x0028: // LongText aTextPosition=ReadPoint(); nDataSize=4+ReadAndDrawText(); break; case 0x0029: // DHText aTextPosition=ReadUnsignedDeltaH(aTextPosition); nDataSize=1+ReadAndDrawText(); break; case 0x002a: // DVText aTextPosition=ReadUnsignedDeltaV(aTextPosition); nDataSize=1+ReadAndDrawText(); break; case 0x002b: // DHDVText aTextPosition=ReadUnsignedDeltaH(aTextPosition); aTextPosition=ReadUnsignedDeltaV(aTextPosition); nDataSize=2+ReadAndDrawText(); break; case 0x002c: { // fontName char sFName[ 256 ], nByteLen; sal_uInt16 nLen; pPict->ReadUInt16( nUSHORT ); nDataSize=nUSHORT+2; pPict->ReadUInt16( nUSHORT ); if (nUSHORT <= 1) aActFont.SetFamily(FAMILY_SWISS); else if (nUSHORT <= 12) aActFont.SetFamily(FAMILY_DECORATIVE); else if (nUSHORT <= 20) aActFont.SetFamily(FAMILY_ROMAN); else if (nUSHORT == 21) aActFont.SetFamily(FAMILY_SWISS); else if (nUSHORT == 22) aActFont.SetFamily(FAMILY_MODERN); else if (nUSHORT <= 1023) aActFont.SetFamily(FAMILY_SWISS); else aActFont.SetFamily(FAMILY_ROMAN); aActFont.SetCharSet(GetTextEncoding(nUSHORT)); pPict->ReadChar( nByteLen ); nLen=static_cast(nByteLen)&0x00ff; pPict->ReadBytes(&sFName, nLen); sFName[ nLen ] = 0; OUString aString( sFName, strlen(sFName), osl_getThreadTextEncoding() ); aActFont.SetFamilyName( aString ); eActMethod = PictDrawingMethod::UNDEFINED; break; } case 0x002d: // lineJustify nDataSize=10; break; case 0x002e: // glyphState pPict->ReadUInt16( nUSHORT ); nDataSize=2+nUSHORT; break; case 0x002f: // Reserved (n Bytes) pPict->ReadUInt16( nUSHORT ); nDataSize=2+nUSHORT; break; case 0x0030: // frameRect case 0x0031: // paintRect case 0x0032: // eraseRect case 0x0033: // invertRect case 0x0034: // fillRect nDataSize=ReadAndDrawRect(shapeDMethod); break; case 0x0035: // Reserved (8 Bytes) case 0x0036: // Reserved (8 Bytes) case 0x0037: // Reserved (8 Bytes) nDataSize=8; break; case 0x0038: // frameSameRect case 0x0039: // paintSameRect case 0x003a: // eraseSameRect case 0x003b: // invertSameRect case 0x003c: // fillSameRect nDataSize=ReadAndDrawSameRect(shapeDMethod); break; case 0x003d: // Reserved (0 Bytes) case 0x003e: // Reserved (0 Bytes) case 0x003f: // Reserved (0 Bytes) nDataSize=0; break; case 0x0040: // frameRRect case 0x0041: // paintRRect case 0x0042: // eraseRRect case 0x0043: // invertRRect case 0x0044: // fillRRect nDataSize=ReadAndDrawRoundRect(shapeDMethod); break; case 0x0045: // Reserved (8 Bytes) case 0x0046: // Reserved (8 Bytes) case 0x0047: // Reserved (8 Bytes) nDataSize=8; break; case 0x0048: // frameSameRRect case 0x0049: // paintSameRRect case 0x004a: // eraseSameRRect case 0x004b: // invertSameRRect case 0x004c: // fillSameRRect nDataSize=ReadAndDrawSameRoundRect(shapeDMethod); break; case 0x004d: // Reserved (0 Bytes) case 0x004e: // Reserved (0 Bytes) case 0x004f: // Reserved (0 Bytes) nDataSize=0; break; case 0x0050: // frameOval case 0x0051: // paintOval case 0x0052: // eraseOval case 0x0053: // invertOval case 0x0054: // fillOval nDataSize=ReadAndDrawOval(shapeDMethod); break; case 0x0055: // Reserved (8 Bytes) case 0x0056: // Reserved (8 Bytes) case 0x0057: // Reserved (8 Bytes) nDataSize=8; break; case 0x0058: // frameSameOval case 0x0059: // paintSameOval case 0x005a: // eraseSameOval case 0x005b: // invertSameOval case 0x005c: // fillSameOval nDataSize=ReadAndDrawSameOval(shapeDMethod); break; case 0x005d: // Reserved (0 Bytes) case 0x005e: // Reserved (0 Bytes) case 0x005f: // Reserved (0 Bytes) nDataSize=0; break; case 0x0060: // frameArc case 0x0061: // paintArc case 0x0062: // eraseArc case 0x0063: // invertArc case 0x0064: // fillArc nDataSize=ReadAndDrawArc(shapeDMethod); break; case 0x0065: // Reserved (12 Bytes) case 0x0066: // Reserved (12 Bytes) case 0x0067: // Reserved (12 Bytes) nDataSize=12; break; case 0x0068: // frameSameArc case 0x0069: // paintSameArc case 0x006a: // eraseSameArc case 0x006b: // invertSameArc case 0x006c: // fillSameArc nDataSize=ReadAndDrawSameArc(shapeDMethod); break; case 0x006d: // Reserved (4 Bytes) case 0x006e: // Reserved (4 Bytes) case 0x006f: // Reserved (4 Bytes) nDataSize=4; break; case 0x0070: // framePoly case 0x0071: // paintPoly case 0x0072: // erasePoly case 0x0073: // invertPoly case 0x0074: // fillPoly nDataSize=ReadAndDrawPolygon(shapeDMethod); break; case 0x0075: // Reserved (Polygon-Size) case 0x0076: // Reserved (Polygon-Size) case 0x0077: // Reserved (Polygon-Size) pPict->ReadUInt16( nUSHORT ); nDataSize=nUSHORT; break; case 0x0078: // frameSamePoly case 0x0079: // paintSamePoly case 0x007a: // eraseSamePoly case 0x007b: // invertSamePoly case 0x007c: // fillSamePoly nDataSize=ReadAndDrawSamePolygon(shapeDMethod); break; case 0x007d: // Reserved (0 Bytes) case 0x007e: // Reserved (0 Bytes) case 0x007f: // Reserved (0 Bytes) nDataSize=0; break; case 0x0080: // frameRgn case 0x0081: // paintRgn case 0x0082: // eraseRgn case 0x0083: // invertRgn case 0x0084: // fillRgn nDataSize=ReadAndDrawRgn(shapeDMethod); break; case 0x0085: // Reserved (Region-Size) case 0x0086: // Reserved (Region-Size) case 0x0087: // Reserved (Region-Size) pPict->ReadUInt16( nUSHORT ); nDataSize=nUSHORT; break; case 0x0088: // frameSameRgn case 0x0089: // paintSameRgn case 0x008a: // eraseSameRgn case 0x008b: // invertSameRgn case 0x008c: // fillSameRgn nDataSize=ReadAndDrawSameRgn(shapeDMethod); break; case 0x008d: // Reserved (0 Bytes) case 0x008e: // Reserved (0 Bytes) case 0x008f: // Reserved (0 Bytes) nDataSize=0; break; case 0x0090: { // BitsRect BitmapEx aBmp; tools::Rectangle aSrcRect, aDestRect; nDataSize=ReadPixMapEtc(aBmp, false, true, &aSrcRect, &aDestRect, true, false); DrawingMethod( PictDrawingMethod::PAINT ); pVirDev->DrawBitmapEx(aDestRect.TopLeft(),aDestRect.GetSize(),aBmp); break; } case 0x0091: { // BitsRgn BitmapEx aBmp; tools::Rectangle aSrcRect, aDestRect; nDataSize=ReadPixMapEtc(aBmp, false, true, &aSrcRect, &aDestRect, true, true); DrawingMethod( PictDrawingMethod::PAINT ); pVirDev->DrawBitmapEx(aDestRect.TopLeft(),aDestRect.GetSize(),aBmp); break; } case 0x0092: // Reserved (n Bytes) case 0x0093: // Reserved (n Bytes) case 0x0094: // Reserved (n Bytes) case 0x0095: // Reserved (n Bytes) case 0x0096: // Reserved (n Bytes) case 0x0097: // Reserved (n Bytes) pPict->ReadUInt16( nUSHORT ); nDataSize=2+nUSHORT; break; case 0x0098: { // PackBitsRect BitmapEx aBmp; tools::Rectangle aSrcRect, aDestRect; nDataSize=ReadPixMapEtc(aBmp, false, true, &aSrcRect, &aDestRect, true, false); DrawingMethod( PictDrawingMethod::PAINT ); pVirDev->DrawBitmapEx(aDestRect.TopLeft(),aDestRect.GetSize(),aBmp); break; } case 0x0099: { // PackBitsRgn BitmapEx aBmp; tools::Rectangle aSrcRect, aDestRect; nDataSize=ReadPixMapEtc(aBmp, false, true, &aSrcRect, &aDestRect, true, true); DrawingMethod( PictDrawingMethod::PAINT ); pVirDev->DrawBitmapEx(aDestRect.TopLeft(),aDestRect.GetSize(),aBmp); break; } case 0x009a: { // DirectBitsRect BitmapEx aBmp; tools::Rectangle aSrcRect, aDestRect; nDataSize=ReadPixMapEtc(aBmp, true, false, &aSrcRect, &aDestRect, true, false); DrawingMethod( PictDrawingMethod::PAINT ); pVirDev->DrawBitmapEx(aDestRect.TopLeft(),aDestRect.GetSize(),aBmp); break; } case 0x009b: { // DirectBitsRgn BitmapEx aBmp; tools::Rectangle aSrcRect, aDestRect; nDataSize=ReadPixMapEtc(aBmp, true, false, &aSrcRect, &aDestRect, true, true); DrawingMethod( PictDrawingMethod::PAINT ); pVirDev->DrawBitmapEx(aDestRect.TopLeft(),aDestRect.GetSize(),aBmp); break; } case 0x009c: // Reserved (n Bytes) case 0x009d: // Reserved (n Bytes) case 0x009e: // Reserved (n Bytes) case 0x009f: // Reserved (n Bytes) pPict->ReadUInt16( nUSHORT ); nDataSize=2+nUSHORT; break; case 0x00a0: // ShortComment nDataSize=2; break; case 0x00a1: // LongComment pPict->SeekRel(2); pPict->ReadUInt16( nUSHORT ); nDataSize=4+nUSHORT; break; default: // 0x00a2 bis 0xffff (most times reserved) if (nOpcode<=0x00af) { pPict->ReadUInt16( nUSHORT ); nDataSize=2+nUSHORT; } else if (nOpcode<=0x00cf) { nDataSize=0; } else if (nOpcode<=0x00fe) { sal_uInt32 nTemp; pPict->ReadUInt32( nTemp ) ; nDataSize = nTemp; nDataSize+=4; } // Osnola: checkme: in the Quickdraw Ref examples ( for pict v2) // 0x00ff(EndOfPict) is also not followed by any data... else if (nOpcode==0x00ff) { nDataSize=IsVersion2 ? 2 : 0; } // OpEndPic else if (nOpcode<=0x01ff) { nDataSize=2; } else if (nOpcode<=0x0bfe) { nDataSize=4; } else if (nOpcode<=0x0bff) { nDataSize=22; } else if (nOpcode==0x0c00) { nDataSize=24; } // HeaderOp else if (nOpcode<=0x7eff) { nDataSize=24; } else if (nOpcode<=0x7fff) { nDataSize=254; } else if (nOpcode<=0x80ff) { nDataSize=0; } else { sal_uInt32 nTemp; pPict->ReadUInt32( nTemp ) ; nDataSize = nTemp; nDataSize+=4; } } if (nDataSize==0xffffffff) { pPict->SetError(SVSTREAM_FILEFORMAT_ERROR); return 0; } return nDataSize; } void PictReader::ReadPict( SvStream & rStreamPict, GDIMetaFile & rGDIMetaFile ) { try { sal_uInt16 nOpcode; sal_uInt8 nOneByteOpcode; sal_uLong nSize; pPict = &rStreamPict; nOrigPos = pPict->Tell(); SvStreamEndian nOrigNumberFormat = pPict->GetEndian(); aActForeColor = COL_BLACK; aActBackColor = COL_WHITE; nActPenSize = Size(1,1); eActROP = RasterOp::OverPaint; eActMethod = PictDrawingMethod::UNDEFINED; aActOvalSize = Size(1,1); aActFont.SetCharSet( GetTextEncoding()); aActFont.SetFamily(FAMILY_SWISS); aActFont.SetFontSize(Size(0,12)); aActFont.SetAlignment(ALIGN_BASELINE); aHRes = aVRes = Fraction( 1, 1 ); pVirDev = VclPtr::Create(); pVirDev->EnableOutput(false); rGDIMetaFile.Record(pVirDev); pPict->SetEndian(SvStreamEndian::BIG); ReadHeader(); aPenPosition=Point(-aBoundingRect.Left(),-aBoundingRect.Top()); aTextPosition=aPenPosition; sal_uInt64 nPos=pPict->Tell(); for (;;) { if (IsVersion2 ) pPict->ReadUInt16( nOpcode ); else { pPict->ReadUChar( nOneByteOpcode ); nOpcode=static_cast(nOneByteOpcode); } if (pPict->GetError()) break; if (pPict->eof()) { pPict->SetError(SVSTREAM_FILEFORMAT_ERROR); break; } if (nOpcode==0x00ff) break; nSize=ReadData(nOpcode); if ( IsVersion2 ) { if ( nSize & 1 ) nSize++; nPos+=2+nSize; } else nPos+=1+nSize; pPict->Seek(nPos); } pVirDev->SetClipRegion(); rGDIMetaFile.Stop(); pVirDev.disposeAndClear(); rGDIMetaFile.SetPrefMapMode( MapMode( MapUnit::MapInch, Point(), aHRes, aVRes ) ); rGDIMetaFile.SetPrefSize( aBoundingRect.GetSize() ); pPict->SetEndian(nOrigNumberFormat); if (pPict->GetError()) pPict->Seek(nOrigPos); } catch (...) { rStreamPict.SetError(SVSTREAM_FILEFORMAT_ERROR); } } namespace pict { void ReadPictFile(SvStream &rStreamPict, GDIMetaFile& rGDIMetaFile) { PictReader aPictReader; aPictReader.ReadPict(rStreamPict, rGDIMetaFile); } } //================== GraphicImport - the exported function ================ extern "C" SAL_DLLPUBLIC_EXPORT bool iptGraphicImport( SvStream& rIStm, Graphic & rGraphic, FilterConfigItem* ) { GDIMetaFile aMTF; bool bRet = false; pict::ReadPictFile( rIStm, aMTF ); if ( !rIStm.GetError() ) { rGraphic = Graphic( aMTF ); bRet = true; } return bRet; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */