1334 lines
51 KiB
C++
1334 lines
51 KiB
C++
/* -*- 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 .
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <sal/config.h>
|
|
|
|
#include <map>
|
|
#include <list>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <memory>
|
|
#include <string_view>
|
|
#include <vector>
|
|
#include <stack>
|
|
#include <variant>
|
|
|
|
#include <pdf/ResourceDict.hxx>
|
|
#include <pdf/BitmapID.hxx>
|
|
#include <pdf/Matrix3.hxx>
|
|
#include <pdf/PDFEncryptor.hxx>
|
|
|
|
#include <com/sun/star/lang/Locale.hpp>
|
|
#include <com/sun/star/util/XURLTransformer.hpp>
|
|
#include <osl/file.hxx>
|
|
#include <rtl/strbuf.hxx>
|
|
#include <rtl/ustring.hxx>
|
|
#include <tools/gen.hxx>
|
|
#include <vcl/bitmapex.hxx>
|
|
#include <vcl/gradient.hxx>
|
|
#include <vcl/graphictools.hxx>
|
|
#include <vcl/hatch.hxx>
|
|
#include <vcl/virdev.hxx>
|
|
#include <vcl/pdfwriter.hxx>
|
|
#include <vcl/wall.hxx>
|
|
#include <o3tl/safeint.hxx>
|
|
#include <o3tl/typed_flags_set.hxx>
|
|
#include <o3tl/lru_map.hxx>
|
|
#include <comphelper/hash.hxx>
|
|
#include <tools/stream.hxx>
|
|
#include <vcl/BinaryDataContainer.hxx>
|
|
#include <vcl/pdf/PDFNote.hxx>
|
|
|
|
#include <vcl/filter/pdfobjectcontainer.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <pdf/ExternalPDFStreams.hxx>
|
|
#include <pdf/pdfbuildin_fonts.hxx>
|
|
#include <salgdi.hxx>
|
|
|
|
class FontSubsetInfo;
|
|
class ZCodec;
|
|
struct BitStreamState;
|
|
namespace vcl::font { class PhysicalFontFace; }
|
|
class SvStream;
|
|
class SvMemoryStream;
|
|
|
|
namespace vcl::pdf
|
|
{
|
|
|
|
enum class GraphicsStateUpdateFlags {
|
|
Font = 0x0001,
|
|
MapMode = 0x0002,
|
|
LineColor = 0x0004,
|
|
FillColor = 0x0008,
|
|
ClipRegion = 0x0040,
|
|
LayoutMode = 0x0100,
|
|
TransparentPercent = 0x0200,
|
|
DigitLanguage = 0x0400,
|
|
All = 0x077f
|
|
};
|
|
|
|
} // end vcl::pdf
|
|
|
|
namespace o3tl {
|
|
template<> struct typed_flags<vcl::pdf::GraphicsStateUpdateFlags> : is_typed_flags<vcl::pdf::GraphicsStateUpdateFlags, 0x077f> {};
|
|
}
|
|
|
|
namespace vcl
|
|
{
|
|
|
|
using namespace vcl::pdf;
|
|
|
|
class PDFStreamIf;
|
|
|
|
namespace filter
|
|
{
|
|
class PDFObjectElement;
|
|
}
|
|
|
|
namespace pdf
|
|
{
|
|
struct PDFPage
|
|
{
|
|
VclPtr<PDFWriterImpl> m_pWriter;
|
|
double m_nPageWidth; // in inch/72
|
|
double m_nPageHeight; // in inch/72
|
|
/**
|
|
* A positive number that gives the size of default user space units, in multiples of points.
|
|
* Typically 1, larger if page size is > 508 cm.
|
|
*/
|
|
sal_Int32 m_nUserUnit;
|
|
PDFWriter::Orientation m_eOrientation;
|
|
sal_Int32 m_nPageObject;
|
|
std::vector<sal_Int32> m_aStreamObjects;
|
|
sal_Int32 m_nStreamLengthObject;
|
|
sal_uInt64 m_nBeginStreamPos;
|
|
std::vector<sal_Int32> m_aAnnotations;
|
|
std::vector<sal_Int32> m_aMCIDParents;
|
|
PDFWriter::PageTransition m_eTransition;
|
|
sal_uInt32 m_nTransTime;
|
|
|
|
PDFPage( PDFWriterImpl* pWriter, double nPageWidth, double nPageHeight, PDFWriter::Orientation eOrientation );
|
|
|
|
void beginStream();
|
|
void endStream();
|
|
bool emit( sal_Int32 nParentPage );
|
|
|
|
// converts point from ref device coordinates to
|
|
// page coordinates and appends the point to the buffer
|
|
// if pOutPoint is set it will be updated to the emitted point
|
|
// (in PDF map mode, that is 10th of point)
|
|
void appendPoint( const Point& rPoint, OStringBuffer& rBuffer ) const;
|
|
// appends a B2DPoint without further transformation
|
|
void appendPixelPoint( const basegfx::B2DPoint& rPoint, OStringBuffer& rBuffer ) const;
|
|
// appends a rectangle
|
|
void appendRect( const tools::Rectangle& rRect, OStringBuffer& rBuffer ) const;
|
|
// converts a rectangle to 10th points page space
|
|
void convertRect( tools::Rectangle& rRect ) const;
|
|
// appends a polygon optionally closing it
|
|
void appendPolygon( const tools::Polygon& rPoly, OStringBuffer& rBuffer, bool bClose = true ) const;
|
|
// appends a polygon optionally closing it
|
|
void appendPolygon( const basegfx::B2DPolygon& rPoly, OStringBuffer& rBuffer ) const;
|
|
// appends a polypolygon optionally closing the subpaths
|
|
void appendPolyPolygon( const tools::PolyPolygon& rPolyPoly, OStringBuffer& rBuffer ) const;
|
|
// appends a polypolygon optionally closing the subpaths
|
|
void appendPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly, OStringBuffer& rBuffer ) const;
|
|
// converts a length (either vertical or horizontal; this
|
|
// can be important if the source MapMode is not
|
|
// symmetrical) to page length and appends it to the buffer
|
|
// if pOutLength is set it will be updated to the emitted length
|
|
// (in PDF map mode, that is 10th of point)
|
|
void appendMappedLength( sal_Int32 nLength, OStringBuffer& rBuffer, bool bVertical = true, sal_Int32* pOutLength = nullptr ) const;
|
|
// the same for double values
|
|
void appendMappedLength( double fLength, OStringBuffer& rBuffer, bool bVertical = true, sal_Int32 nPrecision = 5 ) const;
|
|
// appends LineInfo
|
|
// returns false if too many dash array entry were created for
|
|
// the implementation limits of some PDF readers
|
|
bool appendLineInfo( const LineInfo& rInfo, OStringBuffer& rBuffer ) const;
|
|
// appends a horizontal waveline with vertical offset (helper for drawWaveLine)
|
|
void appendWaveLine( sal_Int32 nLength, sal_Int32 nYOffset, sal_Int32 nDelta, OStringBuffer& rBuffer ) const;
|
|
|
|
void appendMatrix3(Matrix3 const & rMatrix, OStringBuffer& rBuffer);
|
|
|
|
double getHeight() const;
|
|
};
|
|
|
|
/// Contains information to emit a reference XObject.
|
|
struct ReferenceXObjectEmit
|
|
{
|
|
/// ID of the Form XObject, if any.
|
|
sal_Int32 m_nFormObject;
|
|
/// ID of the vector/embedded object, if m_nFormObject is used.
|
|
sal_Int32 m_nEmbeddedObject;
|
|
/// ID of the bitmap object, if m_nFormObject is used.
|
|
sal_Int32 m_nBitmapObject;
|
|
/// Size of the bitmap replacement, in pixels.
|
|
Size m_aPixelSize;
|
|
/// PDF data from the graphic object, if not writing a reference XObject.
|
|
sal_Int32 m_nExternalPDFDataIndex;
|
|
sal_Int32 m_nExternalPDFPageIndex;
|
|
|
|
ReferenceXObjectEmit()
|
|
: m_nFormObject(0)
|
|
, m_nEmbeddedObject(0)
|
|
, m_nBitmapObject(0)
|
|
, m_nExternalPDFDataIndex(-1)
|
|
, m_nExternalPDFPageIndex(-1)
|
|
{
|
|
}
|
|
|
|
/// Returns the ID one should use when referring to this bitmap.
|
|
sal_Int32 getObject() const;
|
|
|
|
bool hasExternalPDFData() const
|
|
{
|
|
return m_nExternalPDFDataIndex >= 0;
|
|
}
|
|
};
|
|
|
|
struct BitmapEmit
|
|
{
|
|
BitmapID m_aID;
|
|
BitmapEx m_aBitmap;
|
|
sal_Int32 m_nObject;
|
|
ReferenceXObjectEmit m_aReferenceXObject;
|
|
|
|
BitmapEmit()
|
|
: m_nObject(0)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct JPGEmit
|
|
{
|
|
BitmapID m_aID;
|
|
std::unique_ptr<SvMemoryStream>
|
|
m_pStream;
|
|
AlphaMask m_aAlphaMask;
|
|
sal_Int32 m_nObject;
|
|
bool m_bTrueColor;
|
|
ReferenceXObjectEmit m_aReferenceXObject;
|
|
|
|
JPGEmit()
|
|
: m_nObject(0)
|
|
, m_bTrueColor(false)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct GradientEmit
|
|
{
|
|
Gradient m_aGradient;
|
|
Size m_aSize;
|
|
sal_Int32 m_nObject;
|
|
};
|
|
|
|
// for tilings (drawWallpaper, begin/endPattern)
|
|
struct TilingEmit
|
|
{
|
|
sal_Int32 m_nObject;
|
|
tools::Rectangle m_aRectangle;
|
|
Size m_aCellSize;
|
|
SvtGraphicFill::Transform m_aTransform;
|
|
ResourceDict m_aResources;
|
|
std::unique_ptr<SvMemoryStream> m_pTilingStream;
|
|
|
|
TilingEmit()
|
|
: m_nObject( 0 )
|
|
{}
|
|
};
|
|
|
|
// for transparency group XObjects
|
|
struct TransparencyEmit
|
|
{
|
|
sal_Int32 m_nObject;
|
|
sal_Int32 m_nExtGStateObject;
|
|
double m_fAlpha;
|
|
tools::Rectangle m_aBoundRect;
|
|
std::unique_ptr<SvMemoryStream> m_pContentStream;
|
|
|
|
TransparencyEmit()
|
|
: m_nObject( 0 ),
|
|
m_nExtGStateObject( -1 ),
|
|
m_fAlpha( 0.0 )
|
|
{}
|
|
};
|
|
|
|
// font subsets
|
|
|
|
struct ColorLayer
|
|
{
|
|
sal_Int32 m_nFontID;
|
|
sal_uInt8 m_nSubsetGlyphID;
|
|
uint32_t m_nColorIndex;
|
|
};
|
|
|
|
class GlyphEmit
|
|
{
|
|
// performance: actually this should probably a vector;
|
|
std::vector<sal_Ucs> m_CodeUnits;
|
|
sal_uInt8 m_nSubsetGlyphID;
|
|
sal_Int32 m_nGlyphWidth;
|
|
std::vector<ColorLayer> m_aColorLayers;
|
|
font::RawFontData m_aColorBitmap;
|
|
tools::Rectangle m_aRect;
|
|
basegfx::B2DPolyPolygon m_aOutline;
|
|
|
|
public:
|
|
GlyphEmit() : m_nSubsetGlyphID(0), m_nGlyphWidth(0)
|
|
{
|
|
}
|
|
|
|
void setGlyphId( sal_uInt8 i_nId ) { m_nSubsetGlyphID = i_nId; }
|
|
sal_uInt8 getGlyphId() const { return m_nSubsetGlyphID; }
|
|
|
|
void setGlyphWidth( sal_Int32 nWidth ) { m_nGlyphWidth = nWidth; }
|
|
sal_Int32 getGlyphWidth() const { return m_nGlyphWidth; }
|
|
|
|
void addColorLayer(ColorLayer aLayer) { m_aColorLayers.push_back(aLayer); }
|
|
const std::vector<ColorLayer>& getColorLayers() const { return m_aColorLayers; }
|
|
|
|
void setColorBitmap(font::RawFontData aData, tools::Rectangle aRect)
|
|
{
|
|
m_aColorBitmap = aData;
|
|
m_aRect = aRect;
|
|
}
|
|
const font::RawFontData& getColorBitmap(tools::Rectangle& rRect) const
|
|
{
|
|
rRect = m_aRect;
|
|
return m_aColorBitmap;
|
|
}
|
|
|
|
void setOutline(const basegfx::B2DPolyPolygon& rOutline) { m_aOutline = rOutline; }
|
|
const basegfx::B2DPolyPolygon& getOutline() const { return m_aOutline; }
|
|
|
|
void addCode( sal_Ucs i_cCode )
|
|
{
|
|
m_CodeUnits.push_back(i_cCode);
|
|
}
|
|
sal_Int32 countCodes() const { return m_CodeUnits.size(); }
|
|
const std::vector<sal_Ucs>& codes() const { return m_CodeUnits; }
|
|
sal_Ucs getCode( sal_Int32 i_nIndex ) const
|
|
{
|
|
sal_Ucs nRet = 0;
|
|
if (o3tl::make_unsigned(i_nIndex) < m_CodeUnits.size())
|
|
nRet = m_CodeUnits[i_nIndex];
|
|
return nRet;
|
|
}
|
|
};
|
|
|
|
struct FontEmit
|
|
{
|
|
sal_Int32 m_nFontID;
|
|
std::map<sal_GlyphId, GlyphEmit> m_aMapping;
|
|
|
|
explicit FontEmit( sal_Int32 nID ) : m_nFontID( nID ) {}
|
|
};
|
|
|
|
struct Glyph
|
|
{
|
|
sal_Int32 m_nFontID;
|
|
sal_uInt8 m_nSubsetGlyphID;
|
|
};
|
|
|
|
struct FontSubset
|
|
{
|
|
std::vector< FontEmit > m_aSubsets;
|
|
std::map<sal_GlyphId, Glyph> m_aMapping;
|
|
};
|
|
|
|
struct EmbedFont
|
|
{
|
|
sal_Int32 m_nNormalFontID;
|
|
LogicalFontInstance* m_pFontInstance;
|
|
|
|
EmbedFont()
|
|
: m_nNormalFontID(0)
|
|
, m_pFontInstance(nullptr) {}
|
|
};
|
|
|
|
struct PDFDest
|
|
{
|
|
sal_Int32 m_nPage;
|
|
PDFWriter::DestAreaType m_eType;
|
|
tools::Rectangle m_aRect;
|
|
};
|
|
|
|
//--->i56629
|
|
struct PDFNamedDest
|
|
{
|
|
OUString m_aDestName;
|
|
sal_Int32 m_nPage;
|
|
PDFWriter::DestAreaType m_eType;
|
|
tools::Rectangle m_aRect;
|
|
};
|
|
|
|
struct PDFOutlineEntry
|
|
{
|
|
sal_Int32 m_nObject;
|
|
sal_Int32 m_nParentObject;
|
|
sal_Int32 m_nNextObject;
|
|
sal_Int32 m_nPrevObject;
|
|
std::vector< sal_Int32 > m_aChildren;
|
|
OUString m_aTitle;
|
|
sal_Int32 m_nDestID;
|
|
|
|
PDFOutlineEntry()
|
|
: m_nObject( 0 ),
|
|
m_nParentObject( 0 ),
|
|
m_nNextObject( 0 ),
|
|
m_nPrevObject( 0 ),
|
|
m_nDestID( -1 )
|
|
{}
|
|
};
|
|
|
|
struct PDFAnnotation
|
|
{
|
|
sal_Int32 m_nObject;
|
|
tools::Rectangle m_aRect;
|
|
sal_Int32 m_nPage;
|
|
|
|
PDFAnnotation()
|
|
: m_nObject( -1 ),
|
|
m_nPage( -1 )
|
|
{}
|
|
};
|
|
|
|
struct PDFLink : public PDFAnnotation
|
|
{
|
|
sal_Int32 m_nDest; // set to -1 for URL, to a dest else
|
|
OUString m_aURL;
|
|
sal_Int32 m_nStructParent; // struct parent entry
|
|
OUString m_AltText;
|
|
|
|
PDFLink(OUString const& rAltText)
|
|
: m_nDest( -1 ),
|
|
m_nStructParent( -1 )
|
|
, m_AltText(rAltText)
|
|
{}
|
|
};
|
|
|
|
/// A PDF embedded file.
|
|
struct PDFEmbeddedFile
|
|
{
|
|
/// ID of the file.
|
|
sal_Int32 m_nObject;
|
|
OUString m_aSubType;
|
|
/// Contents of the file.
|
|
BinaryDataContainer m_aDataContainer;
|
|
std::unique_ptr<PDFOutputStream> m_pStream;
|
|
|
|
PDFEmbeddedFile()
|
|
: m_nObject(0)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct PDFPopupAnnotation : public PDFAnnotation
|
|
{
|
|
/// ID of the parent object.
|
|
sal_Int32 m_nParentObject;
|
|
};
|
|
|
|
struct PDFNoteEntry : public PDFAnnotation
|
|
{
|
|
vcl::pdf::PDFNote m_aContents;
|
|
|
|
PDFPopupAnnotation m_aPopUpAnnotation;
|
|
|
|
sal_Int32 m_nStructParent;
|
|
|
|
PDFNoteEntry()
|
|
: m_nStructParent(-1)
|
|
{}
|
|
};
|
|
|
|
/// A PDF Screen annotation.
|
|
struct PDFScreen : public PDFAnnotation
|
|
{
|
|
/// Linked video.
|
|
OUString m_aURL;
|
|
/// Embedded video.
|
|
OUString m_aTempFileURL;
|
|
/// ID of the EmbeddedFile object.
|
|
sal_Int32 m_nTempFileObject;
|
|
/// alternative text description
|
|
OUString m_AltText;
|
|
sal_Int32 m_nStructParent;
|
|
OUString m_MimeType;
|
|
|
|
PDFScreen(OUString const& rAltText, OUString const& rMimeType)
|
|
: m_nTempFileObject(0)
|
|
, m_AltText(rAltText)
|
|
, m_nStructParent(-1)
|
|
, m_MimeType(rMimeType)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct PDFWidgetCopy
|
|
{
|
|
sal_Int32 m_nObject = -1;
|
|
};
|
|
|
|
struct PDFWidget : public PDFAnnotation
|
|
{
|
|
PDFWriter::WidgetType m_eType;
|
|
OString m_aName;
|
|
OUString m_aDescription;
|
|
OUString m_aText;
|
|
DrawTextFlags m_nTextStyle;
|
|
OUString m_aValue;
|
|
OString m_aDAString;
|
|
OString m_aDRDict;
|
|
OString m_aMKDict;
|
|
OString m_aMKDictCAString; // i12626, added to be able to encrypt the /CA text string
|
|
// since the object number is not known at the moment
|
|
// of filling m_aMKDict, the string will be encrypted when emitted.
|
|
// the /CA string MUST BE the last added to m_aMKDict
|
|
// see code for details
|
|
sal_Int32 m_nFlags;
|
|
sal_Int32 m_nParent; // if not 0, parent's object number
|
|
std::vector<sal_Int32> m_aKids; // widget children, contains object numbers
|
|
std::vector<sal_Int32> m_aKidsIndex; // widget children, contains index to m_aWidgets
|
|
OUString m_aOnValue;
|
|
OUString m_aOffValue;
|
|
sal_Int32 m_nTabOrder; // lowest number gets first in tab order
|
|
sal_Int32 m_nRadioGroup;
|
|
sal_Int32 m_nMaxLen;
|
|
PDFWriter::FormatType m_nFormat;
|
|
OUString m_aCurrencySymbol;
|
|
sal_Int32 m_nDecimalAccuracy;
|
|
bool m_bPrependCurrencySymbol;
|
|
OUString m_aTimeFormat;
|
|
OUString m_aDateFormat;
|
|
bool m_bSubmit;
|
|
bool m_bSubmitGet;
|
|
sal_Int32 m_nDest;
|
|
std::vector<OUString> m_aListEntries;
|
|
std::vector<sal_Int32> m_aSelectedEntries;
|
|
typedef std::unordered_map<OString, SvMemoryStream*> PDFAppearanceStreams;
|
|
std::unordered_map<OString, PDFAppearanceStreams> m_aAppearances;
|
|
sal_Int32 m_nStructParent = -1;
|
|
|
|
PDFWidget()
|
|
: m_eType( PDFWriter::PushButton ),
|
|
m_nTextStyle( DrawTextFlags::NONE ),
|
|
m_nFlags( 0 ),
|
|
m_nParent( 0 ),
|
|
m_nTabOrder( 0 ),
|
|
m_nRadioGroup( -1 ),
|
|
m_nMaxLen( 0 ),
|
|
m_nFormat( PDFWriter::FormatType::Text ),
|
|
m_nDecimalAccuracy ( 0 ),
|
|
m_bPrependCurrencySymbol( false ),
|
|
m_bSubmit( false ),
|
|
m_bSubmitGet( false ),
|
|
m_nDest( -1 )
|
|
{}
|
|
};
|
|
|
|
struct PDFStructureAttribute
|
|
{
|
|
PDFWriter::StructAttributeValue eValue;
|
|
sal_Int32 nValue;
|
|
|
|
PDFStructureAttribute()
|
|
: eValue( PDFWriter::Invalid ),
|
|
nValue( 0 )
|
|
{}
|
|
|
|
explicit PDFStructureAttribute( PDFWriter::StructAttributeValue eVal )
|
|
: eValue( eVal ),
|
|
nValue( 0 )
|
|
{}
|
|
|
|
explicit PDFStructureAttribute( sal_Int32 nVal )
|
|
: eValue( PDFWriter::Invalid ),
|
|
nValue( nVal )
|
|
{}
|
|
};
|
|
|
|
struct ObjReference { sal_Int32 const nObject; };
|
|
struct ObjReferenceObj { sal_Int32 const nObject; };
|
|
struct MCIDReference { sal_Int32 const nPageObj; sal_Int32 const nMCID; };
|
|
typedef ::std::variant<ObjReference, ObjReferenceObj, MCIDReference> PDFStructureElementKid;
|
|
|
|
struct PDFStructureElement
|
|
{
|
|
sal_Int32 m_nObject;
|
|
::std::optional<PDFWriter::StructElement> m_oType;
|
|
OString m_aAlias;
|
|
sal_Int32 m_nOwnElement; // index into structure vector
|
|
sal_Int32 m_nParentElement; // index into structure vector
|
|
sal_Int32 m_nFirstPageObject;
|
|
bool m_bOpenMCSeq;
|
|
std::vector< sal_Int32 > m_aChildren; // indexes into structure vector
|
|
std::list< PDFStructureElementKid > m_aKids;
|
|
std::map<PDFWriter::StructAttribute, PDFStructureAttribute >
|
|
m_aAttributes;
|
|
::std::vector<sal_Int32> m_AnnotIds;
|
|
tools::Rectangle m_aBBox;
|
|
OUString m_aActualText;
|
|
OUString m_aAltText;
|
|
css::lang::Locale m_aLocale;
|
|
|
|
// m_aContents contains the element's marked content sequence
|
|
// as pairs of (page nr, MCID)
|
|
|
|
PDFStructureElement()
|
|
: m_nObject( 0 ),
|
|
m_nOwnElement( -1 ),
|
|
m_nParentElement( -1 ),
|
|
m_nFirstPageObject( 0 ),
|
|
m_bOpenMCSeq( false )
|
|
{
|
|
}
|
|
|
|
PDFStructureElement(sal_Int32 nOwnElement, sal_Int32 nParentElement, sal_Int32 nFirstPageObject)
|
|
: m_nObject(0)
|
|
, m_nOwnElement(nOwnElement)
|
|
, m_nParentElement(nParentElement)
|
|
, m_nFirstPageObject(nFirstPageObject)
|
|
, m_bOpenMCSeq(false )
|
|
{
|
|
}
|
|
};
|
|
|
|
// helper structure for drawLayout and friends
|
|
struct PDFGlyph
|
|
{
|
|
basegfx::B2DPoint const m_aPos;
|
|
const GlyphItem* m_pGlyph;
|
|
const LogicalFontInstance* m_pFont;
|
|
sal_Int32 const m_nNativeWidth;
|
|
sal_Int32 const m_nMappedFontId;
|
|
sal_uInt8 const m_nMappedGlyphId;
|
|
int const m_nCharPos;
|
|
|
|
PDFGlyph( const basegfx::B2DPoint& rPos,
|
|
const GlyphItem* pGlyph,
|
|
const LogicalFontInstance* pFont,
|
|
sal_Int32 nNativeWidth,
|
|
sal_Int32 nFontId,
|
|
sal_uInt8 nMappedGlyphId,
|
|
int nCharPos )
|
|
: m_aPos( rPos ), m_pGlyph(pGlyph), m_pFont(pFont), m_nNativeWidth( nNativeWidth ),
|
|
m_nMappedFontId( nFontId ), m_nMappedGlyphId( nMappedGlyphId ),
|
|
m_nCharPos(nCharPos)
|
|
{}
|
|
};
|
|
|
|
struct StreamRedirect
|
|
{
|
|
SvStream* m_pStream;
|
|
MapMode m_aMapMode;
|
|
tools::Rectangle m_aTargetRect;
|
|
ResourceDict m_aResourceDict;
|
|
};
|
|
|
|
// graphics state
|
|
struct GraphicsState
|
|
{
|
|
vcl::Font m_aFont;
|
|
MapMode m_aMapMode;
|
|
Color m_aLineColor;
|
|
Color m_aFillColor;
|
|
Color m_aTextLineColor;
|
|
Color m_aOverlineColor;
|
|
basegfx::B2DPolyPolygon m_aClipRegion;
|
|
bool m_bClipRegion;
|
|
vcl::text::ComplexTextLayoutFlags m_nLayoutMode;
|
|
LanguageType m_aDigitLanguage;
|
|
PushFlags m_nFlags;
|
|
GraphicsStateUpdateFlags m_nUpdateFlags;
|
|
|
|
GraphicsState() :
|
|
m_aLineColor( COL_TRANSPARENT ),
|
|
m_aFillColor( COL_TRANSPARENT ),
|
|
m_aTextLineColor( COL_TRANSPARENT ),
|
|
m_aOverlineColor( COL_TRANSPARENT ),
|
|
m_bClipRegion( false ),
|
|
m_nLayoutMode( vcl::text::ComplexTextLayoutFlags::Default ),
|
|
m_aDigitLanguage( 0 ),
|
|
m_nFlags( PushFlags::ALL ),
|
|
m_nUpdateFlags( GraphicsStateUpdateFlags::All )
|
|
{}
|
|
};
|
|
|
|
enum class Mode { DEFAULT, NOWRITE };
|
|
|
|
struct PDFDocumentAttachedFile
|
|
{
|
|
OUString maFilename;
|
|
OUString maMimeType;
|
|
OUString maDescription;
|
|
sal_Int32 mnEmbeddedFileObjectId;
|
|
sal_Int32 mnObjectId;
|
|
};
|
|
|
|
} // end pdf namespace
|
|
|
|
class PDFWriterImpl final : public VirtualDevice, public PDFObjectContainer
|
|
{
|
|
friend class PDFStreamIf;
|
|
|
|
public:
|
|
friend struct vcl::pdf::PDFPage;
|
|
|
|
const char* getStructureTag( PDFWriter::StructElement );
|
|
static const char* getAttributeTag( PDFWriter::StructAttribute eAtr );
|
|
static const char* getAttributeValueTag( PDFWriter::StructAttributeValue eVal );
|
|
|
|
// returns true if compression was done
|
|
// else false
|
|
static bool compressStream( SvMemoryStream* );
|
|
|
|
static void convertLineInfoToExtLineInfo( const LineInfo& rIn, PDFWriter::ExtLineInfo& rOut );
|
|
|
|
private:
|
|
bool ImplNewFont() const override;
|
|
void ImplClearFontData(bool bNewFontLists) override;
|
|
void ImplRefreshFontData(bool bNewFontLists) override;
|
|
vcl::Region ClipToDeviceBounds(vcl::Region aRegion) const override;
|
|
void DrawHatchLine_DrawLine(const Point& rStartPoint, const Point& rEndPoint) override;
|
|
|
|
MapMode m_aMapMode; // PDFWriterImpl scaled units
|
|
StyleSettings m_aWidgetStyleSettings;
|
|
std::vector< PDFPage > m_aPages;
|
|
/* maps object numbers to file offsets (needed for xref) */
|
|
std::vector< sal_uInt64 > m_aObjects;
|
|
/* contains Bitmaps until they are written to the
|
|
* file stream as XObjects*/
|
|
std::list< BitmapEmit > m_aBitmaps;
|
|
/* contains JPG streams until written to file */
|
|
std::vector<JPGEmit> m_aJPGs;
|
|
/*--->i56629 contains all named destinations ever set during the PDF creation,
|
|
destination id is always the destination's position in this vector
|
|
*/
|
|
std::vector<PDFNamedDest> m_aNamedDests;
|
|
/* contains all dests ever set during the PDF creation,
|
|
dest id is always the dest's position in this vector
|
|
*/
|
|
std::vector<PDFDest> m_aDests;
|
|
/** contains destinations accessible via a public Id, instead of being linked to by an ordinary link
|
|
*/
|
|
::std::map< sal_Int32, sal_Int32 > m_aDestinationIdTranslation;
|
|
/* contains all links ever set during PDF creation,
|
|
link id is always the link's position in this vector
|
|
*/
|
|
std::vector<PDFLink> m_aLinks;
|
|
/// Contains all screen annotations.
|
|
std::vector<PDFScreen> m_aScreens;
|
|
/// Contains embedded files.
|
|
std::vector<PDFEmbeddedFile> m_aEmbeddedFiles;
|
|
|
|
std::vector<PDFDocumentAttachedFile> m_aDocumentAttachedFiles;
|
|
|
|
/* makes correctly encoded for export to PDF URLS
|
|
*/
|
|
css::uno::Reference< css::util::XURLTransformer > m_xTrans;
|
|
/* maps arbitrary link ids for structure attributes to real link ids
|
|
(for setLinkPropertyId)
|
|
*/
|
|
std::map<sal_Int32, sal_Int32> m_aLinkPropertyMap;
|
|
/* contains all outline items,
|
|
object 0 is the outline root
|
|
*/
|
|
std::vector<PDFOutlineEntry> m_aOutline;
|
|
/* contains all notes set during PDF creation
|
|
*/
|
|
std::vector<PDFNoteEntry> m_aNotes;
|
|
/* the root of the structure tree
|
|
*/
|
|
std::vector<PDFStructureElement> m_aStructure;
|
|
/* current object in the structure hierarchy
|
|
*/
|
|
sal_Int32 m_nCurrentStructElement;
|
|
std::stack<sal_Int32> m_StructElementStack;
|
|
/* structure parent tree */
|
|
std::vector< OString > m_aStructParentTree;
|
|
/* emit structure marks currently (aka. NonStructElement or not)
|
|
*/
|
|
bool m_bEmitStructure;
|
|
/* role map of struct tree root */
|
|
std::unordered_map< OString, OString >
|
|
m_aRoleMap;
|
|
/* structure elements (object ids) that should have ID */
|
|
std::unordered_set<sal_Int32> m_StructElemObjsWithID;
|
|
|
|
/* contains all widgets used in the PDF */
|
|
std::vector<PDFWidget> m_aWidgets;
|
|
std::vector<PDFWidgetCopy> m_aCopiedWidgets;
|
|
|
|
/* maps radio group id to index of radio group control in m_aWidgets */
|
|
std::map< sal_Int32, sal_Int32 > m_aRadioGroupWidgets;
|
|
/* unordered_map for field names, used to ensure unique field names */
|
|
std::unordered_map< OString, sal_Int32 > m_aFieldNameMap;
|
|
|
|
/* contains Bitmaps for gradient functions until they are written
|
|
* to the file stream */
|
|
std::list< GradientEmit > m_aGradients;
|
|
/* contains bitmap tiling patterns */
|
|
std::vector< TilingEmit > m_aTilings;
|
|
std::vector< TransparencyEmit > m_aTransparentObjects;
|
|
/* contains all font subsets in use */
|
|
std::map<const vcl::font::PhysicalFontFace*, FontSubset> m_aSubsets;
|
|
std::map<const vcl::font::PhysicalFontFace*, EmbedFont> m_aSystemFonts;
|
|
std::map<const vcl::font::PhysicalFontFace*, FontSubset> m_aType3Fonts;
|
|
sal_Int32 m_nNextFID;
|
|
|
|
/// Cache some most recent bitmaps we've exported, in case we encounter them again..
|
|
o3tl::lru_map<BitmapChecksum,
|
|
std::shared_ptr<SvMemoryStream>> m_aPDFBmpCache;
|
|
|
|
sal_Int32 m_nCurrentPage;
|
|
|
|
sal_Int32 m_nCatalogObject;
|
|
// object number of the main signature dictionary
|
|
sal_Int32 m_nSignatureObject;
|
|
sal_Int64 m_nSignatureContentOffset;
|
|
sal_Int64 m_nSignatureLastByteRangeNoOffset;
|
|
sal_Int32 m_nResourceDict;
|
|
ResourceDict m_aGlobalResourceDict;
|
|
sal_Int32 m_nFontDictObject;
|
|
std::map< sal_Int32, sal_Int32 > m_aBuildinFontToObjectMap;
|
|
|
|
PDFWriter::PDFWriterContext m_aContext;
|
|
osl::File m_aFile;
|
|
bool m_bOpen;
|
|
|
|
ExternalPDFStreams m_aExternalPDFStreams;
|
|
|
|
std::unique_ptr<IPDFEncryptor> m_pPDFEncryptor;
|
|
|
|
/* output redirection; e.g. to accumulate content streams for
|
|
XObjects
|
|
*/
|
|
std::list< StreamRedirect > m_aOutputStreams;
|
|
|
|
std::list< GraphicsState > m_aGraphicsStack;
|
|
GraphicsState m_aCurrentPDFState;
|
|
|
|
std::unique_ptr<ZCodec> m_pCodec;
|
|
std::unique_ptr<SvMemoryStream> m_pMemStream;
|
|
|
|
std::set< PDFWriter::ErrorCode > m_aErrors;
|
|
|
|
::comphelper::Hash m_DocDigest;
|
|
|
|
// reduce repeated allocations
|
|
OStringBuffer updateGraphicsStateLine{256};
|
|
OStringBuffer drawBitmapLine{80};
|
|
|
|
sal_uInt64 getCurrentFilePosition()
|
|
{
|
|
sal_uInt64 nPosition{};
|
|
if (osl::File::E_None != m_aFile.getPos(nPosition))
|
|
{
|
|
m_aFile.close();
|
|
m_bOpen = false;
|
|
}
|
|
return nPosition;
|
|
}
|
|
|
|
/* string to hold the PDF creation date */
|
|
OString m_aCreationDateString;
|
|
/* string to hold the PDF creation date, for PDF/A metadata */
|
|
OString m_aCreationMetaDateString;
|
|
/* the buffer where the data are encrypted, dynamically allocated */
|
|
std::vector<sal_uInt8> m_vEncryptionBuffer;
|
|
|
|
void addRoleMap(const OString& aAlias, PDFWriter::StructElement eType);
|
|
|
|
void checkAndEnableStreamEncryption( sal_Int32 nObject ) override;
|
|
|
|
void disableStreamEncryption() override;
|
|
|
|
/* */
|
|
void enableStringEncryption( sal_Int32 nObject );
|
|
|
|
public: // Temporary for PDFStructureWriter
|
|
// test if the encryption is active, if yes than encrypt the unicode string and add to the OStringBuffer parameter
|
|
void appendUnicodeTextStringEncrypt( const OUString& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer );
|
|
|
|
void appendLiteralStringEncrypt( std::u16string_view rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer, rtl_TextEncoding nEnc = RTL_TEXTENCODING_ASCII_US );
|
|
void appendLiteralStringEncrypt( std::string_view rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer );
|
|
|
|
private:
|
|
/* creates fonts and subsets that will be emitted later */
|
|
void registerGlyph(const sal_GlyphId, const vcl::font::PhysicalFontFace*, const LogicalFontInstance* pFont, const std::vector<sal_Ucs>&, sal_Int32, sal_uInt8&, sal_Int32&);
|
|
void registerSimpleGlyph(const sal_GlyphId, const vcl::font::PhysicalFontFace*, const std::vector<sal_Ucs>&, sal_Int32, sal_uInt8&, sal_Int32&);
|
|
|
|
/* emits a text object according to the passed layout */
|
|
/* TODO: remove rText as soon as SalLayout will change so that rText is not necessary anymore */
|
|
void drawVerticalGlyphs( const std::vector<PDFGlyph>& rGlyphs, OStringBuffer& rLine, const Point& rAlignOffset, const Matrix3& rRotScale, double fAngle, double fXScale, sal_Int32 nFontHeight );
|
|
void drawHorizontalGlyphs( const std::vector<PDFGlyph>& rGlyphs, OStringBuffer& rLine, const Point& rAlignOffset, bool bFirst, double fAngle, double fXScale, sal_Int32 nFontHeight, sal_Int32 nPixelFontHeight );
|
|
void drawLayout( SalLayout& rLayout, const OUString& rText, bool bTextLines );
|
|
void drawRelief( SalLayout& rLayout, const OUString& rText, bool bTextLines );
|
|
void drawShadow( SalLayout& rLayout, const OUString& rText, bool bTextLines );
|
|
|
|
/* writes differences between graphics stack and current real PDF
|
|
* state to the file
|
|
*/
|
|
void updateGraphicsState(Mode mode = Mode::DEFAULT);
|
|
|
|
/* writes a transparency group object */
|
|
void writeTransparentObject( TransparencyEmit& rObject );
|
|
|
|
/* writes an XObject of type image, may create
|
|
a second for the mask
|
|
*/
|
|
bool writeBitmapObject( const BitmapEmit& rObject, bool bMask = false );
|
|
|
|
void writeJPG( const JPGEmit& rEmit );
|
|
/// Writes the form XObject proxy for the image.
|
|
void writeReferenceXObject(const ReferenceXObjectEmit& rEmit);
|
|
|
|
void mergeAnnotationsFromExternalPage(filter::PDFObjectElement* pPage, std::map<sal_Int32, sal_Int32>& rCopiedResourcesMap);
|
|
|
|
/* tries to find the bitmap by its id and returns its emit data if exists,
|
|
else creates a new emit data block */
|
|
const BitmapEmit& createBitmapEmit( const BitmapEx& rBitmapEx, const Graphic& rGraphic, std::list<BitmapEmit>& rBitmaps, ResourceDict& rResourceDict, std::list<StreamRedirect>& rOutputStreams );
|
|
const BitmapEmit& createBitmapEmit( const BitmapEx& rBitmapEx, const Graphic& rGraphic );
|
|
|
|
/* writes the Do operation inside the content stream */
|
|
void drawBitmap( const Point& rDestPt, const Size& rDestSize, const BitmapEmit& rBitmap, const Color& rFillColor );
|
|
/* write the function object for a Gradient */
|
|
bool writeGradientFunction( GradientEmit const & rObject );
|
|
/* creates a GradientEmit and returns its object number */
|
|
sal_Int32 createGradient( const Gradient& rGradient, const Size& rSize );
|
|
|
|
/* writes all tilings */
|
|
bool emitTilings();
|
|
/* writes all gradient patterns */
|
|
bool emitGradients();
|
|
/* writes a builtin font object and returns its objectid (or 0 in case of failure ) */
|
|
sal_Int32 emitBuildinFont( const pdf::BuildinFontFace*, sal_Int32 nObject );
|
|
/* writes a type1 system font object and returns its mapping from font ids to object ids (or 0 in case of failure ) */
|
|
std::map< sal_Int32, sal_Int32 > emitSystemFont(const vcl::font::PhysicalFontFace*, EmbedFont const &);
|
|
/* writes a type3 font object and appends it to the font id mapping, or returns false in case of failure */
|
|
bool emitType3Font(const vcl::font::PhysicalFontFace*, const FontSubset&, std::map<sal_Int32, sal_Int32>&);
|
|
/* writes a font descriptor and returns its object id (or 0) */
|
|
sal_Int32 emitFontDescriptor(const vcl::font::PhysicalFontFace*, FontSubsetInfo const &, sal_Int32 nSubsetID, sal_Int32 nStream);
|
|
/* writes a ToUnicode cmap, returns the corresponding stream object */
|
|
sal_Int32 createToUnicodeCMap( sal_uInt8 const * pEncoding, const std::vector<sal_Ucs>& CodeUnits, const sal_Int32* pCodeUnitsPerGlyph,
|
|
const sal_Int32* pEncToUnicodeIndex, uint32_t nGlyphs );
|
|
|
|
/* get resource dict object number */
|
|
sal_Int32 getResourceDictObj()
|
|
{
|
|
if( m_nResourceDict <= 0 )
|
|
m_nResourceDict = createObject();
|
|
return m_nResourceDict;
|
|
}
|
|
/* get the font dict object */
|
|
sal_Int32 getFontDictObject()
|
|
{
|
|
if( m_nFontDictObject <= 0 )
|
|
m_nFontDictObject = createObject();
|
|
return m_nFontDictObject;
|
|
}
|
|
/* push resource into current (redirected) resource dict */
|
|
static void pushResource( ResourceKind eKind, const OString& rResource, sal_Int32 nObject, ResourceDict& rResourceDict, std::list<StreamRedirect>& rOutputStreams );
|
|
void pushResource( ResourceKind eKind, const OString& rResource, sal_Int32 nObject );
|
|
|
|
void appendBuildinFontsToDict( OStringBuffer& rDict ) const;
|
|
/* writes the font dictionary and emits all font objects
|
|
* returns object id of font directory (or 0 on error)
|
|
*/
|
|
bool emitFonts();
|
|
/* writes the Resource dictionary;
|
|
* returns dict object id (or 0 on error)
|
|
*/
|
|
sal_Int32 emitResources();
|
|
// appends a dest
|
|
bool appendDest( sal_Int32 nDestID, OStringBuffer& rBuffer );
|
|
// write all links
|
|
bool emitLinkAnnotations();
|
|
// Write all screen annotations.
|
|
bool emitScreenAnnotations();
|
|
|
|
void emitTextAnnotationLine(OStringBuffer & aLine, PDFNoteEntry const & rNote);
|
|
static void emitPopupAnnotationLine(OStringBuffer & aLine, PDFPopupAnnotation const & rPopUp);
|
|
// write all notes
|
|
bool emitNoteAnnotations();
|
|
|
|
// write the appearance streams of a widget
|
|
bool emitAppearances( PDFWidget& rWidget, OStringBuffer& rAnnotDict );
|
|
// clean up radio button "On" values
|
|
void ensureUniqueRadioOnValues();
|
|
// write all widgets
|
|
bool emitWidgetAnnotations();
|
|
// writes all annotation objects
|
|
bool emitAnnotations();
|
|
/// Writes embedded files.
|
|
bool emitEmbeddedFiles();
|
|
//write the named destination stuff
|
|
sal_Int32 emitNamedDestinations();//i56629
|
|
// writes outline dict and tree
|
|
sal_Int32 emitOutline();
|
|
template<typename T> void AppendAnnotKid(PDFStructureElement& i_rEle, T & rAnnot);
|
|
// puts the attribute objects of a structure element into the returned string,
|
|
// helper for emitStructure
|
|
OString emitStructureAttributes( PDFStructureElement& rEle );
|
|
//--->i94258
|
|
// the maximum array elements allowed for PDF array object
|
|
static const sal_uInt32 ncMaxPDFArraySize = 8191;
|
|
//check if internal dummy container are needed in the structure elements
|
|
void addInternalStructureContainer( PDFStructureElement& rEle );
|
|
//<---i94258
|
|
// writes document structure
|
|
sal_Int32 emitStructure( PDFStructureElement& rEle );
|
|
// writes structure parent tree
|
|
sal_Int32 emitStructParentTree( sal_Int32 nTreeObject );
|
|
// writes structure IDTree
|
|
sal_Int32 emitStructIDTree(sal_Int32 nTreeObject);
|
|
// writes page tree and catalog
|
|
bool emitCatalog();
|
|
// writes signature dictionary object
|
|
bool emitSignature();
|
|
// creates a PKCS7 object using the ByteRange and overwrite /Contents
|
|
// of the signature dictionary
|
|
bool finalizeSignature();
|
|
//writes encrypt
|
|
sal_Int32 emitEncrypt();
|
|
// writes xref and trailer
|
|
bool emitTrailer();
|
|
// emits info dict (if applicable)
|
|
sal_Int32 emitInfoDict( );
|
|
|
|
// acrobat reader 5 and 6 use the order of the annotations
|
|
// as their tab order; since PDF1.5 one can make the
|
|
// tab order explicit by using the structure tree
|
|
void sortWidgets();
|
|
|
|
// updates the count numbers of outline items
|
|
sal_Int32 updateOutlineItemCount( std::vector< sal_Int32 >& rCounts,
|
|
sal_Int32 nItemLevel,
|
|
sal_Int32 nCurrentItemId );
|
|
// default appearances for widgets
|
|
sal_Int32 findRadioGroupWidget( const PDFWriter::RadioButtonWidget& rRadio );
|
|
Font replaceFont( const Font& rControlFont, const Font& rAppSetFont );
|
|
sal_Int32 getBestBuildinFont( const Font& rFont );
|
|
sal_Int32 getSystemFont( const Font& i_rFont );
|
|
|
|
// used for edit and listbox
|
|
Font drawFieldBorder( PDFWidget&, const PDFWriter::AnyWidget&, const StyleSettings& );
|
|
|
|
void createDefaultPushButtonAppearance( PDFWidget&, const PDFWriter::PushButtonWidget& rWidget );
|
|
void createDefaultCheckBoxAppearance( PDFWidget&, const PDFWriter::CheckBoxWidget& rWidget );
|
|
void createDefaultRadioButtonAppearance( PDFWidget&, const PDFWriter::RadioButtonWidget& rWidget );
|
|
void createDefaultEditAppearance( PDFWidget&, const PDFWriter::EditWidget& rWidget );
|
|
void createDefaultListBoxAppearance( PDFWidget&, const PDFWriter::ListBoxWidget& rWidget );
|
|
|
|
/* ensure proper escapement and uniqueness of field names */
|
|
void createWidgetFieldName( sal_Int32 i_nWidgetsIndex, const PDFWriter::AnyWidget& i_rInWidget );
|
|
/// See vcl::PDFObjectContainer::createObject().
|
|
sal_Int32 createObject() override;
|
|
/// See vcl::PDFObjectContainer::updateObject().
|
|
bool updateObject( sal_Int32 n ) override;
|
|
|
|
/// See vcl::PDFObjectContainer::writeBuffer().
|
|
bool writeBufferBytes( const void* pBuffer, sal_uInt64 nBytes ) override;
|
|
void beginCompression();
|
|
void endCompression();
|
|
void beginRedirect( SvStream* pStream, const tools::Rectangle& );
|
|
SvStream* endRedirect();
|
|
|
|
void endPage();
|
|
|
|
void beginStructureElementMCSeq();
|
|
enum class EndMode { Default, OnlyStruct };
|
|
void endStructureElementMCSeq(EndMode = EndMode::Default);
|
|
/** checks whether a non struct element lies in the ancestor hierarchy
|
|
of the current structure element
|
|
|
|
@returns
|
|
true if no NonStructElement was found in ancestor path and tagged
|
|
PDF output is enabled
|
|
false else
|
|
*/
|
|
bool checkEmitStructure();
|
|
|
|
/* draws an emphasis mark */
|
|
void drawEmphasisMark( tools::Long nX, tools::Long nY, const tools::PolyPolygon& rPolyPoly, bool bPolyLine, const tools::Rectangle& rRect1, const tools::Rectangle& rRect2 );
|
|
|
|
/* true if PDF/A-1a or PDF/A-1b is output */
|
|
bool m_bIsPDF_A1 = false;
|
|
/* true if PDF/A-2a is output */
|
|
bool m_bIsPDF_A2 = false;
|
|
/* true if PDF/A-3 is output */
|
|
bool m_bIsPDF_A3 = false;
|
|
/* true if PDF/A-4 is output */
|
|
bool m_bIsPDF_A4 = false;
|
|
|
|
sal_Int32 m_nPDFA_Version = 0;
|
|
|
|
/* PDF/UA support enabled */
|
|
bool m_bIsPDF_UA = false;
|
|
|
|
PDFWriter& m_rOuterFace;
|
|
|
|
/*
|
|
i12626
|
|
methods for PDF security
|
|
|
|
pad a password according algorithm 3.2, step 1 */
|
|
void setupDocInfo();
|
|
|
|
// helper for playMetafile
|
|
void implWriteGradient( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient,
|
|
VirtualDevice* pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& );
|
|
void implWriteBitmapEx( const Point& rPoint, const Size& rSize, const BitmapEx& rBitmapEx, const Graphic& i_pGraphic,
|
|
VirtualDevice const * pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& );
|
|
|
|
// helpers for CCITT 1bit bitmap stream
|
|
void putG4Bits( sal_uInt32 i_nLength, sal_uInt32 i_nCode, BitStreamState& io_rState );
|
|
void putG4Span( tools::Long i_nSpan, bool i_bWhitePixel, BitStreamState& io_rState );
|
|
void writeG4Stream( BitmapReadAccess const * i_pBitmap );
|
|
|
|
// color helper functions
|
|
void appendStrokingColor( const Color& rColor, OStringBuffer& rBuffer );
|
|
void appendNonStrokingColor( const Color& rColor, OStringBuffer& rBuffer );
|
|
public:
|
|
PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, const css::uno::Reference< css::beans::XMaterialHolder >&, PDFWriter& );
|
|
~PDFWriterImpl() override;
|
|
void dispose() override;
|
|
|
|
/* document structure */
|
|
void newPage( double nPageWidth , double nPageHeight, PDFWriter::Orientation eOrientation );
|
|
bool emit();
|
|
const std::set< PDFWriter::ErrorCode > & getErrors() const { return m_aErrors;}
|
|
void insertError( PDFWriter::ErrorCode eErr ) { m_aErrors.insert( eErr ); }
|
|
void playMetafile( const GDIMetaFile&, vcl::PDFExtOutDevData*, const vcl::PDFWriter::PlayMetafileContext&, VirtualDevice* pDummyDev = nullptr );
|
|
|
|
Size getCurPageSize() const
|
|
{
|
|
Size aSize;
|
|
if( m_nCurrentPage >= 0 && o3tl::make_unsigned(m_nCurrentPage) < m_aPages.size() )
|
|
aSize = Size( m_aPages[ m_nCurrentPage ].m_nPageWidth, m_aPages[ m_nCurrentPage ].m_nPageHeight );
|
|
return aSize;
|
|
}
|
|
|
|
void setDocumentLocale( const css::lang::Locale& rLoc )
|
|
{ m_aContext.DocumentLocale = rLoc; }
|
|
|
|
/* graphics state */
|
|
void push( PushFlags nFlags );
|
|
void pop();
|
|
|
|
void setFont( const Font& rFont );
|
|
|
|
void setMapMode( const MapMode& rMapMode );
|
|
|
|
const MapMode& getMapMode() { return m_aGraphicsStack.front().m_aMapMode; }
|
|
|
|
void setLineColor( const Color& rColor )
|
|
{
|
|
m_aGraphicsStack.front().m_aLineColor = rColor.IsTransparent() ? COL_TRANSPARENT : rColor;
|
|
m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::LineColor;
|
|
}
|
|
|
|
void setFillColor( const Color& rColor )
|
|
{
|
|
m_aGraphicsStack.front().m_aFillColor = rColor.IsTransparent() ? COL_TRANSPARENT : rColor;
|
|
m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::FillColor;
|
|
}
|
|
|
|
void setTextLineColor()
|
|
{
|
|
m_aGraphicsStack.front().m_aTextLineColor = COL_TRANSPARENT;
|
|
}
|
|
|
|
void setTextLineColor( const Color& rColor )
|
|
{
|
|
m_aGraphicsStack.front().m_aTextLineColor = rColor;
|
|
}
|
|
|
|
void setOverlineColor()
|
|
{
|
|
m_aGraphicsStack.front().m_aOverlineColor = COL_TRANSPARENT;
|
|
}
|
|
|
|
void setOverlineColor( const Color& rColor )
|
|
{
|
|
m_aGraphicsStack.front().m_aOverlineColor = rColor;
|
|
}
|
|
|
|
void setTextFillColor( const Color& rColor )
|
|
{
|
|
m_aGraphicsStack.front().m_aFont.SetFillColor( rColor );
|
|
m_aGraphicsStack.front().m_aFont.SetTransparent( rColor.IsTransparent() );
|
|
m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::Font;
|
|
}
|
|
void setTextFillColor()
|
|
{
|
|
m_aGraphicsStack.front().m_aFont.SetFillColor( COL_TRANSPARENT );
|
|
m_aGraphicsStack.front().m_aFont.SetTransparent( true );
|
|
m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::Font;
|
|
}
|
|
void setTextColor( const Color& rColor )
|
|
{
|
|
m_aGraphicsStack.front().m_aFont.SetColor( rColor );
|
|
m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::Font;
|
|
}
|
|
|
|
void clearClipRegion()
|
|
{
|
|
m_aGraphicsStack.front().m_aClipRegion.clear();
|
|
m_aGraphicsStack.front().m_bClipRegion = false;
|
|
m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::ClipRegion;
|
|
}
|
|
|
|
void setClipRegion( const basegfx::B2DPolyPolygon& rRegion );
|
|
|
|
void moveClipRegion( sal_Int32 nX, sal_Int32 nY );
|
|
|
|
void intersectClipRegion( const tools::Rectangle& rRect );
|
|
|
|
void intersectClipRegion( const basegfx::B2DPolyPolygon& rRegion );
|
|
|
|
void setLayoutMode( vcl::text::ComplexTextLayoutFlags nLayoutMode )
|
|
{
|
|
m_aGraphicsStack.front().m_nLayoutMode = nLayoutMode;
|
|
m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::LayoutMode;
|
|
}
|
|
|
|
void setDigitLanguage( LanguageType eLang )
|
|
{
|
|
m_aGraphicsStack.front().m_aDigitLanguage = eLang;
|
|
m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::DigitLanguage;
|
|
}
|
|
|
|
void setTextAlign( TextAlign eAlign )
|
|
{
|
|
m_aGraphicsStack.front().m_aFont.SetAlignment( eAlign );
|
|
m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::Font;
|
|
}
|
|
|
|
/* actual drawing functions */
|
|
void drawText( const Point& rPos, const OUString& rText, sal_Int32 nIndex, sal_Int32 nLen, bool bTextLines = true );
|
|
void drawTextArray(const Point& rPos, const OUString& rText, KernArraySpan pDXArray,
|
|
std::span<const sal_Bool> pKashidaArray, sal_Int32 nIndex, sal_Int32 nLen,
|
|
sal_Int32 nLayoutContextIndex, sal_Int32 nLayoutContextLen);
|
|
void drawStretchText( const Point& rPos, sal_Int32 nWidth, const OUString& rText,
|
|
sal_Int32 nIndex, sal_Int32 nLen );
|
|
void drawText( const tools::Rectangle& rRect, const OUString& rOrigStr, DrawTextFlags nStyle );
|
|
void drawTextLine( const Point& rPos, tools::Long nWidth, FontStrikeout eStrikeout, FontLineStyle eUnderline, FontLineStyle eOverline, bool bUnderlineAbove );
|
|
void drawWaveTextLine( OStringBuffer& aLine, tools::Long nWidth, FontLineStyle eTextLine, Color aColor, bool bIsAbove );
|
|
void drawStraightTextLine( OStringBuffer& aLine, tools::Long nWidth, FontLineStyle eTextLine, Color aColor, bool bIsAbove );
|
|
void drawStrikeoutLine( OStringBuffer& aLine, tools::Long nWidth, FontStrikeout eStrikeout, Color aColor );
|
|
void drawStrikeoutChar( const Point& rPos, tools::Long nWidth, FontStrikeout eStrikeout );
|
|
|
|
void drawLine( const Point& rStart, const Point& rStop );
|
|
void drawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo );
|
|
void drawPolygon( const tools::Polygon& rPoly );
|
|
void drawPolyPolygon( const tools::PolyPolygon& rPolyPoly );
|
|
void drawPolyLine( const tools::Polygon& rPoly );
|
|
void drawPolyLine( const tools::Polygon& rPoly, const LineInfo& rInfo );
|
|
void drawPolyLine( const tools::Polygon& rPoly, const PDFWriter::ExtLineInfo& rInfo );
|
|
|
|
void drawPixel( const Point& rPt, const Color& rColor );
|
|
|
|
void drawRectangle( const tools::Rectangle& rRect );
|
|
void drawRectangle( const tools::Rectangle& rRect, sal_uInt32 nHorzRound, sal_uInt32 nVertRound );
|
|
void drawEllipse( const tools::Rectangle& rRect );
|
|
void drawArc( const tools::Rectangle& rRect, const Point& rStart, const Point& rStop, bool bWithPie, bool bWidthChord );
|
|
|
|
void drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap, const Graphic& rGraphic );
|
|
void drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEx& rBitmap );
|
|
void drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const tools::Rectangle& rTargetArea, const AlphaMask& rAlphaMask, const Graphic& rGraphic );
|
|
/// Stores the original PDF data from rGraphic as an embedded file.
|
|
void createEmbeddedFile(const Graphic& rGraphic, ReferenceXObjectEmit& rEmit, sal_Int32 nBitmapObject);
|
|
|
|
void drawGradient( const tools::Rectangle& rRect, const Gradient& rGradient );
|
|
void drawHatch( const tools::PolyPolygon& rPolyPoly, const Hatch& rHatch );
|
|
void drawWallpaper( const tools::Rectangle& rRect, const Wallpaper& rWall );
|
|
void drawTransparent( const tools::PolyPolygon& rPolyPoly, sal_uInt32 nTransparentPercent );
|
|
void beginTransparencyGroup();
|
|
void endTransparencyGroup( const tools::Rectangle& rBoundingBox, sal_uInt32 nTransparentPercent );
|
|
|
|
void emitComment( const char* pComment );
|
|
|
|
//--->i56629 named destinations
|
|
sal_Int32 createNamedDest( const OUString& sDestName, const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType );
|
|
|
|
//--->i59651
|
|
//emits output intent
|
|
sal_Int32 emitOutputIntent();
|
|
|
|
//emits the document metadata
|
|
sal_Int32 emitDocumentMetadata();
|
|
|
|
// links
|
|
sal_Int32 createLink(const tools::Rectangle& rRect, sal_Int32 nPageNr, OUString const& rAltText);
|
|
sal_Int32 createDest( const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType );
|
|
sal_Int32 registerDestReference( sal_Int32 nDestId, const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType );
|
|
void setLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId );
|
|
void setLinkURL( sal_Int32 nLinkId, const OUString& rURL );
|
|
void setLinkPropertyId( sal_Int32 nLinkId, sal_Int32 nPropertyId );
|
|
|
|
// screens
|
|
sal_Int32 createScreen(const tools::Rectangle& rRect, sal_Int32 nPageNr, OUString const& rAltText, OUString const& rMimeType);
|
|
void setScreenURL(sal_Int32 nScreenId, const OUString& rURL);
|
|
void setScreenStream(sal_Int32 nScreenId, const OUString& rURL);
|
|
|
|
// outline
|
|
sal_Int32 createOutlineItem( sal_Int32 nParent, std::u16string_view rText, sal_Int32 nDestID );
|
|
void setOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent );
|
|
void setOutlineItemText( sal_Int32 nItem, std::u16string_view rText );
|
|
void setOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID );
|
|
|
|
// notes
|
|
sal_Int32 createNote(const tools::Rectangle& rRect, const tools::Rectangle& rPopupRect, const PDFNote& rNote, sal_Int32 nPageNr);
|
|
// structure elements
|
|
sal_Int32 ensureStructureElement();
|
|
void initStructureElement(sal_Int32 id, PDFWriter::StructElement eType, std::u16string_view rAlias);
|
|
void beginStructureElement(sal_Int32 id);
|
|
void endStructureElement();
|
|
bool setCurrentStructureElement( sal_Int32 nElement );
|
|
bool setStructureAttribute( enum PDFWriter::StructAttribute eAttr, enum PDFWriter::StructAttributeValue eVal );
|
|
bool setStructureAttributeNumerical( enum PDFWriter::StructAttribute eAttr, sal_Int32 nValue );
|
|
void setStructureBoundingBox( const tools::Rectangle& rRect );
|
|
void setStructureAnnotIds(::std::vector<sal_Int32> const& rAnnotIds);
|
|
void setActualText( const OUString& rText );
|
|
void setAlternateText( const OUString& rText );
|
|
|
|
// transitional effects
|
|
void setPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr );
|
|
|
|
// controls
|
|
sal_Int32 createControl( const PDFWriter::AnyWidget& rControl, sal_Int32 nPageNr = -1 );
|
|
|
|
// attached file
|
|
void addDocumentAttachedFile(OUString const& rFileName, OUString const& rMimeType, OUString const& rDescription, std::unique_ptr<PDFOutputStream> rStream);
|
|
|
|
sal_Int32 addEmbeddedFile(BinaryDataContainer const & rDataContainer);
|
|
sal_Int32 addEmbeddedFile(std::unique_ptr<PDFOutputStream> rStream, OUString const& rMimeType);
|
|
|
|
// helper: eventually begin marked content sequence and
|
|
// emit a comment in debug case
|
|
void MARK( const char* pString );
|
|
};
|
|
|
|
} // namespace vcl
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|