mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Editor plugin: Building stream
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2023 Jakub Melka
|
// Copyright (C) 2023-2024 Jakub Melka
|
||||||
//
|
//
|
||||||
// This file is part of PDF4QT.
|
// This file is part of PDF4QT.
|
||||||
//
|
//
|
||||||
@ -41,7 +41,7 @@ EditorPlugin::EditorPlugin() :
|
|||||||
m_scene(nullptr),
|
m_scene(nullptr),
|
||||||
m_sceneSelectionChangeEnabled(true)
|
m_sceneSelectionChangeEnabled(true)
|
||||||
{
|
{
|
||||||
|
m_scene.setIsPageContentDrawSuppressed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorPlugin::setWidget(pdf::PDFWidget* widget)
|
void EditorPlugin::setWidget(pdf::PDFWidget* widget)
|
||||||
|
@ -32,6 +32,9 @@ PDFPageContentEditorProcessor::PDFPageContentEditorProcessor(const PDFPage* page
|
|||||||
BaseClass(page, document, fontCache, CMS, optionalContentActivity, pagePointToDevicePointMatrix, meshQualitySettings)
|
BaseClass(page, document, fontCache, CMS, optionalContentActivity, pagePointToDevicePointMatrix, meshQualitySettings)
|
||||||
{
|
{
|
||||||
m_clippingPaths.push(QPainterPath());
|
m_clippingPaths.push(QPainterPath());
|
||||||
|
|
||||||
|
m_content.setFontDictionary(*getFontDictionary());
|
||||||
|
m_content.setXObjectDictionary(*getXObjectDictionary());
|
||||||
}
|
}
|
||||||
|
|
||||||
const PDFEditedPageContent& PDFPageContentEditorProcessor::getEditedPageContent() const
|
const PDFEditedPageContent& PDFPageContentEditorProcessor::getEditedPageContent() const
|
||||||
@ -451,6 +454,26 @@ PDFEditedPageContentElement* PDFEditedPageContent::getBackElement() const
|
|||||||
return m_contentElements.back().get();
|
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) :
|
PDFEditedPageContentElement::PDFEditedPageContentElement(PDFPageContentProcessorState state, QTransform transform) :
|
||||||
m_state(std::move(state)),
|
m_state(std::move(state)),
|
||||||
m_transform(transform)
|
m_transform(transform)
|
||||||
@ -737,4 +760,102 @@ QString PDFEditedPageContentElementText::getItemsAsText() const
|
|||||||
return text;
|
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
|
} // namespace pdf
|
||||||
|
@ -190,8 +190,38 @@ public:
|
|||||||
|
|
||||||
PDFEditedPageContentElement* getBackElement() const;
|
PDFEditedPageContentElement* getBackElement() const;
|
||||||
|
|
||||||
|
PDFDictionary getFontDictionary() const;
|
||||||
|
void setFontDictionary(const PDFDictionary& newFontDictionary);
|
||||||
|
|
||||||
|
PDFDictionary getXObjectDictionary() const;
|
||||||
|
void setXObjectDictionary(const PDFDictionary& newXobjectDictionary);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<PDFEditedPageContentElement>> m_contentElements;
|
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
|
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentEditorProcessor : public PDFPageContentProcessor
|
||||||
|
@ -742,6 +742,14 @@ protected:
|
|||||||
/// Process form using form stream
|
/// Process form using form stream
|
||||||
void processForm(const PDFStream* 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:
|
private:
|
||||||
/// Initializes the resources dictionaries
|
/// Initializes the resources dictionaries
|
||||||
void initDictionaries(const PDFObject& resourcesObject);
|
void initDictionaries(const PDFObject& resourcesObject);
|
||||||
|
@ -59,6 +59,10 @@ public:
|
|||||||
/// \param painter Painter
|
/// \param painter Painter
|
||||||
/// \param rect Draw rectangle (usually viewport rectangle of the pdf widget)
|
/// \param rect Draw rectangle (usually viewport rectangle of the pdf widget)
|
||||||
virtual void drawPostRendering(QPainter* painter, QRect rect) const;
|
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,
|
/// Input interface for handling events. Implementations should react on these events,
|
||||||
|
@ -809,9 +809,19 @@ void PDFDrawWidgetProxy::drawPages(QPainter* painter, QRect rect, PDFRenderer::F
|
|||||||
|
|
||||||
const PDFPage* page = m_controller->getDocument()->getCatalog()->getPage(item.pageIndex);
|
const PDFPage* page = m_controller->getDocument()->getCatalog()->getPage(item.pageIndex);
|
||||||
QTransform matrix = QTransform(createPagePointToDevicePointMatrix(page, placedRect)) * baseMatrix;
|
QTransform matrix = QTransform(createPagePointToDevicePointMatrix(page, placedRect)) * baseMatrix;
|
||||||
compiledPage->draw(painter, page->getCropBox(), matrix, features, groupInfo.transparency);
|
|
||||||
PDFTextLayoutGetter layoutGetter = m_textLayoutCompiler->getTextLayoutLazy(item.pageIndex);
|
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
|
// Draw text blocks/text lines, if it is enabled
|
||||||
if (features.testFlag(PDFRenderer::DebugTextBlocks))
|
if (features.testFlag(PDFRenderer::DebugTextBlocks))
|
||||||
{
|
{
|
||||||
@ -1629,4 +1639,9 @@ void IDocumentDrawInterface::drawPostRendering(QPainter* painter, QRect rect) co
|
|||||||
Q_UNUSED(rect);
|
Q_UNUSED(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IDocumentDrawInterface::isPageContentDrawSuppressed() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -333,6 +333,7 @@ PDFPageContentScene::PDFPageContentScene(QObject* parent) :
|
|||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_firstFreeId(1),
|
m_firstFreeId(1),
|
||||||
m_isActive(false),
|
m_isActive(false),
|
||||||
|
m_isPageContentDrawSuppressed(false),
|
||||||
m_widget(nullptr),
|
m_widget(nullptr),
|
||||||
m_manipulator(this, nullptr)
|
m_manipulator(this, nullptr)
|
||||||
{
|
{
|
||||||
@ -642,6 +643,11 @@ int PDFPageContentScene::getInputPriority() const
|
|||||||
return ToolPriority + 1;
|
return ToolPriority + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PDFPageContentScene::isPageContentDrawSuppressed() const
|
||||||
|
{
|
||||||
|
return isActive() && m_isPageContentDrawSuppressed;
|
||||||
|
}
|
||||||
|
|
||||||
void PDFPageContentScene::drawElements(QPainter* painter,
|
void PDFPageContentScene::drawElements(QPainter* painter,
|
||||||
PDFInteger pageIndex,
|
PDFInteger pageIndex,
|
||||||
PDFTextLayoutGetter& layoutGetter,
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
@ -823,6 +829,11 @@ void PDFPageContentScene::onSelectionChanged()
|
|||||||
Q_EMIT selectionChanged();
|
Q_EMIT selectionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFPageContentScene::setIsPageContentDrawSuppressed(bool newIsPageContentDrawSuppressed)
|
||||||
|
{
|
||||||
|
m_isPageContentDrawSuppressed = newIsPageContentDrawSuppressed;
|
||||||
|
}
|
||||||
|
|
||||||
PDFWidget* PDFPageContentScene::widget() const
|
PDFWidget* PDFPageContentScene::widget() const
|
||||||
{
|
{
|
||||||
return m_widget;
|
return m_widget;
|
||||||
|
@ -561,6 +561,7 @@ public:
|
|||||||
virtual QString getTooltip() const override;
|
virtual QString getTooltip() const override;
|
||||||
virtual const std::optional<QCursor>& getCursor() const override;
|
virtual const std::optional<QCursor>& getCursor() const override;
|
||||||
virtual int getInputPriority() const override;
|
virtual int getInputPriority() const override;
|
||||||
|
virtual bool isPageContentDrawSuppressed() const;
|
||||||
|
|
||||||
virtual void drawPage(QPainter* painter,
|
virtual void drawPage(QPainter* painter,
|
||||||
PDFInteger pageIndex,
|
PDFInteger pageIndex,
|
||||||
@ -579,6 +580,8 @@ public:
|
|||||||
const PDFPrecompiledPage* compiledPage,
|
const PDFPrecompiledPage* compiledPage,
|
||||||
QList<PDFRenderError>& errors) const;
|
QList<PDFRenderError>& errors) const;
|
||||||
|
|
||||||
|
void setIsPageContentDrawSuppressed(bool newIsPageContentDrawSuppressed);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/// This signal is emitted when scene has changed (including graphics)
|
/// This signal is emitted when scene has changed (including graphics)
|
||||||
void sceneChanged(bool graphicsOnly);
|
void sceneChanged(bool graphicsOnly);
|
||||||
@ -637,6 +640,7 @@ private:
|
|||||||
|
|
||||||
PDFInteger m_firstFreeId;
|
PDFInteger m_firstFreeId;
|
||||||
bool m_isActive;
|
bool m_isActive;
|
||||||
|
bool m_isPageContentDrawSuppressed;
|
||||||
PDFWidget* m_widget;
|
PDFWidget* m_widget;
|
||||||
std::vector<std::unique_ptr<PDFPageContentElement>> m_elements;
|
std::vector<std::unique_ptr<PDFPageContentElement>> m_elements;
|
||||||
std::optional<QCursor> m_cursor;
|
std::optional<QCursor> m_cursor;
|
||||||
|
Reference in New Issue
Block a user