Editor plugin: Building stream

This commit is contained in:
Jakub Melka 2024-04-28 19:50:55 +02:00
parent 75db2de2a0
commit a40faf855d
8 changed files with 196 additions and 3 deletions

View File

@ -1,4 +1,4 @@
// Copyright (C) 2023 Jakub Melka
// Copyright (C) 2023-2024 Jakub Melka
//
// This file is part of PDF4QT.
//
@ -41,7 +41,7 @@ EditorPlugin::EditorPlugin() :
m_scene(nullptr),
m_sceneSelectionChangeEnabled(true)
{
m_scene.setIsPageContentDrawSuppressed(true);
}
void EditorPlugin::setWidget(pdf::PDFWidget* widget)

View File

@ -32,6 +32,9 @@ PDFPageContentEditorProcessor::PDFPageContentEditorProcessor(const PDFPage* page
BaseClass(page, document, fontCache, CMS, optionalContentActivity, pagePointToDevicePointMatrix, meshQualitySettings)
{
m_clippingPaths.push(QPainterPath());
m_content.setFontDictionary(*getFontDictionary());
m_content.setXObjectDictionary(*getXObjectDictionary());
}
const PDFEditedPageContent& PDFPageContentEditorProcessor::getEditedPageContent() const
@ -451,6 +454,26 @@ PDFEditedPageContentElement* PDFEditedPageContent::getBackElement() const
return m_contentElements.back().get();
}
PDFDictionary PDFEditedPageContent::getFontDictionary() const
{
return m_fontDictionary;
}
void PDFEditedPageContent::setFontDictionary(const PDFDictionary& newFontDictionary)
{
m_fontDictionary = newFontDictionary;
}
PDFDictionary PDFEditedPageContent::getXObjectDictionary() const
{
return m_xobjectDictionary;
}
void PDFEditedPageContent::setXObjectDictionary(const PDFDictionary& newXobjectDictionary)
{
m_xobjectDictionary = newXobjectDictionary;
}
PDFEditedPageContentElement::PDFEditedPageContentElement(PDFPageContentProcessorState state, QTransform transform) :
m_state(std::move(state)),
m_transform(transform)
@ -737,4 +760,102 @@ QString PDFEditedPageContentElementText::getItemsAsText() const
return text;
}
void PDFPageContentEditorContentStreamBuilder::writeStateDifference(const PDFPageContentProcessorState& state)
{
}
void PDFPageContentEditorContentStreamBuilder::writeElement(const PDFEditedPageContentElement* element)
{
PDFPageContentProcessorState state = element->getState();
state.setCurrentTransformationMatrix(element->getTransform());
writeStateDifference(state);
QDataStream stream(&m_outputContent, QDataStream::WriteOnly);
if (const PDFEditedPageContentElementImage* imageElement = element->asImage())
{
QImage image = imageElement->getImage();
PDFObject imageObject = imageElement->getImageObject();
}
if (const PDFEditedPageContentElementPath* pathElement = element->asPath())
{
const bool isStroking = pathElement->getStrokePath();
const bool isFilling = pathElement->getFillPath();
writePainterPath(stream, pathElement->getPath(), isStroking, isFilling);
}
stream << Qt::endl;
}
void PDFPageContentEditorContentStreamBuilder::writePainterPath(QDataStream& stream,
const QPainterPath& path,
bool isStroking,
bool isFilling)
{
const int elementCount = path.elementCount();
for (int i = 0; i < elementCount; ++i)
{
QPainterPath::Element element = path.elementAt(i);
switch (element.type)
{
case QPainterPath::MoveToElement:
stream << element.x << " " << element.y << " m" << Qt::endl;
break;
case QPainterPath::LineToElement:
stream << element.x << " " << element.y << " l" << Qt::endl;
break;
case QPainterPath::CurveToElement:
stream << element.x << " " << element.y << " c" << Qt::endl;
break;
case QPainterPath::CurveToDataElement:
stream << element.x << " " << element.y << " ";
break;
default:
break;
}
}
if (isStroking && !isFilling)
{
stream << "S" << Qt::endl;
}
else if (isStroking || isFilling)
{
switch (path.fillRule())
{
case Qt::OddEvenFill:
if (isFilling && isStroking)
{
stream << "B*" << Qt::endl;
}
else
{
stream << "f*" << Qt::endl;
}
break;
case Qt::WindingFill:
if (isFilling && isStroking)
{
stream << "B" << Qt::endl;
}
else
{
stream << "f" << Qt::endl;
}
break;
default:
break;
}
}
else
{
stream << "n" << Qt::endl;
}
}
} // namespace pdf

View File

@ -190,8 +190,38 @@ public:
PDFEditedPageContentElement* getBackElement() const;
PDFDictionary getFontDictionary() const;
void setFontDictionary(const PDFDictionary& newFontDictionary);
PDFDictionary getXObjectDictionary() const;
void setXObjectDictionary(const PDFDictionary& newXobjectDictionary);
private:
std::vector<std::unique_ptr<PDFEditedPageContentElement>> m_contentElements;
PDFDictionary m_fontDictionary;
PDFDictionary m_xobjectDictionary;
};
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentEditorContentStreamBuilder
{
public:
PDFPageContentEditorContentStreamBuilder();
void writeStateDifference(const PDFPageContentProcessorState& state);
void writeElement(const PDFEditedPageContentElement* element);
const QByteArray& getOutputContent() const;
private:
void writePainterPath(QDataStream& stream,
const QPainterPath& path,
bool isStroking,
bool isFilling);
PDFDictionary m_fontDictionary;
PDFDictionary m_xobjectDictionary;
QByteArray m_outputContent;
PDFPageContentProcessorState m_currentState;
};
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentEditorProcessor : public PDFPageContentProcessor

View File

@ -742,6 +742,14 @@ protected:
/// Process form using form stream
void processForm(const PDFStream* stream);
const PDFDictionary* getColorSpaceDictionary() const { return m_colorSpaceDictionary; }
const PDFDictionary* getFontDictionary() const { return m_fontDictionary; }
const PDFDictionary* getXObjectDictionary() const { return m_xobjectDictionary; }
const PDFDictionary* getExtendedGraphicStateDictionary() const { return m_extendedGraphicStateDictionary; }
const PDFDictionary* getPropertiesDictionary() const { return m_propertiesDictionary; }
const PDFDictionary* getShadingDictionary() const { return m_shadingDictionary; }
const PDFDictionary* getPatternDictionary() const { return m_patternDictionary; }
private:
/// Initializes the resources dictionaries
void initDictionaries(const PDFObject& resourcesObject);

View File

@ -59,6 +59,10 @@ public:
/// \param painter Painter
/// \param rect Draw rectangle (usually viewport rectangle of the pdf widget)
virtual void drawPostRendering(QPainter* painter, QRect rect) const;
/// Returns true if drawing of the page content should be suppressed.
/// This is used for special purposes, such as rendering edited page content.
virtual bool isPageContentDrawSuppressed() const;
};
/// Input interface for handling events. Implementations should react on these events,

View File

@ -809,9 +809,19 @@ void PDFDrawWidgetProxy::drawPages(QPainter* painter, QRect rect, PDFRenderer::F
const PDFPage* page = m_controller->getDocument()->getCatalog()->getPage(item.pageIndex);
QTransform matrix = QTransform(createPagePointToDevicePointMatrix(page, placedRect)) * baseMatrix;
compiledPage->draw(painter, page->getCropBox(), matrix, features, groupInfo.transparency);
PDFTextLayoutGetter layoutGetter = m_textLayoutCompiler->getTextLayoutLazy(item.pageIndex);
bool isPageContentDrawSuppressed = false;
for (IDocumentDrawInterface* drawInterface : m_drawInterfaces)
{
isPageContentDrawSuppressed = isPageContentDrawSuppressed || drawInterface->isPageContentDrawSuppressed();
}
if (!isPageContentDrawSuppressed)
{
compiledPage->draw(painter, page->getCropBox(), matrix, features, groupInfo.transparency);
}
// Draw text blocks/text lines, if it is enabled
if (features.testFlag(PDFRenderer::DebugTextBlocks))
{
@ -1629,4 +1639,9 @@ void IDocumentDrawInterface::drawPostRendering(QPainter* painter, QRect rect) co
Q_UNUSED(rect);
}
bool IDocumentDrawInterface::isPageContentDrawSuppressed() const
{
return false;
}
} // namespace pdf

View File

@ -333,6 +333,7 @@ PDFPageContentScene::PDFPageContentScene(QObject* parent) :
QObject(parent),
m_firstFreeId(1),
m_isActive(false),
m_isPageContentDrawSuppressed(false),
m_widget(nullptr),
m_manipulator(this, nullptr)
{
@ -642,6 +643,11 @@ int PDFPageContentScene::getInputPriority() const
return ToolPriority + 1;
}
bool PDFPageContentScene::isPageContentDrawSuppressed() const
{
return isActive() && m_isPageContentDrawSuppressed;
}
void PDFPageContentScene::drawElements(QPainter* painter,
PDFInteger pageIndex,
PDFTextLayoutGetter& layoutGetter,
@ -823,6 +829,11 @@ void PDFPageContentScene::onSelectionChanged()
Q_EMIT selectionChanged();
}
void PDFPageContentScene::setIsPageContentDrawSuppressed(bool newIsPageContentDrawSuppressed)
{
m_isPageContentDrawSuppressed = newIsPageContentDrawSuppressed;
}
PDFWidget* PDFPageContentScene::widget() const
{
return m_widget;

View File

@ -561,6 +561,7 @@ public:
virtual QString getTooltip() const override;
virtual const std::optional<QCursor>& getCursor() const override;
virtual int getInputPriority() const override;
virtual bool isPageContentDrawSuppressed() const;
virtual void drawPage(QPainter* painter,
PDFInteger pageIndex,
@ -579,6 +580,8 @@ public:
const PDFPrecompiledPage* compiledPage,
QList<PDFRenderError>& errors) const;
void setIsPageContentDrawSuppressed(bool newIsPageContentDrawSuppressed);
signals:
/// This signal is emitted when scene has changed (including graphics)
void sceneChanged(bool graphicsOnly);
@ -637,6 +640,7 @@ private:
PDFInteger m_firstFreeId;
bool m_isActive;
bool m_isPageContentDrawSuppressed;
PDFWidget* m_widget;
std::vector<std::unique_ptr<PDFPageContentElement>> m_elements;
std::optional<QCursor> m_cursor;