Editor plugin: Content stream builder

This commit is contained in:
Jakub Melka 2024-05-19 20:13:57 +02:00
parent 21ff8d45fc
commit 17b275c8b1
5 changed files with 80 additions and 25 deletions

View File

@ -246,8 +246,13 @@ void PDFArray::optimize()
bool PDFDictionary::equals(const PDFObjectContent* other) const
{
Q_ASSERT(dynamic_cast<const PDFDictionary*>(other));
const PDFDictionary* otherStream = static_cast<const PDFDictionary*>(other);
return m_dictionary == otherStream->m_dictionary;
const PDFDictionary* otherDictionary = static_cast<const PDFDictionary*>(other);
return m_dictionary == otherDictionary->m_dictionary;
}
bool PDFDictionary::operator==(const PDFDictionary& other) const
{
return m_dictionary == other.m_dictionary;
}
const PDFObject& PDFDictionary::get(const QByteArray& key) const

View File

@ -364,6 +364,8 @@ public:
virtual bool equals(const PDFObjectContent* other) const override;
bool operator==(const PDFDictionary&other) const;
/// Returns object for the key. If key is not found in the dictionary,
/// then valid reference to the null object is returned.
/// \param key Key

View File

@ -17,6 +17,8 @@
#include "pdfpagecontenteditorprocessor.h"
#include "pdfdocumentbuilder.h"
#include "pdfobject.h"
#include "pdfstreamfilters.h"
#include <QStringBuilder>
#include <QXmlStreamReader>
@ -968,7 +970,7 @@ void PDFPageContentEditorContentStreamBuilder::writeStateDifference(QTextStream&
QString blendModeName = PDFBlendModeInfo::getBlendModeName(m_currentState.getBlendMode());
stateDictionary.beginDictionaryItem("BM");
stateDictionary << WrapName(blendModeName);
stateDictionary << WrapName(blendModeName.toLatin1());
stateDictionary.endDictionaryItem();
}
@ -1016,7 +1018,7 @@ void PDFPageContentEditorContentStreamBuilder::writeStateDifference(QTextStream&
QByteArray currentKey = QString("s%1").arg(++i).toLatin1();
if (!m_graphicStateDictionary.hasKey(currentKey))
{
m_graphicStateDictionary.addEntry(currentKey, std::move(stateObject));
m_graphicStateDictionary.addEntry(PDFInplaceOrMemoryString(currentKey), std::move(stateObject));
key = currentKey;
break;
}
@ -1038,9 +1040,8 @@ void PDFPageContentEditorContentStreamBuilder::writeElement(const PDFEditedPageC
if (const PDFEditedPageContentElementImage* imageElement = element->asImage())
{
QImage image = imageElement->getImage();
PDFObject imageObject = imageElement->getImageObject();
writeImage(image);
writeImage(stream, image);
}
if (const PDFEditedPageContentElementPath* pathElement = element->asPath())
@ -1361,6 +1362,45 @@ void PDFPageContentEditorContentStreamBuilder::writeText(QTextStream& stream, co
stream << "ET Q" << Qt::endl;
}
void PDFPageContentEditorContentStreamBuilder::writeImage(QTextStream& stream, const QImage& image)
{
QByteArray key;
int i = 0;
while (true)
{
QByteArray currentKey = QString("Im%1").arg(++i).toLatin1();
if (!m_xobjectDictionary.hasKey(currentKey))
{
PDFArray array;
array.appendItem(PDFObject::createName("FlateDecode"));
QImage codedImage = image;
codedImage = codedImage.convertToFormat(QImage::Format_ARGB32);
QByteArray decodedStream(reinterpret_cast<const char*>(image.constBits()), image.sizeInBytes());
// Compress the content stream
QByteArray compressedData = PDFFlateDecodeFilter::compress(decodedStream);
PDFDictionary imageDictionary;
imageDictionary.setEntry(PDFInplaceOrMemoryString("Subtitle"), PDFObject::createName("Image"));
imageDictionary.setEntry(PDFInplaceOrMemoryString("Width"), PDFObject::createInteger(image.width()));
imageDictionary.setEntry(PDFInplaceOrMemoryString("Height"), PDFObject::createInteger(image.height()));
imageDictionary.setEntry(PDFInplaceOrMemoryString("ColorSpace"), PDFObject::createName("DeviceRGB"));
imageDictionary.setEntry(PDFInplaceOrMemoryString("BitsPerComponent"), PDFObject::createInteger(8));
imageDictionary.setEntry(PDFInplaceOrMemoryString("Length"), PDFObject::createInteger(compressedData.size()));
imageDictionary.setEntry(PDFInplaceOrMemoryString("Filter"), PDFObject::createArray(std::make_shared<PDFArray>(qMove(array))));
PDFObject imageObject = PDFObject::createStream(std::make_shared<PDFStream>(qMove(imageDictionary), qMove(compressedData)));
m_xobjectDictionary.addEntry(PDFInplaceOrMemoryString(currentKey), std::move(imageObject));
key = currentKey;
break;
}
}
stream << "/" << key << " Do" << Qt::endl;
}
QByteArray PDFPageContentEditorContentStreamBuilder::selectFont(const QByteArray& font)
{
m_textFont = nullptr;
@ -1404,12 +1444,15 @@ QByteArray PDFPageContentEditorContentStreamBuilder::selectFont(const QByteArray
}
m_textFont = PDFFont::createFont(fontObject, font, m_document);
return defaultFontKey;
}
return font;
}
void PDFPageContentEditorContentStreamBuilder::addError(const QString& error)
{
m_errors << error;
}
} // namespace pdf

View File

@ -225,6 +225,8 @@ private:
bool isFilling);
void writeText(QTextStream& stream, const QString& text);
void writeImage(QTextStream& stream, const QImage& image);
QByteArray selectFont(const QByteArray& font);
void addError(const QString& error);
@ -235,6 +237,7 @@ private:
QByteArray m_outputContent;
PDFPageContentProcessorState m_currentState;
PDFFontPointer m_textFont;
QStringList m_errors;
};
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentEditorProcessor : public PDFPageContentProcessor

View File

@ -504,6 +504,26 @@ public:
/// Returns true, if we are in a text processing
bool isTextProcessing() const;
/// Converts PDF line cap to Qt's pen cap style. Function always succeeds,
/// if invalid \p lineCap occurs, then some valid pen cap style is returned.
/// \param lineCap PDF Line cap style (see PDF Reference 1.7, values can be 0, 1, and 2)
static Qt::PenCapStyle convertLineCapToPenCapStyle(PDFInteger lineCap);
/// 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
static PDFInteger convertPenCapStyleToLineCap(Qt::PenCapStyle penCapStyle);
/// Converts PDF line join to Qt's pen join style. Function always succeeds,
/// if invalid \p lineJoin occurs, then some valid pen join style is returned.
/// \param lineJoin PDF Line join style (see PDF Reference 1.7, values can be 0, 1, and 2)
static Qt::PenJoinStyle convertLineJoinToPenJoinStyle(PDFInteger lineJoin);
/// 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
static PDFInteger convertPenJoinStyleToLineJoin(Qt::PenJoinStyle penJoinStyle);
protected:
struct PDFTransparencyGroup
@ -900,24 +920,6 @@ private:
}
}
/// Converts PDF line cap to Qt's pen cap style. Function always succeeds,
/// if invalid \p lineCap occurs, then some valid pen cap style is returned.
/// \param lineCap PDF Line cap style (see PDF Reference 1.7, values can be 0, 1, and 2)
static Qt::PenCapStyle convertLineCapToPenCapStyle(PDFInteger lineCap);
/// 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
static PDFInteger convertPenCapStyleToLineCap(Qt::PenCapStyle penCapStyle);
/// Converts PDF line join to Qt's pen join style. Function always succeeds,
/// if invalid \p lineJoin occurs, then some valid pen join style is returned.
/// \param lineJoin PDF Line join style (see PDF Reference 1.7, values can be 0, 1, and 2)
static Qt::PenJoinStyle convertLineJoinToPenJoinStyle(PDFInteger lineJoin);
/// 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
static PDFInteger convertPenJoinStyleToLineJoin(Qt::PenJoinStyle penJoinStyle);
// General graphic state w, J, j, M, d, ri, i, gs
void operatorSetLineWidth(PDFReal lineWidth); ///< w, sets the line width
void operatorSetLineCap(PDFInteger lineCap); ///< J, sets the line cap