mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Editor plugin: Create content stream
This commit is contained in:
@ -776,25 +776,271 @@ void PDFEditedPageContentElementText::setItemsAsText(const QString& newItemsAsTe
|
|||||||
m_itemsAsText = newItemsAsText;
|
m_itemsAsText = newItemsAsText;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPageContentEditorContentStreamBuilder::writeStateDifference(const PDFPageContentProcessorState& state)
|
void PDFPageContentEditorContentStreamBuilder::writeStateDifference(QTextStream& stream, const PDFPageContentProcessorState& state)
|
||||||
{
|
{
|
||||||
|
m_currentState.setState(state);
|
||||||
|
|
||||||
|
auto stateFlags = m_currentState.getStateFlags();
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateCurrentTransformationMatrix))
|
||||||
|
{
|
||||||
|
QTransform transform = m_currentState.getCurrentTransformationMatrix();
|
||||||
|
|
||||||
|
PDFReal m11 = transform.m11();
|
||||||
|
PDFReal m12 = transform.m12();
|
||||||
|
PDFReal m21 = transform.m21();
|
||||||
|
PDFReal m22 = transform.m22();
|
||||||
|
PDFReal x = transform.dx();
|
||||||
|
PDFReal y = transform.dy();
|
||||||
|
|
||||||
|
stream << m11 << " " << m12 << " " << m21 << " " << m22 << " " << x << " " << y << " cm" << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateLineWidth))
|
||||||
|
{
|
||||||
|
stream << m_currentState.getLineWidth() << " w" << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateLineCapStyle))
|
||||||
|
{
|
||||||
|
stream << PDFPageContentProcessor::convertPenCapStyleToLineCap(m_currentState.getLineCapStyle()) << " J" << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateLineJoinStyle))
|
||||||
|
{
|
||||||
|
stream << PDFPageContentProcessor::convertPenJoinStyleToLineJoin(m_currentState.getLineJoinStyle()) << " j" << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateMitterLimit))
|
||||||
|
{
|
||||||
|
stream << m_currentState.getMitterLimit() << " M" << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateLineDashPattern))
|
||||||
|
{
|
||||||
|
const PDFLineDashPattern& dashPattern = m_currentState.getLineDashPattern();
|
||||||
|
|
||||||
|
if (dashPattern.isSolid())
|
||||||
|
{
|
||||||
|
stream << "[] 0 d" << Qt::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stream << "[ ";
|
||||||
|
|
||||||
|
for (PDFReal arrayItem : dashPattern.getDashArray())
|
||||||
|
{
|
||||||
|
stream << arrayItem << " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
stream << " ] " << dashPattern.getDashOffset() << " d";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateRenderingIntent))
|
||||||
|
{
|
||||||
|
switch (m_currentState.getRenderingIntent())
|
||||||
|
{
|
||||||
|
case pdf::RenderingIntent::Perceptual:
|
||||||
|
stream << "/Perceptual ri" << Qt::endl;
|
||||||
|
break;
|
||||||
|
case pdf::RenderingIntent::AbsoluteColorimetric:
|
||||||
|
stream << "/AbsoluteColorimetric ri" << Qt::endl;
|
||||||
|
break;
|
||||||
|
case pdf::RenderingIntent::RelativeColorimetric:
|
||||||
|
stream << "/RelativeColorimetric ri" << Qt::endl;
|
||||||
|
break;
|
||||||
|
case pdf::RenderingIntent::Saturation:
|
||||||
|
stream << "/Saturation ri" << Qt::endl;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateMitterLimit))
|
||||||
|
{
|
||||||
|
stream << m_currentState.getMitterLimit() << " M" << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateFlatness))
|
||||||
|
{
|
||||||
|
stream << m_currentState.getFlatness() << " i" << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateStrokeColor) ||
|
||||||
|
stateFlags.testFlag(PDFPageContentProcessorState::StateStrokeColorSpace))
|
||||||
|
{
|
||||||
|
QColor color = m_currentState.getStrokeColor();
|
||||||
|
const PDFAbstractColorSpace* strokeColorSpace = m_currentState.getStrokeColorSpace();
|
||||||
|
if (strokeColorSpace && strokeColorSpace->getColorSpace() == PDFAbstractColorSpace::ColorSpace::DeviceGray)
|
||||||
|
{
|
||||||
|
stream << qGray(color.rgb()) / 255.0 << " G" << Qt::endl;
|
||||||
|
}
|
||||||
|
else if (strokeColorSpace && strokeColorSpace->getColorSpace() == PDFAbstractColorSpace::ColorSpace::DeviceCMYK)
|
||||||
|
{
|
||||||
|
const PDFColor& color = m_currentState.getStrokeColorOriginal();
|
||||||
|
if (color.size() >= 4)
|
||||||
|
{
|
||||||
|
stream << color[0] << " " << color[1] << " " << color[2] << " " << color[3] << " K";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stream << color.redF() << " " << color.greenF() << " " << color.blueF() << " RG";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateFillColor) ||
|
||||||
|
stateFlags.testFlag(PDFPageContentProcessorState::StateFillColorSpace))
|
||||||
|
{
|
||||||
|
QColor color = m_currentState.getFillColor();
|
||||||
|
const PDFAbstractColorSpace* fillColorSpace = m_currentState.getFillColorSpace();
|
||||||
|
if (fillColorSpace && fillColorSpace->getColorSpace() == PDFAbstractColorSpace::ColorSpace::DeviceGray)
|
||||||
|
{
|
||||||
|
stream << qGray(color.rgb()) / 255.0 << " G" << Qt::endl;
|
||||||
|
}
|
||||||
|
else if (fillColorSpace && fillColorSpace->getColorSpace() == PDFAbstractColorSpace::ColorSpace::DeviceCMYK)
|
||||||
|
{
|
||||||
|
const PDFColor& color = m_currentState.getFillColorOriginal();
|
||||||
|
if (color.size() >= 4)
|
||||||
|
{
|
||||||
|
stream << color[0] << " " << color[1] << " " << color[2] << " " << color[3] << " K";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stream << color.redF() << " " << color.greenF() << " " << color.blueF() << " RG";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_currentState.setStateFlags(PDFPageContentProcessorState::StateFlags());
|
||||||
|
|
||||||
|
|
||||||
|
PDFObjectFactory stateDictionary;
|
||||||
|
stateDictionary.beginDictionary();
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateSmoothness))
|
||||||
|
{
|
||||||
|
stateDictionary.beginDictionaryItem("SM");
|
||||||
|
stateDictionary << m_currentState.getSmoothness();
|
||||||
|
stateDictionary.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateAlphaStroking))
|
||||||
|
{
|
||||||
|
stateDictionary.beginDictionaryItem("CA");
|
||||||
|
stateDictionary << m_currentState.getAlphaStroking();
|
||||||
|
stateDictionary.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateAlphaFilling))
|
||||||
|
{
|
||||||
|
stateDictionary.beginDictionaryItem("ca");
|
||||||
|
stateDictionary << m_currentState.getAlphaFilling();
|
||||||
|
stateDictionary.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateAlphaIsShape))
|
||||||
|
{
|
||||||
|
stateDictionary.beginDictionaryItem("AIS");
|
||||||
|
stateDictionary << m_currentState.getAlphaIsShape();
|
||||||
|
stateDictionary.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateTextKnockout))
|
||||||
|
{
|
||||||
|
stateDictionary.beginDictionaryItem("TK");
|
||||||
|
stateDictionary << m_currentState.getTextKnockout();
|
||||||
|
stateDictionary.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateStrokeAdjustment))
|
||||||
|
{
|
||||||
|
stateDictionary.beginDictionaryItem("SA");
|
||||||
|
stateDictionary << m_currentState.getStrokeAdjustment();
|
||||||
|
stateDictionary.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateBlendMode))
|
||||||
|
{
|
||||||
|
QString blendModeName = PDFBlendModeInfo::getBlendModeName(m_currentState.getBlendMode());
|
||||||
|
|
||||||
|
stateDictionary.beginDictionaryItem("BM");
|
||||||
|
stateDictionary << WrapName(blendModeName);
|
||||||
|
stateDictionary.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateFlags.testFlag(PDFPageContentProcessorState::StateOverprint))
|
||||||
|
{
|
||||||
|
PDFOverprintMode overprintMode = m_currentState.getOverprintMode();
|
||||||
|
|
||||||
|
stateDictionary.beginDictionaryItem("OPM");
|
||||||
|
stateDictionary << overprintMode.overprintMode;
|
||||||
|
stateDictionary.endDictionaryItem();
|
||||||
|
|
||||||
|
stateDictionary.beginDictionaryItem("OP");
|
||||||
|
stateDictionary << overprintMode.overprintStroking;
|
||||||
|
stateDictionary.endDictionaryItem();
|
||||||
|
|
||||||
|
stateDictionary.beginDictionaryItem("op");
|
||||||
|
stateDictionary << overprintMode.overprintFilling;
|
||||||
|
stateDictionary.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
stateDictionary.endDictionary();
|
||||||
|
PDFObject stateObject = stateDictionary.takeObject();
|
||||||
|
|
||||||
|
const PDFDictionary* dictionary = m_document->getDictionaryFromObject(stateObject);
|
||||||
|
if (dictionary && dictionary->getCount() > 0)
|
||||||
|
{
|
||||||
|
// Apply state
|
||||||
|
QByteArray key;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_graphicStateDictionary.getCount(); ++i)
|
||||||
|
{
|
||||||
|
const PDFDictionary* currentDictionary = m_document->getDictionaryFromObject(m_graphicStateDictionary.getValue(i));
|
||||||
|
if (*currentDictionary == *dictionary)
|
||||||
|
{
|
||||||
|
key = m_graphicStateDictionary.getKey(i).getString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.isEmpty())
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
QByteArray currentKey = QString("s%1").arg(++i).toLatin1();
|
||||||
|
if (!m_graphicStateDictionary.hasKey(currentKey))
|
||||||
|
{
|
||||||
|
m_graphicStateDictionary.addEntry(currentKey, std::move(stateObject));
|
||||||
|
key = currentKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream << "/" << key << " gs" << Qt::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPageContentEditorContentStreamBuilder::writeElement(const PDFEditedPageContentElement* element)
|
void PDFPageContentEditorContentStreamBuilder::writeElement(const PDFEditedPageContentElement* element)
|
||||||
{
|
{
|
||||||
PDFPageContentProcessorState state = element->getState();
|
PDFPageContentProcessorState state = element->getState();
|
||||||
state.setCurrentTransformationMatrix(element->getTransform());
|
state.setCurrentTransformationMatrix(element->getTransform());
|
||||||
writeStateDifference(state);
|
|
||||||
|
|
||||||
QTextStream stream(&m_outputContent, QDataStream::WriteOnly);
|
QTextStream stream(&m_outputContent, QDataStream::WriteOnly);
|
||||||
|
writeStateDifference(stream, state);
|
||||||
|
|
||||||
if (const PDFEditedPageContentElementImage* imageElement = element->asImage())
|
if (const PDFEditedPageContentElementImage* imageElement = element->asImage())
|
||||||
{
|
{
|
||||||
QImage image = imageElement->getImage();
|
QImage image = imageElement->getImage();
|
||||||
PDFObject imageObject = imageElement->getImageObject();
|
PDFObject imageObject = imageElement->getImageObject();
|
||||||
|
|
||||||
|
writeImage(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const PDFEditedPageContentElementPath* pathElement = element->asPath())
|
if (const PDFEditedPageContentElementPath* pathElement = element->asPath())
|
||||||
@ -1002,7 +1248,7 @@ void PDFPageContentEditorContentStreamBuilder::writeText(QTextStream& stream, co
|
|||||||
if (attributes.hasAttribute("font") && attributes.hasAttribute("size"))
|
if (attributes.hasAttribute("font") && attributes.hasAttribute("size"))
|
||||||
{
|
{
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
QString v1 = attributes.value("font").toString();
|
QByteArray v1 = attributes.value("font").toString().toLatin1();
|
||||||
PDFReal v2 = attributes.value("size").toDouble(&ok);
|
PDFReal v2 = attributes.value("size").toDouble(&ok);
|
||||||
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
|
@ -213,7 +213,7 @@ class PDF4QTLIBCORESHARED_EXPORT PDFPageContentEditorContentStreamBuilder
|
|||||||
public:
|
public:
|
||||||
PDFPageContentEditorContentStreamBuilder();
|
PDFPageContentEditorContentStreamBuilder();
|
||||||
|
|
||||||
void writeStateDifference(const PDFPageContentProcessorState& state);
|
void writeStateDifference(QTextStream& stream, const PDFPageContentProcessorState& state);
|
||||||
void writeElement(const PDFEditedPageContentElement* element);
|
void writeElement(const PDFEditedPageContentElement* element);
|
||||||
|
|
||||||
const QByteArray& getOutputContent() const;
|
const QByteArray& getOutputContent() const;
|
||||||
@ -231,6 +231,7 @@ private:
|
|||||||
PDFDocument* m_document = nullptr;
|
PDFDocument* m_document = nullptr;
|
||||||
PDFDictionary m_fontDictionary;
|
PDFDictionary m_fontDictionary;
|
||||||
PDFDictionary m_xobjectDictionary;
|
PDFDictionary m_xobjectDictionary;
|
||||||
|
PDFDictionary m_graphicStateDictionary;
|
||||||
QByteArray m_outputContent;
|
QByteArray m_outputContent;
|
||||||
PDFPageContentProcessorState m_currentState;
|
PDFPageContentProcessorState m_currentState;
|
||||||
PDFFontPointer m_textFont;
|
PDFFontPointer m_textFont;
|
||||||
|
@ -905,7 +905,7 @@ private:
|
|||||||
/// \param lineCap PDF Line cap style (see PDF Reference 1.7, values can be 0, 1, and 2)
|
/// \param lineCap PDF Line cap style (see PDF Reference 1.7, values can be 0, 1, and 2)
|
||||||
static Qt::PenCapStyle convertLineCapToPenCapStyle(PDFInteger lineCap);
|
static Qt::PenCapStyle convertLineCapToPenCapStyle(PDFInteger lineCap);
|
||||||
|
|
||||||
/// Convers Qt's pen cap style to PDF's line cap style (defined in the PDF Reference)
|
/// Converts Qt's pen cap style to PDF's line cap style (defined in the PDF Reference)
|
||||||
/// \param penCapStyle Qt's pen cap style to be converted
|
/// \param penCapStyle Qt's pen cap style to be converted
|
||||||
static PDFInteger convertPenCapStyleToLineCap(Qt::PenCapStyle penCapStyle);
|
static PDFInteger convertPenCapStyleToLineCap(Qt::PenCapStyle penCapStyle);
|
||||||
|
|
||||||
@ -914,7 +914,7 @@ private:
|
|||||||
/// \param lineJoin PDF Line join style (see PDF Reference 1.7, values can be 0, 1, and 2)
|
/// \param lineJoin PDF Line join style (see PDF Reference 1.7, values can be 0, 1, and 2)
|
||||||
static Qt::PenJoinStyle convertLineJoinToPenJoinStyle(PDFInteger lineJoin);
|
static Qt::PenJoinStyle convertLineJoinToPenJoinStyle(PDFInteger lineJoin);
|
||||||
|
|
||||||
/// Convers Qt's pen join style to PDF's line join style (defined in the PDF Reference)
|
/// Converts Qt's pen join style to PDF's line join style (defined in the PDF Reference)
|
||||||
/// \param penJoinStyle Qt's pen join style to be converted
|
/// \param penJoinStyle Qt's pen join style to be converted
|
||||||
static PDFInteger convertPenJoinStyleToLineJoin(Qt::PenJoinStyle penJoinStyle);
|
static PDFInteger convertPenJoinStyleToLineJoin(Qt::PenJoinStyle penJoinStyle);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user