Text operators (first part)

This commit is contained in:
Jakub Melka
2019-03-25 18:44:45 +01:00
parent 8c417b2afb
commit 21e125bd40
9 changed files with 5198 additions and 20 deletions

View File

@ -53,7 +53,9 @@ SOURCES += \
sources/pdfpagecontentprocessor.cpp \ sources/pdfpagecontentprocessor.cpp \
sources/pdfpainter.cpp \ sources/pdfpainter.cpp \
sources/pdfrenderingerrorswidget.cpp \ sources/pdfrenderingerrorswidget.cpp \
sources/pdffunction.cpp sources/pdffunction.cpp \
sources/pdfnametounicode.cpp \
sources/pdffont.cpp
HEADERS += \ HEADERS += \
sources/pdfobject.h \ sources/pdfobject.h \
@ -79,7 +81,9 @@ HEADERS += \
sources/pdfpainter.h \ sources/pdfpainter.h \
sources/pdfutils.h \ sources/pdfutils.h \
sources/pdfrenderingerrorswidget.h \ sources/pdfrenderingerrorswidget.h \
sources/pdffunction.h sources/pdffunction.h \
sources/pdfnametounicode.h \
sources/pdffont.h
unix { unix {
target.path = /usr/lib target.path = /usr/lib

View File

@ -288,6 +288,18 @@ PDFReal PDFDocumentDataLoaderDecorator::readNumber(const PDFObject& object, PDFR
return defaultValue; return defaultValue;
} }
bool PDFDocumentDataLoaderDecorator::readBoolean(const PDFObject& object, bool defaultValue) const
{
const PDFObject& dereferencedObject = m_document->getObject(object);
if (dereferencedObject.isBool())
{
return dereferencedObject.getBool();
}
return defaultValue;
}
QString PDFDocumentDataLoaderDecorator::readTextString(const PDFObject& object, const QString& defaultValue) const QString PDFDocumentDataLoaderDecorator::readTextString(const PDFObject& object, const QString& defaultValue) const
{ {
const PDFObject& dereferencedObject = m_document->getObject(object); const PDFObject& dereferencedObject = m_document->getObject(object);
@ -436,4 +448,14 @@ std::vector<PDFInteger> PDFDocumentDataLoaderDecorator::readIntegerArray(const P
return std::vector<PDFInteger>(); return std::vector<PDFInteger>();
} }
bool PDFDocumentDataLoaderDecorator::readBooleanFromDictionary(const PDFDictionary* dictionary, const char* key, bool defaultValue) const
{
if (dictionary->hasKey(key))
{
return readBoolean(dictionary->get(key), defaultValue);
}
return defaultValue;
}
} // namespace pdf } // namespace pdf

View File

@ -98,6 +98,11 @@ public:
/// \param defaultValue Default value /// \param defaultValue Default value
PDFReal readNumber(const PDFObject& object, PDFReal defaultValue) const; PDFReal readNumber(const PDFObject& object, PDFReal defaultValue) const;
/// Reads a boolean from the object, if it is possible.
/// \param object Object, can be an indirect reference to object (it is dereferenced)
/// \param defaultValue Default value
bool readBoolean(const PDFObject& object, bool defaultValue) const;
/// Reads a text string from the object, if it is possible. /// Reads a text string from the object, if it is possible.
/// \param object Object, can be an indirect reference to object (it is dereferenced) /// \param object Object, can be an indirect reference to object (it is dereferenced)
/// \param defaultValue Default value /// \param defaultValue Default value
@ -206,6 +211,12 @@ public:
/// \param object Object containing array of numbers /// \param object Object containing array of numbers
std::vector<PDFInteger> readIntegerArray(const PDFObject& object) const; std::vector<PDFInteger> readIntegerArray(const PDFObject& object) const;
/// Reads boolean from dictionary. If dictionary entry doesn't exist, or error occurs, default value is returned.
/// \param dictionary Dictionary containing desired data
/// \param key Entry key
/// \param defaultValue Default value
bool readBooleanFromDictionary(const PDFDictionary* dictionary, const char* key, bool defaultValue) const;
private: private:
const PDFDocument* m_document; const PDFDocument* m_document;
}; };

View File

@ -0,0 +1,28 @@
// Copyright (C) 2019 Jakub Melka
//
// This file is part of PdfForQt.
//
// PdfForQt is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// PdfForQt is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
#include "pdffont.h"
namespace pdf
{
PDFFont::PDFFont()
{
}
} // namespace pdf

View File

@ -0,0 +1,95 @@
// Copyright (C) 2019 Jakub Melka
//
// This file is part of PdfForQt.
//
// PdfForQt is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// PdfForQt is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFFONT_H
#define PDFFONT_H
#include "pdfglobal.h"
#include <QSharedPointer>
namespace pdf
{
enum class TextRenderingMode
{
Fill = 0,
Stroke = 1,
FillStroke = 2,
Invisible = 3,
FillClip = 4,
StrokeClip = 5,
FillStrokeClip = 6,
Clip = 7
};
constexpr bool isTextRenderingModeFilled(TextRenderingMode mode)
{
switch (mode)
{
case TextRenderingMode::Fill:
case TextRenderingMode::FillClip:
case TextRenderingMode::FillStroke:
case TextRenderingMode::FillStrokeClip:
return true;
default:
return false;
}
}
constexpr bool isTextRenderingModeStroked(TextRenderingMode mode)
{
switch (mode)
{
case TextRenderingMode::Stroke:
case TextRenderingMode::FillStroke:
case TextRenderingMode::StrokeClip:
case TextRenderingMode::FillStrokeClip:
return true;
default:
return false;
}
}
constexpr bool isTextRenderingModeClipped(TextRenderingMode mode)
{
switch (mode)
{
case TextRenderingMode::Clip:
case TextRenderingMode::FillClip:
case TextRenderingMode::StrokeClip:
case TextRenderingMode::FillStrokeClip:
return true;
default:
return false;
}
}
class PDFFont
{
public:
PDFFont();
};
using PDFFontPointer = QSharedPointer<PDFFont>;
} // namespace pdf
#endif // PDFFONT_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,61 @@
// Copyright (C) 2018 Jakub Melka
//
// This file is part of PdfForQt.
//
// PdfForQt is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// PdfForQt is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFNAMETOUNICODE_H
#define PDFNAMETOUNICODE_H
#include "pdfglobal.h"
#include <QChar>
#include <QByteArray>
namespace pdf
{
class PDFFORQTLIBSHARED_EXPORT PDFNameToUnicode
{
public:
explicit PDFNameToUnicode() = delete;
/// Returns unicode character for name. If name is not found, then null character is returned.
static QChar getUnicodeForName(const QByteArray& name);
/// Returns unicode character for name (for ZapfDingbats). If name is not found, then null character is returned.
static QChar getUnicodeForNameZapfDingbats(const QByteArray& name);
private:
struct Comparator
{
inline bool operator()(const QByteArray& left, const std::pair<QChar, const char*>& right)
{
return left < right.second;
}
inline bool operator()(const std::pair<QChar, const char*>& left, const QByteArray& right)
{
return left.second < right;
}
inline bool operator()(const std::pair<QChar, const char*>& left, const std::pair<QChar, const char*>& right)
{
return QLatin1String(left.second) < QLatin1String(right.second);
}
};
};
} // namespace pdf
#endif // PDFNAMETOUNICODE_H

View File

@ -152,7 +152,8 @@ static constexpr const std::pair<const char*, PDFPageContentProcessor::Operator>
PDFPageContentProcessor::PDFPageContentProcessor(const PDFPage* page, const PDFDocument* document) : PDFPageContentProcessor::PDFPageContentProcessor(const PDFPage* page, const PDFDocument* document) :
m_page(page), m_page(page),
m_document(document), m_document(document),
m_colorSpaceDictionary(nullptr) m_colorSpaceDictionary(nullptr),
m_textBeginEndState(0)
{ {
Q_ASSERT(page); Q_ASSERT(page);
Q_ASSERT(document); Q_ASSERT(document);
@ -597,6 +598,97 @@ void PDFPageContentProcessor::processCommand(const QByteArray& command)
break; break;
} }
case Operator::TextBegin:
{
// BT, begin text object, initialize text matrices, cannot be nested
operatorTextBegin();
break;
}
case Operator::TextEnd:
{
// ET, end text object, cannot be nested
operatorTextEnd();
break;
}
case Operator::TextSetCharacterSpacing:
{
// Tc, set text character spacing
invokeOperator(&PDFPageContentProcessor::operatorTextSetCharacterSpacing);
break;
}
case Operator::TextSetWordSpacing:
{
// Tw, set text word spacing
invokeOperator(&PDFPageContentProcessor::operatorTextSetWordSpacing);
break;
}
case Operator::TextSetHorizontalScale:
{
// Tz, set text horizontal scaling (in percents, 100% = normal scaling)
invokeOperator(&PDFPageContentProcessor::operatorTextSetHorizontalScale);
break;
}
case Operator::TextSetLeading:
{
// TL, set text leading
invokeOperator(&PDFPageContentProcessor::operatorTextSetLeading);
break;
}
case Operator::TextSetFontAndFontSize:
{
// Tf, set text font (name from dictionary) and its size
invokeOperator(&PDFPageContentProcessor::operatorTextSetFontAndFontSize);
break;
}
case Operator::TextSetRenderMode:
{
// Tr, set text render mode
invokeOperator(&PDFPageContentProcessor::operatorTextSetRenderMode);
break;
}
case Operator::TextSetRise:
{
// Ts, set text rise
invokeOperator(&PDFPageContentProcessor::operatorTextSetRise);
break;
}
case Operator::TextMoveByOffset:
{
// Td, move by offset
invokeOperator(&PDFPageContentProcessor::operatorTextMoveByOffset);
break;
}
case Operator::TextSetLeadingAndMoveByOffset:
{
// TD, sets text leading and moves by offset, x y TD is equivalent to sequence -y TL x y Td
invokeOperator(&PDFPageContentProcessor::operatorTextSetLeadingAndMoveByOffset);
break;
}
case Operator::TextSetMatrix:
{
// Tm, set text matrix
invokeOperator(&PDFPageContentProcessor::operatorTextSetMatrix);
break;
}
case Operator::TextMoveByLeading:
{
// T*, moves text by leading, equivalent to 0 leading Td
operatorTextMoveByLeading();
break;
}
case Operator::Invalid: case Operator::Invalid:
{ {
m_errorList.append(PDFRenderError(RenderErrorType::Error, PDFTranslationContext::tr("Unknown operator '%1'.").arg(QString::fromLatin1(command)))); m_errorList.append(PDFRenderError(RenderErrorType::Error, PDFTranslationContext::tr("Unknown operator '%1'.").arg(QString::fromLatin1(command))));
@ -867,6 +959,7 @@ void PDFPageContentProcessor::operatorSetGraphicState(PDFName dictionaryName)
const PDFReal flatness = loader.readNumberFromDictionary(graphicStateDictionary, "FL", m_graphicState.getFlatness()); const PDFReal flatness = loader.readNumberFromDictionary(graphicStateDictionary, "FL", m_graphicState.getFlatness());
const PDFReal smoothness = loader.readNumberFromDictionary(graphicStateDictionary, "SM", m_graphicState.getSmoothness()); const PDFReal smoothness = loader.readNumberFromDictionary(graphicStateDictionary, "SM", m_graphicState.getSmoothness());
const bool textKnockout = loader.readBooleanFromDictionary(graphicStateDictionary, "TK", m_graphicState.getTextKnockout());
m_graphicState.setLineWidth(lineWidth); m_graphicState.setLineWidth(lineWidth);
m_graphicState.setLineCapStyle(penCapStyle); m_graphicState.setLineCapStyle(penCapStyle);
@ -874,6 +967,7 @@ void PDFPageContentProcessor::operatorSetGraphicState(PDFName dictionaryName)
m_graphicState.setMitterLimit(mitterLimit); m_graphicState.setMitterLimit(mitterLimit);
m_graphicState.setFlatness(flatness); m_graphicState.setFlatness(flatness);
m_graphicState.setSmoothness(smoothness); m_graphicState.setSmoothness(smoothness);
m_graphicState.setTextKnockout(textKnockout);
updateGraphicState(); updateGraphicState();
} }
else else
@ -1315,6 +1409,130 @@ void PDFPageContentProcessor::operatorColorSetDeviceCMYKFilling(PDFReal c, PDFRe
updateGraphicState(); updateGraphicState();
} }
void PDFPageContentProcessor::operatorTextBegin()
{
m_graphicState.setTextMatrix(QMatrix());
m_graphicState.setTextLineMatrix(QMatrix());
updateGraphicState();
++m_textBeginEndState;
if (m_textBeginEndState > 1)
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Text object already started."));
}
}
void PDFPageContentProcessor::operatorTextEnd()
{
if (--m_textBeginEndState < 0)
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Text object ended more than once."));
}
}
void PDFPageContentProcessor::operatorTextSetCharacterSpacing(PDFReal charSpacing)
{
m_graphicState.setTextCharacterSpacing(charSpacing);
updateGraphicState();
}
void PDFPageContentProcessor::operatorTextSetWordSpacing(PDFReal wordSpacing)
{
m_graphicState.setTextWordSpacing(wordSpacing);
updateGraphicState();
}
void PDFPageContentProcessor::operatorTextSetHorizontalScale(PDFReal horizontalScaling)
{
// We disable horizontal scaling to less than 1%
horizontalScaling = qMax(horizontalScaling, 1.0);
m_graphicState.setTextHorizontalScaling(horizontalScaling / 100.0);
updateGraphicState();
}
void PDFPageContentProcessor::operatorTextSetLeading(PDFReal leading)
{
m_graphicState.setTextLeading(leading);
updateGraphicState();
}
void PDFPageContentProcessor::operatorTextSetFontAndFontSize(PDFPageContentProcessor::PDFName fontName, PDFReal fontSize)
{
Q_UNUSED(fontName);
Q_UNUSED(fontSize);
// TODO: Implement this operator
throw PDFRendererException(RenderErrorType::NotImplemented, PDFTranslationContext::tr("Set font not implemented."));
}
void PDFPageContentProcessor::operatorTextSetRenderMode(PDFInteger mode)
{
mode = qBound<PDFInteger>(0, mode, 7);
m_graphicState.setTextRenderingMode(static_cast<TextRenderingMode>(mode));
updateGraphicState();
}
void PDFPageContentProcessor::operatorTextSetRise(PDFReal rise)
{
m_graphicState.setTextRise(rise);
updateGraphicState();
}
void PDFPageContentProcessor::operatorTextMoveByOffset(PDFReal t_x, PDFReal t_y)
{
const QMatrix& textLineMatrix = m_graphicState.getTextLineMatrix();
QMatrix translationMatrix;
translationMatrix.translate(t_x, t_y);
QMatrix resultMatrix = textLineMatrix * translationMatrix;
m_graphicState.setTextMatrix(resultMatrix);
m_graphicState.setTextLineMatrix(resultMatrix);
updateGraphicState();
}
void PDFPageContentProcessor::operatorTextSetLeadingAndMoveByOffset(PDFReal t_x, PDFReal t_y)
{
// Update of graphic state is
m_graphicState.setTextLeading(-t_y);
operatorTextMoveByOffset(t_x, t_y);
}
void PDFPageContentProcessor::operatorTextSetMatrix(PDFReal a, PDFReal b, PDFReal c, PDFReal d, PDFReal e, PDFReal f)
{
// We will comment following equation:
// Adobe PDF Reference 1.7 says, that we have this transformation using coefficient a, b, c, d, e and f:
// [ a, b, 0 ]
// [x', y', 1] = [ x, y, 1] * [ c, d, 0 ]
// [ e, f, 1 ]
// If we transpose this equation (we want this, because Qt uses transposed matrices (QMatrix).
// So, we will get following result:
//
// [ x' ] [ a, c, e] [ x ]
// [ y' ] = [ b, d, f] * [ y ]
// [ 1 ] [ 0, 0, 1] [ 1 ]
//
// So, it is obvious, than we will have following coefficients:
// m_11 = a, m_21 = c, dx = e
// m_12 = b, m_22 = d, dy = f
//
// We must also check, that matrix is invertible. If it is not, then we will throw exception
// to avoid errors later (for some operations, we assume matrix is invertible).
QMatrix matrix(a, b, c, d, e, f);
m_graphicState.setTextMatrix(matrix);
m_graphicState.setTextLineMatrix(matrix);
updateGraphicState();
}
void PDFPageContentProcessor::operatorTextMoveByLeading()
{
operatorTextMoveByOffset(0.0, m_graphicState.getTextLeading());
}
PDFPageContentProcessor::PDFPageContentProcessorState::PDFPageContentProcessorState() : PDFPageContentProcessor::PDFPageContentProcessorState::PDFPageContentProcessorState() :
m_currentTransformationMatrix(), m_currentTransformationMatrix(),
m_fillColorSpace(), m_fillColorSpace(),
@ -1328,6 +1546,14 @@ PDFPageContentProcessor::PDFPageContentProcessorState::PDFPageContentProcessorSt
m_renderingIntent(), m_renderingIntent(),
m_flatness(1.0), m_flatness(1.0),
m_smoothness(0.01), m_smoothness(0.01),
m_textCharacterSpacing(0.0),
m_textWordSpacing(0.0),
m_textHorizontalScaling(100.0),
m_textLeading(0.0),
m_textFontSize(0.0),
m_textRenderingMode(TextRenderingMode::Fill),
m_textRise(0.0),
m_textKnockout(true),
m_stateFlags(StateUnchanged) m_stateFlags(StateUnchanged)
{ {
m_fillColorSpace.reset(new PDFDeviceGrayColorSpace); m_fillColorSpace.reset(new PDFDeviceGrayColorSpace);
@ -1354,6 +1580,17 @@ PDFPageContentProcessor::PDFPageContentProcessorState& PDFPageContentProcessor::
setRenderingIntent(other.getRenderingIntent()); setRenderingIntent(other.getRenderingIntent());
setFlatness(other.getFlatness()); setFlatness(other.getFlatness());
setSmoothness(other.getSmoothness()); setSmoothness(other.getSmoothness());
setTextCharacterSpacing(other.getTextCharacterSpacing());
setTextWordSpacing(other.getTextWordSpacing());
setTextHorizontalScaling(other.getTextHorizontalScaling());
setTextLeading(other.getTextLeading());
setTextFont(other.getTextFont());
setTextFontSize(other.getTextFontSize());
setTextRenderingMode(other.getTextRenderingMode());
setTextRise(other.getTextRise());
setTextKnockout(other.getTextKnockout());
setTextMatrix(other.getTextMatrix());
setTextLineMatrix(other.getTextLineMatrix());
return *this; return *this;
} }
@ -1429,7 +1666,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setLineJoinStyle(Qt:
} }
} }
void PDFPageContentProcessor::PDFPageContentProcessorState::setMitterLimit(const PDFReal& mitterLimit) void PDFPageContentProcessor::PDFPageContentProcessorState::setMitterLimit(PDFReal mitterLimit)
{ {
if (m_mitterLimit != mitterLimit) if (m_mitterLimit != mitterLimit)
{ {
@ -1474,4 +1711,103 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setSmoothness(PDFRea
} }
} }
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextLeading(PDFReal textLeading)
{
if (m_textLeading != textLeading)
{
m_textLeading = textLeading;
m_stateFlags |= StateTextLeading;
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextFontSize(PDFReal textFontSize)
{
if (m_textFontSize != textFontSize)
{
m_textFontSize = textFontSize;
m_stateFlags |= StateTextFontSize;
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextKnockout(bool textKnockout)
{
if (m_textKnockout != textKnockout)
{
m_textKnockout = textKnockout;
m_stateFlags |= StateTextKnockout;
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextLineMatrix(const QMatrix& textLineMatrix)
{
if (m_textLineMatrix != textLineMatrix)
{
m_textLineMatrix = textLineMatrix;
m_stateFlags |= StateTextLineMatrix;
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextMatrix(const QMatrix& textMatrix)
{
if (m_textMatrix != textMatrix)
{
m_textMatrix = textMatrix;
m_stateFlags |= StateTextMatrix;
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextRise(PDFReal textRise)
{
if (m_textRise != textRise)
{
m_textRise = textRise;
m_stateFlags |= StateTextRise;
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextRenderingMode(TextRenderingMode textRenderingMode)
{
if (m_textRenderingMode != textRenderingMode)
{
m_textRenderingMode = textRenderingMode;
m_stateFlags |= StateTextRenderingMode;
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextFont(const PDFFontPointer& textFont)
{
if (m_textFont != textFont)
{
m_textFont = textFont;
m_stateFlags |= StateTextFont;
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextHorizontalScaling(PDFReal textHorizontalScaling)
{
if (m_textHorizontalScaling != textHorizontalScaling)
{
m_textHorizontalScaling = textHorizontalScaling;
m_stateFlags |= StateTextHorizontalScaling;
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextWordSpacing(PDFReal textWordSpacing)
{
if (m_textWordSpacing != textWordSpacing)
{
m_textWordSpacing = textWordSpacing;
m_stateFlags |= StateTextWordSpacing;
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextCharacterSpacing(PDFReal textCharacterSpacing)
{
if (m_textCharacterSpacing != textCharacterSpacing)
{
m_textCharacterSpacing = textCharacterSpacing;
m_stateFlags |= StateTextCharacterSpacing;
}
}
} // namespace pdf } // namespace pdf

View File

@ -21,6 +21,7 @@
#include "pdfrenderer.h" #include "pdfrenderer.h"
#include "pdfparser.h" #include "pdfparser.h"
#include "pdfcolorspaces.h" #include "pdfcolorspaces.h"
#include "pdffont.h"
#include <QMatrix> #include <QMatrix>
#include <QPainterPath> #include <QPainterPath>
@ -113,7 +114,7 @@ public:
// Text positioning: Td, TD, Tm, T* // Text positioning: Td, TD, Tm, T*
TextMoveByOffset, ///< Td, move by offset TextMoveByOffset, ///< Td, move by offset
TextSetLeadingAndMoveByOffset, ///< TD, sets thext leading and moves by offset, x y TD is equivalent to sequence -y TL x y Td TextSetLeadingAndMoveByOffset, ///< TD, sets text leading and moves by offset, x y TD is equivalent to sequence -y TL x y Td
TextSetMatrix, ///< Tm, set text matrix TextSetMatrix, ///< Tm, set text matrix
TextMoveByLeading, ///< T*, moves text by leading, equivalent to 0 leading Td TextMoveByLeading, ///< T*, moves text by leading, equivalent to 0 leading Td
@ -214,20 +215,31 @@ protected:
enum StateFlag enum StateFlag
{ {
StateUnchanged = 0x0000, StateUnchanged = 0x00000000,
StateCurrentTransformationMatrix = 0x0001, StateCurrentTransformationMatrix = 0x00000001,
StateStrokeColorSpace = 0x0002, StateStrokeColorSpace = 0x00000002,
StateFillColorSpace = 0x0004, StateFillColorSpace = 0x00000004,
StateStrokeColor = 0x0008, StateStrokeColor = 0x00000008,
StateFillColor = 0x0010, StateFillColor = 0x00000010,
StateLineWidth = 0x0020, StateLineWidth = 0x00000020,
StateLineCapStyle = 0x0040, StateLineCapStyle = 0x00000040,
StateLineJoinStyle = 0x0080, StateLineJoinStyle = 0x00000080,
StateMitterLimit = 0x0100, StateMitterLimit = 0x00000100,
StateLineDashPattern = 0x0200, StateLineDashPattern = 0x00000200,
StateRenderingIntent = 0x0400, StateRenderingIntent = 0x00000400,
StateFlatness = 0x0800, StateFlatness = 0x00000800,
StateSmoothness = 0x1000, StateSmoothness = 0x00001000,
StateTextMatrix = 0x00002000,
StateTextLineMatrix = 0x00004000,
StateTextCharacterSpacing = 0x00008000,
StateTextWordSpacing = 0x00010000,
StateTextHorizontalScaling = 0x00020000,
StateTextLeading = 0x00040000,
StateTextFont = 0x00080000,
StateTextFontSize = 0x00100000,
StateTextRenderingMode = 0x00200000,
StateTextRise = 0x00400000,
StateTextKnockout = 0x00800000,
StateAll = 0xFFFF StateAll = 0xFFFF
}; };
@ -258,7 +270,7 @@ protected:
void setLineJoinStyle(Qt::PenJoinStyle lineJoinStyle); void setLineJoinStyle(Qt::PenJoinStyle lineJoinStyle);
PDFReal getMitterLimit() const { return m_mitterLimit; } PDFReal getMitterLimit() const { return m_mitterLimit; }
void setMitterLimit(const PDFReal& mitterLimit); void setMitterLimit(PDFReal mitterLimit);
const PDFLineDashPattern& getLineDashPattern() const { return m_lineDashPattern; } const PDFLineDashPattern& getLineDashPattern() const { return m_lineDashPattern; }
void setLineDashPattern(PDFLineDashPattern pattern); void setLineDashPattern(PDFLineDashPattern pattern);
@ -275,6 +287,39 @@ protected:
StateFlags getStateFlags() const { return m_stateFlags; } StateFlags getStateFlags() const { return m_stateFlags; }
void setStateFlags(StateFlags stateFlags) { m_stateFlags = stateFlags; } void setStateFlags(StateFlags stateFlags) { m_stateFlags = stateFlags; }
PDFReal getTextCharacterSpacing() const { return m_textCharacterSpacing; }
void setTextCharacterSpacing(PDFReal textCharacterSpacing);
PDFReal getTextWordSpacing() const { return m_textWordSpacing; }
void setTextWordSpacing(PDFReal textWordSpacing);
PDFReal getTextHorizontalScaling() const { return m_textHorizontalScaling; }
void setTextHorizontalScaling(PDFReal textHorizontalScaling);
PDFReal getTextLeading() const { return m_textLeading; }
void setTextLeading(PDFReal textLeading);
const PDFFontPointer& getTextFont() const { return m_textFont; }
void setTextFont(const PDFFontPointer& textFont);
PDFReal getTextFontSize() const { return m_textFontSize; }
void setTextFontSize(PDFReal textFontSize);
TextRenderingMode getTextRenderingMode() const { return m_textRenderingMode; }
void setTextRenderingMode(TextRenderingMode textRenderingMode);
PDFReal getTextRise() const { return m_textRise; }
void setTextRise(PDFReal textRise);
bool getTextKnockout() const { return m_textKnockout; }
void setTextKnockout(bool textKnockout);
const QMatrix& getTextMatrix() const { return m_textMatrix; }
void setTextMatrix(const QMatrix& textMatrix);
const QMatrix& getTextLineMatrix() const { return m_textLineMatrix; }
void setTextLineMatrix(const QMatrix& textLineMatrix);
private: private:
QMatrix m_currentTransformationMatrix; QMatrix m_currentTransformationMatrix;
PDFColorSpacePointer m_strokeColorSpace; PDFColorSpacePointer m_strokeColorSpace;
@ -289,6 +334,17 @@ protected:
QByteArray m_renderingIntent; QByteArray m_renderingIntent;
PDFReal m_flatness; PDFReal m_flatness;
PDFReal m_smoothness; PDFReal m_smoothness;
PDFReal m_textCharacterSpacing; // T_c
PDFReal m_textWordSpacing; // T_w
PDFReal m_textHorizontalScaling; // T_h, percentage
PDFReal m_textLeading; // T_l
PDFFontPointer m_textFont; // Text font
PDFReal m_textFontSize; // T_fs
TextRenderingMode m_textRenderingMode; // Text rendering mode
PDFReal m_textRise; // T_rise
bool m_textKnockout;
QMatrix m_textMatrix;
QMatrix m_textLineMatrix;
StateFlags m_stateFlags; StateFlags m_stateFlags;
}; };
@ -475,6 +531,25 @@ private:
void operatorColorSetDeviceCMYKStroking(PDFReal c, PDFReal m, PDFReal y, PDFReal k); ///< K, set DeviceCMYK color space for stroking color and set color void operatorColorSetDeviceCMYKStroking(PDFReal c, PDFReal m, PDFReal y, PDFReal k); ///< K, set DeviceCMYK color space for stroking color and set color
void operatorColorSetDeviceCMYKFilling(PDFReal c, PDFReal m, PDFReal y, PDFReal k); ///< k, set DeviceCMYK color space for filling color and set color void operatorColorSetDeviceCMYKFilling(PDFReal c, PDFReal m, PDFReal y, PDFReal k); ///< k, set DeviceCMYK color space for filling color and set color
// Text object: BT, ET
void operatorTextBegin(); ///< BT, begin text object, initialize text matrices, cannot be nested
void operatorTextEnd(); ///< ET, end text object, cannot be nested
// Text state: Tc, Tw, Tz, TL, Tf, Tr, Ts
void operatorTextSetCharacterSpacing(PDFReal charSpacing); ///< Tc, set text character spacing
void operatorTextSetWordSpacing(PDFReal wordSpacing); ///< Tw, set text word spacing
void operatorTextSetHorizontalScale(PDFReal horizontalScaling); ///< Tz, set text horizontal scaling (in percents, 100% = normal scaling)
void operatorTextSetLeading(PDFReal leading); ///< TL, set text leading
void operatorTextSetFontAndFontSize(PDFName fontName, PDFReal fontSize); ///< Tf, set text font (name from dictionary) and its size
void operatorTextSetRenderMode(PDFInteger mode); ///< Tr, set text render mode
void operatorTextSetRise(PDFReal rise); ///< Ts, set text rise
// Text positioning: Td, TD, Tm, T*
void operatorTextMoveByOffset(PDFReal t_x, PDFReal t_y); ///< Td, move by offset
void operatorTextSetLeadingAndMoveByOffset(PDFReal t_x, PDFReal t_y); ///< TD, sets text leading and moves by offset, x y TD is equivalent to sequence -y TL x y Td
void operatorTextSetMatrix(PDFReal a, PDFReal b, PDFReal c, PDFReal d, PDFReal e, PDFReal f); ///< Tm, set text matrix
void operatorTextMoveByLeading(); ///< T*, moves text by leading, equivalent to 0 leading Td
const PDFPage* m_page; const PDFPage* m_page;
const PDFDocument* m_document; const PDFDocument* m_document;
const PDFDictionary* m_colorSpaceDictionary; const PDFDictionary* m_colorSpaceDictionary;
@ -498,6 +573,9 @@ private:
/// Current painter path /// Current painter path
QPainterPath m_currentPath; QPainterPath m_currentPath;
/// Nesting level of the begin/end of text object
int m_textBeginEndState;
}; };
} // namespace pdf } // namespace pdf