Merge remote-tracking branch 'remotes/origin/branches/editor_plugin_REBASED4'

This commit is contained in:
Jakub Melka 2024-06-26 14:58:56 +02:00
commit 1e79871b9b
81 changed files with 6147 additions and 568 deletions

View File

@ -302,6 +302,7 @@ void DifferencesDrawInterface::drawPage(QPainter* painter,
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const pdf::PDFColorConvertor& convertor,
QList<pdf::PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
@ -329,7 +330,7 @@ void DifferencesDrawInterface::drawPage(QPainter* painter,
const auto& item = *it;
if (item.first == leftPageIndex)
{
QColor color = getColorForIndex(i);
QColor color = convertor.convert(getColorForIndex(i), false, true);
drawRectangle(painter, pagePointToDevicePointMatrix, item.second, color);
drawMarker(painter, pagePointToDevicePointMatrix, item.second, color, true);
}
@ -352,7 +353,7 @@ void DifferencesDrawInterface::drawPage(QPainter* painter,
const auto& item = *it;
if (item.first == rightPageIndex)
{
QColor color = getColorForIndex(i);
QColor color = convertor.convert(getColorForIndex(i), false, true);
drawRectangle(painter, pagePointToDevicePointMatrix, item.second, color);
drawMarker(painter, pagePointToDevicePointMatrix, item.second, color, false);
}
@ -388,7 +389,7 @@ void DifferencesDrawInterface::drawPage(QPainter* painter,
break;
}
QColor color = getColorForIndex(*pageMoveIndex);
QColor color = convertor.convert(getColorForIndex(*pageMoveIndex), false, true);
QPointF targetPoint = pagePointToDevicePointMatrix.map(QPointF(5, 5));
pdf::PDFPainterHelper::drawBubble(painter, targetPoint.toPoint(), color, text, Qt::AlignRight | Qt::AlignTop);
}

View File

@ -93,6 +93,7 @@ public:
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const pdf::PDFColorConvertor& convertor,
QList<pdf::PDFRenderError>& errors) const override;
virtual void drawPostRendering(QPainter* painter, QRect rect) const override;

View File

@ -20,6 +20,7 @@
#include "pdfwidgettool.h"
#include "pdfutils.h"
#include "pdfwidgetutils.h"
#include "pdfcms.h"
#include "audiobookcreator.h"
#include <QAction>
@ -170,6 +171,7 @@ void AudioBookPlugin::drawPage(QPainter* painter,
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const pdf::PDFColorConvertor& convertor,
QList<pdf::PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
@ -208,8 +210,8 @@ void AudioBookPlugin::drawPage(QPainter* painter,
fillColor.setAlphaF(0.2f);
pen.setColor(strokeColor);
painter->setPen(pen);
painter->setBrush(QBrush(fillColor));
painter->setPen(convertor.convert(pen));
painter->setBrush(convertor.convert(QBrush(fillColor)));
QPainterPath path;
path.addRect(boundingRect);

View File

@ -53,6 +53,7 @@ public:
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const pdf::PDFColorConvertor& convertor,
QList<pdf::PDFRenderError>& errors) const override;
// IDrawWidgetInputInterface interface

View File

@ -1,4 +1,4 @@
# Copyright (C) 2022 Jakub Melka
# Copyright (C) 2022-2023 Jakub Melka
#
# This file is part of PDF4QT.
#
@ -28,3 +28,4 @@ add_subdirectory(OutputPreviewPlugin)
add_subdirectory(RedactPlugin)
add_subdirectory(SignaturePlugin)
add_subdirectory(SoftProofingPlugin)
add_subdirectory(EditorPlugin)

View File

@ -18,6 +18,7 @@
#include "dimensionsplugin.h"
#include "pdfdrawwidget.h"
#include "pdfwidgetutils.h"
#include "pdfcms.h"
#include "settingsdialog.h"
#include <QPainter>
@ -149,6 +150,7 @@ void DimensionsPlugin::drawPage(QPainter* painter,
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const pdf::PDFColorConvertor& convertor,
QList<pdf::PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
@ -196,7 +198,7 @@ void DimensionsPlugin::drawPage(QPainter* painter,
QPointF unitVector = unitVectorLine.p2() - unitVectorLine.p1();
qreal extensionLineSize = pdf::PDFWidgetUtils::scaleDPI_y(painter->device(), 5);
painter->setPen(Qt::black);
painter->setPen(convertor.convert(QColor(Qt::black), false, true));
painter->drawLine(line);
QLineF extensionLineLeft(p1 - unitVector * extensionLineSize, p1 + unitVector * extensionLineSize);
@ -237,14 +239,14 @@ void DimensionsPlugin::drawPage(QPainter* painter,
QColor brushColor = Qt::black;
brushColor.setAlphaF(0.1f);
painter->setPen(qMove(pen));
painter->setBrush(QBrush(brushColor, isArea ? Qt::SolidPattern : Qt::DiagCrossPattern));
painter->setPen(convertor.convert(pen));
painter->setBrush(convertor.convert(QBrush(brushColor, isArea ? Qt::SolidPattern : Qt::DiagCrossPattern)));
painter->setTransform(QTransform(pagePointToDevicePointMatrix), true);
painter->drawPolygon(polygon.data(), int(polygon.size()), Qt::OddEvenFill);
painter->restore();
QPen penPoint(Qt::black);
QPen penPoint(convertor.convert(QColor(Qt::black), false, true));
penPoint.setCapStyle(Qt::RoundCap);
penPoint.setWidthF(pointSize);
painter->setPen(penPoint);
@ -287,7 +289,7 @@ void DimensionsPlugin::drawPage(QPainter* painter,
line1.setLength(maxLength);
line2.setLength(maxLength);
QPen pen(Qt::black);
QPen pen(convertor.convert(QColor(Qt::black), false, true));
pen.setWidthF(lineSize);
painter->setPen(qMove(pen));
@ -301,7 +303,7 @@ void DimensionsPlugin::drawPage(QPainter* painter,
rect.translate(line1.p1());
painter->drawArc(rect, startAngle - angleLength, angleLength);
QPen penPoint(Qt::black);
QPen penPoint(convertor.convert(QColor(Qt::black), false, true));
penPoint.setCapStyle(Qt::RoundCap);
penPoint.setWidthF(pointSize);
painter->setPen(penPoint);

View File

@ -47,6 +47,7 @@ public:
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const pdf::PDFColorConvertor& convertor,
QList<pdf::PDFRenderError>& errors) const override;
private:

View File

@ -18,6 +18,7 @@
#include "dimensiontool.h"
#include "pdfwidgetutils.h"
#include "pdfdrawwidget.h"
#include "pdfcms.h"
#include <QPainter>
@ -41,6 +42,7 @@ void DimensionTool::drawPage(QPainter* painter,
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const pdf::PDFColorConvertor& convertor,
QList<pdf::PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
@ -59,7 +61,7 @@ void DimensionTool::drawPage(QPainter* painter,
return;
}
painter->setPen(Qt::black);
painter->setPen(convertor.convert(QColor(Qt::black), false, true));
const std::vector<QPointF>& points = m_pickTool->getPickedPoints();
for (size_t i = 1; i < points.size(); ++i)
{

View File

@ -111,6 +111,7 @@ public:
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const pdf::PDFColorConvertor& convertor,
QList<pdf::PDFRenderError>& errors) const override;
signals:

View File

@ -0,0 +1,32 @@
# Copyright (C) 2023 Jakub Melka
#
# This file is part of PDF4QT.
#
# PDF4QT 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
# with the written consent of the copyright owner, any later version.
#
# PDF4QT 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 PDF4QT. If not, see <https://www.gnu.org/licenses/>.
add_library(EditorPlugin SHARED
editorplugin.cpp
icons.qrc
)
target_link_libraries(EditorPlugin PRIVATE Pdf4QtLibCore Pdf4QtLibWidgets Qt6::Core Qt6::Gui Qt6::Widgets)
set_target_properties(EditorPlugin PROPERTIES
VERSION ${PDF4QT_VERSION}
SOVERSION ${PDF4QT_VERSION}
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PDF4QT_PLUGINS_DIR}
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PDF4QT_PLUGINS_DIR})
install(TARGETS EditorPlugin RUNTIME DESTINATION ${PDF4QT_PLUGINS_DIR} LIBRARY DESTINATION ${PDF4QT_PLUGINS_DIR})

View File

@ -0,0 +1,7 @@
{
"Name" : "Editor",
"Author" : "Jakub Melka",
"Version" : "1.0.0",
"License" : "LGPL v3",
"Description" : "Edit content of PDF document."
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<circle fill="#21E900" cx="12" cy="12" r="11.098"/>
<g>
<path fill="#FFFFFF" d="M10.896,18.354c-0.24,0-0.474-0.087-0.658-0.247L6.28,14.649c-0.416-0.363-0.459-0.995-0.095-1.411
c0.363-0.414,0.996-0.458,1.411-0.095l3.042,2.656l5.56-9.652c0.274-0.478,0.887-0.643,1.365-0.368
c0.479,0.276,0.644,0.887,0.367,1.366l-6.167,10.707c-0.149,0.26-0.407,0.438-0.702,0.487
C11.005,18.349,10.95,18.354,10.896,18.354z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 889 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<g>
<g>
<path fill="#292D32" d="M22.52,5.539c-0.156-0.208-0.406-0.292-0.654-0.239c-0.215,0.042-0.379,0.179-0.491,0.411
c-0.093,0.199-0.188,0.396-0.286,0.594L21,6.484l-0.076-0.036l0.385-0.784c0.229-0.49,0.318-0.908,0.283-1.315
c-0.098-1.286-0.982-2.325-2.246-2.646C19.1,1.643,18.85,1.611,18.6,1.611c-1.072,0-2.012,0.56-2.447,1.46
c-2.148,4.415-4.289,8.831-6.421,13.25c-0.104,0.213-0.163,0.475-0.158,0.72c0.017,1.006,0.06,2.015,0.102,2.961
c0.009,0.183,0.021,0.431,0.146,0.597c0.143,0.189,0.136,0.334-0.034,0.594c-0.023,0.039-0.041,0.082-0.062,0.131
c-0.147,0.347-0.01,0.728,0.319,0.886c0.087,0.043,0.179,0.065,0.274,0.065c0.238,0,0.458-0.135,0.586-0.355
c0.042-0.07,0.077-0.146,0.112-0.221c0.03-0.067,0.062-0.133,0.093-0.188c0.012-0.017,0.042-0.037,0.049-0.041
c0.349-0.018,0.665-0.14,0.964-0.369c0.743-0.55,1.489-1.097,2.237-1.637c0.252-0.182,0.443-0.413,0.589-0.707
c1.016-2.102,2.034-4.197,3.055-6.297c0.771-1.588,1.544-3.177,2.313-4.767c0.009-0.017,0.017-0.033,0.024-0.05
c0.024,0.012,0.05,0.025,0.073,0.037l-2.311,4.762c-0.051,0.104-0.095,0.209-0.123,0.317c-0.086,0.35,0.111,0.688,0.463,0.782
c0.063,0.019,0.123,0.026,0.183,0.026c0.183,0,0.44-0.084,0.638-0.478l2.248-4.64c0.225-0.458,0.446-0.915,0.67-1.373l0.401-0.827
C22.709,6.001,22.686,5.755,22.52,5.539z M18.052,9.316c-0.135,0.285-0.27,0.563-0.401,0.838l-1.301,2.679
c-0.826,1.701-1.652,3.403-2.477,5.104c-0.075,0.151-0.107,0.106-0.188,0.092c-1.023-0.163-1.89-0.596-2.646-1.319
c-0.025-0.022-0.032-0.034-0.014-0.062c1.055-2.166,2.105-4.33,3.156-6.496l1.064-2.195C16.184,8.41,17.113,8.861,18.052,9.316z
M18.563,2.766v0.169c0.666,0,1.168,0.278,1.496,0.825c0.267,0.446,0.273,0.889,0.022,1.395c-0.349,0.691-0.685,1.388-1.021,2.084
L18.654,8.08c-0.008,0.012-0.014,0.024-0.02,0.038L15.831,6.76c0.071-0.151,0.144-0.298,0.212-0.442l0.466-0.963
c0.253-0.521,0.507-1.042,0.757-1.563c0.271-0.564,0.703-0.852,1.28-0.858L18.563,2.766L18.563,2.766z M12.541,19.15l-0.27,0.197
c-0.317,0.231-0.635,0.463-0.948,0.695c-0.119,0.086-0.185,0.105-0.25,0.07c-0.055-0.027-0.081-0.067-0.086-0.236
c-0.012-0.35-0.025-0.693-0.039-1.053l-0.02-0.496C11.438,18.672,11.96,18.939,12.541,19.15z"/>
</g>
<g>
<path fill="#292D32" d="M7.684,22.389c-1.105,0-1.947-0.215-2.457-0.847c-0.683-0.847-0.629-2.28,0.173-4.651
c0.505-1.492,0.518-2.516,0.035-2.955c-0.804-0.738-2.982-0.025-3.682,0.281l-0.418-0.951c0.339-0.146,3.359-1.419,4.801-0.098
c0.82,0.751,0.903,2.116,0.247,4.055c-0.648,1.916-0.766,3.15-0.349,3.668c0.465,0.578,1.855,0.504,3.152,0.357l0.116,1.031
C8.716,22.346,8.174,22.389,7.684,22.389z"/>
</g>
</g>
<circle fill="#F12D32" cx="8.572" cy="5.808" r="4.197"/>
<g>
<path fill="#FFFFFF" d="M6.366,7.536c0-0.004,0-0.009,0-0.013C6.367,7.508,6.375,7.502,6.377,7.49
c0.006-0.127,0.07-0.231,0.157-0.32c0.438-0.433,0.866-0.871,1.301-1.302c0.066-0.063,0.066-0.049,0-0.115
C7.401,5.316,6.969,4.88,6.531,4.446C6.457,4.373,6.402,4.285,6.384,4.18c-0.006-0.028-0.012-0.051-0.018-0.08
c0-0.004,0-0.011,0-0.016C6.37,4.071,6.377,4.057,6.377,4.042c0.019-0.201,0.161-0.374,0.365-0.419
c0.033-0.008,0.07-0.015,0.106-0.022c0.005,0,0.008,0,0.008,0C6.867,3.604,6.878,3.61,6.886,3.61
c0.141,0.005,0.249,0.076,0.344,0.174c0.435,0.437,0.874,0.873,1.312,1.31c0.027,0.026,0.048,0.032,0.073,0
c0.006-0.009,0.015-0.02,0.027-0.027C9.076,4.63,9.51,4.199,9.945,3.765c0.072-0.076,0.159-0.125,0.259-0.147
c0.032-0.004,0.059-0.011,0.091-0.016h0.005c0.018,0.002,0.036,0.009,0.049,0.009c0.237,0.017,0.442,0.261,0.429,0.495
c-0.013,0.14-0.069,0.251-0.164,0.345c-0.44,0.438-0.88,0.875-1.315,1.315c-0.042,0.042-0.042,0.042,0,0.086
c0.435,0.437,0.871,0.868,1.306,1.307c0.019,0.013,0.034,0.035,0.051,0.048c0.227,0.247,0.136,0.652-0.177,0.768
c-0.2,0.076-0.38,0.035-0.531-0.116C9.51,7.421,9.064,6.976,8.629,6.539c-0.048-0.05-0.048-0.05-0.096,0
c-0.444,0.44-0.887,0.888-1.329,1.328C7.068,8,6.907,8.042,6.727,7.992c-0.184-0.05-0.293-0.178-0.339-0.365
C6.375,7.595,6.372,7.565,6.366,7.536z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<g>
<g>
<path fill="#292D32" d="M4.679,14.168c0-2.972,2.008-5.06,4.817-5.06c2.811,0,4.735,2.088,4.735,5.06
c0,2.889-1.848,5.057-4.815,5.057C6.604,19.225,4.679,17.057,4.679,14.168z"/>
</g>
<path fill="#292D32" d="M12.926,7.973c0,0.318,0.227,0.577,0.506,0.577h5.382c0.277,0,0.507-0.259,0.507-0.577l0,0
c0-0.318-0.229-0.576-0.507-0.576h-5.382C13.152,7.396,12.926,7.655,12.926,7.973L12.926,7.973z"/>
<path fill="#292D32" d="M16.121,11.169c0.317,0,0.576-0.228,0.576-0.508V5.283c0-0.279-0.259-0.508-0.576-0.508l0,0
c-0.315,0-0.574,0.229-0.574,0.508v5.38C15.547,10.943,15.806,11.169,16.121,11.169L16.121,11.169z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<g>
<path fill="none" stroke="#292D32" stroke-width="1.5" stroke-miterlimit="10" d="M2.219,16.916c0,0,1.829-5.375,9.253-3.27
c7.8,2.213,8.95,1.967,10.308-0.605"/>
<path fill="#292D32" d="M14.854,9.8c0,0.271,0.192,0.49,0.429,0.49h4.568c0.236,0,0.431-0.22,0.431-0.49l0,0
c0-0.27-0.193-0.489-0.431-0.489h-4.568C15.047,9.311,14.854,9.53,14.854,9.8L14.854,9.8z"/>
<path fill="#292D32" d="M17.567,12.516c0.27,0,0.489-0.196,0.489-0.433V7.517c0-0.237-0.22-0.432-0.489-0.432l0,0
c-0.269,0-0.488,0.194-0.488,0.432v4.565C17.079,12.322,17.299,12.516,17.567,12.516L17.567,12.516z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<g>
<g>
<circle fill="#292D32" cx="3.012" cy="14.734" r="1.631"/>
<path fill="#292D32" d="M22.55,14.455c-0.039-0.09-0.091-0.176-0.163-0.242l-2.266-2.265c-0.294-0.297-0.771-0.297-1.064,0
c-0.293,0.292-0.293,0.767,0,1.062l0.948,0.938h-7.672H5.83v1.584h14.18l-0.938,0.939c-0.295,0.293-0.295,0.771,0,1.057
c0.144,0.15,0.337,0.221,0.527,0.221c0.194,0,0.38-0.07,0.528-0.221l2.263-2.27c0.074-0.061,0.134-0.143,0.164-0.236
c0.049-0.082,0.065-0.184,0.065-0.285C22.604,14.645,22.586,14.543,22.55,14.455z"/>
</g>
<path fill="#292D32" d="M13.716,9.075c0,0.281,0.2,0.51,0.445,0.51h4.749c0.246,0,0.448-0.229,0.448-0.51l0,0
c0-0.28-0.201-0.509-0.448-0.509h-4.749C13.916,8.566,13.716,8.794,13.716,9.075L13.716,9.075z"/>
<path fill="#292D32" d="M16.536,6.252c-0.279,0-0.508,0.202-0.508,0.449v4.746c0,0.25,0.229,0.451,0.508,0.451l0,0
c0.28,0,0.509-0.203,0.509-0.45V6.701C17.045,6.455,16.816,6.252,16.536,6.252"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<g>
<rect x="3.138" y="12.585" transform="matrix(-0.7801 0.6256 -0.6256 -0.7801 29.7118 16.3621)" fill="#292D32" width="17.685" height="1.633"/>
<path fill="#292D32" d="M14.923,5.652h-1.865V3.788c0-0.247-0.229-0.449-0.511-0.449c-0.279,0-0.508,0.202-0.508,0.449v1.864
h-1.867C9.928,5.653,9.727,5.881,9.727,6.161c0,0.281,0.201,0.51,0.445,0.51h1.867v1.862c0,0.25,0.229,0.451,0.508,0.451
c0.282,0,0.511-0.203,0.511-0.449V6.671h1.865c0.246,0,0.447-0.229,0.447-0.51C15.37,5.881,15.169,5.652,14.923,5.652z"/>
<path fill="#292D32" d="M3.815,20.035c0.579,0.721,1.634,0.836,2.356,0.256c0.723-0.58,0.839-1.633,0.261-2.354
c-0.58-0.725-1.635-0.842-2.358-0.262C3.352,18.256,3.236,19.313,3.815,20.035z"/>
<circle fill="#292D32" cx="18.878" cy="7.87" r="1.677"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<g>
<circle fill="#F12D32" cx="10.482" cy="13.178" r="7.749"/>
<g>
<path fill="#FFFFFF" d="M6.412,16.367c0-0.009,0-0.015,0-0.023c0.002-0.028,0.013-0.04,0.02-0.062
c0.01-0.233,0.13-0.426,0.289-0.586c0.81-0.802,1.6-1.61,2.403-2.405c0.122-0.117,0.122-0.09,0-0.211
c-0.803-0.808-1.602-1.614-2.411-2.411c-0.132-0.142-0.234-0.306-0.269-0.494c-0.01-0.053-0.019-0.096-0.032-0.147
c0-0.008,0-0.021,0-0.028c0.006-0.027,0.02-0.049,0.02-0.078c0.033-0.371,0.298-0.688,0.671-0.778
c0.065-0.012,0.131-0.024,0.201-0.037c0.004,0,0.01,0,0.01,0c0.021,0.002,0.038,0.017,0.055,0.017
C7.63,9.131,7.826,9.262,8.002,9.443c0.803,0.807,1.612,1.614,2.419,2.416c0.049,0.051,0.09,0.062,0.137,0
c0.01-0.017,0.027-0.037,0.048-0.047c0.803-0.803,1.603-1.604,2.41-2.402c0.131-0.143,0.293-0.233,0.477-0.274
c0.06-0.008,0.113-0.021,0.169-0.031h0.008c0.034,0.002,0.067,0.019,0.096,0.019c0.435,0.032,0.814,0.479,0.79,0.913
c-0.027,0.258-0.127,0.465-0.305,0.641c-0.813,0.804-1.626,1.615-2.427,2.418c-0.082,0.082-0.082,0.082,0,0.164
c0.801,0.805,1.605,1.604,2.409,2.412c0.032,0.024,0.064,0.066,0.094,0.091c0.417,0.454,0.25,1.204-0.326,1.421
c-0.368,0.137-0.702,0.057-0.976-0.217c-0.815-0.812-1.637-1.626-2.439-2.443c-0.088-0.086-0.088-0.086-0.176,0
c-0.82,0.817-1.638,1.645-2.454,2.455c-0.251,0.244-0.548,0.323-0.883,0.231c-0.335-0.092-0.539-0.329-0.623-0.675
C6.428,16.475,6.425,16.422,6.412,16.367z"/>
</g>
<path fill="#292D32" d="M15.623,5.896c0,0.281,0.2,0.51,0.445,0.51h4.749c0.246,0,0.448-0.229,0.448-0.51l0,0
c0-0.28-0.201-0.509-0.448-0.509h-4.749C15.823,5.388,15.623,5.616,15.623,5.896L15.623,5.896z"/>
<path fill="#292D32" d="M18.443,3.074c-0.279,0-0.508,0.202-0.508,0.449v4.746c0,0.25,0.229,0.451,0.508,0.451l0,0
c0.28,0,0.509-0.203,0.509-0.45V3.523C18.952,3.276,18.724,3.074,18.443,3.074"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<g>
<rect x="3.069" y="8.156" fill="none" stroke="#292D32" stroke-width="1.4" stroke-miterlimit="10" width="12.628" height="12.629"/>
<path fill="#292D32" d="M15.287,6.038c0,0.281,0.2,0.51,0.445,0.51h4.749c0.246,0,0.448-0.229,0.448-0.51l0,0
c0-0.279-0.201-0.508-0.448-0.508h-4.749C15.487,5.53,15.287,5.758,15.287,6.038L15.287,6.038z"/>
<path fill="#292D32" d="M18.107,3.215c-0.279,0-0.508,0.203-0.508,0.449v4.746c0,0.25,0.229,0.451,0.508,0.451l0,0
c0.28,0,0.509-0.203,0.509-0.45V3.665C18.616,3.418,18.388,3.215,18.107,3.215"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1014 B

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<g>
<path fill="none" stroke="#292D32" stroke-width="1.4" stroke-miterlimit="10" d="M5.069,8.156h8.628c1.104,0,2,0.896,2,2v8.629
c0,1.104-0.896,2-2,2H5.069c-1.104,0-2-0.896-2-2v-8.629C3.069,9.051,3.965,8.156,5.069,8.156z"/>
<path fill="#292D32" d="M15.287,6.038c0,0.281,0.2,0.51,0.445,0.51h4.749c0.246,0,0.448-0.229,0.448-0.51l0,0
c0-0.279-0.201-0.508-0.448-0.508h-4.749C15.487,5.53,15.287,5.758,15.287,6.038L15.287,6.038z"/>
<path fill="#292D32" d="M18.107,3.215c-0.279,0-0.508,0.203-0.508,0.449v4.746c0,0.25,0.229,0.451,0.508,0.451l0,0
c0.28,0,0.509-0.203,0.509-0.45V3.665C18.616,3.418,18.388,3.215,18.107,3.215"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<g>
<path fill="none" stroke="#292D32" stroke-width="1.4" stroke-miterlimit="10" d="M5.069,8.156h8.628c1.104,0,2,0.896,2,2v8.629
c0,1.104-0.896,2-2,2H5.069c-1.104,0-2-0.896-2-2v-8.629C3.069,9.051,3.965,8.156,5.069,8.156z"/>
<path fill="#292D32" d="M15.287,6.038c0,0.281,0.199,0.51,0.445,0.51h4.748c0.246,0,0.449-0.229,0.449-0.51l0,0
c0-0.279-0.201-0.508-0.449-0.508h-4.748C15.486,5.53,15.287,5.758,15.287,6.038L15.287,6.038z"/>
<path fill="#292D32" d="M18.107,3.215c-0.279,0-0.508,0.203-0.508,0.449V8.41c0,0.25,0.229,0.451,0.508,0.451l0,0
c0.279,0,0.509-0.203,0.509-0.45V3.665C18.616,3.418,18.389,3.215,18.107,3.215"/>
</g>
<path fill="#292D32" d="M13.564,12.111c0.007,1.156-0.962,2.128-2.12,2.13c-1.174,0-2.135-0.961-2.135-2.13
c0-1.165,0.947-2.117,2.12-2.128C12.591,9.969,13.559,10.933,13.564,12.111z M11.429,13.078c0.525,0.007,0.974-0.435,0.975-0.963
c0.002-0.53-0.437-0.972-0.969-0.972c-0.52,0-0.955,0.43-0.965,0.955C10.458,12.627,10.894,13.072,11.429,13.078z"/>
<path fill="#292D32" d="M15.411,17.156c-0.478-0.384-0.938-0.75-1.396-1.104c-0.638-0.505-1.34-0.527-1.999-0.055
c-0.583,0.417-1.176,0.846-1.758,1.273c-0.252,0.176-0.407,0.165-0.627-0.044c-0.57-0.582-1.141-1.153-1.713-1.724
c-0.681-0.681-1.526-0.715-2.263-0.088c-0.935,0.79-1.867,1.57-2.802,2.361c-0.011,0.011-0.021,0.022-0.044,0.032v1.594
c0.056-0.109,0.154-0.221,0.275-0.319c1.121-0.912,2.23-1.856,3.351-2.789c0.252-0.221,0.428-0.21,0.658,0.033
c0.572,0.581,1.143,1.164,1.713,1.746c0.649,0.659,1.461,0.715,2.197,0.153c0.55-0.428,1.099-0.856,1.66-1.285
c0.23-0.187,0.384-0.187,0.614,0c0.704,0.56,1.417,1.132,2.109,1.702c0.01,0.007,0.015,0.02,0.023,0.027V17.156z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<g>
<g>
<path fill="#292D32" d="M6.694,16.22h-3.22l-0.465,1.132H1.275l2.947-7.224h1.734l2.949,7.224H7.157L6.694,16.22z M6.155,14.905
l-1.072-2.64l-1.072,2.64H6.155z"/>
<path fill="#292D32" d="M15.564,14.633c0,1.666-1.047,2.851-2.5,2.851c-0.763,0-1.388-0.327-1.82-0.897v0.766H9.706v-7.349h1.539
v2.672c0.432-0.557,1.057-0.881,1.82-0.881C14.518,11.794,15.564,12.968,15.564,14.633z M14.072,14.633
c0-0.905-0.598-1.545-1.453-1.545c-0.748,0-1.292,0.546-1.375,1.331v0.425c0.083,0.794,0.626,1.347,1.375,1.347
C13.475,16.188,14.072,15.545,14.072,14.633z"/>
<path fill="#292D32" d="M16.34,14.633c0-1.545,1.367-2.839,2.98-2.839c0.879,0,1.605,0.354,2.133,0.921l-1.021,0.875
c-0.273-0.307-0.705-0.505-1.125-0.505c-0.799,0-1.48,0.708-1.48,1.536c0,0.851,0.682,1.568,1.494,1.568
c0.422,0,0.859-0.208,1.146-0.53l1.02,0.86c-0.539,0.592-1.271,0.961-2.178,0.961C17.697,17.483,16.34,16.169,16.34,14.633z"/>
</g>
<path fill="#292D32" d="M18.639,8.562c0,0.203,0.145,0.369,0.322,0.369h3.438c0.18,0,0.326-0.166,0.326-0.369l0,0
c0-0.202-0.146-0.368-0.326-0.368h-3.438C18.783,8.193,18.639,8.359,18.639,8.562L18.639,8.562z"/>
<path fill="#292D32" d="M20.682,6.518c-0.203,0-0.369,0.146-0.369,0.325v3.436c0,0.183,0.166,0.328,0.369,0.328l0,0
c0.201,0,0.367-0.147,0.367-0.326V6.843C21.049,6.664,20.885,6.518,20.682,6.518"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<g>
<g>
<circle fill="#292D32" cx="8.556" cy="20.988" r="1.631"/>
<path fill="#292D32" d="M8.277,1.45c-0.09,0.038-0.176,0.091-0.242,0.163L5.77,3.879c-0.297,0.294-0.297,0.771,0,1.064
c0.292,0.293,0.767,0.293,1.062,0l0.938-0.948v7.672v6.503h1.584V3.99l0.939,0.938c0.293,0.295,0.772,0.295,1.057,0
c0.15-0.144,0.222-0.337,0.222-0.527c0-0.193-0.069-0.379-0.222-0.527L9.08,1.609C9.019,1.536,8.937,1.477,8.843,1.445
C8.761,1.396,8.66,1.381,8.558,1.381C8.466,1.396,8.365,1.414,8.277,1.45z"/>
</g>
<path fill="#292D32" d="M12.793,4.273c0,0.281,0.2,0.51,0.445,0.51h4.749c0.246,0,0.447-0.229,0.447-0.51l0,0
c0-0.28-0.2-0.509-0.447-0.509h-4.749C12.993,3.764,12.793,3.992,12.793,4.273L12.793,4.273z"/>
<path fill="#292D32" d="M15.613,1.45c-0.279,0-0.509,0.202-0.509,0.449v4.746c0,0.25,0.229,0.451,0.509,0.451l0,0
c0.28,0,0.509-0.203,0.509-0.45V1.899C16.122,1.653,15.894,1.45,15.613,1.45"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<circle fill="#57B400" cx="10.453" cy="13.176" r="7.736"/>
<g>
<path fill="#FFFFFF" d="M15.982,10.202c-0.053,0.27-0.221,0.466-0.413,0.657c-1.996,1.992-3.996,3.988-5.987,5.976
c-0.271,0.276-0.585,0.392-0.961,0.259c-0.131-0.047-0.262-0.134-0.364-0.235c-1.016-1.004-2.024-2.022-3.038-3.034
c-0.152-0.15-0.243-0.329-0.291-0.535c0-0.074,0-0.147,0-0.22c0.049-0.203,0.127-0.39,0.287-0.536
c0.378-0.332,0.881-0.307,1.255,0.068c0.783,0.776,1.562,1.557,2.346,2.342c0.026,0.03,0.05,0.06,0.089,0.121
c0.047-0.057,0.063-0.091,0.094-0.116c1.812-1.81,3.625-3.625,5.441-5.445c0.262-0.262,0.568-0.376,0.931-0.262
c0.32,0.104,0.507,0.323,0.591,0.648c0.008,0.026,0.016,0.047,0.022,0.065C15.982,10.043,15.982,10.121,15.982,10.202z"/>
</g>
<g>
<path fill="#292D32" d="M15.623,5.896c0,0.281,0.2,0.51,0.445,0.51h4.748c0.246,0,0.449-0.229,0.449-0.51l0,0
c0-0.28-0.201-0.509-0.449-0.509h-4.748C15.823,5.388,15.623,5.616,15.623,5.896L15.623,5.896z"/>
<path fill="#292D32" d="M18.443,3.074c-0.279,0-0.508,0.202-0.508,0.449v4.746c0,0.25,0.229,0.451,0.508,0.451l0,0
c0.279,0,0.509-0.203,0.509-0.45V3.523C18.952,3.276,18.725,3.074,18.443,3.074"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,835 @@
// Copyright (C) 2023-2024 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT 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
// with the written consent of the copyright owner, any later version.
//
// PDF4QT 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 PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "editorplugin.h"
#include "pdfdrawwidget.h"
#include "pdfutils.h"
#include "pdfpagecontenteditorwidget.h"
#include "pdfpagecontenteditorstylesettings.h"
#include "pdfdocumentbuilder.h"
#include "pdfcertificatemanagerdialog.h"
#include "pdfdocumentwriter.h"
#include "pdfpagecontenteditorprocessor.h"
#include "pdfpagecontenteditorcontentstreambuilder.h"
#include "pdfstreamfilters.h"
#include "pdfoptimizer.h"
#include <QAction>
#include <QToolButton>
#include <QMainWindow>
#include <QMessageBox>
#include <QFileDialog>
namespace pdfplugin
{
EditorPlugin::EditorPlugin() :
pdf::PDFPlugin(nullptr),
m_actions({ }),
m_tools({ }),
m_editorWidget(nullptr),
m_scene(nullptr),
m_sceneSelectionChangeEnabled(true),
m_isSaving(false)
{
m_scene.setIsPageContentDrawSuppressed(true);
}
// TODO: When text is edited, old text remains
void EditorPlugin::setWidget(pdf::PDFWidget* widget)
{
Q_ASSERT(!m_widget);
BaseClass::setWidget(widget);
QAction* activateAction = new QAction(QIcon(":/pdfplugins/editorplugin/activate.svg"), tr("&Edit page content"), this);
QAction* createTextAction = new QAction(QIcon(":/pdfplugins/editorplugin/create-text.svg"), tr("Create &Text Label"), this);
QAction* createFreehandCurveAction = new QAction(QIcon(":/pdfplugins/editorplugin/create-freehand-curve.svg"), tr("Create &Freehand Curve"), this);
QAction* createAcceptMarkAction = new QAction(QIcon(":/pdfplugins/editorplugin/create-yes-mark.svg"), tr("Create &Accept Mark"), this);
QAction* createRejectMarkAction = new QAction(QIcon(":/pdfplugins/editorplugin/create-no-mark.svg"), tr("Create &Reject Mark"), this);
QAction* createRectangleAction = new QAction(QIcon(":/pdfplugins/editorplugin/create-rectangle.svg"), tr("Create R&ectangle"), this);
QAction* createRoundedRectangleAction = new QAction(QIcon(":/pdfplugins/editorplugin/create-rounded-rectangle.svg"), tr("&Create Rounded Rectangle"), this);
QAction* createHorizontalLineAction = new QAction(QIcon(":/pdfplugins/editorplugin/create-horizontal-line.svg"), tr("Create &Horizontal Line"), this);
QAction* createVerticalLineAction = new QAction(QIcon(":/pdfplugins/editorplugin/create-vertical-line.svg"), tr("Create &Vertical Line"), this);
QAction* createLineAction = new QAction(QIcon(":/pdfplugins/editorplugin/create-line.svg"), tr("Create L&ine"), this);
QAction* createDotAction = new QAction(QIcon(":/pdfplugins/editorplugin/create-dot.svg"), tr("Create &Dot"), this);
QAction* createSvgImageAction = new QAction(QIcon(":/pdfplugins/editorplugin/create-svg-image.svg"), tr("Create &SVG Image"), this);
QAction* clearAction = new QAction(QIcon(":/pdfplugins/editorplugin/clear.svg"), tr("Clear A&ll Graphics"), this);
QAction* certificatesAction = new QAction(QIcon(":/pdfplugins/editorplugin/certificates.svg"), tr("Certificates &Manager"), this);
activateAction->setObjectName("editortool_activateAction");
createTextAction->setObjectName("editortool_createTextAction");
createFreehandCurveAction->setObjectName("editortool_createFreehandCurveAction");
createAcceptMarkAction->setObjectName("editortool_createAcceptMarkAction");
createRejectMarkAction->setObjectName("editortool_createRejectMarkAction");
createRectangleAction->setObjectName("editortool_createRectangleAction");
createRoundedRectangleAction->setObjectName("editortool_createRoundedRectangleAction");
createHorizontalLineAction->setObjectName("editortool_createHorizontalLineAction");
createVerticalLineAction->setObjectName("editortool_createVerticalLineAction");
createLineAction->setObjectName("editortool_createLineAction");
createDotAction->setObjectName("editortool_createDotAction");
createSvgImageAction->setObjectName("editortool_createSvgImageAction");
clearAction->setObjectName("editortool_clearAction");
certificatesAction->setObjectName("editortool_certificatesAction");
activateAction->setCheckable(true);
createTextAction->setCheckable(true);
createFreehandCurveAction->setCheckable(true);
createAcceptMarkAction->setCheckable(true);
createRejectMarkAction->setCheckable(true);
createRectangleAction->setCheckable(true);
createRoundedRectangleAction->setCheckable(true);
createHorizontalLineAction->setCheckable(true);
createVerticalLineAction->setCheckable(true);
createLineAction->setCheckable(true);
createDotAction->setCheckable(true);
createSvgImageAction->setCheckable(true);
m_actions[Activate] = activateAction;
m_actions[Text] = createTextAction;
m_actions[FreehandCurve] = createFreehandCurveAction;
m_actions[AcceptMark] = createAcceptMarkAction;
m_actions[RejectMark] = createRejectMarkAction;
m_actions[Rectangle] = createRectangleAction;
m_actions[RoundedRectangle] = createRoundedRectangleAction;
m_actions[HorizontalLine] = createHorizontalLineAction;
m_actions[VerticalLine] = createVerticalLineAction;
m_actions[Line] = createLineAction;
m_actions[Dot] = createDotAction;
m_actions[SvgImage] = createSvgImageAction;
m_actions[Clear] = clearAction;
QFile acceptMarkFile(":/pdfplugins/editorplugin/accept-mark.svg");
QByteArray acceptMarkContent;
if (acceptMarkFile.open(QFile::ReadOnly))
{
acceptMarkContent = acceptMarkFile.readAll();
acceptMarkFile.close();
}
QFile rejectMarkFile(":/pdfplugins/editorplugin/reject-mark.svg");
QByteArray rejectMarkContent;
if (rejectMarkFile.open(QFile::ReadOnly))
{
rejectMarkContent = rejectMarkFile.readAll();
rejectMarkFile.close();
}
m_tools[TextTool] = new pdf::PDFCreatePCElementTextTool(widget->getDrawWidgetProxy(), &m_scene, createTextAction, this);
m_tools[FreehandCurveTool] = new pdf::PDFCreatePCElementFreehandCurveTool(widget->getDrawWidgetProxy(), &m_scene, createFreehandCurveAction, this);
m_tools[AcceptMarkTool] = new pdf::PDFCreatePCElementImageTool(widget->getDrawWidgetProxy(), &m_scene, createAcceptMarkAction, acceptMarkContent, false, this);
m_tools[RejectMarkTool] = new pdf::PDFCreatePCElementImageTool(widget->getDrawWidgetProxy(), &m_scene, createRejectMarkAction, rejectMarkContent, false, this);
m_tools[RectangleTool] = new pdf::PDFCreatePCElementRectangleTool(widget->getDrawWidgetProxy(), &m_scene, createRectangleAction, false, this);
m_tools[RoundedRectangleTool] = new pdf::PDFCreatePCElementRectangleTool(widget->getDrawWidgetProxy(), &m_scene, createRoundedRectangleAction, true, this);
m_tools[HorizontalLineTool] = new pdf::PDFCreatePCElementLineTool(widget->getDrawWidgetProxy(), &m_scene, createHorizontalLineAction, true, false, this);
m_tools[VerticalLineTool] = new pdf::PDFCreatePCElementLineTool(widget->getDrawWidgetProxy(), &m_scene, createVerticalLineAction, false, true, this);
m_tools[LineTool] = new pdf::PDFCreatePCElementLineTool(widget->getDrawWidgetProxy(), &m_scene, createLineAction, false, false, this);
m_tools[DotTool] = new pdf::PDFCreatePCElementDotTool(widget->getDrawWidgetProxy(), &m_scene, createDotAction, this);
m_tools[ImageTool] = new pdf::PDFCreatePCElementImageTool(widget->getDrawWidgetProxy(), &m_scene, createSvgImageAction, QByteArray(), true, this);
pdf::PDFToolManager* toolManager = widget->getToolManager();
for (pdf::PDFWidgetTool* tool : m_tools)
{
toolManager->addTool(tool);
connect(tool, &pdf::PDFWidgetTool::toolActivityChanged, this, &EditorPlugin::onToolActivityChanged);
}
m_widget->addInputInterface(&m_scene);
m_widget->getDrawWidgetProxy()->registerDrawInterface(&m_scene);
m_scene.setWidget(m_widget);
connect(&m_scene, &pdf::PDFPageContentScene::sceneChanged, this, &EditorPlugin::onSceneChanged);
connect(&m_scene, &pdf::PDFPageContentScene::selectionChanged, this, &EditorPlugin::onSceneSelectionChanged);
connect(&m_scene, &pdf::PDFPageContentScene::editElementRequest, this, &EditorPlugin::onSceneEditElement);
connect(clearAction, &QAction::triggered, &m_scene, &pdf::PDFPageContentScene::clear);
connect(activateAction, &QAction::triggered, this, &EditorPlugin::onSetActive);
connect(m_widget->getDrawWidgetProxy(), &pdf::PDFDrawWidgetProxy::drawSpaceChanged, this, &EditorPlugin::onDrawSpaceChanged);
connect(m_widget, &pdf::PDFWidget::sceneActivityChanged, this, &EditorPlugin::onSceneActivityChanged);
updateActions();
}
void EditorPlugin::setDocument(const pdf::PDFModifiedDocument& document)
{
BaseClass::setDocument(document);
if (document.hasReset())
{
setActive(false);
updateActions();
}
}
std::vector<QAction*> EditorPlugin::getActions() const
{
std::vector<QAction*> result;
result.push_back(m_actions[Activate]);
return result;
}
QString EditorPlugin::getPluginMenuName() const
{
return tr("Edi&tor");
}
bool EditorPlugin::updatePageContent(pdf::PDFInteger pageIndex,
const std::vector<const pdf::PDFPageContentElement*>& elements,
pdf::PDFDocumentBuilder* builder)
{
pdf::PDFColorConvertor convertor;
const pdf::PDFPage* page = m_document->getCatalog()->getPage(pageIndex);
const pdf::PDFEditedPageContent& editedPageContent = m_editedPageContent.at(pageIndex);
QRectF mediaBox = page->getMediaBox();
QRectF mediaBoxMM = page->getMediaBoxMM();
pdf::PDFPageContentEditorContentStreamBuilder contentStreamBuilder(m_document);
contentStreamBuilder.setFontDictionary(editedPageContent.getFontDictionary());
for (const pdf::PDFPageContentElement* element : elements)
{
const pdf::PDFPageContentElementEdited* editedElement = element->asElementEdited();
const pdf::PDFPageContentElementRectangle* elementRectangle = element->asElementRectangle();
const pdf::PDFPageContentElementLine* elementLine = element->asElementLine();
const pdf::PDFPageContentElementDot* elementDot = element->asElementDot();
const pdf::PDFPageContentElementFreehandCurve* elementFreehandCurve = element->asElementFreehandCurve();
const pdf::PDFPageContentImageElement* elementImage = element->asElementImage();
const pdf::PDFPageContentElementTextBox* elementTextBox = element->asElementTextBox();
if (editedElement)
{
contentStreamBuilder.writeEditedElement(editedElement->getElement());
}
if (elementRectangle)
{
QRectF rect = elementRectangle->getRectangle();
QPainterPath path;
if (elementRectangle->isRounded())
{
qreal radius = qMin(rect.width(), rect.height()) * 0.25;
path.addRoundedRect(rect, radius, radius, Qt::AbsoluteSize);
}
else
{
path.addRect(rect);
}
const bool stroke = elementRectangle->getPen().style() != Qt::NoPen;
const bool fill = elementRectangle->getBrush().style() != Qt::NoBrush;
contentStreamBuilder.writeStyledPath(path, elementRectangle->getPen(), elementRectangle->getBrush(), stroke, fill);
}
if (elementLine)
{
QLineF line = elementLine->getLine();
QPainterPath path;
path.moveTo(line.p1());
path.lineTo(line.p2());
contentStreamBuilder.writeStyledPath(path, elementLine->getPen(), elementLine->getBrush(), true, false);
}
if (elementDot)
{
QPen pen = elementDot->getPen();
const qreal radius = pen.widthF() * 0.5;
QPainterPath path;
path.addEllipse(elementDot->getPoint(), radius, radius);
contentStreamBuilder.writeStyledPath(path, Qt::NoPen, QBrush(pen.color()), false, true);
}
if (elementFreehandCurve)
{
QPainterPath path = elementFreehandCurve->getCurve();
contentStreamBuilder.writeStyledPath(path, elementFreehandCurve->getPen(), elementFreehandCurve->getBrush(), true, false);
}
if (elementImage)
{
QImage image = elementImage->getImage();
if (!image.isNull())
{
contentStreamBuilder.writeImage(image, elementImage->getRectangle());
}
else
{
// It is probably an SVG image
pdf::PDFContentEditorPaintDevice paintDevice(&contentStreamBuilder, mediaBox, mediaBoxMM);
QPainter painter(&paintDevice);
QList<pdf::PDFRenderError> errors;
pdf::PDFTextLayoutGetter textLayoutGetter(nullptr, pageIndex);
elementImage->drawPage(&painter, &m_scene, pageIndex, nullptr, textLayoutGetter, QTransform(), convertor, errors);
}
}
if (elementTextBox)
{
pdf::PDFContentEditorPaintDevice paintDevice(&contentStreamBuilder, mediaBox, mediaBoxMM);
QPainter painter(&paintDevice);
QList<pdf::PDFRenderError> errors;
pdf::PDFTextLayoutGetter textLayoutGetter(nullptr, pageIndex);
elementTextBox->drawPage(&painter, &m_scene, pageIndex, nullptr, textLayoutGetter, QTransform(), convertor, errors);
}
}
QStringList errors = contentStreamBuilder.getErrors();
contentStreamBuilder.clearErrors();
if (!errors.empty())
{
const int errorCount = errors.size();
if (errors.size() > 3)
{
errors.resize(3);
}
QString message = tr("Errors (%2) occured while creating content stream on page %3.<br>%1").arg(errors.join("<br>")).arg(errorCount).arg(pageIndex + 1);
if (QMessageBox::question(m_dataExchangeInterface->getMainWindow(), tr("Error"), message, QMessageBox::Abort, QMessageBox::Ignore) == QMessageBox::Abort)
{
return false;
}
}
pdf::PDFDictionary fontDictionary = contentStreamBuilder.getFontDictionary();
pdf::PDFDictionary xobjectDictionary = contentStreamBuilder.getXObjectDictionary();
pdf::PDFDictionary graphicStateDictionary = contentStreamBuilder.getGraphicStateDictionary();
builder->replaceObjectsByReferences(fontDictionary);
builder->replaceObjectsByReferences(xobjectDictionary);
builder->replaceObjectsByReferences(graphicStateDictionary);
pdf::PDFArray array;
array.appendItem(pdf::PDFObject::createName("FlateDecode"));
// Compress the content stream
QByteArray compressedData = pdf::PDFFlateDecodeFilter::compress(contentStreamBuilder.getOutputContent());
pdf::PDFDictionary contentDictionary;
contentDictionary.setEntry(pdf::PDFInplaceOrMemoryString("Length"), pdf::PDFObject::createInteger(compressedData.size()));
contentDictionary.setEntry(pdf::PDFInplaceOrMemoryString("Filter"), pdf::PDFObject::createArray(std::make_shared<pdf::PDFArray>(qMove(array))));
pdf::PDFObject contentObject = pdf::PDFObject::createStream(std::make_shared<pdf::PDFStream>(qMove(contentDictionary), qMove(compressedData)));
pdf::PDFObject pageObject = builder->getObjectByReference(page->getPageReference());
pdf::PDFObjectFactory factory;
factory.beginDictionary();
factory.beginDictionaryItem("Resources");
factory.beginDictionary();
if (!fontDictionary.isEmpty())
{
factory.beginDictionaryItem("Font");
factory << fontDictionary;
factory.endDictionaryItem();
}
if (!xobjectDictionary.isEmpty())
{
factory.beginDictionaryItem("XObject");
factory << xobjectDictionary;
factory.endDictionaryItem();
}
if (!graphicStateDictionary.isEmpty())
{
factory.beginDictionaryItem("ExtGState");
factory << graphicStateDictionary;
factory.endDictionaryItem();
}
factory.endDictionary();
factory.endDictionaryItem();
factory.beginDictionaryItem("Contents");
factory << builder->addObject(std::move(contentObject));
factory.endDictionaryItem();
factory.endDictionary();
pageObject = pdf::PDFObjectManipulator::merge(pageObject, factory.takeObject(), pdf::PDFObjectManipulator::RemoveNullObjects);
builder->setObject(page->getPageReference(), std::move(pageObject));
return true;
}
bool EditorPlugin::save()
{
pdf::PDFTemporaryValueChange guard(&m_isSaving, true);
auto answer = QMessageBox::question(m_dataExchangeInterface->getMainWindow(), tr("Confirm Changes"), tr("The changes to the page content will be written to the document. Do you want to continue?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Cancel);
if (answer == QMessageBox::Cancel)
{
return false;
}
if (answer == QMessageBox::Yes)
{
pdf::PDFDocumentModifier modifier(m_document);
pdf::PDFDocumentBuilder* builder = modifier.getBuilder();
std::set<pdf::PDFInteger> pageIndices;
for (const auto& item : m_editedPageContent)
{
pageIndices.insert(item.first);
}
std::map<pdf::PDFInteger, std::vector<const pdf::PDFPageContentElement*>> elementsByPage = m_scene.getElementsByPage();
for (pdf::PDFInteger pageIndex : pageIndices)
{
if (m_editedPageContent.count(pageIndex) == 0)
{
continue;
}
std::vector<const pdf::PDFPageContentElement*> elements;
auto it = elementsByPage.find(pageIndex);
if (it != elementsByPage.cend())
{
elements = std::move(it->second);
}
if (!updatePageContent(pageIndex, elements, builder))
{
return false;
}
modifier.markReset();
}
m_scene.clear();
m_editedPageContent.clear();
if (modifier.finalize())
{
pdf::PDFDocument document = *modifier.getDocument();
pdf::PDFOptimizer optimizer(pdf::PDFOptimizer::DereferenceSimpleObjects |
pdf::PDFOptimizer::RemoveNullObjects |
pdf::PDFOptimizer::RemoveUnusedObjects |
pdf::PDFOptimizer::MergeIdenticalObjects |
pdf::PDFOptimizer::ShrinkObjectStorage, nullptr);
optimizer.setDocument(&document);
optimizer.optimize();
document = optimizer.takeOptimizedDocument();
Q_EMIT m_widget->getToolManager()->documentModified(pdf::PDFModifiedDocument(pdf::PDFDocumentPointer(new pdf::PDFDocument(std::move(document))), nullptr, modifier.getFlags()));
}
}
return true;
}
void EditorPlugin::onSceneActivityChanged()
{
updateActions();
}
void EditorPlugin::onSceneChanged(bool graphicsOnly)
{
if (!graphicsOnly)
{
updateActions();
}
if (m_editorWidget)
{
m_editorWidget->updateItemsInListWidget();
}
updateGraphics();
}
void EditorPlugin::onSceneSelectionChanged()
{
if (m_editorWidget && m_sceneSelectionChangeEnabled)
{
m_editorWidget->setSelection(m_scene.getSelectedElementIds());
}
}
void EditorPlugin::onWidgetSelectionChanged()
{
Q_ASSERT(m_editorWidget);
pdf::PDFTemporaryValueChange guard(&m_sceneSelectionChangeEnabled, false);
m_scene.setSelectedElementIds(m_editorWidget->getSelection());
}
pdf::PDFWidgetTool* EditorPlugin::getActiveTool()
{
for (pdf::PDFWidgetTool* currentTool : m_tools)
{
if (currentTool->isActive())
{
return currentTool;
}
}
return nullptr;
}
void EditorPlugin::onToolActivityChanged()
{
if (m_editorWidget)
{
pdf::PDFWidgetTool* activeTool = getActiveTool();
const pdf::PDFPageContentElement* element = nullptr;
pdf::PDFCreatePCElementTool* tool = qobject_cast<pdf::PDFCreatePCElementTool*>(activeTool);
if (tool)
{
element = tool->getElement();
}
m_editorWidget->loadStyleFromElement(element);
}
}
void EditorPlugin::onSceneEditElement(const std::set<pdf::PDFInteger>& elements)
{
if (elements.empty())
{
return;
}
pdf::PDFPageContentElement* element = nullptr;
for (pdf::PDFInteger id : elements)
{
element = m_scene.getElementById(id);
if (element)
{
break;
}
}
if (!element)
{
return;
}
std::unique_ptr<pdf::PDFPageContentElement> clonedElement(element->clone());
if (pdf::PDFPageContentEditorStyleSettings::showEditElementStyleDialog(m_dataExchangeInterface->getMainWindow(), clonedElement.get()))
{
if (clonedElement->asElementEdited())
{
pdf::PDFPageContentElementEdited* editedElement = dynamic_cast<pdf::PDFPageContentElementEdited*>(clonedElement.get());
if (editedElement->getElement()->asText())
{
if (!updateTextElement(editedElement))
{
return;
}
}
}
m_scene.replaceElement(clonedElement.release());
updateGraphics();
}
}
void EditorPlugin::onSceneEditSingleElement(pdf::PDFInteger elementId)
{
onSceneEditElement({ elementId });
}
void EditorPlugin::onPenChanged(const QPen& pen)
{
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
{
activeTool->setPen(pen);
}
}
void EditorPlugin::onBrushChanged(const QBrush& brush)
{
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
{
activeTool->setBrush(brush);
}
}
void EditorPlugin::onFontChanged(const QFont& font)
{
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
{
activeTool->setFont(font);
}
}
void EditorPlugin::onAlignmentChanged(Qt::Alignment alignment)
{
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
{
activeTool->setAlignment(alignment);
}
}
void EditorPlugin::onTextAngleChanged(pdf::PDFReal angle)
{
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
{
activeTool->setTextAngle(angle);
}
}
void EditorPlugin::setActive(bool active)
{
if (m_scene.isActive() != active)
{
// Abort active tool, if we are deactivating the plugin
if (!active)
{
if (pdf::PDFWidgetTool* tool = m_widget->getToolManager()->getActiveTool())
{
auto it = std::find(m_tools.cbegin(), m_tools.cend(), tool);
if (it != m_tools.cend())
{
m_widget->getToolManager()->setActiveTool(nullptr);
}
}
}
m_scene.setActive(active);
if (!active)
{
m_scene.clear();
m_editedPageContent.clear();
}
else
{
updateDockWidget();
updateEditedPages();
}
m_actions[Activate]->setChecked(active);
updateActions();
// If editor is not active, remove the widget
if (m_editorWidget && !active)
{
delete m_editorWidget;
m_editorWidget = nullptr;
}
}
}
void EditorPlugin::onSetActive(bool active)
{
if (m_scene.isActive() && !active && !save())
{
updateActions();
m_actions[Activate]->setChecked(true);
return;
}
setActive(active);
}
void EditorPlugin::updateActions()
{
m_actions[Activate]->setEnabled(m_document);
if (!m_scene.isActive() || !m_document)
{
// Inactive scene - disable all except activate action
for (QAction* action : m_actions)
{
if (action == m_actions[Activate])
{
action->setEnabled(m_widget && !m_widget->isAnySceneActive(&m_scene));
continue;
}
action->setEnabled(false);
}
return;
}
const bool isSceneNonempty = !m_scene.isEmpty();
// Tool actions
for (auto actionId : { Text, FreehandCurve, AcceptMark, RejectMark,
Rectangle, RoundedRectangle, HorizontalLine,
VerticalLine, Line, Dot, SvgImage })
{
m_actions[actionId]->setEnabled(true);
}
// Clear action
QAction* clearAction = m_actions[Clear];
clearAction->setEnabled(isSceneNonempty);
}
void EditorPlugin::updateGraphics()
{
if (m_widget)
{
m_widget->getDrawWidget()->getWidget()->update();
}
}
void EditorPlugin::updateDockWidget()
{
if (m_editorWidget)
{
return;
}
m_editorWidget = new pdf::PDFPageContentEditorWidget(m_dataExchangeInterface->getMainWindow());
m_editorWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_dataExchangeInterface->getMainWindow()->addDockWidget(Qt::RightDockWidgetArea, m_editorWidget, Qt::Vertical);
m_editorWidget->setFloating(false);
m_editorWidget->setWindowTitle(tr("Editor Toolbox"));
m_editorWidget->setScene(&m_scene);
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::operationTriggered, &m_scene, &pdf::PDFPageContentScene::performOperation);
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::itemSelectionChangedByUser, this, &EditorPlugin::onWidgetSelectionChanged);
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::editElementRequest, this, &EditorPlugin::onSceneEditSingleElement);
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignTop))->setIcon(QIcon(":/resources/pce-align-top.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignCenterVertically))->setIcon(QIcon(":/resources/pce-align-v-center.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignBottom))->setIcon(QIcon(":/resources/pce-align-bottom.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignLeft))->setIcon(QIcon(":/resources/pce-align-left.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignCenterHorizontally))->setIcon(QIcon(":/resources/pce-align-h-center.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignRight))->setIcon(QIcon(":/resources/pce-align-right.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::SetSameHeight))->setIcon(QIcon(":/resources/pce-same-height.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::SetSameWidth))->setIcon(QIcon(":/resources/pce-same-width.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::SetSameSize))->setIcon(QIcon(":/resources/pce-same-size.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::CenterHorizontally))->setIcon(QIcon(":/resources/pce-center-h.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::CenterVertically))->setIcon(QIcon(":/resources/pce-center-v.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::CenterHorAndVert))->setIcon(QIcon(":/resources/pce-center-vh.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::LayoutVertically))->setIcon(QIcon(":/resources/pce-layout-v.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::LayoutHorizontally))->setIcon(QIcon(":/resources/pce-layout-h.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::LayoutForm))->setIcon(QIcon(":/resources/pce-layout-form.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::LayoutGrid))->setIcon(QIcon(":/resources/pce-layout-grid.svg"));
for (QAction* action : m_actions)
{
m_editorWidget->addAction(action);
}
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::penChanged, this, &EditorPlugin::onPenChanged);
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::brushChanged, this, &EditorPlugin::onBrushChanged);
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::fontChanged, this, &EditorPlugin::onFontChanged);
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::alignmentChanged, this, &EditorPlugin::onAlignmentChanged);
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::textAngleChanged, this, &EditorPlugin::onTextAngleChanged);
}
void EditorPlugin::updateEditedPages()
{
if (!m_scene.isActive() || m_isSaving)
{
// Editor is not active or we are saving the document
return;
}
std::vector<pdf::PDFInteger> currentPages = m_widget->getDrawWidget()->getCurrentPages();
for (pdf::PDFInteger pageIndex : currentPages)
{
if (m_editedPageContent.count(pageIndex))
{
continue;
}
const pdf::PDFPage* page = m_document->getCatalog()->getPage(pageIndex);
auto cms = m_widget->getDrawWidgetProxy()->getCMSManager()->getCurrentCMS();
pdf::PDFPageContentEditorProcessor processor(page,
m_document,
m_widget->getDrawWidgetProxy()->getFontCache(),
cms.data(),
m_widget->getDrawWidgetProxy()->getOptionalContentActivity(),
QTransform(),
pdf::PDFMeshQualitySettings());
QList<pdf::PDFRenderError> errors = processor.processContents();
Q_UNUSED(errors);
m_editedPageContent[pageIndex] = processor.takeEditedPageContent();
size_t elementCount = m_editedPageContent[pageIndex].getElementCount();
for (size_t i = 0; i < elementCount; ++i)
{
pdf::PDFEditedPageContentElement* element = m_editedPageContent[pageIndex].getElement(i);
pdf::PDFPageContentElementEdited* editedElement = new pdf::PDFPageContentElementEdited(element);
editedElement->setPageIndex(pageIndex);
m_scene.addElement(editedElement);
}
}
}
bool EditorPlugin::updateTextElement(pdf::PDFPageContentElementEdited* element)
{
pdf::PDFPageContentElementEdited* elementEdited = dynamic_cast<pdf::PDFPageContentElementEdited*>(element);
pdf::PDFEditedPageContentElementText* targetTextElement = elementEdited->getElement()->asText();
if (!targetTextElement)
{
return false;
}
pdf::PDFDocumentModifier modifier(m_document);
pdf::PDFDocumentBuilder* builder = modifier.getBuilder();
if (!updatePageContent(element->getPageIndex(), { element }, builder))
{
return false;
}
if (modifier.finalize())
{
pdf::PDFDocument* document = modifier.getDocument().get();
const pdf::PDFPage* page = document->getCatalog()->getPage(element->getPageIndex());
auto cms = m_widget->getDrawWidgetProxy()->getCMSManager()->getCurrentCMS();
pdf::PDFFontCache fontCache(64, 64);
pdf::PDFOptionalContentActivity activity(document, pdf::OCUsage::View, nullptr);
fontCache.setDocument(pdf::PDFModifiedDocument(document, &activity));
pdf::PDFPageContentEditorProcessor processor(page, document, &fontCache, cms.data(), &activity, QTransform(), pdf::PDFMeshQualitySettings());
QList<pdf::PDFRenderError> errors = processor.processContents();
Q_UNUSED(errors);
pdf::PDFEditedPageContent content = processor.takeEditedPageContent();
if (content.getElementCount() == 1)
{
pdf::PDFEditedPageContentElement* sourceElement = content.getElement(0);
pdf::PDFEditedPageContentElementText* sourceElementText = sourceElement->asText();
targetTextElement->setState(sourceElementText->getState());
targetTextElement->setTextPath(sourceElementText->getTextPath());
}
else
{
return false;
}
}
return true;
}
void EditorPlugin::onDrawSpaceChanged()
{
updateEditedPages();
}
}

View File

@ -0,0 +1,136 @@
// Copyright (C) 2023 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT 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
// with the written consent of the copyright owner, any later version.
//
// PDF4QT 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 PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef EDITORSPLUGIN_H
#define EDITORSPLUGIN_H
#include "pdfplugin.h"
#include "pdfpagecontentelements.h"
#include "pdfpagecontenteditortools.h"
#include "pdfpagecontenteditorprocessor.h"
#include <QObject>
namespace pdf
{
class PDFPageContentEditorWidget;
}
namespace pdfplugin
{
class EditorPlugin : public pdf::PDFPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "PDF4QT.EditorPlugin" FILE "EditorPlugin.json")
private:
using BaseClass = pdf::PDFPlugin;
public:
EditorPlugin();
virtual void setWidget(pdf::PDFWidget* widget) override;
virtual void setDocument(const pdf::PDFModifiedDocument& document) override;
virtual std::vector<QAction*> getActions() const override;
virtual QString getPluginMenuName() const override;
bool save();
private:
void onSceneActivityChanged();
void onSceneChanged(bool graphicsOnly);
void onSceneSelectionChanged();
void onWidgetSelectionChanged();
void onToolActivityChanged();
void onSceneEditElement(const std::set<pdf::PDFInteger>& elements);
void onSceneEditSingleElement(pdf::PDFInteger elementId);
void onPenChanged(const QPen& pen);
void onBrushChanged(const QBrush& brush);
void onFontChanged(const QFont& font);
void onAlignmentChanged(Qt::Alignment alignment);
void onTextAngleChanged(pdf::PDFReal angle);
enum Action
{
// Activate action
Activate,
// Create graphics actions
Text,
FreehandCurve,
AcceptMark,
RejectMark,
Rectangle,
RoundedRectangle,
HorizontalLine,
VerticalLine,
Line,
Dot,
SvgImage,
Clear,
LastAction
};
enum Tools
{
TextTool,
FreehandCurveTool,
AcceptMarkTool,
RejectMarkTool,
RectangleTool,
RoundedRectangleTool,
HorizontalLineTool,
VerticalLineTool,
LineTool,
DotTool,
ImageTool,
LastTool
};
void setActive(bool active);
void onSetActive(bool active);
void updateActions();
void updateGraphics();
void updateDockWidget();
void updateEditedPages();
bool updatePageContent(pdf::PDFInteger pageIndex,
const std::vector<const pdf::PDFPageContentElement*>& elements,
pdf::PDFDocumentBuilder* builder);
bool updateTextElement(pdf::PDFPageContentElementEdited* element);
void onDrawSpaceChanged();
pdf::PDFWidgetTool* getActiveTool();
std::array<QAction*, LastAction> m_actions;
std::array<pdf::PDFWidgetTool*, LastTool> m_tools;
pdf::PDFPageContentEditorWidget* m_editorWidget;
pdf::PDFPageContentScene m_scene;
std::map<pdf::PDFInteger, pdf::PDFEditedPageContent> m_editedPageContent;
bool m_sceneSelectionChangeEnabled;
bool m_isSaving;
};
} // namespace pdfplugin
#endif // EDITORSPLUGIN_H

View File

@ -0,0 +1,19 @@
<RCC>
<qresource prefix="/pdfplugins/editorplugin">
<file>accept-mark.svg</file>
<file>reject-mark.svg</file>
<file>activate.svg</file>
<file>clear.svg</file>
<file>create-dot.svg</file>
<file>create-freehand-curve.svg</file>
<file>create-horizontal-line.svg</file>
<file>create-line.svg</file>
<file>create-no-mark.svg</file>
<file>create-rectangle.svg</file>
<file>create-rounded-rectangle.svg</file>
<file>create-svg-image.svg</file>
<file>create-text.svg</file>
<file>create-vertical-line.svg</file>
<file>create-yes-mark.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<circle fill="#C80000" cx="12" cy="12" r="11.098"/>
<g>
<g>
<path fill="#FFFFFF" d="M13.713,12l5.063-4.201c0.46-0.381,0.524-1.07,0.143-1.539c-0.394-0.466-1.077-0.531-1.54-0.141
l-5.382,4.466L6.622,6.119C6.157,5.733,5.469,5.796,5.084,6.26C4.699,6.728,4.763,7.417,5.227,7.798L10.289,12l-5.062,4.204
c-0.464,0.389-0.528,1.074-0.143,1.54c0.216,0.258,0.527,0.394,0.84,0.394c0.246,0,0.491-0.079,0.697-0.253l5.377-4.462
l5.38,4.462c0.207,0.174,0.458,0.253,0.698,0.253c0.31,0,0.625-0.133,0.842-0.394c0.382-0.466,0.317-1.151-0.143-1.54L13.713,12z"
/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -162,6 +162,7 @@ void SignaturePlugin::setWidget(pdf::PDFWidget* widget)
connect(signElectronicallyAction, &QAction::triggered, this, &SignaturePlugin::onSignElectronically);
connect(signDigitallyAction, &QAction::triggered, this, &SignaturePlugin::onSignDigitally);
connect(certificatesAction, &QAction::triggered, this, &SignaturePlugin::onOpenCertificatesManager);
connect(m_widget, &pdf::PDFWidget::sceneActivityChanged, this, &SignaturePlugin::onSceneActivityChanged);
updateActions();
}
@ -288,6 +289,8 @@ void SignaturePlugin::onSignElectronically()
Q_ASSERT(m_document);
Q_ASSERT(!m_scene.isEmpty());
pdf::PDFColorConvertor convertor;
if (QMessageBox::question(m_dataExchangeInterface->getMainWindow(), tr("Confirm Signature"), tr("Document will be signed electronically. Do you want to continue?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{
pdf::PDFDocumentModifier modifier(m_document);
@ -302,7 +305,7 @@ void SignaturePlugin::onSignElectronically()
QPainter* painter = pageContentStreamBuilder.begin(page->getPageReference());
QList<pdf::PDFRenderError> errors;
pdf::PDFTextLayoutGetter nullGetter(nullptr, pageIndex);
m_scene.drawElements(painter, pageIndex, nullGetter, QTransform(), nullptr, errors);
m_scene.drawElements(painter, pageIndex, nullGetter, QTransform(), nullptr, convertor, errors);
pageContentStreamBuilder.end(painter);
modifier.markPageContentsChanged();
}
@ -369,12 +372,13 @@ void SignaturePlugin::onSignDigitally()
Q_ASSERT(!m_scene.isEmpty());
const pdf::PDFInteger pageIndex = *m_scene.getPageIndices().begin();
const pdf::PDFPage* page = catalog->getPage(pageIndex);
pdf::PDFColorConvertor convertor;
pdf::PDFContentStreamBuilder contentBuilder(page->getMediaBox().size(), pdf::PDFContentStreamBuilder::CoordinateSystem::PDF);
QPainter* painter = contentBuilder.begin();
QList<pdf::PDFRenderError> errors;
pdf::PDFTextLayoutGetter nullGetter(nullptr, pageIndex);
m_scene.drawPage(painter, pageIndex, nullptr, nullGetter, QTransform(), errors);
m_scene.drawPage(painter, pageIndex, nullptr, nullGetter, QTransform(), convertor, errors);
pdf::PDFContentStreamBuilder::ContentStream contentStream = contentBuilder.end(painter);
QRectF boundingRect = m_scene.getBoundingBox(pageIndex);
@ -505,6 +509,11 @@ void SignaturePlugin::onOpenCertificatesManager()
dialog.exec();
}
void SignaturePlugin::onSceneActivityChanged()
{
updateActions();
}
void SignaturePlugin::onPenChanged(const QPen& pen)
{
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
@ -574,6 +583,13 @@ void SignaturePlugin::setActive(bool active)
m_actions[Activate]->setChecked(active);
updateActions();
// If editor is not active, remove the widget
if (m_editorWidget && !active)
{
delete m_editorWidget;
m_editorWidget = nullptr;
}
}
}
@ -586,6 +602,11 @@ void SignaturePlugin::updateActions()
// Inactive scene - disable all except activate action and certificates
for (QAction* action : m_actions)
{
if (action == m_actions[Activate])
{
action->setEnabled(m_widget && !m_widget->isAnySceneActive(&m_scene));
}
if (action == m_actions[Activate] ||
action == m_actions[Certificates])
{
@ -642,6 +663,7 @@ void SignaturePlugin::updateDockWidget()
m_editorWidget->setScene(&m_scene);
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::operationTriggered, &m_scene, &pdf::PDFPageContentScene::performOperation);
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::itemSelectionChangedByUser, this, &SignaturePlugin::onWidgetSelectionChanged);
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::editElementRequest, this, &SignaturePlugin::onSceneEditSingleElement);
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignTop))->setIcon(QIcon(":/resources/pce-align-top.svg"));
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignCenterVertically))->setIcon(QIcon(":/resources/pce-align-v-center.svg"));
@ -672,4 +694,9 @@ void SignaturePlugin::updateDockWidget()
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::textAngleChanged, this, &SignaturePlugin::onTextAngleChanged);
}
void SignaturePlugin::onSceneEditSingleElement(pdf::PDFInteger elementId)
{
onSceneEditElement({ elementId });
}
}

View File

@ -57,12 +57,14 @@ private:
void onSignElectronically();
void onSignDigitally();
void onOpenCertificatesManager();
void onSceneActivityChanged();
void onPenChanged(const QPen& pen);
void onBrushChanged(const QBrush& brush);
void onFontChanged(const QFont& font);
void onAlignmentChanged(Qt::Alignment alignment);
void onTextAngleChanged(pdf::PDFReal angle);
void onSceneEditSingleElement(pdf::PDFInteger elementId);
enum Action
{

View File

@ -148,6 +148,10 @@ add_library(Pdf4QtLibCore SHARED
sources/pdfcertificatestore.cpp
sources/pdfblpainter.h
sources/pdfblpainter.cpp
sources/pdfpagecontenteditorprocessor.h
sources/pdfpagecontenteditorprocessor.cpp
sources/pdfpagecontenteditorcontentstreambuilder.h
sources/pdfpagecontenteditorcontentstreambuilder.cpp
)
include(GenerateExportHeader)

View File

@ -168,6 +168,19 @@ QPainter::CompositionMode PDFBlendModeInfo::getCompositionModeFromBlendMode(Blen
return QPainter::CompositionMode_SourceOver;
}
BlendMode PDFBlendModeInfo::getBlendModeFromCompositionMode(QPainter::CompositionMode mode)
{
for (BlendMode blendMode : getBlendModes())
{
if (mode == getCompositionModeFromBlendMode(blendMode))
{
return blendMode;
}
}
return BlendMode::Normal;
}
QString PDFBlendModeInfo::getBlendModeName(BlendMode mode)
{
for (const std::pair<const char*, BlendMode>& info : BLEND_MODE_INFOS)

View File

@ -86,6 +86,9 @@ public:
/// \param mode Blend mode
static QPainter::CompositionMode getCompositionModeFromBlendMode(BlendMode mode);
/// Returns blend mode from QPainter's composition mode.
static BlendMode getBlendModeFromCompositionMode(QPainter::CompositionMode mode);
/// Returns blend mode name
/// \param mode Blend mode
static QString getBlendModeName(BlendMode mode);

View File

@ -971,6 +971,14 @@ void PDFBLPaintEngine::setBLPen(BLContext& context, const QPen& pen)
break;
}
case Qt::CustomDashLine:
{
auto dashPattern = pen.dashPattern();
strokeOptions.dashArray.assignData(dashPattern.data(), dashPattern.size());
strokeOptions.dashOffset = pen.dashOffset();
break;
}
default:
break;
}

View File

@ -225,6 +225,20 @@ QColor PDFColorConvertor::getForegroundColor() const
return m_foregroundColor;
}
QPen PDFColorConvertor::convert(const QPen& pen, bool background, bool foreground) const
{
QPen newPen = pen;
newPen.setColor(convert(pen.color(), background, foreground));
return newPen;
}
QBrush PDFColorConvertor::convert(const QBrush& brush, bool background, bool foreground) const
{
QBrush newBrush = brush;
newBrush.setColor(convert(brush.color(), background, foreground));
return newBrush;
}
QColor PDFColorConvertor::getBackgroundColor() const
{
return m_backgroundColor;

View File

@ -20,6 +20,8 @@
#include "pdfglobal.h"
#include <QPen>
#include <QBrush>
#include <QColor>
#include <QImage>
@ -103,6 +105,9 @@ public:
QColor getBackgroundColor() const;
QColor getForegroundColor() const;
QPen convert(const QPen& pen, bool background = false, bool foreground = true) const;
QBrush convert(const QBrush& brush, bool background = false, bool foreground = true) const;
private:
/// Correct lightness using sigmoid function
/// \return Adjusted lightness normalized in range [0.0, 1.0]

View File

@ -285,6 +285,12 @@ PDFObjectFactory& PDFObjectFactory::operator<<(AnnotationBorderStyle style)
return *this;
}
PDFObjectFactory& PDFObjectFactory::operator<<(PDFDictionary dictionary)
{
*this << PDFObject::createDictionary(std::make_shared<pdf::PDFDictionary>(std::move(dictionary)));
return *this;
}
PDFObjectFactory& PDFObjectFactory::operator<<(const QDateTime& dateTime)
{
addObject(PDFObject::createString(PDFEncoding::convertDateTimeToString(dateTime)));
@ -708,6 +714,19 @@ PDFDocument PDFDocumentBuilder::build()
return PDFDocument(PDFObjectStorage(m_storage), m_version, QByteArray());
}
void PDFDocumentBuilder::replaceObjectsByReferences(PDFDictionary& dictionary)
{
for (size_t i = 0; i < dictionary.getCount(); ++i)
{
const PDFObject& object = dictionary.getValue(i);
if (!object.isReference())
{
auto key = dictionary.getKey(i);
dictionary.setEntry(key, PDFObject::createReference(addObject(object)));
}
}
}
QByteArray PDFDocumentBuilder::getDecodedStream(const PDFStream* stream) const
{
return m_storage.getDecodedStream(stream);

View File

@ -133,6 +133,7 @@ public:
PDFObjectFactory& operator<<(const PDFDestination& destination);
PDFObjectFactory& operator<<(PageRotation pageRotation);
PDFObjectFactory& operator<<(PDFFormSubmitFlags flags);
PDFObjectFactory& operator<<(PDFDictionary dictionary);
/// Treat containers - write them as array
template<typename Container, typename ValueType = decltype(*std::begin(std::declval<Container>()))>
@ -343,6 +344,9 @@ public:
/// if document being built was invalid.
PDFDocument build();
/// Replaces all objects by references in the dictionary
void replaceObjectsByReferences(PDFDictionary& dictionary);
/// If object is reference, the dereference attempt is performed
/// and object is returned. If it is not a reference, then self
/// is returned. If dereference attempt fails, then null object

View File

@ -564,9 +564,10 @@ QString PDFSystemFontInfoStorage::getFontPostscriptName(QString fontName)
return fontName.remove(QChar(' ')).remove(QChar('-')).remove(QChar(',')).trimmed();
}
PDFFont::PDFFont(CIDSystemInfo CIDSystemInfo, FontDescriptor fontDescriptor) :
PDFFont::PDFFont(CIDSystemInfo CIDSystemInfo, QByteArray fontId, FontDescriptor fontDescriptor) :
m_CIDSystemInfo(qMove(CIDSystemInfo)),
m_fontDescriptor(qMove(fontDescriptor))
m_fontDescriptor(qMove(fontDescriptor)),
m_fontId(qMove(fontId))
{
}
@ -749,7 +750,7 @@ void PDFRealizedFontImpl::fillTextSequence(const QByteArray& byteArray, TextSequ
if (glyphIndex)
{
const Glyph& glyph = getGlyph(glyphIndex);
textSequence.items.emplace_back(&glyph.glyph, (*encoding)[static_cast<uint8_t>(byteArray[i])], glyph.advance);
textSequence.items.emplace_back(&glyph.glyph, (*encoding)[static_cast<uint8_t>(byteArray[i])], glyph.advance, static_cast<CID>(byteArray[i]));
}
else
{
@ -757,7 +758,7 @@ void PDFRealizedFontImpl::fillTextSequence(const QByteArray& byteArray, TextSequ
if (glyphWidth > 0)
{
const QPainterPath* nullpath = nullptr;
textSequence.items.emplace_back(nullpath, QChar(), glyphWidth * m_pixelSize * FONT_WIDTH_MULTIPLIER);
textSequence.items.emplace_back(nullpath, QChar(), glyphWidth * m_pixelSize * FONT_WIDTH_MULTIPLIER, static_cast<CID>(byteArray[i]));
}
}
}
@ -784,7 +785,7 @@ void PDFRealizedFontImpl::fillTextSequence(const QByteArray& byteArray, TextSequ
{
QChar character = toUnicode->getToUnicode(cid);
const Glyph& glyph = getGlyph(glyphIndex);
textSequence.items.emplace_back(&glyph.glyph, character, glyph.advance);
textSequence.items.emplace_back(&glyph.glyph, character, glyph.advance, cid);
}
else
{
@ -799,7 +800,7 @@ void PDFRealizedFontImpl::fillTextSequence(const QByteArray& byteArray, TextSequ
// We do not multiply advance with font size and FONT_WIDTH_MULTIPLIER, because in the code,
// "advance" is treated as in font space.
const QPainterPath* nullpath = nullptr;
textSequence.items.emplace_back(nullpath, QChar(), -glyphWidth);
textSequence.items.emplace_back(nullpath, QChar(), -glyphWidth, cid);
}
}
}
@ -1284,7 +1285,53 @@ CIDSystemInfo PDFFont::readCIDSystemInfo(const PDFObject& cidSystemInfoObject, c
return cidSystemInfo;
}
PDFFontPointer PDFFont::createFont(const PDFObject& object, const PDFDocument* document)
QByteArray PDFFont::getFontId() const
{
return m_fontId;
}
PDFEncodedText PDFFont::encodeText(const QString& text) const
{
PDFEncodedText result;
result.isValid = true;
const PDFFontCMap* cmap = getCMap();
const PDFFontCMap* toUnicode = getToUnicode();
if (!cmap || !toUnicode)
{
result.errorString = PDFTranslationContext::tr("Invalid font encoding.");
return result;
}
for (const QChar& character : text)
{
CID cid = toUnicode->getFromUnicode(character);
if (cid != CID())
{
QByteArray encoded = cmap->encode(cid);
if (!encoded.isEmpty())
{
result.encodedText.append(encoded);
result.errorString += "_";
}
else
{
result.isValid = false;
result.errorString += character;
}
}
else
{
result.isValid = false;
result.errorString += character;
}
}
return result;
}
PDFFontPointer PDFFont::createFont(const PDFObject& object, QByteArray fontId, const PDFDocument* document)
{
const PDFObject& dereferencedFontDictionary = document->getObject(object);
if (!dereferencedFontDictionary.isDictionary())
@ -1763,7 +1810,7 @@ PDFFontPointer PDFFont::createFont(const PDFObject& object, const PDFDocument* d
toUnicodeCMap = PDFFontCMap::createFromData(decodedStream);
}
return PDFFontPointer(new PDFType0Font(qMove(cidSystemInfo), qMove(fontDescriptor), qMove(cmap), qMove(toUnicodeCMap), qMove(cidToGidMapper), defaultWidth, qMove(advances)));
return PDFFontPointer(new PDFType0Font(qMove(cidSystemInfo), qMove(fontId), qMove(fontDescriptor), qMove(cmap), qMove(toUnicodeCMap), qMove(cidToGidMapper), defaultWidth, qMove(advances)));
}
case FontType::Type3:
@ -1853,7 +1900,7 @@ PDFFontPointer PDFFont::createFont(const PDFObject& object, const PDFDocument* d
}
std::vector<PDFReal> widthsF3 = fontLoader.readNumberArrayFromDictionary(fontDictionary, "Widths");
return PDFFontPointer(new PDFType3Font(qMove(fontDescriptor), firstCharF3, lastCharF3, fontMatrix, qMove(characterContentStreams), qMove(widthsF3), document->getObject(fontDictionary->get("Resources")), qMove(toUnicodeCMap)));
return PDFFontPointer(new PDFType3Font(qMove(fontDescriptor), qMove(fontId), firstCharF3, lastCharF3, fontMatrix, qMove(characterContentStreams), qMove(widthsF3), document->getObject(fontDictionary->get("Resources")), qMove(toUnicodeCMap)));
}
default:
@ -1867,10 +1914,10 @@ PDFFontPointer PDFFont::createFont(const PDFObject& object, const PDFDocument* d
{
case FontType::Type1:
case FontType::MMType1:
return PDFFontPointer(new PDFType1Font(fontType, qMove(cidSystemInfo), qMove(fontDescriptor), qMove(name), qMove(baseFont), firstChar, lastChar, qMove(widths), encoding, simpleFontEncodingTable, standardFont, glyphIndexArray));
return PDFFontPointer(new PDFType1Font(fontType, qMove(fontId), qMove(cidSystemInfo), qMove(fontDescriptor), qMove(name), qMove(baseFont), firstChar, lastChar, qMove(widths), encoding, simpleFontEncodingTable, standardFont, glyphIndexArray));
case FontType::TrueType:
return PDFFontPointer(new PDFTrueTypeFont(qMove(cidSystemInfo), qMove(fontDescriptor), qMove(name), qMove(baseFont), firstChar, lastChar, qMove(widths), encoding, simpleFontEncodingTable, glyphIndexArray));
return PDFFontPointer(new PDFTrueTypeFont(qMove(cidSystemInfo), qMove(fontId), qMove(fontDescriptor), qMove(name), qMove(baseFont), firstChar, lastChar, qMove(widths), encoding, simpleFontEncodingTable, glyphIndexArray));
default:
{
@ -1883,6 +1930,7 @@ PDFFontPointer PDFFont::createFont(const PDFObject& object, const PDFDocument* d
}
PDFSimpleFont::PDFSimpleFont(CIDSystemInfo cidSystemInfo,
QByteArray fontId,
FontDescriptor fontDescriptor,
QByteArray name,
QByteArray baseFont,
@ -1892,7 +1940,7 @@ PDFSimpleFont::PDFSimpleFont(CIDSystemInfo cidSystemInfo,
PDFEncoding::Encoding encodingType,
encoding::EncodingTable encoding,
GlyphIndices glyphIndices) :
PDFFont(qMove(cidSystemInfo), qMove(fontDescriptor)),
PDFFont(qMove(cidSystemInfo), qMove(fontId), qMove(fontDescriptor)),
m_name(qMove(name)),
m_baseFont(qMove(baseFont)),
m_firstChar(firstChar),
@ -1922,6 +1970,45 @@ PDFInteger PDFSimpleFont::getGlyphAdvance(size_t index) const
return 0;
}
PDFEncodedText PDFSimpleFont::encodeText(const QString& text) const
{
PDFEncodedText result;
result.isValid = true;
const encoding::EncodingTable* encodingTable = getEncoding();
for (const QChar& character : text)
{
ushort unicode = character.unicode();
unsigned char converted = 0;
bool isFound = false;
for (size_t i = 0; i < encodingTable->size(); ++i)
{
if (unicode == (*encodingTable)[static_cast<unsigned char>(i)] &&
m_glyphIndices[i] != GID())
{
isFound = true;
converted = static_cast<unsigned char>(i);
break;
}
}
if (isFound)
{
result.encodedText.append(static_cast<char>(converted));
result.errorString += "_";
}
else
{
result.isValid = false;
result.errorString += character;
}
}
return result;
}
void PDFSimpleFont::dumpFontToTreeItem(ITreeFactory* treeFactory) const
{
BaseClass::dumpFontToTreeItem(treeFactory);
@ -1976,6 +2063,7 @@ void PDFSimpleFont::dumpFontToTreeItem(ITreeFactory* treeFactory) const
}
PDFType1Font::PDFType1Font(FontType fontType,
QByteArray fontId,
CIDSystemInfo cidSystemInfo,
FontDescriptor fontDescriptor,
QByteArray name,
@ -1987,7 +2075,7 @@ PDFType1Font::PDFType1Font(FontType fontType,
encoding::EncodingTable encoding,
StandardFontType standardFontType,
GlyphIndices glyphIndices) :
PDFSimpleFont(qMove(cidSystemInfo), qMove(fontDescriptor), qMove(name), qMove(baseFont), firstChar, lastChar, qMove(widths), encodingType, encoding, glyphIndices),
PDFSimpleFont(qMove(cidSystemInfo), qMove(fontId), qMove(fontDescriptor), qMove(name), qMove(baseFont), firstChar, lastChar, qMove(widths), encodingType, encoding, glyphIndices),
m_fontType(fontType),
m_standardFontType(standardFontType)
{
@ -2068,7 +2156,7 @@ void PDFFontCache::setDocument(const PDFModifiedDocument& document)
}
}
PDFFontPointer PDFFontCache::getFont(const PDFObject& fontObject) const
PDFFontPointer PDFFontCache::getFont(const PDFObject& fontObject, const QByteArray& fontId) const
{
if (fontObject.isReference())
{
@ -2081,7 +2169,7 @@ PDFFontPointer PDFFontCache::getFont(const PDFObject& fontObject) const
if (it == m_fontCache.cend())
{
// We must create the font
PDFFontPointer font = PDFFont::createFont(fontObject, m_document);
PDFFontPointer font = PDFFont::createFont(fontObject, fontId, m_document);
if (m_fontCacheShrinkDisabledObjects.empty() && m_fontCache.size() >= m_fontCacheLimit)
{
@ -2096,7 +2184,7 @@ PDFFontPointer PDFFontCache::getFont(const PDFObject& fontObject) const
else
{
// Object is not a reference. Create font directly and return it.
return PDFFont::createFont(fontObject, m_document);
return PDFFont::createFont(fontObject, fontId, m_document);
}
}
@ -2488,6 +2576,35 @@ std::vector<CID> PDFFontCMap::interpret(const QByteArray& byteArray) const
return result;
}
QByteArray PDFFontCMap::encode(CID cid) const
{
QByteArray byteArray;
for (const auto& entry : m_entries)
{
unsigned int minPossibleValue = entry.from + entry.cid;
unsigned int maxPossibleValue = entry.to + entry.cid;
if (cid >= minPossibleValue && cid <= maxPossibleValue)
{
// Calculate the original value from cid
unsigned int value = cid - entry.cid + entry.from;
byteArray.reserve(entry.byteCount);
// Construct byte array for this value based on the entry's byteCount
for (int i = entry.byteCount - 1; i >= 0; --i)
{
byteArray.append(static_cast<char>((value >> (8 * i)) & 0xFF));
}
break;
}
}
return byteArray;
}
QChar PDFFontCMap::getToUnicode(CID cid) const
{
if (isValid())
@ -2504,6 +2621,29 @@ QChar PDFFontCMap::getToUnicode(CID cid) const
return QChar();
}
CID PDFFontCMap::getFromUnicode(QChar character) const
{
if (!character.isNull())
{
char16_t ucs4 = character.unicode();
const CID unicodeCID = ucs4;
for (const Entry& entry : m_entries)
{
const CID minUnicodeCID = entry.cid;
const CID maxUnicodeCID = (entry.to - entry.from) + entry.cid;
if (unicodeCID >= minUnicodeCID && unicodeCID <= maxUnicodeCID)
{
const CID cid = unicodeCID + entry.from - entry.cid;
return cid;
}
}
}
return CID();
}
PDFFontCMap::PDFFontCMap(Entries&& entries, bool vertical) :
m_entries(qMove(entries)),
m_maxKeyLength(0),
@ -2611,6 +2751,7 @@ PDFReal PDFType0Font::getGlyphAdvance(CID cid) const
}
PDFType3Font::PDFType3Font(FontDescriptor fontDescriptor,
QByteArray fontId,
int firstCharacterIndex,
int lastCharacterIndex,
QTransform fontMatrix,
@ -2618,7 +2759,7 @@ PDFType3Font::PDFType3Font(FontDescriptor fontDescriptor,
std::vector<double>&& widths,
const PDFObject& resources,
PDFFontCMap toUnicode) :
PDFFont(CIDSystemInfo(), qMove(fontDescriptor)),
PDFFont(CIDSystemInfo(), qMove(fontId), qMove(fontDescriptor)),
m_firstCharacterIndex(firstCharacterIndex),
m_lastCharacterIndex(lastCharacterIndex),
m_fontMatrix(fontMatrix),
@ -2680,7 +2821,7 @@ void PDFRealizedType3FontImpl::fillTextSequence(const QByteArray& byteArray, Tex
if (contentStream)
{
textSequence.items.emplace_back(contentStream, character, width);
textSequence.items.emplace_back(contentStream, character, width, index);
}
else
{

View File

@ -70,9 +70,9 @@ public:
struct TextSequenceItem
{
inline explicit TextSequenceItem() = default;
inline explicit TextSequenceItem(const QPainterPath* glyph, QChar character, PDFReal advance) : glyph(glyph), character(character), advance(advance) { }
inline explicit TextSequenceItem(const QPainterPath* glyph, QChar character, PDFReal advance, CID cid) : glyph(glyph), character(character), advance(advance), cid(cid) { }
inline explicit TextSequenceItem(PDFReal advance) : character(), advance(advance) { }
inline explicit TextSequenceItem(const QByteArray* characterContentStream, QChar character, PDFReal advance) : characterContentStream(characterContentStream), character(character), advance(advance) { }
inline explicit TextSequenceItem(const QByteArray* characterContentStream, QChar character, PDFReal advance, uint cid) : characterContentStream(characterContentStream), character(character), advance(advance), cid(cid) { }
inline bool isContentStream() const { return characterContentStream; }
inline bool isCharacter() const { return glyph; }
@ -83,6 +83,7 @@ struct TextSequenceItem
const QByteArray* characterContentStream = nullptr;
QChar character;
PDFReal advance = 0;
CID cid = 0;
};
struct TextSequence
@ -290,11 +291,18 @@ private:
IRealizedFontImpl* m_impl;
};
struct PDFEncodedText
{
QByteArray encodedText;
QString errorString;
bool isValid = false;
};
/// Base class representing font in the PDF file
class PDF4QTLIBCORESHARED_EXPORT PDFFont
{
public:
explicit PDFFont(CIDSystemInfo CIDSystemInfo, FontDescriptor fontDescriptor);
explicit PDFFont(CIDSystemInfo CIDSystemInfo, QByteArray fontId, FontDescriptor fontDescriptor);
virtual ~PDFFont() = default;
/// Returns the font type
@ -317,8 +325,9 @@ public:
/// Creates font from the object. If font can't be created, exception is thrown.
/// \param object Font dictionary
/// \param fontId Font ID
/// \param document Document
static PDFFontPointer createFont(const PDFObject& object, const PDFDocument* document);
static PDFFontPointer createFont(const PDFObject& object, QByteArray fontId, const PDFDocument* document);
/// Tries to read font descriptor from the object
/// \param fontDescriptorObject Font descriptor dictionary
@ -330,9 +339,16 @@ public:
/// \param document Document
static CIDSystemInfo readCIDSystemInfo(const PDFObject& cidSystemInfoObject, const PDFDocument* document);
/// Returns font id from the font dictionary
QByteArray getFontId() const;
/// Encodes text into font encoding
virtual PDFEncodedText encodeText(const QString& text) const;
protected:
CIDSystemInfo m_CIDSystemInfo;
FontDescriptor m_fontDescriptor;
QByteArray m_fontId;
};
/// Simple font, see PDF reference 1.7, chapter 5.5. Simple fonts have encoding table,
@ -343,6 +359,7 @@ class PDFSimpleFont : public PDFFont
public:
explicit PDFSimpleFont(CIDSystemInfo cidSystemInfo,
QByteArray fontId,
FontDescriptor fontDescriptor,
QByteArray name,
QByteArray baseFont,
@ -361,6 +378,8 @@ public:
/// Returns the glyph advance (or zero, if glyph advance is invalid)
PDFInteger getGlyphAdvance(size_t index) const;
virtual PDFEncodedText encodeText(const QString& text) const override;
virtual void dumpFontToTreeItem(ITreeFactory* treeFactory) const override;
protected:
@ -380,6 +399,7 @@ class PDFType1Font : public PDFSimpleFont
public:
explicit PDFType1Font(FontType fontType,
QByteArray fontId,
CIDSystemInfo cidSystemInfo,
FontDescriptor fontDescriptor,
QByteArray name,
@ -433,7 +453,8 @@ public:
/// Retrieves font from the cache. If font can't be accessed or created,
/// then exception is thrown.
/// \param fontObject Font object
PDFFontPointer getFont(const PDFObject& fontObject) const;
/// \param fontId Font identification in resource dictionary
PDFFontPointer getFont(const PDFObject& fontObject, const QByteArray& fontId) const;
/// Retrieves realized font from the cache. If realized font can't be accessed or created,
/// then exception is thrown.
@ -547,9 +568,15 @@ public:
/// Converts byte array to array of CIDs
std::vector<CID> interpret(const QByteArray& byteArray) const;
/// Encodes character to byte array
QByteArray encode(CID cid) const;
/// Converts CID to QChar, use only on ToUnicode CMaps
QChar getToUnicode(CID cid) const;
/// Converts QChar to CID, use only on ToUnicode CMaps
CID getFromUnicode(QChar character) const;
private:
struct Entry
@ -599,6 +626,7 @@ class PDFType3Font : public PDFFont
{
public:
explicit PDFType3Font(FontDescriptor fontDescriptor,
QByteArray fontId,
int firstCharacterIndex,
int lastCharacterIndex,
QTransform fontMatrix,
@ -640,8 +668,15 @@ private:
class PDFType0Font : public PDFFont
{
public:
explicit inline PDFType0Font(CIDSystemInfo cidSystemInfo, FontDescriptor fontDescriptor, PDFFontCMap cmap, PDFFontCMap toUnicode, PDFCIDtoGIDMapper mapper, PDFReal defaultAdvance, std::unordered_map<CID, PDFReal> advances) :
PDFFont(qMove(cidSystemInfo), qMove(fontDescriptor)),
explicit inline PDFType0Font(CIDSystemInfo cidSystemInfo,
QByteArray fontId,
FontDescriptor fontDescriptor,
PDFFontCMap cmap,
PDFFontCMap toUnicode,
PDFCIDtoGIDMapper mapper,
PDFReal defaultAdvance,
std::unordered_map<CID, PDFReal> advances) :
PDFFont(qMove(cidSystemInfo), qMove(fontId), qMove(fontDescriptor)),
m_cmap(qMove(cmap)),
m_toUnicode(qMove(toUnicode)),
m_mapper(qMove(mapper)),

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
@ -425,6 +427,8 @@ public:
/// Removes null objects from dictionary
void removeNullObjects();
bool isEmpty() const { return getCount() == 0; }
/// Optimizes the dictionary for memory consumption
virtual void optimize() override;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,114 @@
// Copyright (C) 2024 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT 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
// with the written consent of the copyright owner, any later version.
//
// PDF4QT 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 PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFPAGECONTENTEDITORCONTENTSTREAMBUILDER_H
#define PDFPAGECONTENTEDITORCONTENTSTREAMBUILDER_H
#include "pdfpagecontenteditorprocessor.h"
#include <QPaintDevice>
namespace pdf
{
class PDFPageContentElement;
class PDFContentEditorPaintEngine;
class PDFPageContentEditorContentStreamBuilder;
class PDF4QTLIBCORESHARED_EXPORT PDFContentEditorPaintDevice : public QPaintDevice
{
public:
PDFContentEditorPaintDevice(PDFPageContentEditorContentStreamBuilder* builder, QRectF mediaRect, QRectF mediaRectMM);
virtual ~PDFContentEditorPaintDevice() override;
virtual int devType() const override;
virtual QPaintEngine* paintEngine() const override;
protected:
virtual int metric(PaintDeviceMetric metric) const override;
private:
PDFContentEditorPaintEngine* m_paintEngine;
QRectF m_mediaRect;
QRectF m_mediaRectMM;
};
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentEditorContentStreamBuilder
{
public:
PDFPageContentEditorContentStreamBuilder(PDFDocument* document);
void writeEditedElement(const PDFEditedPageContentElement* element);
const QByteArray& getOutputContent() const;
const PDFDictionary& getFontDictionary() const { return m_fontDictionary; }
const PDFDictionary& getXObjectDictionary() const { return m_xobjectDictionary; }
const PDFDictionary& getGraphicStateDictionary() const { return m_graphicStateDictionary; }
void setFontDictionary(const PDFDictionary& newFontDictionary);
const QStringList& getErrors() const { return m_errors; }
void clearErrors() { m_errors.clear(); }
void writeStyledPath(const QPainterPath& path,
const QPen& pen,
const QBrush& brush,
bool isStroking,
bool isFilling);
void writeStyledPath(const QPainterPath& path,
const PDFPageContentProcessorState& state,
bool isStroking,
bool isFilling);
void writeImage(const QImage& image, const QRectF& rectangle);
void writeImage(const QImage& image, QTransform transform, const QRectF& rectangle);
const PDFPageContentProcessorState& getCurrentState() { return m_currentState; }
private:
bool isNeededToWriteCurrentTransformationMatrix() const;
void writeCurrentTransformationMatrix(QTextStream& stream);
void writeStateDifference(QTextStream& stream, const PDFPageContentProcessorState& state);
void writePainterPath(QTextStream& stream,
const QPainterPath& path,
bool isStroking,
bool isFilling);
void writeText(QTextStream& stream, const QString& text);
void writeTextCommand(QTextStream& stream, const QXmlStreamReader& reader);
void writeImage(QTextStream& stream, const QImage& image);
QByteArray selectFont(const QByteArray& font);
void addError(const QString& error);
PDFDocument* m_document = nullptr;
PDFDictionary m_fontDictionary;
PDFDictionary m_xobjectDictionary;
PDFDictionary m_graphicStateDictionary;
QByteArray m_outputContent;
PDFPageContentProcessorState m_currentState;
PDFFontPointer m_textFont;
QStringList m_errors;
};
} // namespace pdf
#endif // PDFPAGECONTENTEDITORCONTENTSTREAMBUILDER_H

View File

@ -0,0 +1,792 @@
// Copyright (C) 2023-2024 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT 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
// with the written consent of the copyright owner, any later version.
//
// PDF4QT 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 PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "pdfpagecontenteditorprocessor.h"
namespace pdf
{
PDFPageContentEditorProcessor::PDFPageContentEditorProcessor(const PDFPage* page,
const PDFDocument* document,
const PDFFontCache* fontCache,
const PDFCMS* CMS,
const PDFOptionalContentActivity* optionalContentActivity,
QTransform pagePointToDevicePointMatrix,
const PDFMeshQualitySettings& meshQualitySettings) :
BaseClass(page, document, fontCache, CMS, optionalContentActivity, pagePointToDevicePointMatrix, meshQualitySettings)
{
m_clippingPaths.push(QPainterPath());
if (auto fontDictionary = getFontDictionary())
{
m_content.setFontDictionary(*fontDictionary);
}
if (auto xObjectDictionary = getXObjectDictionary())
{
m_content.setXObjectDictionary(*xObjectDictionary);
}
}
const PDFEditedPageContent& PDFPageContentEditorProcessor::getEditedPageContent() const
{
return m_content;
}
PDFEditedPageContent PDFPageContentEditorProcessor::takeEditedPageContent()
{
return std::move(m_content);
}
void PDFPageContentEditorProcessor::performInterceptInstruction(Operator currentOperator,
ProcessOrder processOrder,
const QByteArray& operatorAsText)
{
BaseClass::performInterceptInstruction(currentOperator, processOrder, operatorAsText);
if (processOrder == ProcessOrder::BeforeOperation)
{
if (currentOperator == Operator::TextBegin && !isTextProcessing())
{
m_contentElementText.reset(new PDFEditedPageContentElementText(*getGraphicState(), getGraphicState()->getCurrentTransformationMatrix()));
}
}
else
{
if (currentOperator == Operator::TextEnd && !isTextProcessing())
{
if (m_contentElementText)
{
m_contentElementText->optimize();
if (!m_contentElementText->isEmpty())
{
m_contentElementText->setTextPath(std::move(m_textPath));
m_contentElementText->setItemsAsText(PDFEditedPageContentElementText::createItemsAsText(m_contentElementText->getState(), m_contentElementText->getItems()));
m_content.addContentElement(std::move(m_contentElementText));
}
}
m_contentElementText.reset();
m_textPath = QPainterPath();
}
}
}
void PDFPageContentEditorProcessor::performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule)
{
BaseClass::performPathPainting(path, stroke, fill, text, fillRule);
if (path.isEmpty())
{
return;
}
if (text)
{
m_textPath.addPath(path);
}
else
{
m_content.addContentPath(*getGraphicState(), path, stroke, fill);
}
}
void PDFPageContentEditorProcessor::performUpdateGraphicsState(const PDFPageContentProcessorState& state)
{
BaseClass::performUpdateGraphicsState(state);
if (isTextProcessing() && m_contentElementText)
{
PDFEditedPageContentElementText::Item item;
item.isUpdateGraphicState = true;
item.state = state;
m_contentElementText->addItem(item);
}
}
void PDFPageContentEditorProcessor::performProcessTextSequence(const TextSequence& textSequence, ProcessOrder order)
{
BaseClass::performProcessTextSequence(textSequence, order);
if (order == ProcessOrder::BeforeOperation)
{
PDFEditedPageContentElementText::Item item;
item.isText = true;
item.textSequence = textSequence;
m_contentElementText->addItem(item);
}
}
bool PDFPageContentEditorProcessor::performOriginalImagePainting(const PDFImage& image, const PDFStream* stream)
{
BaseClass::performOriginalImagePainting(image, stream);
PDFObject imageObject = PDFObject::createStream(std::make_shared<PDFStream>(*stream));
m_content.addContentImage(*getGraphicState(), std::move(imageObject), QImage());
return false;
}
void PDFPageContentEditorProcessor::performImagePainting(const QImage& image)
{
BaseClass::performImagePainting(image);
PDFEditedPageContentElement* backElement = m_content.getBackElement();
Q_ASSERT(backElement);
PDFEditedPageContentElementImage* imageElement = backElement->asImage();
imageElement->setImage(image);
}
void PDFPageContentEditorProcessor::performSaveGraphicState(ProcessOrder order)
{
BaseClass::performSaveGraphicState(order);
if (order == ProcessOrder::BeforeOperation)
{
m_clippingPaths.push(m_clippingPaths.top());
}
}
void PDFPageContentEditorProcessor::performRestoreGraphicState(ProcessOrder order)
{
BaseClass::performRestoreGraphicState(order);
if (order == ProcessOrder::AfterOperation)
{
m_clippingPaths.pop();
}
}
void PDFPageContentEditorProcessor::performClipping(const QPainterPath& path, Qt::FillRule fillRule)
{
BaseClass::performClipping(path, fillRule);
if (m_clippingPaths.top().isEmpty())
{
m_clippingPaths.top() = path;
}
else
{
m_clippingPaths.top() = m_clippingPaths.top().intersected(path);
}
}
bool PDFPageContentEditorProcessor::isContentKindSuppressed(ContentKind kind) const
{
switch (kind)
{
case ContentKind::Shading:
case ContentKind::Tiling:
return true;
default:
break;
}
return false;
}
QString PDFEditedPageContent::getOperatorToString(PDFPageContentProcessor::Operator operatorValue)
{
switch (operatorValue)
{
case pdf::PDFPageContentProcessor::Operator::SetLineWidth:
return "set_line_width";
case pdf::PDFPageContentProcessor::Operator::SetLineCap:
return "set_line_cap";
case pdf::PDFPageContentProcessor::Operator::SetLineJoin:
return "set_line_join";
case pdf::PDFPageContentProcessor::Operator::SetMitterLimit:
return "set_mitter_limit";
case pdf::PDFPageContentProcessor::Operator::SetLineDashPattern:
return "set_line_dash_pattern";
case pdf::PDFPageContentProcessor::Operator::SetRenderingIntent:
return "set_rendering_intent";
case pdf::PDFPageContentProcessor::Operator::SetFlatness:
return "set_flatness";
case pdf::PDFPageContentProcessor::Operator::SetGraphicState:
return "set_graphic_state";
case pdf::PDFPageContentProcessor::Operator::SaveGraphicState:
return "save";
case pdf::PDFPageContentProcessor::Operator::RestoreGraphicState:
return "restore";
case pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix:
return "set_cm";
case pdf::PDFPageContentProcessor::Operator::MoveCurrentPoint:
return "move_to";
case pdf::PDFPageContentProcessor::Operator::LineTo:
return "line_to";
case pdf::PDFPageContentProcessor::Operator::Bezier123To:
return "cubic123_to";
case pdf::PDFPageContentProcessor::Operator::Bezier23To:
return "cubic23_to";
case pdf::PDFPageContentProcessor::Operator::Bezier13To:
return "cubic13_to";
case pdf::PDFPageContentProcessor::Operator::EndSubpath:
return "close_path";
case pdf::PDFPageContentProcessor::Operator::Rectangle:
return "rect";
case pdf::PDFPageContentProcessor::Operator::PathStroke:
return "path_stroke";
case pdf::PDFPageContentProcessor::Operator::PathCloseStroke:
return "path_close_and_stroke";
case pdf::PDFPageContentProcessor::Operator::PathFillWinding:
return "path_fill_winding";
case pdf::PDFPageContentProcessor::Operator::PathFillWinding2:
return "path_fill_winding";
case pdf::PDFPageContentProcessor::Operator::PathFillEvenOdd:
return "path_fill_even_odd";
case pdf::PDFPageContentProcessor::Operator::PathFillStrokeWinding:
return "path_fill_stroke_winding";
case pdf::PDFPageContentProcessor::Operator::PathFillStrokeEvenOdd:
return "path_fill_stroke_even_odd";
case pdf::PDFPageContentProcessor::Operator::PathCloseFillStrokeWinding:
return "path_close_fill_stroke_winding";
case pdf::PDFPageContentProcessor::Operator::PathCloseFillStrokeEvenOdd:
return "path_close_fill_stroke_even_odd";
case pdf::PDFPageContentProcessor::Operator::PathClear:
return "path_clear";
case pdf::PDFPageContentProcessor::Operator::ClipWinding:
return "clip_winding";
case pdf::PDFPageContentProcessor::Operator::ClipEvenOdd:
return "clip_even_odd";
case pdf::PDFPageContentProcessor::Operator::TextBegin:
return "text_begin";
case pdf::PDFPageContentProcessor::Operator::TextEnd:
return "text_end";
case pdf::PDFPageContentProcessor::Operator::TextSetCharacterSpacing:
return "set_char_spacing";
case pdf::PDFPageContentProcessor::Operator::TextSetWordSpacing:
return "set_word_spacing";
case pdf::PDFPageContentProcessor::Operator::TextSetHorizontalScale:
return "set_hor_scale";
case pdf::PDFPageContentProcessor::Operator::TextSetLeading:
return "set_leading";
case pdf::PDFPageContentProcessor::Operator::TextSetFontAndFontSize:
return "set_font";
case pdf::PDFPageContentProcessor::Operator::TextSetRenderMode:
return "set_text_render_mode";
case pdf::PDFPageContentProcessor::Operator::TextSetRise:
return "set_text_rise";
case pdf::PDFPageContentProcessor::Operator::TextMoveByOffset:
return "text_move_by_offset";
case pdf::PDFPageContentProcessor::Operator::TextSetLeadingAndMoveByOffset:
return "text_set_leading_and_move_by_offset";
case pdf::PDFPageContentProcessor::Operator::TextSetMatrix:
return "text_set_matrix";
case pdf::PDFPageContentProcessor::Operator::TextMoveByLeading:
return "text_move_by_leading";
case pdf::PDFPageContentProcessor::Operator::TextShowTextString:
return "text_show_string";
case pdf::PDFPageContentProcessor::Operator::TextShowTextIndividualSpacing:
return "text_show_string_with_spacing";
case pdf::PDFPageContentProcessor::Operator::TextNextLineShowText:
return "text_next_line_and_show_text";
case pdf::PDFPageContentProcessor::Operator::TextSetSpacingAndShowText:
return "text_set_spacing_and_show_text";
case pdf::PDFPageContentProcessor::Operator::Type3FontSetOffset:
return "text_t3_set_offset";
case pdf::PDFPageContentProcessor::Operator::Type3FontSetOffsetAndBB:
return "text_t3_set_offset_and_bb";
case pdf::PDFPageContentProcessor::Operator::ColorSetStrokingColorSpace:
return "set_stroke_color_space";
case pdf::PDFPageContentProcessor::Operator::ColorSetFillingColorSpace:
return "set_filling_color_space";
case pdf::PDFPageContentProcessor::Operator::ColorSetStrokingColor:
return "set_stroke_color";
case pdf::PDFPageContentProcessor::Operator::ColorSetStrokingColorN:
return "set_stroke_color_n";
case pdf::PDFPageContentProcessor::Operator::ColorSetFillingColor:
return "set_filling_color";
case pdf::PDFPageContentProcessor::Operator::ColorSetFillingColorN:
return "set_filling_color_n";
case pdf::PDFPageContentProcessor::Operator::ColorSetDeviceGrayStroking:
return "set_stroke_gray_cs";
case pdf::PDFPageContentProcessor::Operator::ColorSetDeviceGrayFilling:
return "set_filling_gray_cs";
case pdf::PDFPageContentProcessor::Operator::ColorSetDeviceRGBStroking:
return "set_stroke_rgb_cs";
case pdf::PDFPageContentProcessor::Operator::ColorSetDeviceRGBFilling:
return "set_filling_rgb_cs";
case pdf::PDFPageContentProcessor::Operator::ColorSetDeviceCMYKStroking:
return "set_stroke_cmyk_cs";
case pdf::PDFPageContentProcessor::Operator::ColorSetDeviceCMYKFilling:
return "set_filling_cmyk_cs";
case pdf::PDFPageContentProcessor::Operator::ShadingPaintShape:
return "shading_paint";
case pdf::PDFPageContentProcessor::Operator::InlineImageBegin:
return "ib";
case pdf::PDFPageContentProcessor::Operator::InlineImageData:
return "id";
case pdf::PDFPageContentProcessor::Operator::InlineImageEnd:
return "ie";
case pdf::PDFPageContentProcessor::Operator::PaintXObject:
return "paint_object";
case pdf::PDFPageContentProcessor::Operator::MarkedContentPoint:
return "mc_point";
case pdf::PDFPageContentProcessor::Operator::MarkedContentPointWithProperties:
return "mc_point_prop";
case pdf::PDFPageContentProcessor::Operator::MarkedContentBegin:
return "mc_begin";
case pdf::PDFPageContentProcessor::Operator::MarkedContentBeginWithProperties:
return "mc_begin_prop";
case pdf::PDFPageContentProcessor::Operator::MarkedContentEnd:
return "mc_end";
case pdf::PDFPageContentProcessor::Operator::CompatibilityBegin:
return "compat_begin";
case pdf::PDFPageContentProcessor::Operator::CompatibilityEnd:
return "compat_end";
default:
break;
}
return QString();
}
QString PDFEditedPageContent::getOperandName(PDFPageContentProcessor::Operator operatorValue, int operandIndex)
{
static const std::map<std::pair<PDFPageContentProcessor::Operator, int>, QString> operands =
{
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetLineWidth, 0), "lineWidth" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetLineCap, 0), "lineCap" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetLineJoin, 0), "lineJoin" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetMitterLimit, 0), "mitterLimit" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetRenderingIntent, 0), "renderingIntent" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetFlatness, 0), "flatness" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetGraphicState, 0), "graphicState" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix, 0), "a" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix, 1), "b" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix, 2), "c" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix, 3), "d" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix, 4), "e" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix, 5), "f" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::MoveCurrentPoint, 0), "x" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::MoveCurrentPoint, 1), "y" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::LineTo, 0), "x" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::LineTo, 1), "y" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier123To, 0), "x1" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier123To, 1), "y1" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier123To, 2), "x2" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier123To, 3), "y2" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier123To, 4), "x3" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier123To, 5), "y3" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier23To, 0), "x2" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier23To, 1), "y2" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier23To, 2), "x3" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier23To, 3), "y3" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier13To, 0), "x1" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier13To, 1), "y1" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier13To, 2), "x3" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier13To, 3), "y3" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Rectangle, 0), "x" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Rectangle, 1), "y" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Rectangle, 2), "width" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Rectangle, 3), "height" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetCharacterSpacing, 0), "charSpacing" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetWordSpacing, 0), "wordSpacing" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetHorizontalScale, 0), "scale" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetLeading, 0), "leading" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetFontAndFontSize, 0), "font" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetFontAndFontSize, 1), "fontSize" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetRenderMode, 0), "renderMode" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetRise, 0), "rise" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextMoveByOffset, 0), "tx" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextMoveByOffset, 1), "ty" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetLeadingAndMoveByOffset, 0), "tx" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetLeadingAndMoveByOffset, 1), "ty" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetMatrix, 0), "a" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetMatrix, 1), "b" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetMatrix, 2), "c" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetMatrix, 3), "d" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetMatrix, 4), "e" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetMatrix, 5), "f" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextShowTextString, 0), "string" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextNextLineShowText, 0), "string" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextShowTextIndividualSpacing, 0), "wSpacing" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextShowTextIndividualSpacing, 1), "chSpacing" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextShowTextIndividualSpacing, 2), "string" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetSpacingAndShowText, 0), "string" },
};
auto it = operands.find(std::make_pair(operatorValue, operandIndex));
if (it != operands.cend())
{
return it->second;
}
return QString("op%1").arg(operandIndex);
}
void PDFEditedPageContent::addContentPath(PDFPageContentProcessorState state, QPainterPath path, bool strokePath, bool fillPath)
{
QTransform transform = state.getCurrentTransformationMatrix();
m_contentElements.emplace_back(new PDFEditedPageContentElementPath(std::move(state), std::move(path), strokePath, fillPath, transform));
}
void PDFEditedPageContent::addContentImage(PDFPageContentProcessorState state, PDFObject imageObject, QImage image)
{
QTransform transform = state.getCurrentTransformationMatrix();
m_contentElements.emplace_back(new PDFEditedPageContentElementImage(std::move(state), std::move(imageObject), std::move(image), transform));
}
void PDFEditedPageContent::addContentElement(std::unique_ptr<PDFEditedPageContentElement> element)
{
m_contentElements.emplace_back(std::move(element));
}
PDFEditedPageContentElement* PDFEditedPageContent::getBackElement() const
{
if (m_contentElements.empty())
{
return nullptr;
}
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)
{
}
const PDFPageContentProcessorState& PDFEditedPageContentElement::getState() const
{
return m_state;
}
void PDFEditedPageContentElement::setState(const PDFPageContentProcessorState& newState)
{
m_state = newState;
}
QTransform PDFEditedPageContentElement::getTransform() const
{
return m_transform;
}
void PDFEditedPageContentElement::setTransform(const QTransform& newTransform)
{
m_transform = newTransform;
}
PDFEditedPageContentElementPath::PDFEditedPageContentElementPath(PDFPageContentProcessorState state, QPainterPath path, bool strokePath, bool fillPath, QTransform transform) :
PDFEditedPageContentElement(std::move(state), transform),
m_path(std::move(path)),
m_strokePath(strokePath),
m_fillPath(fillPath)
{
}
PDFEditedPageContentElement::Type PDFEditedPageContentElementPath::getType() const
{
return Type::Path;
}
PDFEditedPageContentElementPath* PDFEditedPageContentElementPath::clone() const
{
return new PDFEditedPageContentElementPath(getState(), getPath(), getStrokePath(), getFillPath(), getTransform());
}
QRectF PDFEditedPageContentElementPath::getBoundingBox() const
{
QPainterPath mappedPath = getTransform().map(m_path);
return mappedPath.boundingRect();
}
QPainterPath PDFEditedPageContentElementPath::getPath() const
{
return m_path;
}
void PDFEditedPageContentElementPath::setPath(QPainterPath newPath)
{
m_path = newPath;
}
bool PDFEditedPageContentElementPath::getStrokePath() const
{
return m_strokePath;
}
void PDFEditedPageContentElementPath::setStrokePath(bool newStrokePath)
{
m_strokePath = newStrokePath;
}
bool PDFEditedPageContentElementPath::getFillPath() const
{
return m_fillPath;
}
void PDFEditedPageContentElementPath::setFillPath(bool newFillPath)
{
m_fillPath = newFillPath;
}
PDFEditedPageContentElementImage::PDFEditedPageContentElementImage(PDFPageContentProcessorState state, PDFObject imageObject, QImage image, QTransform transform) :
PDFEditedPageContentElement(std::move(state), transform),
m_imageObject(std::move(imageObject)),
m_image(std::move(image))
{
}
PDFEditedPageContentElement::Type PDFEditedPageContentElementImage::getType() const
{
return PDFEditedPageContentElement::Type::Image;
}
PDFEditedPageContentElementImage* PDFEditedPageContentElementImage::clone() const
{
return new PDFEditedPageContentElementImage(getState(), getImageObject(), getImage(), getTransform());
}
QRectF PDFEditedPageContentElementImage::getBoundingBox() const
{
return getTransform().mapRect(QRectF(0, 0, 1, 1));
}
PDFObject PDFEditedPageContentElementImage::getImageObject() const
{
return m_imageObject;
}
void PDFEditedPageContentElementImage::setImageObject(const PDFObject& newImageObject)
{
m_imageObject = newImageObject;
}
QImage PDFEditedPageContentElementImage::getImage() const
{
return m_image;
}
void PDFEditedPageContentElementImage::setImage(const QImage& newImage)
{
m_image = newImage;
}
PDFEditedPageContentElementText::PDFEditedPageContentElementText(PDFPageContentProcessorState state, QTransform transform) :
PDFEditedPageContentElement(state, transform)
{
}
PDFEditedPageContentElementText::PDFEditedPageContentElementText(PDFPageContentProcessorState state,
std::vector<Item> items,
QPainterPath textPath,
QTransform transform,
QString itemsAsText) :
PDFEditedPageContentElement(state, transform),
m_items(std::move(items)),
m_textPath(std::move(textPath)),
m_itemsAsText(itemsAsText)
{
}
PDFEditedPageContentElement::Type PDFEditedPageContentElementText::getType() const
{
return Type::Text;
}
PDFEditedPageContentElementText* PDFEditedPageContentElementText::clone() const
{
return new PDFEditedPageContentElementText(getState(), getItems(), getTextPath(), getTransform(), getItemsAsText());
}
void PDFEditedPageContentElementText::addItem(Item item)
{
m_items.emplace_back(std::move(item));
}
const std::vector<PDFEditedPageContentElementText::Item>& PDFEditedPageContentElementText::getItems() const
{
return m_items;
}
void PDFEditedPageContentElementText::setItems(const std::vector<Item>& newItems)
{
m_items = newItems;
}
QRectF PDFEditedPageContentElementText::getBoundingBox() const
{
return getTransform().mapRect(m_textPath.boundingRect());
}
QPainterPath PDFEditedPageContentElementText::getTextPath() const
{
return m_textPath;
}
void PDFEditedPageContentElementText::setTextPath(QPainterPath newTextPath)
{
m_textPath = newTextPath;
}
QString PDFEditedPageContentElementText::createItemsAsText(const PDFPageContentProcessorState& initialState,
const std::vector<Item>& items)
{
QString text;
PDFPageContentProcessorState state = initialState;
state.setStateFlags(PDFPageContentProcessorState::StateFlags());
for (const Item& item : items)
{
if (item.isText)
{
for (const TextSequenceItem& textItem : item.textSequence.items)
{
if (textItem.isCharacter())
{
if (!textItem.character.isNull())
{
text += QString(textItem.character).toHtmlEscaped();
}
else if (textItem.isAdvance())
{
text += QString("<space advance=\"%1\"/>").arg(textItem.advance);
}
else if (textItem.cid != 0)
{
text += QString("<character cid=\"%1\"/>").arg(textItem.cid);
}
}
}
}
else if (item.isUpdateGraphicState)
{
PDFPageContentProcessorState newState = state;
newState.setStateFlags(PDFPageContentProcessorState::StateFlags());
newState.setState(item.state);
PDFPageContentProcessorState::StateFlags flags = newState.getStateFlags();
if (flags.testFlag(PDFPageContentProcessorState::StateTextRenderingMode))
{
text += QString("<tr v=\"%1\"/>").arg(int(newState.getTextRenderingMode()));
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextRise))
{
text += QString("<ts v=\"%1\"/>").arg(newState.getTextRise());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextCharacterSpacing))
{
text += QString("<tc v=\"%1\"/>").arg(newState.getTextCharacterSpacing());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextWordSpacing))
{
text += QString("<tw v=\"%1\"/>").arg(newState.getTextWordSpacing());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextLeading))
{
text += QString("<tl v=\"%1\"/>").arg(newState.getTextLeading());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextHorizontalScaling))
{
text += QString("<tz v=\"%1\"/>").arg(newState.getTextHorizontalScaling());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextKnockout))
{
text += QString("<tk v=\"%1\"/>").arg(newState.getTextKnockout());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextFont) ||
flags.testFlag(PDFPageContentProcessorState::StateTextFontSize))
{
text += QString("<tf font=\"%1\" size=\"%2\"/>").arg(newState.getTextFont()->getFontId()).arg(newState.getTextFontSize());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextMatrix))
{
QTransform transform = newState.getTextMatrix();
qreal x = transform.dx();
qreal y = transform.dy();
if (transform.isTranslating())
{
text += QString("<tpos x=\"%1\" y=\"%2\"/>").arg(x).arg(y);
}
else
{
text += QString("<tmatrix m11=\"%1\" m12=\"%2\" m21=\"%3\" m22=\"%4\" x=\"%5\" y=\"%6\"/>").arg(transform.m11()).arg(transform.m12()).arg(transform.m21()).arg(transform.m22()).arg(x).arg(y);
}
}
state = newState;
state.setStateFlags(PDFPageContentProcessorState::StateFlags());
}
}
return text;
}
QString PDFEditedPageContentElementText::getItemsAsText() const
{
return m_itemsAsText;
}
void PDFEditedPageContentElementText::setItemsAsText(const QString& newItemsAsText)
{
m_itemsAsText = newItemsAsText;
}
void PDFEditedPageContentElementText::optimize()
{
while (!m_items.empty() && !m_items.back().isText)
{
m_items.pop_back();
}
}
} // namespace pdf

View File

@ -0,0 +1,252 @@
// Copyright (C) 2023-2024 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT 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
// with the written consent of the copyright owner, any later version.
//
// PDF4QT 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 PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFPAGECONTENTEDITORPROCESSOR_H
#define PDFPAGECONTENTEDITORPROCESSOR_H
#include "pdfpagecontentprocessor.h"
#include <memory>
class QXmlStreamReader;
namespace pdf
{
class PDFEditedPageContentElementPath;
class PDFEditedPageContentElementText;
class PDFEditedPageContentElementImage;
class PDF4QTLIBCORESHARED_EXPORT PDFEditedPageContentElement
{
public:
PDFEditedPageContentElement() = default;
PDFEditedPageContentElement(PDFPageContentProcessorState state, QTransform transform);
virtual ~PDFEditedPageContentElement() = default;
enum class Type
{
Path,
Text,
Image
};
virtual Type getType() const = 0;
virtual PDFEditedPageContentElement* clone() const = 0;
virtual PDFEditedPageContentElementPath* asPath() { return nullptr; }
virtual const PDFEditedPageContentElementPath* asPath() const { return nullptr; }
virtual PDFEditedPageContentElementText* asText() { return nullptr; }
virtual const PDFEditedPageContentElementText* asText() const { return nullptr; }
virtual PDFEditedPageContentElementImage* asImage() { return nullptr; }
virtual const PDFEditedPageContentElementImage* asImage() const { return nullptr; }
const PDFPageContentProcessorState& getState() const;
void setState(const PDFPageContentProcessorState& newState);
virtual QRectF getBoundingBox() const = 0;
QTransform getTransform() const;
void setTransform(const QTransform& newTransform);
protected:
PDFPageContentProcessorState m_state;
QTransform m_transform;
};
class PDF4QTLIBCORESHARED_EXPORT PDFEditedPageContentElementPath : public PDFEditedPageContentElement
{
public:
PDFEditedPageContentElementPath(PDFPageContentProcessorState state,
QPainterPath path,
bool strokePath,
bool fillPath,
QTransform transform);
virtual ~PDFEditedPageContentElementPath() = default;
virtual Type getType() const override;
virtual PDFEditedPageContentElementPath* clone() const override;
virtual PDFEditedPageContentElementPath* asPath() override { return this; }
virtual const PDFEditedPageContentElementPath* asPath() const override { return this; }
virtual QRectF getBoundingBox() const override;
QPainterPath getPath() const;
void setPath(QPainterPath newPath);
bool getStrokePath() const;
void setStrokePath(bool newStrokePath);
bool getFillPath() const;
void setFillPath(bool newFillPath);
private:
QPainterPath m_path;
bool m_strokePath;
bool m_fillPath;
};
class PDF4QTLIBCORESHARED_EXPORT PDFEditedPageContentElementImage : public PDFEditedPageContentElement
{
public:
PDFEditedPageContentElementImage(PDFPageContentProcessorState state,
PDFObject imageObject,
QImage image,
QTransform transform);
virtual ~PDFEditedPageContentElementImage() = default;
virtual Type getType() const override;
virtual PDFEditedPageContentElementImage* clone() const override;
virtual PDFEditedPageContentElementImage* asImage() override { return this; }
virtual const PDFEditedPageContentElementImage* asImage() const override { return this; }
virtual QRectF getBoundingBox() const override;
PDFObject getImageObject() const;
void setImageObject(const PDFObject& newImageObject);
QImage getImage() const;
void setImage(const QImage& newImage);
private:
PDFObject m_imageObject;
QImage m_image;
};
class PDF4QTLIBCORESHARED_EXPORT PDFEditedPageContentElementText : public PDFEditedPageContentElement
{
public:
struct Item
{
bool isUpdateGraphicState = false;
bool isText = false;
TextSequence textSequence;
PDFPageContentProcessorState state;
};
PDFEditedPageContentElementText(PDFPageContentProcessorState state, QTransform transform);
PDFEditedPageContentElementText(PDFPageContentProcessorState state,
std::vector<Item> items,
QPainterPath textPath,
QTransform transform,
QString itemsAsText);
virtual ~PDFEditedPageContentElementText() = default;
virtual Type getType() const override;
virtual PDFEditedPageContentElementText* clone() const override;
virtual PDFEditedPageContentElementText* asText() override { return this; }
virtual const PDFEditedPageContentElementText* asText() const override { return this; }
virtual QRectF getBoundingBox() const override;
void addItem(Item item);
const std::vector<Item>& getItems() const;
void setItems(const std::vector<Item>& newItems);
bool isEmpty() const { return m_items.empty(); }
QPainterPath getTextPath() const;
void setTextPath(QPainterPath newTextPath);
static QString createItemsAsText(const PDFPageContentProcessorState& initialState,
const std::vector<Item>& items);
QString getItemsAsText() const;
void setItemsAsText(const QString& newItemsAsText);
void optimize();
private:
std::vector<Item> m_items;
QPainterPath m_textPath;
QString m_itemsAsText;
};
class PDF4QTLIBCORESHARED_EXPORT PDFEditedPageContent
{
public:
PDFEditedPageContent() = default;
PDFEditedPageContent(const PDFEditedPageContent&) = delete;
PDFEditedPageContent(PDFEditedPageContent&&) = default;
PDFEditedPageContent& operator=(const PDFEditedPageContent&) = delete;
PDFEditedPageContent& operator=(PDFEditedPageContent&&) = default;
static QString getOperatorToString(PDFPageContentProcessor::Operator operatorValue);
static QString getOperandName(PDFPageContentProcessor::Operator operatorValue, int operandIndex);
void addContentPath(PDFPageContentProcessorState state, QPainterPath path, bool strokePath, bool fillPath);
void addContentImage(PDFPageContentProcessorState state, PDFObject imageObject, QImage image);
void addContentClipping(PDFPageContentProcessorState state, QPainterPath path);
void addContentElement(std::unique_ptr<PDFEditedPageContentElement> element);
std::size_t getElementCount() const { return m_contentElements.size(); }
PDFEditedPageContentElement* getElement(size_t index) const { return m_contentElements.at(index).get(); }
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 PDFPageContentEditorProcessor : public PDFPageContentProcessor
{
using BaseClass = PDFPageContentProcessor;
public:
PDFPageContentEditorProcessor(const PDFPage* page,
const PDFDocument* document,
const PDFFontCache* fontCache,
const PDFCMS* CMS,
const PDFOptionalContentActivity* optionalContentActivity,
QTransform pagePointToDevicePointMatrix,
const PDFMeshQualitySettings& meshQualitySettings);
const PDFEditedPageContent& getEditedPageContent() const;
PDFEditedPageContent takeEditedPageContent();
protected:
virtual void performInterceptInstruction(Operator currentOperator, ProcessOrder processOrder, const QByteArray& operatorAsText) override;
virtual void performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule) override;
virtual bool isContentKindSuppressed(ContentKind kind) const override;
virtual bool performOriginalImagePainting(const PDFImage& image, const PDFStream* stream) override;
virtual void performImagePainting(const QImage& image) override;
virtual void performClipping(const QPainterPath& path, Qt::FillRule fillRule) override;
virtual void performSaveGraphicState(ProcessOrder order) override;
virtual void performRestoreGraphicState(ProcessOrder order) override;
virtual void performUpdateGraphicsState(const PDFPageContentProcessorState& state) override;
virtual void performProcessTextSequence(const TextSequence& textSequence, ProcessOrder order) override;
private:
PDFEditedPageContent m_content;
std::stack<QPainterPath> m_clippingPaths;
std::unique_ptr<PDFEditedPageContentElementText> m_contentElementText;
QPainterPath m_textPath;
};
} // namespace pdf
#endif // PDFPAGECONTENTEDITORPROCESSOR_H

View File

@ -23,6 +23,7 @@
#include "pdfexecutionpolicy.h"
#include "pdfstreamfilters.h"
#include <QScopeGuard>
#include <QPainterPathStroker>
#include <QtMath>
@ -390,9 +391,10 @@ void PDFPageContentProcessor::performClipping(const QPainterPath& path, Qt::Fill
Q_UNUSED(fillRule);
}
bool PDFPageContentProcessor::performOriginalImagePainting(const PDFImage& image)
bool PDFPageContentProcessor::performOriginalImagePainting(const PDFImage& image, const PDFStream* stream)
{
Q_UNUSED(image);
Q_UNUSED(stream);
return false;
}
@ -485,6 +487,12 @@ void PDFPageContentProcessor::performTextEnd(ProcessOrder order)
Q_UNUSED(order);
}
void PDFPageContentProcessor::performProcessTextSequence(const TextSequence& textSequence, ProcessOrder order)
{
Q_UNUSED(textSequence);
Q_UNUSED(order);
}
bool PDFPageContentProcessor::isContentKindSuppressed(ContentKind kind) const
{
Q_UNUSED(kind);
@ -528,6 +536,15 @@ PDFPageContentProcessor::PDFTransparencyGroup PDFPageContentProcessor::parseTran
return group;
}
void PDFPageContentProcessor::performInterceptInstruction(Operator currentOperator,
ProcessOrder processOrder,
const QByteArray& operatorAsText)
{
Q_UNUSED(currentOperator);
Q_UNUSED(processOrder);
Q_UNUSED(operatorAsText);
}
void PDFPageContentProcessor::processContent(const QByteArray& content)
{
PDFLexicalAnalyzer parser(content.constBegin(), content.constEnd());
@ -738,6 +755,12 @@ void PDFPageContentProcessor::processForm(const QTransform& matrix,
const QByteArray& content,
PDFInteger formStructuralParent)
{
if (isContentKindSuppressed(ContentKind::Forms))
{
// Process of forms is suppressed
return;
}
PDFPageContentProcessorStateGuard guard(this);
PDFTemporaryValueChange structuralParentChangeGuard(&m_structuralParentKey, formStructuralParent);
@ -1129,6 +1152,9 @@ void PDFPageContentProcessor::processCommand(const QByteArray& command)
}
}
performInterceptInstruction(op, ProcessOrder::BeforeOperation, command);
auto callInterceptInstAtEnd = qScopeGuard([&, this](){ performInterceptInstruction(op, ProcessOrder::AfterOperation, command); });
switch (op)
{
case Operator::SetLineWidth:
@ -1855,6 +1881,11 @@ bool PDFPageContentProcessor::isProcessingCancelled() const
return m_operationControl && m_operationControl->isOperationCancelled();
}
bool PDFPageContentProcessor::isTextProcessing() const
{
return m_textBeginEndState > 0;
}
void PDFPageContentProcessor::reportRenderErrorOnce(RenderErrorType type, QString message)
{
if (!m_onceReportedErrors.count(message))
@ -2718,7 +2749,7 @@ void PDFPageContentProcessor::operatorTextSetFontAndFontSize(PDFOperandName font
{
try
{
PDFFontPointer font = m_fontCache->getFont(m_fontDictionary->get(fontName.name));
PDFFontPointer font = m_fontCache->getFont(m_fontDictionary->get(fontName.name), fontName.name);
m_graphicState.setTextFont(qMove(font));
m_graphicState.setTextFontSize(fontSize);
@ -2973,7 +3004,7 @@ void PDFPageContentProcessor::paintXObjectImage(const PDFStream* stream)
PDFImage pdfImage = PDFImage::createImage(m_document, stream, qMove(colorSpace), false, m_graphicState.getRenderingIntent(), this);
if (!performOriginalImagePainting(pdfImage))
if (!performOriginalImagePainting(pdfImage, stream))
{
QImage image = pdfImage.getImage(m_CMS, this, m_operationControl);
@ -3007,6 +3038,12 @@ void PDFPageContentProcessor::reportWarningAboutColorOperatorsInUTP()
void PDFPageContentProcessor::processForm(const PDFStream* stream)
{
if (isContentKindSuppressed(ContentKind::Forms))
{
// Process of forms is suppressed
return;
}
PDFDocumentDataLoaderDecorator loader(getDocument());
const PDFDictionary* streamDictionary = stream->getDictionary();
@ -3165,6 +3202,8 @@ void PDFPageContentProcessor::drawText(const TextSequence& textSequence)
return;
}
performProcessTextSequence(textSequence, ProcessOrder::BeforeOperation);
const PDFRealizedFontPointer& font = getRealizedFont();
if (font)
{
@ -3340,6 +3379,8 @@ void PDFPageContentProcessor::drawText(const TextSequence& textSequence)
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid font, text can't be printed."));
}
performProcessTextSequence(textSequence, ProcessOrder::AfterOperation);
}
PDFRealizedFontPointer PDFPageContentProcessor::getRealizedFontImpl()
@ -3415,7 +3456,7 @@ bool PDFPageContentProcessor::isContentSuppressedByOC(PDFObjectReference ocgOrOc
return false;
}
PDFPageContentProcessor::PDFPageContentProcessorState::PDFPageContentProcessorState() :
PDFPageContentProcessorState::PDFPageContentProcessorState() :
m_currentTransformationMatrix(),
m_strokeColorSpace(),
m_fillColorSpace(),
@ -3456,55 +3497,60 @@ PDFPageContentProcessor::PDFPageContentProcessorState::PDFPageContentProcessorSt
m_strokeColorOriginal = m_fillColorOriginal;
}
PDFPageContentProcessor::PDFPageContentProcessorState::~PDFPageContentProcessorState()
PDFPageContentProcessorState::~PDFPageContentProcessorState()
{
}
PDFPageContentProcessor::PDFPageContentProcessorState& PDFPageContentProcessor::PDFPageContentProcessorState::operator=(const PDFPageContentProcessor::PDFPageContentProcessorState& other)
PDFPageContentProcessorState& PDFPageContentProcessorState::operator=(const PDFPageContentProcessorState& other)
{
setCurrentTransformationMatrix(other.getCurrentTransformationMatrix());
setStrokeColorSpace(other.m_strokeColorSpace);
setFillColorSpace(other.m_fillColorSpace);
setStrokeColor(other.getStrokeColor(), other.getStrokeColorOriginal());
setFillColor(other.getFillColor(), other.getFillColorOriginal());
setLineWidth(other.getLineWidth());
setLineCapStyle(other.getLineCapStyle());
setLineJoinStyle(other.getLineJoinStyle());
setMitterLimit(other.getMitterLimit());
setLineDashPattern(other.getLineDashPattern());
setRenderingIntentName(other.getRenderingIntentName());
setFlatness(other.getFlatness());
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());
setAlphaStroking(other.getAlphaStroking());
setAlphaFilling(other.getAlphaFilling());
setBlendMode(other.getBlendMode());
setRenderingIntent(other.getRenderingIntent());
setOverprintMode(other.getOverprintMode());
setAlphaIsShape(other.getAlphaIsShape());
setStrokeAdjustment(other.getStrokeAdjustment());
setSoftMask(other.getSoftMask());
setBlackPointCompensationMode(other.getBlackPointCompensationMode());
setBlackGenerationFunction(other.getBlackGenerationFunction());
setUndercolorRemovalFunction(other.getUndercolorRemovalFunction());
setTransferFunction(other.getTransferFunction());
setHalftone(other.getHalftone());
setHalftoneOrigin(other.getHalftoneOrigin());
setState(other);
return *this;
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setCurrentTransformationMatrix(const QTransform& currentTransformationMatrix)
void PDFPageContentProcessorState::setState(const PDFPageContentProcessorState& state)
{
setCurrentTransformationMatrix(state.getCurrentTransformationMatrix());
setStrokeColorSpace(state.m_strokeColorSpace);
setFillColorSpace(state.m_fillColorSpace);
setStrokeColor(state.getStrokeColor(), state.getStrokeColorOriginal());
setFillColor(state.getFillColor(), state.getFillColorOriginal());
setLineWidth(state.getLineWidth());
setLineCapStyle(state.getLineCapStyle());
setLineJoinStyle(state.getLineJoinStyle());
setMitterLimit(state.getMitterLimit());
setLineDashPattern(state.getLineDashPattern());
setRenderingIntentName(state.getRenderingIntentName());
setFlatness(state.getFlatness());
setSmoothness(state.getSmoothness());
setTextCharacterSpacing(state.getTextCharacterSpacing());
setTextWordSpacing(state.getTextWordSpacing());
setTextHorizontalScaling(state.getTextHorizontalScaling());
setTextLeading(state.getTextLeading());
setTextFont(state.getTextFont());
setTextFontSize(state.getTextFontSize());
setTextRenderingMode(state.getTextRenderingMode());
setTextRise(state.getTextRise());
setTextKnockout(state.getTextKnockout());
setTextMatrix(state.getTextMatrix());
setTextLineMatrix(state.getTextLineMatrix());
setAlphaStroking(state.getAlphaStroking());
setAlphaFilling(state.getAlphaFilling());
setBlendMode(state.getBlendMode());
setRenderingIntent(state.getRenderingIntent());
setOverprintMode(state.getOverprintMode());
setAlphaIsShape(state.getAlphaIsShape());
setStrokeAdjustment(state.getStrokeAdjustment());
setSoftMask(state.getSoftMask());
setBlackPointCompensationMode(state.getBlackPointCompensationMode());
setBlackGenerationFunction(state.getBlackGenerationFunction());
setUndercolorRemovalFunction(state.getUndercolorRemovalFunction());
setTransferFunction(state.getTransferFunction());
setHalftone(state.getHalftone());
setHalftoneOrigin(state.getHalftoneOrigin());
}
void PDFPageContentProcessorState::setCurrentTransformationMatrix(const QTransform& currentTransformationMatrix)
{
if (m_currentTransformationMatrix != currentTransformationMatrix)
{
@ -3513,7 +3559,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setCurrentTransforma
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setStrokeColorSpace(const QSharedPointer<PDFAbstractColorSpace>& strokeColorSpace)
void PDFPageContentProcessorState::setStrokeColorSpace(const QSharedPointer<PDFAbstractColorSpace>& strokeColorSpace)
{
if (m_strokeColorSpace != strokeColorSpace)
{
@ -3522,7 +3568,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setStrokeColorSpace(
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setFillColorSpace(const QSharedPointer<PDFAbstractColorSpace>& fillColorSpace)
void PDFPageContentProcessorState::setFillColorSpace(const QSharedPointer<PDFAbstractColorSpace>& fillColorSpace)
{
if (m_fillColorSpace != fillColorSpace)
{
@ -3531,7 +3577,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setFillColorSpace(co
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setStrokeColor(const QColor& strokeColor, const PDFColor& originalColor)
void PDFPageContentProcessorState::setStrokeColor(const QColor& strokeColor, const PDFColor& originalColor)
{
if (m_strokeColor != strokeColor || m_strokeColorOriginal != originalColor)
{
@ -3541,7 +3587,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setStrokeColor(const
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setFillColor(const QColor& fillColor, const PDFColor& originalColor)
void PDFPageContentProcessorState::setFillColor(const QColor& fillColor, const PDFColor& originalColor)
{
if (m_fillColor != fillColor || m_fillColorOriginal != originalColor)
{
@ -3551,7 +3597,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setFillColor(const Q
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setLineWidth(PDFReal lineWidth)
void PDFPageContentProcessorState::setLineWidth(PDFReal lineWidth)
{
if (m_lineWidth != lineWidth)
{
@ -3560,7 +3606,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setLineWidth(PDFReal
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setLineCapStyle(Qt::PenCapStyle lineCapStyle)
void PDFPageContentProcessorState::setLineCapStyle(Qt::PenCapStyle lineCapStyle)
{
if (m_lineCapStyle != lineCapStyle)
{
@ -3569,7 +3615,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setLineCapStyle(Qt::
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setLineJoinStyle(Qt::PenJoinStyle lineJoinStyle)
void PDFPageContentProcessorState::setLineJoinStyle(Qt::PenJoinStyle lineJoinStyle)
{
if (m_lineJoinStyle != lineJoinStyle)
{
@ -3578,7 +3624,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setLineJoinStyle(Qt:
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setMitterLimit(PDFReal mitterLimit)
void PDFPageContentProcessorState::setMitterLimit(PDFReal mitterLimit)
{
if (m_mitterLimit != mitterLimit)
{
@ -3587,7 +3633,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setMitterLimit(PDFRe
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setLineDashPattern(PDFLineDashPattern pattern)
void PDFPageContentProcessorState::setLineDashPattern(PDFLineDashPattern pattern)
{
if (m_lineDashPattern != pattern)
{
@ -3596,7 +3642,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setLineDashPattern(P
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setRenderingIntentName(const QByteArray& renderingIntentName)
void PDFPageContentProcessorState::setRenderingIntentName(const QByteArray& renderingIntentName)
{
if (m_renderingIntentName != renderingIntentName)
{
@ -3605,7 +3651,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setRenderingIntentNa
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setFlatness(PDFReal flatness)
void PDFPageContentProcessorState::setFlatness(PDFReal flatness)
{
if (m_flatness != flatness)
{
@ -3614,7 +3660,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setFlatness(PDFReal
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setSmoothness(PDFReal smoothness)
void PDFPageContentProcessorState::setSmoothness(PDFReal smoothness)
{
if (m_smoothness != smoothness)
{
@ -3623,7 +3669,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setSmoothness(PDFRea
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextLeading(PDFReal textLeading)
void PDFPageContentProcessorState::setTextLeading(PDFReal textLeading)
{
if (m_textLeading != textLeading)
{
@ -3632,7 +3678,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTextLeading(PDFRe
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextFontSize(PDFReal textFontSize)
void PDFPageContentProcessorState::setTextFontSize(PDFReal textFontSize)
{
if (m_textFontSize != textFontSize)
{
@ -3641,7 +3687,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTextFontSize(PDFR
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextKnockout(bool textKnockout)
void PDFPageContentProcessorState::setTextKnockout(bool textKnockout)
{
if (m_textKnockout != textKnockout)
{
@ -3650,7 +3696,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTextKnockout(bool
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextLineMatrix(const QTransform& textLineMatrix)
void PDFPageContentProcessorState::setTextLineMatrix(const QTransform& textLineMatrix)
{
if (m_textLineMatrix != textLineMatrix)
{
@ -3659,7 +3705,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTextLineMatrix(co
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setAlphaStroking(PDFReal alpha)
void PDFPageContentProcessorState::setAlphaStroking(PDFReal alpha)
{
if (m_alphaStroking != alpha)
{
@ -3668,7 +3714,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setAlphaStroking(PDF
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setAlphaFilling(PDFReal alpha)
void PDFPageContentProcessorState::setAlphaFilling(PDFReal alpha)
{
if (m_alphaFilling != alpha)
{
@ -3677,7 +3723,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setAlphaFilling(PDFR
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setBlendMode(BlendMode mode)
void PDFPageContentProcessorState::setBlendMode(BlendMode mode)
{
if (m_blendMode != mode)
{
@ -3686,7 +3732,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setBlendMode(BlendMo
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setRenderingIntent(RenderingIntent renderingIntent)
void PDFPageContentProcessorState::setRenderingIntent(RenderingIntent renderingIntent)
{
if (m_renderingIntent != renderingIntent)
{
@ -3695,21 +3741,21 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setRenderingIntent(R
}
}
QColor PDFPageContentProcessor::PDFPageContentProcessorState::getStrokeColorWithAlpha() const
QColor PDFPageContentProcessorState::getStrokeColorWithAlpha() const
{
QColor color = getStrokeColor();
color.setAlphaF(m_alphaStroking);
return color;
}
QColor PDFPageContentProcessor::PDFPageContentProcessorState::getFillColorWithAlpha() const
QColor PDFPageContentProcessorState::getFillColorWithAlpha() const
{
QColor color = getFillColor();
color.setAlphaF(m_alphaFilling);
return color;
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setOverprintMode(PDFOverprintMode overprintMode)
void PDFPageContentProcessorState::setOverprintMode(PDFOverprintMode overprintMode)
{
if (m_overprintMode != overprintMode)
{
@ -3718,7 +3764,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setOverprintMode(PDF
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setAlphaIsShape(bool alphaIsShape)
void PDFPageContentProcessorState::setAlphaIsShape(bool alphaIsShape)
{
if (m_alphaIsShape != alphaIsShape)
{
@ -3727,12 +3773,12 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setAlphaIsShape(bool
}
}
bool PDFPageContentProcessor::PDFPageContentProcessorState::getStrokeAdjustment() const
bool PDFPageContentProcessorState::getStrokeAdjustment() const
{
return m_strokeAdjustment;
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setStrokeAdjustment(bool strokeAdjustment)
void PDFPageContentProcessorState::setStrokeAdjustment(bool strokeAdjustment)
{
if (m_strokeAdjustment != strokeAdjustment)
{
@ -3741,12 +3787,12 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setStrokeAdjustment(
}
}
const PDFDictionary* PDFPageContentProcessor::PDFPageContentProcessorState::getSoftMask() const
const PDFDictionary* PDFPageContentProcessorState::getSoftMask() const
{
return m_softMask;
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setSoftMask(const PDFDictionary* softMask)
void PDFPageContentProcessorState::setSoftMask(const PDFDictionary* softMask)
{
if (m_softMask != softMask)
{
@ -3755,12 +3801,12 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setSoftMask(const PD
}
}
BlackPointCompensationMode PDFPageContentProcessor::PDFPageContentProcessorState::getBlackPointCompensationMode() const
BlackPointCompensationMode PDFPageContentProcessorState::getBlackPointCompensationMode() const
{
return m_blackPointCompensationMode;
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setBlackPointCompensationMode(BlackPointCompensationMode blackPointCompensationMode)
void PDFPageContentProcessorState::setBlackPointCompensationMode(BlackPointCompensationMode blackPointCompensationMode)
{
if (m_blackPointCompensationMode != blackPointCompensationMode)
{
@ -3769,12 +3815,12 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setBlackPointCompens
}
}
PDFObject PDFPageContentProcessor::PDFPageContentProcessorState::getHalftone() const
PDFObject PDFPageContentProcessorState::getHalftone() const
{
return m_halftone;
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setHalftone(const PDFObject& halftone)
void PDFPageContentProcessorState::setHalftone(const PDFObject& halftone)
{
if (m_halftone != halftone)
{
@ -3783,12 +3829,12 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setHalftone(const PD
}
}
QPointF PDFPageContentProcessor::PDFPageContentProcessorState::getHalftoneOrigin() const
QPointF PDFPageContentProcessorState::getHalftoneOrigin() const
{
return m_halftoneOrigin;
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setHalftoneOrigin(const QPointF& halftoneOrigin)
void PDFPageContentProcessorState::setHalftoneOrigin(const QPointF& halftoneOrigin)
{
if (m_halftoneOrigin != halftoneOrigin)
{
@ -3797,12 +3843,12 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setHalftoneOrigin(co
}
}
PDFObject PDFPageContentProcessor::PDFPageContentProcessorState::getTransferFunction() const
PDFObject PDFPageContentProcessorState::getTransferFunction() const
{
return m_transferFunction;
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTransferFunction(const PDFObject& transferFunction)
void PDFPageContentProcessorState::setTransferFunction(const PDFObject& transferFunction)
{
if (m_transferFunction != transferFunction)
{
@ -3811,12 +3857,12 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTransferFunction(
}
}
PDFObject PDFPageContentProcessor::PDFPageContentProcessorState::getUndercolorRemovalFunction() const
PDFObject PDFPageContentProcessorState::getUndercolorRemovalFunction() const
{
return m_undercolorRemovalFunction;
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setUndercolorRemovalFunction(const PDFObject& undercolorRemovalFunction)
void PDFPageContentProcessorState::setUndercolorRemovalFunction(const PDFObject& undercolorRemovalFunction)
{
if (m_undercolorRemovalFunction != undercolorRemovalFunction)
{
@ -3825,12 +3871,12 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setUndercolorRemoval
}
}
PDFObject PDFPageContentProcessor::PDFPageContentProcessorState::getBlackGenerationFunction() const
PDFObject PDFPageContentProcessorState::getBlackGenerationFunction() const
{
return m_blackGenerationFunction;
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setBlackGenerationFunction(const PDFObject& blackGenerationFunction)
void PDFPageContentProcessorState::setBlackGenerationFunction(const PDFObject& blackGenerationFunction)
{
if (m_blackGenerationFunction != blackGenerationFunction)
{
@ -3839,7 +3885,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setBlackGenerationFu
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextMatrix(const QTransform& textMatrix)
void PDFPageContentProcessorState::setTextMatrix(const QTransform& textMatrix)
{
if (m_textMatrix != textMatrix)
{
@ -3848,7 +3894,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTextMatrix(const
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextRise(PDFReal textRise)
void PDFPageContentProcessorState::setTextRise(PDFReal textRise)
{
if (m_textRise != textRise)
{
@ -3857,7 +3903,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTextRise(PDFReal
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextRenderingMode(TextRenderingMode textRenderingMode)
void PDFPageContentProcessorState::setTextRenderingMode(TextRenderingMode textRenderingMode)
{
if (m_textRenderingMode != textRenderingMode)
{
@ -3866,7 +3912,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTextRenderingMode
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextFont(const PDFFontPointer& textFont)
void PDFPageContentProcessorState::setTextFont(const PDFFontPointer& textFont)
{
if (m_textFont != textFont)
{
@ -3875,7 +3921,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTextFont(const PD
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextHorizontalScaling(PDFReal textHorizontalScaling)
void PDFPageContentProcessorState::setTextHorizontalScaling(PDFReal textHorizontalScaling)
{
if (m_textHorizontalScaling != textHorizontalScaling)
{
@ -3884,7 +3930,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTextHorizontalSca
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextWordSpacing(PDFReal textWordSpacing)
void PDFPageContentProcessorState::setTextWordSpacing(PDFReal textWordSpacing)
{
if (m_textWordSpacing != textWordSpacing)
{
@ -3893,7 +3939,7 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTextWordSpacing(P
}
}
void PDFPageContentProcessor::PDFPageContentProcessorState::setTextCharacterSpacing(PDFReal textCharacterSpacing)
void PDFPageContentProcessorState::setTextCharacterSpacing(PDFReal textCharacterSpacing)
{
if (m_textCharacterSpacing != textCharacterSpacing)
{

View File

@ -48,6 +48,7 @@ class PDFOptionalContentActivity;
static constexpr const char* PDF_RESOURCE_EXTGSTATE = "ExtGState";
class PDFLineDashPattern
{
public:
@ -79,6 +80,253 @@ private:
PDFReal m_dashOffset = 0.0;
};
struct PDFOverprintMode
{
bool overprintStroking = false;
bool overprintFilling = false;
int overprintMode = 0;
inline bool operator==(const PDFOverprintMode& other) const
{
return std::tie(overprintStroking, overprintFilling, overprintMode) == std::tie(other.overprintStroking, other.overprintFilling, other.overprintMode);
}
inline bool operator!=(const PDFOverprintMode& other) const
{
return !(*this == other);
}
};
/// Represents graphic state of the PDF (holding current graphic state parameters).
/// Please see PDF Reference 1.7, Chapter 4.3 "Graphic State"
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentProcessorState
{
public:
explicit PDFPageContentProcessorState();
~PDFPageContentProcessorState();
PDFPageContentProcessorState(const PDFPageContentProcessorState&) = default;
PDFPageContentProcessorState(PDFPageContentProcessorState&&) = default;
PDFPageContentProcessorState& operator=(PDFPageContentProcessorState&&) = delete;
PDFPageContentProcessorState& operator=(const PDFPageContentProcessorState& other);
enum StateFlag : uint64_t
{
StateUnchanged = 0x0000000000000000,
StateCurrentTransformationMatrix = 0x0000000000000001,
StateStrokeColorSpace = 0x0000000000000002,
StateFillColorSpace = 0x0000000000000004,
StateStrokeColor = 0x0000000000000008,
StateFillColor = 0x0000000000000010,
StateLineWidth = 0x0000000000000020,
StateLineCapStyle = 0x0000000000000040,
StateLineJoinStyle = 0x0000000000000080,
StateMitterLimit = 0x0000000000000100,
StateLineDashPattern = 0x0000000000000200,
StateRenderingIntentName = 0x0000000000000400,
StateFlatness = 0x0000000000000800,
StateSmoothness = 0x0000000000001000,
StateTextMatrix = 0x0000000000002000,
StateTextLineMatrix = 0x0000000000004000,
StateTextCharacterSpacing = 0x0000000000008000,
StateTextWordSpacing = 0x0000000000010000,
StateTextHorizontalScaling = 0x0000000000020000,
StateTextLeading = 0x0000000000040000,
StateTextFont = 0x0000000000080000,
StateTextFontSize = 0x0000000000100000,
StateTextRenderingMode = 0x0000000000200000,
StateTextRise = 0x0000000000400000,
StateTextKnockout = 0x0000000000800000,
StateAlphaStroking = 0x0000000001000000,
StateAlphaFilling = 0x0000000002000000,
StateBlendMode = 0x0000000004000000,
StateRenderingIntent = 0x0000000008000000,
StateOverprint = 0x0000000010000000,
StateAlphaIsShape = 0x0000000020000000,
StateStrokeAdjustment = 0x0000000040000000,
StateSoftMask = 0x0000000080000000,
StateBlackPointCompensation = 0x0000000100000000,
StateBlackGenerationFunction = 0x0000000200000000,
StateUndercolorRemovalFunction = 0x0000000400000000,
StateTransferFunction = 0x0000000800000000,
StateHalftone = 0x0000001000000000,
StateHalftoneOrigin = 0x0000002000000000,
StateAll = 0xFFFFFFFFFFFFFFFF
};
using StateFlags = PDFFlags<StateFlag>;
void setState(const PDFPageContentProcessorState& state);
const QTransform& getCurrentTransformationMatrix() const { return m_currentTransformationMatrix; }
void setCurrentTransformationMatrix(const QTransform& currentTransformationMatrix);
const PDFAbstractColorSpace* getStrokeColorSpace() const { return m_strokeColorSpace.data(); }
void setStrokeColorSpace(const QSharedPointer<PDFAbstractColorSpace>& strokeColorSpace);
const PDFAbstractColorSpace* getFillColorSpace() const { return m_fillColorSpace.data(); }
void setFillColorSpace(const QSharedPointer<PDFAbstractColorSpace>& fillColorSpace);
const QColor& getStrokeColor() const { return m_strokeColor; }
const PDFColor& getStrokeColorOriginal() const { return m_strokeColorOriginal; }
void setStrokeColor(const QColor& strokeColor, const PDFColor& originalColor);
const QColor& getFillColor() const { return m_fillColor; }
const PDFColor& getFillColorOriginal() const { return m_fillColorOriginal; }
void setFillColor(const QColor& fillColor, const PDFColor& originalColor);
PDFReal getLineWidth() const { return m_lineWidth; }
void setLineWidth(PDFReal lineWidth);
Qt::PenCapStyle getLineCapStyle() const { return m_lineCapStyle; }
void setLineCapStyle(Qt::PenCapStyle lineCapStyle);
Qt::PenJoinStyle getLineJoinStyle() const { return m_lineJoinStyle; }
void setLineJoinStyle(Qt::PenJoinStyle lineJoinStyle);
PDFReal getMitterLimit() const { return m_mitterLimit; }
void setMitterLimit(PDFReal mitterLimit);
const PDFLineDashPattern& getLineDashPattern() const { return m_lineDashPattern; }
void setLineDashPattern(PDFLineDashPattern pattern);
const QByteArray& getRenderingIntentName() const { return m_renderingIntentName; }
void setRenderingIntentName(const QByteArray& renderingIntentName);
PDFReal getFlatness() const { return m_flatness; }
void setFlatness(PDFReal flatness);
PDFReal getSmoothness() const { return m_smoothness; }
void setSmoothness(PDFReal smoothness);
StateFlags getStateFlags() const { return m_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 QTransform& getTextMatrix() const { return m_textMatrix; }
void setTextMatrix(const QTransform& textMatrix);
const QTransform& getTextLineMatrix() const { return m_textLineMatrix; }
void setTextLineMatrix(const QTransform& textLineMatrix);
PDFReal getAlphaStroking() const { return m_alphaStroking; }
void setAlphaStroking(PDFReal alpha);
PDFReal getAlphaFilling() const { return m_alphaFilling; }
void setAlphaFilling(PDFReal alpha);
BlendMode getBlendMode() const { return m_blendMode; }
void setBlendMode(BlendMode mode);
RenderingIntent getRenderingIntent() const { return m_renderingIntent; }
void setRenderingIntent(RenderingIntent renderingIntent);
/// Returns stroke color with alpha channel
QColor getStrokeColorWithAlpha() const;
/// Returns fill color with alpha channel
QColor getFillColorWithAlpha() const;
PDFOverprintMode getOverprintMode() const { return m_overprintMode; }
void setOverprintMode(PDFOverprintMode overprintMode);
bool getAlphaIsShape() const { return m_alphaIsShape; }
void setAlphaIsShape(bool alphaIsShape);
bool getStrokeAdjustment() const;
void setStrokeAdjustment(bool strokeAdjustment);
const PDFDictionary* getSoftMask() const;
void setSoftMask(const PDFDictionary* softMask);
BlackPointCompensationMode getBlackPointCompensationMode() const;
void setBlackPointCompensationMode(BlackPointCompensationMode blackPointCompensationMode);
PDFObject getBlackGenerationFunction() const;
void setBlackGenerationFunction(const PDFObject& blackGenerationFunction);
PDFObject getUndercolorRemovalFunction() const;
void setUndercolorRemovalFunction(const PDFObject& undercolorRemovalFunction);
PDFObject getTransferFunction() const;
void setTransferFunction(const PDFObject& transferFunction);
PDFObject getHalftone() const;
void setHalftone(const PDFObject& halftone);
QPointF getHalftoneOrigin() const;
void setHalftoneOrigin(const QPointF& halftoneOrigin);
private:
QTransform m_currentTransformationMatrix;
PDFColorSpacePointer m_strokeColorSpace;
PDFColorSpacePointer m_fillColorSpace;
QColor m_strokeColor;
PDFColor m_strokeColorOriginal;
QColor m_fillColor;
PDFColor m_fillColorOriginal;
PDFReal m_lineWidth;
Qt::PenCapStyle m_lineCapStyle;
Qt::PenJoinStyle m_lineJoinStyle;
PDFReal m_mitterLimit;
PDFLineDashPattern m_lineDashPattern;
QByteArray m_renderingIntentName;
PDFReal m_flatness;
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;
QTransform m_textMatrix;
QTransform m_textLineMatrix;
PDFReal m_alphaStroking;
PDFReal m_alphaFilling;
BlendMode m_blendMode;
RenderingIntent m_renderingIntent;
PDFOverprintMode m_overprintMode;
bool m_alphaIsShape;
bool m_strokeAdjustment;
const PDFDictionary* m_softMask;
BlackPointCompensationMode m_blackPointCompensationMode;
PDFObject m_blackGenerationFunction;
PDFObject m_undercolorRemovalFunction;
PDFObject m_transferFunction;
PDFObject m_halftone;
QPointF m_halftoneOrigin;
StateFlags m_stateFlags;
};
/// Process the contents of the page.
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentProcessor : public PDFRenderErrorReporter
{
@ -253,6 +501,29 @@ public:
/// Returns true, if page content processing is being cancelled
bool isProcessingCancelled() const;
/// 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
@ -296,257 +567,21 @@ protected:
friend class PDFPageContentProcessor;
};
struct PDFOverprintMode
{
bool overprintStroking = false;
bool overprintFilling = false;
int overprintMode = 0;
inline bool operator==(const PDFOverprintMode& other) const
{
return std::tie(overprintStroking, overprintFilling, overprintMode) == std::tie(other.overprintStroking, other.overprintFilling, other.overprintMode);
}
inline bool operator!=(const PDFOverprintMode& other) const
{
return !(*this == other);
}
};
/// Represents graphic state of the PDF (holding current graphic state parameters).
/// Please see PDF Reference 1.7, Chapter 4.3 "Graphic State"
class PDFPageContentProcessorState
{
public:
explicit PDFPageContentProcessorState();
~PDFPageContentProcessorState();
PDFPageContentProcessorState(const PDFPageContentProcessorState&) = default;
PDFPageContentProcessorState(PDFPageContentProcessorState&&) = default;
PDFPageContentProcessorState& operator=(PDFPageContentProcessorState&&) = delete;
PDFPageContentProcessorState& operator=(const PDFPageContentProcessorState& other);
enum StateFlag : uint64_t
{
StateUnchanged = 0x0000000000000000,
StateCurrentTransformationMatrix = 0x0000000000000001,
StateStrokeColorSpace = 0x0000000000000002,
StateFillColorSpace = 0x0000000000000004,
StateStrokeColor = 0x0000000000000008,
StateFillColor = 0x0000000000000010,
StateLineWidth = 0x0000000000000020,
StateLineCapStyle = 0x0000000000000040,
StateLineJoinStyle = 0x0000000000000080,
StateMitterLimit = 0x0000000000000100,
StateLineDashPattern = 0x0000000000000200,
StateRenderingIntentName = 0x0000000000000400,
StateFlatness = 0x0000000000000800,
StateSmoothness = 0x0000000000001000,
StateTextMatrix = 0x0000000000002000,
StateTextLineMatrix = 0x0000000000004000,
StateTextCharacterSpacing = 0x0000000000008000,
StateTextWordSpacing = 0x0000000000010000,
StateTextHorizontalScaling = 0x0000000000020000,
StateTextLeading = 0x0000000000040000,
StateTextFont = 0x0000000000080000,
StateTextFontSize = 0x0000000000100000,
StateTextRenderingMode = 0x0000000000200000,
StateTextRise = 0x0000000000400000,
StateTextKnockout = 0x0000000000800000,
StateAlphaStroking = 0x0000000001000000,
StateAlphaFilling = 0x0000000002000000,
StateBlendMode = 0x0000000004000000,
StateRenderingIntent = 0x0000000008000000,
StateOverprint = 0x0000000010000000,
StateAlphaIsShape = 0x0000000020000000,
StateStrokeAdjustment = 0x0000000040000000,
StateSoftMask = 0x0000000080000000,
StateBlackPointCompensation = 0x0000000100000000,
StateBlackGenerationFunction = 0x0000000200000000,
StateUndercolorRemovalFunction = 0x0000000400000000,
StateTransferFunction = 0x0000000800000000,
StateHalftone = 0x0000001000000000,
StateHalftoneOrigin = 0x0000002000000000,
StateAll = 0xFFFFFFFFFFFFFFFF
};
using StateFlags = PDFFlags<StateFlag>;
const QTransform& getCurrentTransformationMatrix() const { return m_currentTransformationMatrix; }
void setCurrentTransformationMatrix(const QTransform& currentTransformationMatrix);
const PDFAbstractColorSpace* getStrokeColorSpace() const { return m_strokeColorSpace.data(); }
void setStrokeColorSpace(const QSharedPointer<PDFAbstractColorSpace>& strokeColorSpace);
const PDFAbstractColorSpace* getFillColorSpace() const { return m_fillColorSpace.data(); }
void setFillColorSpace(const QSharedPointer<PDFAbstractColorSpace>& fillColorSpace);
const QColor& getStrokeColor() const { return m_strokeColor; }
const PDFColor& getStrokeColorOriginal() const { return m_strokeColorOriginal; }
void setStrokeColor(const QColor& strokeColor, const PDFColor& originalColor);
const QColor& getFillColor() const { return m_fillColor; }
const PDFColor& getFillColorOriginal() const { return m_fillColorOriginal; }
void setFillColor(const QColor& fillColor, const PDFColor& originalColor);
PDFReal getLineWidth() const { return m_lineWidth; }
void setLineWidth(PDFReal lineWidth);
Qt::PenCapStyle getLineCapStyle() const { return m_lineCapStyle; }
void setLineCapStyle(Qt::PenCapStyle lineCapStyle);
Qt::PenJoinStyle getLineJoinStyle() const { return m_lineJoinStyle; }
void setLineJoinStyle(Qt::PenJoinStyle lineJoinStyle);
PDFReal getMitterLimit() const { return m_mitterLimit; }
void setMitterLimit(PDFReal mitterLimit);
const PDFLineDashPattern& getLineDashPattern() const { return m_lineDashPattern; }
void setLineDashPattern(PDFLineDashPattern pattern);
const QByteArray& getRenderingIntentName() const { return m_renderingIntentName; }
void setRenderingIntentName(const QByteArray& renderingIntentName);
PDFReal getFlatness() const { return m_flatness; }
void setFlatness(PDFReal flatness);
PDFReal getSmoothness() const { return m_smoothness; }
void setSmoothness(PDFReal smoothness);
StateFlags getStateFlags() const { return m_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 QTransform& getTextMatrix() const { return m_textMatrix; }
void setTextMatrix(const QTransform& textMatrix);
const QTransform& getTextLineMatrix() const { return m_textLineMatrix; }
void setTextLineMatrix(const QTransform& textLineMatrix);
PDFReal getAlphaStroking() const { return m_alphaStroking; }
void setAlphaStroking(PDFReal alpha);
PDFReal getAlphaFilling() const { return m_alphaFilling; }
void setAlphaFilling(PDFReal alpha);
BlendMode getBlendMode() const { return m_blendMode; }
void setBlendMode(BlendMode mode);
RenderingIntent getRenderingIntent() const { return m_renderingIntent; }
void setRenderingIntent(RenderingIntent renderingIntent);
/// Returns stroke color with alpha channel
QColor getStrokeColorWithAlpha() const;
/// Returns fill color with alpha channel
QColor getFillColorWithAlpha() const;
PDFOverprintMode getOverprintMode() const { return m_overprintMode; }
void setOverprintMode(PDFOverprintMode overprintMode);
bool getAlphaIsShape() const { return m_alphaIsShape; }
void setAlphaIsShape(bool alphaIsShape);
bool getStrokeAdjustment() const;
void setStrokeAdjustment(bool strokeAdjustment);
const PDFDictionary* getSoftMask() const;
void setSoftMask(const PDFDictionary* softMask);
BlackPointCompensationMode getBlackPointCompensationMode() const;
void setBlackPointCompensationMode(BlackPointCompensationMode blackPointCompensationMode);
PDFObject getBlackGenerationFunction() const;
void setBlackGenerationFunction(const PDFObject& blackGenerationFunction);
PDFObject getUndercolorRemovalFunction() const;
void setUndercolorRemovalFunction(const PDFObject& undercolorRemovalFunction);
PDFObject getTransferFunction() const;
void setTransferFunction(const PDFObject& transferFunction);
PDFObject getHalftone() const;
void setHalftone(const PDFObject& halftone);
QPointF getHalftoneOrigin() const;
void setHalftoneOrigin(const QPointF& halftoneOrigin);
private:
QTransform m_currentTransformationMatrix;
PDFColorSpacePointer m_strokeColorSpace;
PDFColorSpacePointer m_fillColorSpace;
QColor m_strokeColor;
PDFColor m_strokeColorOriginal;
QColor m_fillColor;
PDFColor m_fillColorOriginal;
PDFReal m_lineWidth;
Qt::PenCapStyle m_lineCapStyle;
Qt::PenJoinStyle m_lineJoinStyle;
PDFReal m_mitterLimit;
PDFLineDashPattern m_lineDashPattern;
QByteArray m_renderingIntentName;
PDFReal m_flatness;
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;
QTransform m_textMatrix;
QTransform m_textLineMatrix;
PDFReal m_alphaStroking;
PDFReal m_alphaFilling;
BlendMode m_blendMode;
RenderingIntent m_renderingIntent;
PDFOverprintMode m_overprintMode;
bool m_alphaIsShape;
bool m_strokeAdjustment;
const PDFDictionary* m_softMask;
BlackPointCompensationMode m_blackPointCompensationMode;
PDFObject m_blackGenerationFunction;
PDFObject m_undercolorRemovalFunction;
PDFObject m_transferFunction;
PDFObject m_halftone;
QPointF m_halftoneOrigin;
StateFlags m_stateFlags;
};
enum class ProcessOrder
{
BeforeOperation,
AfterOperation
};
/// This function is used, when we directly want to intercept content
/// stream instructions and operands.
/// \param currentOperator Current operator
/// \param processOrder Mark before/after instruction is executed
/// \param operatorAsText Operator converted to text
virtual void performInterceptInstruction(Operator currentOperator,
ProcessOrder processOrder,
const QByteArray& operatorAsText);
/// This function has to be implemented in the client drawing implementation, it should
/// draw the path according to the parameters.
/// \param path Path, which should be drawn (can be emtpy - in that case nothing happens)
@ -575,8 +610,9 @@ protected:
/// original image, it should return true, so no conversion to QImage occurs,
/// which can be performance bottleneck.
/// \param image Image
/// \param stream Stream, from which image originated
/// \returns true, if image is successfully processed
virtual bool performOriginalImagePainting(const PDFImage& image);
virtual bool performOriginalImagePainting(const PDFImage& image, const PDFStream* stream);
/// This function has to be implemented in the client drawing implementation, it should
/// draw the image.
@ -645,6 +681,9 @@ protected:
/// Implement to respond to text end operator
virtual void performTextEnd(ProcessOrder order);
/// Implement to respond to text sequence processing
virtual void performProcessTextSequence(const TextSequence& textSequence, ProcessOrder order);
enum class ContentKind
{
Shapes, ///< General shapes (they can be also shaded / tiled)
@ -652,6 +691,7 @@ protected:
Images, ///< Images
Shading, ///< Shading
Tiling, ///< Tiling
Forms, ///< Forms
};
/// Override this function to disable particular content type (for example
@ -706,6 +746,9 @@ protected:
/// Returns optional content activity
const PDFOptionalContentActivity* getOptionalContentActivity() const { return m_optionalContentActivity; }
/// Returns operand for current operator
const PDFFlatArray<PDFLexicalAnalyzer::Token, 33>& getOperands() const { return m_operands; }
class PDF4QTLIBCORESHARED_EXPORT PDFTransparencyGroupGuard
{
public:
@ -719,6 +762,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);
@ -857,8 +908,6 @@ private:
template<typename... Operands>
inline QColor getColorFromColorSpace(const PDFAbstractColorSpace* colorSpace, Operands... operands)
{
constexpr const size_t operandCount = sizeof...(Operands);
const size_t colorSpaceComponentCount = colorSpace->getColorComponentCount();
if (operandCount == colorSpaceComponentCount)
@ -871,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);
/// Convers 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);
/// Convers 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

View File

@ -114,56 +114,12 @@ bool PDFPainterBase::isContentSuppressedByOC(PDFObjectReference ocgOrOcmd)
QPen PDFPainterBase::getCurrentPenImpl() const
{
const PDFPageContentProcessorState* graphicState = getGraphicState();
QColor color = graphicState->getStrokeColor();
if (color.isValid())
{
color.setAlphaF(getEffectiveStrokingAlpha());
const PDFReal lineWidth = graphicState->getLineWidth();
Qt::PenCapStyle penCapStyle = graphicState->getLineCapStyle();
Qt::PenJoinStyle penJoinStyle = graphicState->getLineJoinStyle();
const PDFLineDashPattern& lineDashPattern = graphicState->getLineDashPattern();
const PDFReal mitterLimit = graphicState->getMitterLimit();
QPen pen(color);
pen.setWidthF(lineWidth);
pen.setCapStyle(penCapStyle);
pen.setJoinStyle(penJoinStyle);
pen.setMiterLimit(mitterLimit);
if (lineDashPattern.isSolid())
{
pen.setStyle(Qt::SolidLine);
}
else
{
pen.setStyle(Qt::CustomDashLine);
pen.setDashPattern(lineDashPattern.createForQPen(pen.widthF()));
pen.setDashOffset(lineDashPattern.getDashOffset());
}
return pen;
}
else
{
return QPen(Qt::NoPen);
}
return PDFPainterHelper::createPenFromState(getGraphicState(), getEffectiveStrokingAlpha());
}
QBrush PDFPainterBase::getCurrentBrushImpl() const
{
const PDFPageContentProcessorState* graphicState = getGraphicState();
QColor color = graphicState->getFillColor();
if (color.isValid())
{
color.setAlphaF(getEffectiveFillingAlpha());
return QBrush(color, Qt::SolidPattern);
}
else
{
return QBrush(Qt::NoBrush);
}
return PDFPainterHelper::createBrushFromState(getGraphicState(), getEffectiveFillingAlpha());
}
PDFReal PDFPainterBase::getEffectiveStrokingAlpha() const

View File

@ -16,6 +16,7 @@
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "pdfpainterutils.h"
#include "pdfpagecontentprocessor.h"
#include <QPainterPath>
#include <QFontMetrics>
@ -64,5 +65,171 @@ QRect PDFPainterHelper::drawBubble(QPainter* painter, QPoint point, QColor color
return rectangle;
}
QPen PDFPainterHelper::createPenFromState(const PDFPageContentProcessorState* graphicState, double alpha)
{
QColor color = graphicState->getStrokeColor();
if (color.isValid())
{
color.setAlphaF(alpha);
const PDFReal lineWidth = graphicState->getLineWidth();
Qt::PenCapStyle penCapStyle = graphicState->getLineCapStyle();
Qt::PenJoinStyle penJoinStyle = graphicState->getLineJoinStyle();
const PDFLineDashPattern& lineDashPattern = graphicState->getLineDashPattern();
const PDFReal mitterLimit = graphicState->getMitterLimit();
QPen pen(color);
pen.setWidthF(lineWidth);
pen.setCapStyle(penCapStyle);
pen.setJoinStyle(penJoinStyle);
pen.setMiterLimit(mitterLimit);
if (lineDashPattern.isSolid())
{
pen.setStyle(Qt::SolidLine);
}
else
{
pen.setStyle(Qt::CustomDashLine);
pen.setDashPattern(lineDashPattern.createForQPen(pen.widthF()));
pen.setDashOffset(lineDashPattern.getDashOffset());
}
return pen;
}
else
{
return QPen(Qt::NoPen);
}
}
QBrush PDFPainterHelper::createBrushFromState(const PDFPageContentProcessorState* graphicState, double alpha)
{
QColor color = graphicState->getFillColor();
if (color.isValid())
{
color.setAlphaF(alpha);
return QBrush(color, Qt::SolidPattern);
}
else
{
return QBrush(Qt::NoBrush);
}
}
void PDFPainterHelper::applyPenToGraphicState(PDFPageContentProcessorState* graphicState, const QPen& pen)
{
if (pen.style() != Qt::NoPen)
{
graphicState->setLineWidth(pen.widthF());
graphicState->setLineCapStyle(pen.capStyle());
graphicState->setLineJoinStyle(pen.joinStyle());
graphicState->setMitterLimit(pen.miterLimit());
QColor color = pen.color();
graphicState->setAlphaStroking(color.alphaF());
const PDFAbstractColorSpace* strokeColorSpace = graphicState->getStrokeColorSpace();
if (!strokeColorSpace || strokeColorSpace->getColorSpace() != PDFAbstractColorSpace::ColorSpace::DeviceRGB)
{
graphicState->setStrokeColorSpace(QSharedPointer<PDFAbstractColorSpace>(new PDFDeviceRGBColorSpace()));
}
graphicState->setStrokeColor(color, PDFColor(color.redF(), color.greenF(), color.blueF()));
if (pen.style() == Qt::SolidLine)
{
graphicState->setLineDashPattern(PDFLineDashPattern());
}
else
{
PDFLineDashPattern lineDashPattern;
QList<qreal> penPattern = pen.dashPattern();
PDFReal penWidth = pen.widthF();
std::vector<PDFReal> dashArray;
for (qreal value : penPattern)
{
dashArray.push_back(value * penWidth);
}
lineDashPattern.setDashArray(std::move(dashArray));
lineDashPattern.setDashOffset(pen.dashOffset());
graphicState->setLineDashPattern(std::move(lineDashPattern));
}
}
}
void PDFPainterHelper::applyBrushToGraphicState(PDFPageContentProcessorState* graphicState, const QBrush& brush)
{
if (brush.style() != Qt::NoBrush)
{
QColor color = brush.color();
graphicState->setAlphaFilling(color.alphaF());
const PDFAbstractColorSpace* fillColorSpace = graphicState->getFillColorSpace();
if (!fillColorSpace || fillColorSpace->getColorSpace() != PDFAbstractColorSpace::ColorSpace::DeviceRGB)
{
graphicState->setFillColorSpace(QSharedPointer<PDFAbstractColorSpace>(new PDFDeviceRGBColorSpace()));
}
graphicState->setFillColor(color, PDFColor(color.redF(), color.greenF(), color.blueF()));
}
}
PDFTransformationDecomposition PDFPainterHelper::decomposeTransform(const QTransform& transform)
{
PDFTransformationDecomposition result;
const qreal m11 = transform.m11();
const qreal m12 = transform.m12();
const qreal m21 = transform.m21();
const qreal m22 = transform.m22();
const qreal dx = transform.dx();
const qreal dy = transform.dy();
const qreal sx = std::sqrt(m11 * m11 + m21 * m21);
const qreal phi = std::atan2(m21, m11);
const qreal msy = m12 * std::cos(phi) + m22 * std::sin(phi);
const qreal sy = -m12 * std::sin(phi) + m22 * std::cos(phi);
result.rotationAngle = phi;
result.scaleX = sx;
result.scaleY = sy;
if (!qFuzzyIsNull(sy))
{
result.shearFactor = msy / sy;
}
else
{
result.shearFactor = 0.0;
}
result.translateX = dx;
result.translateY = dy;
return result;
}
QTransform PDFPainterHelper::composeTransform(const PDFTransformationDecomposition& decomposition)
{
const qreal s = std::sin(decomposition.rotationAngle);
const qreal c = std::cos(decomposition.rotationAngle);
const qreal m = decomposition.shearFactor;
const qreal sx = decomposition.scaleX;
const qreal sy = decomposition.scaleY;
const qreal dx = decomposition.translateX;
const qreal dy = decomposition.translateY;
const qreal m11 = sx * c;
const qreal m12 = sy * m * c - sy * s;
const qreal m21 = sx * s;
const qreal m22 = sy * m * s + sy * c;
return QTransform(m11, m12, m21, m22, dx, dy);
}
} // namespace pdf

View File

@ -24,6 +24,7 @@
namespace pdf
{
class PDFPageContentProcessorState;
/// RAII wrapper for painter save/restore
class PDFPainterStateGuard
@ -44,6 +45,16 @@ private:
QPainter* m_painter;
};
struct PDFTransformationDecomposition
{
double rotationAngle = 0.0;
double shearFactor = 0.0;
double scaleX = 0.0;
double scaleY = 0.0;
double translateX = 0.0;
double translateY = 0.0;
};
class PDF4QTLIBCORESHARED_EXPORT PDFPainterHelper
{
public:
@ -55,6 +66,21 @@ public:
/// \param text Text inside the bubble
/// \param alignment Bubble alignment relative to the bubble position point
static QRect drawBubble(QPainter* painter, QPoint point, QColor color, QString text, Qt::Alignment alignment);
/// Creates pen from painter graphicState
static QPen createPenFromState(const PDFPageContentProcessorState* graphicState, double alpha);
/// Creates brush from painter graphicState
static QBrush createBrushFromState(const PDFPageContentProcessorState* graphicState, double alpha);
static void applyPenToGraphicState(PDFPageContentProcessorState* graphicState, const QPen& pen);
static void applyBrushToGraphicState(PDFPageContentProcessorState* graphicState, const QBrush& brush);
/// Decompose transform
static PDFTransformationDecomposition decomposeTransform(const QTransform& transform);
/// Compose transform
static QTransform composeTransform(const PDFTransformationDecomposition& decomposition);
};
} // namespace pdf

View File

@ -18,6 +18,7 @@
#include "pdftextlayout.h"
#include "pdfutils.h"
#include "pdfexecutionpolicy.h"
#include "pdfcms.h"
#include <QtMath>
#include <QMutex>
@ -1509,7 +1510,11 @@ PDFTextLayout PDFTextLayoutStorageGetter::getTextLayoutImpl() const
return m_storage ? m_storage->getTextLayout(m_pageIndex) : PDFTextLayout();
}
void PDFTextSelectionPainter::draw(QPainter* painter, PDFInteger pageIndex, PDFTextLayoutGetter& textLayoutGetter, const QTransform& matrix)
void PDFTextSelectionPainter::draw(QPainter* painter,
PDFInteger pageIndex,
PDFTextLayoutGetter& textLayoutGetter,
const QTransform& matrix,
const PDFColorConvertor& convertor)
{
Q_ASSERT(painter);
@ -1548,8 +1553,8 @@ void PDFTextSelectionPainter::draw(QPainter* painter, PDFInteger pageIndex, PDFT
QColor brushColor = item.color;
brushColor.setAlphaF(SELECTION_ALPHA);
painter->setPen(penColor);
painter->setBrush(QBrush(brushColor, Qt::SolidPattern));
painter->setPen(convertor.convert(QPen(penColor)));
painter->setBrush(convertor.convert(QBrush(brushColor, Qt::SolidPattern)));
painter->drawPath(path);
}

View File

@ -35,6 +35,7 @@ namespace pdf
class PDFTextLayout;
class PDFTextLayoutStorage;
struct PDFCharacterPointer;
class PDFColorConvertor;
struct PDFTextCharacterInfo
{
@ -522,7 +523,7 @@ public:
/// \param pageIndex Page index
/// \param textLayoutGetter Text layout getter
/// \param matrix Matrix which translates from page space to device space
void draw(QPainter* painter, PDFInteger pageIndex, PDFTextLayoutGetter& textLayoutGetter, const QTransform& matrix);
void draw(QPainter* painter, PDFInteger pageIndex, PDFTextLayoutGetter& textLayoutGetter, const QTransform& matrix, const PDFColorConvertor& convertor);
/// Prepares geometry for text selection drawing, using text layout and matrix. If current text selection
/// doesn't contain items from active page, then text layout is not accessed.

View File

@ -2615,8 +2615,10 @@ void PDFTransparencyRenderer::performTextEnd(ProcessOrder order)
}
}
bool PDFTransparencyRenderer::performOriginalImagePainting(const PDFImage& image)
bool PDFTransparencyRenderer::performOriginalImagePainting(const PDFImage& image, const PDFStream* stream)
{
Q_UNUSED(stream);
PDFFloatBitmap texture = getImage(image);
if (m_settings.flags.testFlag(PDFTransparencyRendererSettings::SmoothImageTransformation) && image.isInterpolated())

View File

@ -703,7 +703,7 @@ public:
virtual void performEndTransparencyGroup(ProcessOrder order, const PDFTransparencyGroup& transparencyGroup) override;
virtual void performTextBegin(ProcessOrder order) override;
virtual void performTextEnd(ProcessOrder order) override;
virtual bool performOriginalImagePainting(const PDFImage& image) override;
virtual bool performOriginalImagePainting(const PDFImage& image, const PDFStream* stream) override;
virtual void performImagePainting(const QImage& image) override;
virtual void performMeshPainting(const PDFMesh& mesh) override;

View File

@ -18,6 +18,7 @@
#include "pdfadvancedfindwidget.h"
#include "ui_pdfadvancedfindwidget.h"
#include "pdfcms.h"
#include "pdfcompiler.h"
#include "pdfdocument.h"
#include "pdfdrawspacecontroller.h"
@ -196,6 +197,7 @@ void PDFAdvancedFindWidget::drawPage(QPainter* painter,
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const pdf::PDFColorConvertor& convertor,
QList<pdf::PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
@ -203,7 +205,7 @@ void PDFAdvancedFindWidget::drawPage(QPainter* painter,
const pdf::PDFTextSelection& textSelection = getTextSelection();
pdf::PDFTextSelectionPainter textSelectionPainter(&textSelection);
textSelectionPainter.draw(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix);
textSelectionPainter.draw(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix, convertor);
}
void PDFAdvancedFindWidget::performSearch()

View File

@ -54,6 +54,7 @@ public:
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const pdf::PDFColorConvertor& convertor,
QList<pdf::PDFRenderError>& errors) const override;
void setDocument(const pdf::PDFModifiedDocument& document);

View File

@ -331,7 +331,7 @@ void PDFDocumentPropertiesDialog::initializeFonts(const pdf::PDFDocument* docume
try
{
if (pdf::PDFFontPointer font = pdf::PDFFont::createFont(object, document))
if (pdf::PDFFontPointer font = pdf::PDFFont::createFont(object, fontsDictionary->getKey(i).getString(), document))
{
pdf::PDFRenderErrorReporterDummy dummyReporter;
pdf::PDFRealizedFontPointer realizedFont = pdf::PDFRealizedFont::createRealizedFont(font, 8.0, &dummyReporter);

View File

@ -65,6 +65,7 @@ add_library(Pdf4QtLibWidgets SHARED
sources/pdfwidgetsglobal.h
sources/pdfcertificatelisthelper.h
sources/pdfcertificatelisthelper.cpp
sources/pdfpagecontenteditorediteditemsettings.h sources/pdfpagecontenteditorediteditemsettings.cpp sources/pdfpagecontenteditorediteditemsettings.ui
)
include(GenerateExportHeader)

View File

@ -461,6 +461,7 @@ void PDFCreateLineTypeTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(pageIndex);
@ -468,7 +469,7 @@ void PDFCreateLineTypeTool::drawPage(QPainter* painter,
Q_UNUSED(layoutGetter);
Q_UNUSED(errors);
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
if (pageIndex != m_pickTool->getPageIndex())
{
@ -485,8 +486,8 @@ void PDFCreateLineTypeTool::drawPage(QPainter* painter,
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
QPen pen(m_strokeColor);
QBrush brush(m_fillColor, Qt::SolidPattern);
QPen pen = convertor.convert(QPen(m_strokeColor));
QBrush brush = convertor.convert(QBrush(m_fillColor, Qt::SolidPattern));
pen.setWidthF(m_penWidth);
painter->setPen(qMove(pen));
painter->setBrush(qMove(brush));
@ -592,9 +593,10 @@ void PDFCreateEllipseTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
if (pageIndex != m_pickTool->getPageIndex())
{
@ -611,8 +613,8 @@ void PDFCreateEllipseTool::drawPage(QPainter* painter,
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
QPen pen(m_strokeColor);
QBrush brush(m_fillColor, Qt::SolidPattern);
QPen pen = convertor.convert(QPen(m_strokeColor));
QBrush brush = convertor.convert(QBrush(m_fillColor, Qt::SolidPattern));
pen.setWidthF(m_penWidth);
painter->setPen(qMove(pen));
painter->setBrush(qMove(brush));
@ -672,9 +674,10 @@ void PDFCreateFreehandCurveTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
if (pageIndex != m_pageIndex || m_pickedPoints.empty())
{
@ -683,7 +686,7 @@ void PDFCreateFreehandCurveTool::drawPage(QPainter* painter,
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
QPen pen(m_strokeColor);
QPen pen = convertor.convert(QPen(m_strokeColor));
pen.setWidthF(m_penWidth);
painter->setPen(qMove(pen));
painter->setRenderHint(QPainter::Antialiasing);
@ -833,6 +836,7 @@ void PDFCreateStampTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
@ -854,7 +858,7 @@ void PDFCreateStampTool::drawPage(QPainter* painter,
parameters.painter = painter;
parameters.annotation = const_cast<PDFStampAnnotation*>(&m_stampAnnotation);
parameters.key.first = PDFAppeareanceStreams::Appearance::Normal;
parameters.colorConvertor = getProxy()->getCMSManager()->getColorConvertor();
parameters.colorConvertor = convertor;
PDFRenderer::applyFeaturesToColorConvertor(getProxy()->getFeatures(), parameters.colorConvertor);
m_stampAnnotation.draw(parameters);
@ -933,13 +937,15 @@ void PDFCreateHighlightTextTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(errors);
Q_UNUSED(convertor);
pdf::PDFTextSelectionPainter textSelectionPainter(&m_textSelection);
textSelectionPainter.draw(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix);
textSelectionPainter.draw(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix, convertor);
}
void PDFCreateHighlightTextTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
@ -1173,13 +1179,15 @@ void PDFCreateRedactTextTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(errors);
Q_UNUSED(convertor);
pdf::PDFTextSelectionPainter textSelectionPainter(&m_textSelection);
textSelectionPainter.draw(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix);
textSelectionPainter.draw(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix, convertor);
}
void PDFCreateRedactTextTool::mousePressEvent(QWidget* widget, QMouseEvent* event)

View File

@ -130,10 +130,12 @@ public:
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
virtual void keyReleaseEvent(QWidget* widget, QKeyEvent* event) override;
virtual void drawPage(QPainter* painter, PDFInteger pageIndex,
virtual void drawPage(QPainter* painter,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
PDFReal getPenWidth() const;
@ -176,6 +178,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
PDFReal getPenWidth() const;
@ -211,6 +214,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
@ -249,6 +253,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
@ -289,6 +294,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
@ -353,6 +359,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;

View File

@ -31,6 +31,7 @@ class QWheelEvent;
namespace pdf
{
class PDFColorConvertor;
class PDFPrecompiledPage;
class PDFTextLayoutGetter;
@ -47,18 +48,24 @@ public:
/// \param compiledPage Compiled page
/// \param layoutGetter Layout getter
/// \param pagePointToDevicePointMatrix Matrix mapping page space to device point space
/// \param convertor Color convertor
/// \param[out] errors Output parameter - rendering errors
virtual void drawPage(QPainter* painter,
pdf::PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const;
/// Performs drawing of additional graphics after all pages are drawn onto the painter.
/// \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

@ -784,6 +784,11 @@ void PDFDrawWidgetProxy::drawPages(QPainter* painter, QRect rect, PDFRenderer::F
// Use current paper color (it can be a bit different from white)
QColor paperColor = getPaperColor();
// Color management system
PDFCMSPointer cms = getCMSManager()->getCurrentCMS();
PDFColorConvertor convertor = cms->getColorConvertor();
PDFRenderer::applyFeaturesToColorConvertor(features, convertor);
// Iterate trough pages and display them on the painter device
for (const LayoutItem& item : m_layout.items)
{
@ -809,9 +814,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))
{
@ -869,7 +884,7 @@ void PDFDrawWidgetProxy::drawPages(QPainter* painter, QRect rect, PDFRenderer::F
for (IDocumentDrawInterface* drawInterface : m_drawInterfaces)
{
painter->save();
drawInterface->drawPage(painter, item.pageIndex, compiledPage, layoutGetter, matrix, drawInterfaceErrors);
drawInterface->drawPage(painter, item.pageIndex, compiledPage, layoutGetter, matrix, convertor, drawInterfaceErrors);
painter->restore();
}
}
@ -1613,6 +1628,7 @@ void IDocumentDrawInterface::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const pdf::PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(painter);
@ -1620,6 +1636,7 @@ void IDocumentDrawInterface::drawPage(QPainter* painter,
Q_UNUSED(compiledPage);
Q_UNUSED(layoutGetter);
Q_UNUSED(pagePointToDevicePointMatrix);
Q_UNUSED(convertor);
Q_UNUSED(errors);
}
@ -1629,4 +1646,9 @@ void IDocumentDrawInterface::drawPostRendering(QPainter* painter, QRect rect) co
Q_UNUSED(rect);
}
bool IDocumentDrawInterface::isPageContentDrawSuppressed() const
{
return false;
}
} // namespace pdf

View File

@ -23,6 +23,7 @@
#include "pdfwidgetannotation.h"
#include "pdfwidgetformmanager.h"
#include "pdfblpainter.h"
#include "pdfpagecontentelements.h"
#include <QPainter>
#include <QGridLayout>
@ -145,6 +146,11 @@ void PDFWidget::onPageImageChanged(bool all, const std::vector<PDFInteger>& page
}
}
void PDFWidget::onSceneActiveStateChanged(bool)
{
Q_EMIT sceneActivityChanged();
}
void PDFWidget::removeInputInterface(IDrawWidgetInputInterface* inputInterface)
{
auto it = std::find(m_inputInterfaces.begin(), m_inputInterfaces.end(), inputInterface);
@ -152,6 +158,17 @@ void PDFWidget::removeInputInterface(IDrawWidgetInputInterface* inputInterface)
{
m_inputInterfaces.erase(it);
}
PDFPageContentScene* scene = dynamic_cast<PDFPageContentScene*>(inputInterface);
if (scene)
{
auto itScene = std::find(m_scenes.begin(), m_scenes.end(), inputInterface);
if (itScene != m_scenes.end())
{
m_scenes.erase(itScene);
disconnect(scene, &PDFPageContentScene::sceneActiveStateChanged, this, &PDFWidget::onSceneActiveStateChanged);
}
}
}
void PDFWidget::addInputInterface(IDrawWidgetInputInterface* inputInterface)
@ -160,9 +177,29 @@ void PDFWidget::addInputInterface(IDrawWidgetInputInterface* inputInterface)
{
m_inputInterfaces.push_back(inputInterface);
std::sort(m_inputInterfaces.begin(), m_inputInterfaces.end(), IDrawWidgetInputInterface::Comparator());
PDFPageContentScene* scene = dynamic_cast<PDFPageContentScene*>(inputInterface);
if (scene)
{
m_scenes.push_back(scene);
connect(scene, &PDFPageContentScene::sceneActiveStateChanged, this, &PDFWidget::onSceneActiveStateChanged);
}
}
}
bool PDFWidget::isAnySceneActive(PDFPageContentScene* sceneToSkip) const
{
for (PDFPageContentScene* scene : m_scenes)
{
if (scene->isActive() && scene != sceneToSkip)
{
return true;
}
}
return false;
}
PDFWidgetFormManager* PDFWidget::getFormManager() const
{
return m_formManager;

View File

@ -38,6 +38,7 @@ class PDFDrawWidgetProxy;
class PDFModifiedDocument;
class PDFWidgetAnnotationManager;
class IDrawWidgetInputInterface;
class PDFPageContentScene;
class IDrawWidget
{
@ -105,12 +106,17 @@ public:
void removeInputInterface(IDrawWidgetInputInterface* inputInterface);
void addInputInterface(IDrawWidgetInputInterface* inputInterface);
/// Returns true, if any scene is active
bool isAnySceneActive(PDFPageContentScene* sceneToSkip) const;
signals:
void sceneActivityChanged();
void pageRenderingErrorsChanged(pdf::PDFInteger pageIndex, int errorsCount);
private:
void onRenderingError(PDFInteger pageIndex, const QList<PDFRenderError>& errors);
void onPageImageChanged(bool all, const std::vector<PDFInteger>& pages);
void onSceneActiveStateChanged(bool);
const PDFCMSManager* m_cmsManager;
PDFToolManager* m_toolManager;
@ -122,6 +128,7 @@ private:
PDFDrawWidgetProxy* m_proxy;
PageRenderingErrors m_pageRenderingErrors;
std::vector<IDrawWidgetInputInterface*> m_inputInterfaces;
std::vector<PDFPageContentScene*> m_scenes;
RendererEngine m_rendererEngine;
};

View File

@ -0,0 +1,476 @@
// Copyright (C) 2024 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT 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
// with the written consent of the copyright owner, any later version.
//
// PDF4QT 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 PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "pdfpagecontenteditorediteditemsettings.h"
#include "ui_pdfpagecontenteditorediteditemsettings.h"
#include "pdfpagecontentelements.h"
#include "pdfpagecontenteditorprocessor.h"
#include "pdfwidgetutils.h"
#include "pdfpainterutils.h"
#include <QDir>
#include <QFileDialog>
#include <QImageReader>
#include <QStandardPaths>
#include <QColorDialog>
namespace pdf
{
PDFPageContentEditorEditedItemSettings::PDFPageContentEditorEditedItemSettings(QWidget* parent) :
QWidget(parent),
ui(new Ui::PDFPageContentEditorEditedItemSettings)
{
ui->setupUi(this);
connect(ui->loadImageButton, &QPushButton::clicked, this, &PDFPageContentEditorEditedItemSettings::selectImage);
for (const QString& colorName : QColor::colorNames())
{
QColor color(colorName);
QIcon icon = getIconForColor(color);
ui->penColorCombo->addItem(icon, colorName, color);
ui->brushColorCombo->addItem(icon, colorName, color);
}
ui->penStyleCombo->addItem(tr("Solid"), int(Qt::SolidLine));
ui->penStyleCombo->addItem(tr("Dashed"), int(Qt::DashLine));
ui->penStyleCombo->addItem(tr("Dotted"), int(Qt::DotLine));
ui->penStyleCombo->addItem(tr("Dash-dot"), int(Qt::DashDotLine));
ui->penStyleCombo->addItem(tr("Dash-dot-dot"), int(Qt::DashDotDotLine));
ui->penStyleCombo->addItem(tr("Custom"), int(Qt::CustomDashLine));
ui->brushStyleCombo->addItem(tr("Solid"), int(Qt::SolidPattern));
connect(ui->selectPenColorButton, &QToolButton::clicked, this, &PDFPageContentEditorEditedItemSettings::onSelectPenColorButtonClicked);
connect(ui->selectBrushColorButton, &QToolButton::clicked, this, &PDFPageContentEditorEditedItemSettings::onSelectBrushColorButtonClicked);
connect(ui->penWidthEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &PDFPageContentEditorEditedItemSettings::onPenWidthChanged);
connect(ui->penStyleCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFPageContentEditorEditedItemSettings::onPenStyleChanged);
connect(ui->brushStyleCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFPageContentEditorEditedItemSettings::onBrushStyleChanged);
connect(ui->penColorCombo->lineEdit(), &QLineEdit::editingFinished, this, &PDFPageContentEditorEditedItemSettings::onPenColorComboTextChanged);
connect(ui->penColorCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFPageContentEditorEditedItemSettings::onPenColorComboIndexChanged);
connect(ui->brushColorCombo->lineEdit(), &QLineEdit::editingFinished, this, &PDFPageContentEditorEditedItemSettings::onBrushColorComboTextChanged);
connect(ui->brushColorCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFPageContentEditorEditedItemSettings::onBrushColorComboIndexChanged);
}
QIcon PDFPageContentEditorEditedItemSettings::getIconForColor(QColor color) const
{
QIcon icon;
QSize iconSize = PDFWidgetUtils::scaleDPI(this, QSize(16, 16));
QPixmap pixmap(iconSize.width(), iconSize.height());
pixmap.fill(color);
icon.addPixmap(pixmap);
return icon;
}
PDFPageContentEditorEditedItemSettings::~PDFPageContentEditorEditedItemSettings()
{
delete ui;
}
void PDFPageContentEditorEditedItemSettings::loadFromElement(PDFPageContentElementEdited* editedElement)
{
const PDFEditedPageContentElement* contentElement = editedElement->getElement();
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->imageTab));
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->textTab));
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->styleTab));
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->transformationTab));
if (const PDFEditedPageContentElementImage* imageElement = contentElement->asImage())
{
ui->tabWidget->addTab(ui->imageTab, tr("Image"));
m_image = imageElement->getImage();
setImage(imageElement->getImage());
}
if (PDFEditedPageContentElementText* textElement = editedElement->getElement()->asText())
{
ui->tabWidget->addTab(ui->textTab, tr("Text"));
QString text = textElement->getItemsAsText();
ui->plainTextEdit->setPlainText(text);
}
if (editedElement->getElement()->asText() || editedElement->getElement()->asPath())
{
ui->tabWidget->addTab(ui->styleTab, tr("Style"));
}
QTransform matrix = editedElement->getElement()->getTransform();
PDFTransformationDecomposition decomposedTransformation = PDFPainterHelper::decomposeTransform(matrix);
ui->rotationAngleEdit->setValue(qRadiansToDegrees(decomposedTransformation.rotationAngle));
ui->scaleInXEdit->setValue(decomposedTransformation.scaleX);
ui->scaleInYEdit->setValue(decomposedTransformation.scaleY);
ui->shearFactorEdit->setValue(decomposedTransformation.shearFactor);
ui->translateInXEdit->setValue(decomposedTransformation.translateX);
ui->translateInYEdit->setValue(decomposedTransformation.translateY);
ui->tabWidget->addTab(ui->transformationTab, tr("Transformation"));
// Style
const PDFEditedPageContentElement* element = editedElement->getElement();
StyleFeatures features = None;
if (element->asPath())
{
features.setFlag(Pen);
features.setFlag(PenColor);
features.setFlag(Brush);
features.setFlag(StrokeFill);
}
if (element->asText())
{
features.setFlag(PenColor);
}
const bool hasPen = features.testFlag(Pen);
const bool hasPenColor = features.testFlag(PenColor);
const bool hasBrush = features.testFlag(Brush);
const bool hasStrokeFill = features.testFlag(StrokeFill);
ui->penWidthEdit->setEnabled(hasPen);
ui->penWidthLabel->setEnabled(hasPen);
ui->penStyleCombo->setEnabled(hasPen);
ui->penStyleLabel->setEnabled(hasPen);
ui->penColorCombo->setEnabled(hasPenColor);
ui->penColorLabel->setEnabled(hasPenColor);
ui->selectPenColorButton->setEnabled(hasPenColor);
ui->brushStyleLabel->setEnabled(hasBrush);
ui->brushStyleCombo->setEnabled(hasBrush);
ui->brushColorCombo->setEnabled(hasBrush);
ui->brushColorLabel->setEnabled(hasBrush);
ui->selectBrushColorButton->setEnabled(hasBrush);
ui->strokePathCheckBox->setEnabled(hasStrokeFill);
ui->fillPathCheckBox->setEnabled(hasStrokeFill);
if (const PDFEditedPageContentElementPath* pathElement = element->asPath())
{
ui->strokePathCheckBox->setChecked(pathElement->getStrokePath());
ui->fillPathCheckBox->setChecked(pathElement->getFillPath());
}
const PDFPageContentProcessorState& graphicState = element->getState();
QPen pen = pdf::PDFPainterHelper::createPenFromState(&graphicState, graphicState.getAlphaStroking());
QBrush brush = pdf::PDFPainterHelper::createBrushFromState(&graphicState, graphicState.getAlphaFilling());
if (element->asText())
{
pen.setColor(brush.color());
}
setPen(pen, true);
setBrush(brush, true);
}
void PDFPageContentEditorEditedItemSettings::setPen(const QPen& pen, bool forceUpdate)
{
if (m_pen != pen || forceUpdate)
{
m_pen = pen;
ui->penWidthEdit->setValue(pen.widthF());
ui->penStyleCombo->setCurrentIndex(ui->penStyleCombo->findData(int(pen.style())));
setColorToComboBox(ui->penColorCombo, pen.color());
}
}
void PDFPageContentEditorEditedItemSettings::setBrush(const QBrush& brush, bool forceUpdate)
{
if (m_brush != brush || forceUpdate)
{
m_brush = brush;
ui->brushStyleCombo->setCurrentIndex(ui->brushStyleCombo->findData(int(brush.style())));
setColorToComboBox(ui->brushColorCombo, brush.color());
}
}
void PDFPageContentEditorEditedItemSettings::setColorToComboBox(QComboBox* comboBox, QColor color)
{
if (!color.isValid())
{
return;
}
QString name = color.name(QColor::HexArgb);
int index = comboBox->findData(color, Qt::UserRole, Qt::MatchExactly);
if (index == -1)
{
// Jakub Melka: try to find text (color name)
index = comboBox->findText(name);
}
if (index != -1)
{
comboBox->setCurrentIndex(index);
}
else
{
comboBox->addItem(getIconForColor(color), name, color);
comboBox->setCurrentIndex(comboBox->count() - 1);
}
}
void PDFPageContentEditorEditedItemSettings::saveToElement(PDFPageContentElementEdited* editedElement)
{
if (PDFEditedPageContentElementImage* imageElement = editedElement->getElement()->asImage())
{
imageElement->setImage(m_image);
imageElement->setImageObject(PDFObject());
}
if (PDFEditedPageContentElementText* textElement = editedElement->getElement()->asText())
{
textElement->setItemsAsText(ui->plainTextEdit->toPlainText());
}
if (PDFEditedPageContentElementPath* pathElement = editedElement->getElement()->asPath())
{
pathElement->setStrokePath(ui->strokePathCheckBox->isChecked());
pathElement->setFillPath(ui->fillPathCheckBox->isChecked());
}
PDFTransformationDecomposition decomposedTransformation;
decomposedTransformation.rotationAngle = ui->rotationAngleEdit->value();
decomposedTransformation.shearFactor = ui->shearFactorEdit->value();
decomposedTransformation.scaleX = ui->scaleInXEdit->value();
decomposedTransformation.scaleY = ui->scaleInYEdit->value();
decomposedTransformation.translateX = ui->translateInXEdit->value();
decomposedTransformation.translateY = ui->translateInYEdit->value();
QTransform transform = PDFPainterHelper::composeTransform(decomposedTransformation);
editedElement->getElement()->setTransform(transform);
if (editedElement->getElement()->asPath())
{
PDFPageContentProcessorState graphicState = editedElement->getElement()->getState();
PDFPainterHelper::applyPenToGraphicState(&graphicState, m_pen);
PDFPainterHelper::applyBrushToGraphicState(&graphicState, m_brush);
editedElement->getElement()->setState(graphicState);
}
if (editedElement->getElement()->asText())
{
PDFPageContentProcessorState graphicState = editedElement->getElement()->getState();
QBrush brush(m_pen.color(), Qt::SolidPattern);
PDFPainterHelper::applyBrushToGraphicState(&graphicState, brush);
editedElement->getElement()->setState(graphicState);
}
}
static int PDF_gcd(int a, int b)
{
if (b == 0)
{
return a;
}
return PDF_gcd(b, a % b);
}
void PDFPageContentEditorEditedItemSettings::setImage(QImage image)
{
QSize imageSize = QSize(200, 200);
int width = image.width();
int height = image.height();
int n = width;
int d = height;
int divisor = PDF_gcd(n, d);
if (divisor > 1)
{
n /= divisor;
d /= divisor;
}
ui->imageWidthEdit->setText(QString("%1 px").arg(width));
ui->imageHeightEdit->setText(QString("%1 px").arg(height));
ui->imageRatioEdit->setText(QString("%1 : %2").arg(n).arg(d));
image.setDevicePixelRatio(this->devicePixelRatioF());
image = image.scaled(imageSize * this->devicePixelRatioF(), Qt::KeepAspectRatio);
ui->imageLabel->setPixmap(QPixmap::fromImage(image));
ui->imageLabel->setFixedSize(PDFWidgetUtils::scaleDPI(this, imageSize));
}
void PDFPageContentEditorEditedItemSettings::selectImage()
{
QString imageDirectory;
QStringList pictureDirectiories = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
if (!pictureDirectiories.isEmpty())
{
imageDirectory = pictureDirectiories.last();
}
else
{
imageDirectory = QDir::currentPath();
}
QList<QByteArray> mimeTypes = QImageReader::supportedMimeTypes();
QStringList mimeTypeFilters;
for (const QByteArray& mimeType : mimeTypes)
{
mimeTypeFilters.append(mimeType);
}
QFileDialog dialog(this, tr("Select Image"));
dialog.setDirectory(imageDirectory);
dialog.setMimeTypeFilters(mimeTypeFilters);
dialog.selectMimeTypeFilter("image/svg+xml");
dialog.setAcceptMode(QFileDialog::AcceptOpen);
dialog.setFileMode(QFileDialog::ExistingFile);
if (dialog.exec() == QFileDialog::Accepted)
{
QString fileName = dialog.selectedFiles().constFirst();
QImageReader reader(fileName);
QImage image = reader.read();
if (!image.isNull())
{
setImage(image);
m_image = std::move(image);
}
}
}
void PDFPageContentEditorEditedItemSettings::setPenColor(QColor color)
{
if (color.isValid())
{
m_pen.setColor(color);
setColorToComboBox(ui->penColorCombo, color);
}
}
void PDFPageContentEditorEditedItemSettings::onSelectPenColorButtonClicked()
{
QColor color = QColorDialog::getColor(m_pen.color(), this, tr("Select Color for Pen"), QColorDialog::ShowAlphaChannel);
setPenColor(color);
}
void PDFPageContentEditorEditedItemSettings::setBrushColor(QColor color)
{
if (color.isValid() && m_brush.color() != color)
{
m_brush.setColor(color);
setColorToComboBox(ui->brushColorCombo, color);
}
}
const QBrush& PDFPageContentEditorEditedItemSettings::getBrush() const
{
return m_brush;
}
const QPen& PDFPageContentEditorEditedItemSettings::getPen() const
{
return m_pen;
}
void PDFPageContentEditorEditedItemSettings::onSelectBrushColorButtonClicked()
{
QColor color = QColorDialog::getColor(m_pen.color(), this, tr("Select Color for Brush"), QColorDialog::ShowAlphaChannel);
setBrushColor(color);
}
void PDFPageContentEditorEditedItemSettings::onPenWidthChanged(double value)
{
m_pen.setWidthF(value);
}
void PDFPageContentEditorEditedItemSettings::onPenStyleChanged()
{
Qt::PenStyle penStyle = static_cast<Qt::PenStyle>(ui->penStyleCombo->currentData().toInt());
m_pen.setStyle(penStyle);
}
void PDFPageContentEditorEditedItemSettings::onBrushStyleChanged()
{
Qt::BrushStyle brushStyle = static_cast<Qt::BrushStyle>(ui->brushStyleCombo->currentData().toInt());
m_brush.setStyle(brushStyle);
}
void PDFPageContentEditorEditedItemSettings::onPenColorComboTextChanged()
{
QColor color(ui->penColorCombo->currentText());
if (color.isValid())
{
setColorToComboBox(ui->penColorCombo, color);
m_pen.setColor(color);
}
else if (ui->penColorCombo->currentIndex() != -1)
{
ui->penColorCombo->setEditText(ui->penColorCombo->itemText(ui->penColorCombo->currentIndex()));
}
}
void PDFPageContentEditorEditedItemSettings::onPenColorComboIndexChanged()
{
const int index = ui->penColorCombo->currentIndex();
QColor color = ui->penColorCombo->itemData(index, Qt::UserRole).value<QColor>();
if (color.isValid() && m_pen.color() != color)
{
m_pen.setColor(color);
}
}
void PDFPageContentEditorEditedItemSettings::onBrushColorComboTextChanged()
{
QColor color(ui->brushColorCombo->currentText());
if (color.isValid())
{
setColorToComboBox(ui->brushColorCombo, color);
m_brush.setColor(color);
}
else if (ui->brushColorCombo->currentIndex() != -1)
{
ui->brushColorCombo->setEditText(ui->brushColorCombo->itemText(ui->brushColorCombo->currentIndex()));
}
}
void PDFPageContentEditorEditedItemSettings::onBrushColorComboIndexChanged()
{
const int index = ui->brushColorCombo->currentIndex();
QColor color = ui->brushColorCombo->itemData(index, Qt::UserRole).value<QColor>();
if (color.isValid())
{
m_brush.setColor(color);
}
}
} // namespace pdf

View File

@ -0,0 +1,91 @@
// Copyright (C) 2024 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT 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
// with the written consent of the copyright owner, any later version.
//
// PDF4QT 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 PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFPAGECONTENTEDITOREDITEDITEMSETTINGS_H
#define PDFPAGECONTENTEDITOREDITEDITEMSETTINGS_H
#include <QDialog>
#include <QPen>
#include <QBrush>
class QComboBox;
namespace Ui
{
class PDFPageContentEditorEditedItemSettings;
}
namespace pdf
{
class PDFPageContentElementEdited;
class PDFPageContentEditorEditedItemSettings : public QWidget
{
Q_OBJECT
public:
explicit PDFPageContentEditorEditedItemSettings(QWidget* parent);
virtual ~PDFPageContentEditorEditedItemSettings() override;
void loadFromElement(PDFPageContentElementEdited* editedElement);
void saveToElement(PDFPageContentElementEdited* editedElement);
void setPen(const QPen& pen, bool forceUpdate);
void setBrush(const QBrush& brush, bool forceUpdate);
const QPen& getPen() const;
const QBrush& getBrush() const;
private:
void onSelectPenColorButtonClicked();
void onSelectBrushColorButtonClicked();
void onPenWidthChanged(double value);
void onPenStyleChanged();
void onBrushStyleChanged();
void onPenColorComboTextChanged();
void onPenColorComboIndexChanged();
void onBrushColorComboTextChanged();
void onBrushColorComboIndexChanged();
void setImage(QImage image);
void selectImage();
enum StyleFeature
{
None = 0,
Pen = 1 << 0,
PenColor = 1 << 1,
Brush = 1 << 2,
StrokeFill = 1 << 3,
};
Q_DECLARE_FLAGS(StyleFeatures, StyleFeature)
void setColorToComboBox(QComboBox* comboBox, QColor color);
QIcon getIconForColor(QColor color) const;
void setPenColor(QColor color);
void setBrushColor(QColor color);
Ui::PDFPageContentEditorEditedItemSettings* ui;
QImage m_image;
QPen m_pen;
QBrush m_brush;
};
} // namespace pdf
#endif // PDFPAGECONTENTEDITOREDITEDITEMSETTINGS_H

View File

@ -0,0 +1,421 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PDFPageContentEditorEditedItemSettings</class>
<widget class="QWidget" name="PDFPageContentEditorEditedItemSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>571</width>
<height>461</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="textTab">
<attribute name="title">
<string>Text</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="textGroupBox">
<property name="title">
<string>Text Content</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QPlainTextEdit" name="plainTextEdit"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="imageTab">
<attribute name="title">
<string>Image</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Image Content</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="0,1,0">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="imageHeightLabel">
<property name="text">
<string>Height</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="imageWidthLabel">
<property name="text">
<string>Width</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="imageHeightEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="imageWidthEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="imageRatioLabel">
<property name="text">
<string>Ratio</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="imageRatioEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="imageLabel">
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="loadImageButton">
<property name="text">
<string>Load Image</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="styleTab">
<attribute name="title">
<string>Style</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="4" column="2">
<widget class="QToolButton" name="selectBrushColorButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QComboBox" name="brushStyleCombo"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="penStyleLabel">
<property name="text">
<string>Pen Style</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="penColorLabel">
<property name="text">
<string>Pen Color</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QToolButton" name="selectPenColorButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QComboBox" name="penStyleCombo"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="brushStyleLabel">
<property name="text">
<string>Brush Style</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="penWidthLabel">
<property name="text">
<string>Pen Width</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="strokePathCheckBox">
<property name="text">
<string>Stroke path</string>
</property>
</widget>
</item>
<item row="7" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1" colspan="2">
<widget class="QDoubleSpinBox" name="penWidthEdit"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="brushColorLabel">
<property name="text">
<string>Brush Color</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="penColorCombo">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="brushColorCombo">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="fillPathCheckBox">
<property name="text">
<string>Fill path</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="transformationTab">
<attribute name="title">
<string>Transformation</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<layout class="QGridLayout" name="transformationTabWidgetsLayout" columnstretch="1,0,1">
<item row="5" column="0">
<widget class="QLabel" name="translationInYLabel">
<property name="text">
<string>Translation in Y</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QDoubleSpinBox" name="translateInYEdit">
<property name="minimum">
<double>-1000000.000000000000000</double>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="translationInXLabel">
<property name="text">
<string>Translation in X</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QDoubleSpinBox" name="scaleInXEdit">
<property name="minimum">
<double>-1000000.000000000000000</double>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="scaleInXLabel">
<property name="text">
<string>Scale in X</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QDoubleSpinBox" name="rotationAngleEdit">
<property name="minimum">
<double>-360.000000000000000</double>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QDoubleSpinBox" name="translateInXEdit">
<property name="minimum">
<double>-1000000.000000000000000</double>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QDoubleSpinBox" name="shearFactorEdit">
<property name="minimum">
<double>-1000000.000000000000000</double>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="scaleInYLabel">
<property name="text">
<string>Scale in Y</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="shearFactorLabel">
<property name="text">
<string>Shear factor</string>
</property>
</widget>
</item>
<item row="6" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="rotationAngleLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Rotation angle&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QDoubleSpinBox" name="scaleInYEdit">
<property name="minimum">
<double>-1000000.000000000000000</double>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="rotationAngleSymbolLabel">
<property name="text">
<string>φ</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="scaleInXSymbolLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;s&lt;span style=&quot; vertical-align:sub;&quot;&gt;x&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="scaleInYSymbolLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;s&lt;span style=&quot; vertical-align:sub;&quot;&gt;y&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="shearFactorSymbolLabel">
<property name="text">
<string>m</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="translationInXSymbolLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;t&lt;span style=&quot; vertical-align:sub;&quot;&gt;x&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="translationInYSymbolLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;t&lt;span style=&quot; vertical-align:sub;&quot;&gt;y&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
<slots>
<slot>accept()</slot>
<slot>reject()</slot>
</slots>
</ui>

View File

@ -20,6 +20,7 @@
#include "pdfwidgetutils.h"
#include "pdfpagecontentelements.h"
#include "pdfpagecontenteditorediteditemsettings.h"
#include <QFontDialog>
#include <QColorDialog>
@ -38,7 +39,7 @@ PDFPageContentEditorStyleSettings::PDFPageContentEditorStyleSettings(QWidget* pa
{
ui->setupUi(this);
for (QString colorName : QColor::colorNames())
for (const QString& colorName : QColor::colorNames())
{
QColor color(colorName);
QIcon icon = getIconForColor(color);
@ -263,59 +264,88 @@ bool PDFPageContentEditorStyleSettings::showEditElementStyleDialog(QWidget* pare
dialog.setWindowTitle(tr("Edit Item"));
dialog.setLayout(new QVBoxLayout());
QTextEdit* textEdit = nullptr;
PDFPageContentStyledElement* styledElement = dynamic_cast<PDFPageContentStyledElement*>(element);
PDFPageContentElementTextBox* textElement = dynamic_cast<PDFPageContentElementTextBox*>(element);
if (textElement)
PDFPageContentEditorStyleSettings* appearanceWidget = nullptr;
PDFPageContentElementEdited* editedElement = dynamic_cast<PDFPageContentElementEdited*>(element);
if (editedElement)
{
QGroupBox* contentGroupBox = new QGroupBox(&dialog);
textEdit = new QTextEdit(textElement->getText(), contentGroupBox);
textEdit->setFont(textElement->getFont());
textEdit->setAlignment(textElement->getAlignment());
textEdit->setTextColor(textElement->getPen().color());
contentGroupBox->setTitle(tr("Content"));
contentGroupBox->setLayout(new QVBoxLayout());
contentGroupBox->layout()->addWidget(textEdit);
dialog.layout()->addWidget(contentGroupBox);
}
PDFPageContentEditorEditedItemSettings* widget = new PDFPageContentEditorEditedItemSettings(&dialog);
dialog.layout()->addWidget(widget);
PDFPageContentEditorStyleSettings* appearanceWidget = new PDFPageContentEditorStyleSettings(&dialog);
appearanceWidget->loadFromElement(element, true);
if (textEdit)
{
connect(appearanceWidget, &PDFPageContentEditorStyleSettings::alignmentChanged, textEdit, &QTextEdit::setAlignment);
connect(appearanceWidget, &PDFPageContentEditorStyleSettings::fontChanged, textEdit, &QTextEdit::setFont);
connect(appearanceWidget, &PDFPageContentEditorStyleSettings::penChanged, textEdit, [textEdit](const QPen& pen) { textEdit->setTextColor(pen.color()); });
}
QDialogButtonBox* dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
connect(dialogButtonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
connect(dialogButtonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
dialog.layout()->addWidget(dialogButtonBox);
QGroupBox* appearanceGroupBox = new QGroupBox(&dialog);
appearanceGroupBox->setTitle(tr("Appearance"));
appearanceGroupBox->setLayout(new QVBoxLayout());
appearanceGroupBox->layout()->addWidget(appearanceWidget);
dialog.layout()->addWidget(appearanceGroupBox);
pdf::PDFWidgetUtils::style(&dialog);
QDialogButtonBox* dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
connect(dialogButtonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
connect(dialogButtonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
dialog.layout()->addWidget(dialogButtonBox);
widget->loadFromElement(editedElement);
if (dialog.exec() == QDialog::Accepted)
{
if (styledElement)
if (dialog.exec() == QDialog::Accepted)
{
styledElement->setPen(appearanceWidget->getPen());
styledElement->setBrush(appearanceWidget->getBrush());
widget->saveToElement(editedElement);
return true;
}
}
else
{
QTextEdit* textEdit = nullptr;
PDFPageContentStyledElement* styledElement = dynamic_cast<PDFPageContentStyledElement*>(element);
PDFPageContentElementTextBox* textElement = dynamic_cast<PDFPageContentElementTextBox*>(element);
if (textElement)
{
textElement->setText(textEdit->toPlainText());
textElement->setFont(appearanceWidget->getFont());
textElement->setAlignment(appearanceWidget->getAlignment());
textElement->setAngle(appearanceWidget->getTextAngle());
QGroupBox* contentGroupBox = new QGroupBox(&dialog);
textEdit = new QTextEdit(textElement->getText(), contentGroupBox);
textEdit->setFont(textElement->getFont());
textEdit->setAlignment(textElement->getAlignment());
textEdit->setTextColor(textElement->getPen().color());
contentGroupBox->setTitle(tr("Content"));
contentGroupBox->setLayout(new QVBoxLayout());
contentGroupBox->layout()->addWidget(textEdit);
dialog.layout()->addWidget(contentGroupBox);
}
return true;
appearanceWidget = new PDFPageContentEditorStyleSettings(&dialog);
appearanceWidget->loadFromElement(element, true);
if (textEdit)
{
connect(appearanceWidget, &PDFPageContentEditorStyleSettings::alignmentChanged, textEdit, &QTextEdit::setAlignment);
connect(appearanceWidget, &PDFPageContentEditorStyleSettings::fontChanged, textEdit, &QTextEdit::setFont);
connect(appearanceWidget, &PDFPageContentEditorStyleSettings::penChanged, textEdit, [textEdit](const QPen& pen) { textEdit->setTextColor(pen.color()); });
}
QGroupBox* appearanceGroupBox = new QGroupBox(&dialog);
appearanceGroupBox->setTitle(tr("Appearance"));
appearanceGroupBox->setLayout(new QVBoxLayout());
appearanceGroupBox->layout()->addWidget(appearanceWidget);
dialog.layout()->addWidget(appearanceGroupBox);
QDialogButtonBox* dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
connect(dialogButtonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
connect(dialogButtonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
dialog.layout()->addWidget(dialogButtonBox);
pdf::PDFWidgetUtils::style(&dialog);
if (dialog.exec() == QDialog::Accepted)
{
if (styledElement)
{
styledElement->setPen(appearanceWidget->getPen());
styledElement->setBrush(appearanceWidget->getBrush());
}
if (textElement)
{
textElement->setText(textEdit->toPlainText());
textElement->setFont(appearanceWidget->getFont());
textElement->setAlignment(appearanceWidget->getAlignment());
textElement->setAngle(appearanceWidget->getTextAngle());
}
return true;
}
}
return false;

View File

@ -148,9 +148,10 @@ void PDFCreatePCElementRectangleTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
if (pageIndex != m_pickTool->getPageIndex())
{
@ -166,7 +167,7 @@ void PDFCreatePCElementRectangleTool::drawPage(QPainter* painter,
m_element->setPageIndex(pageIndex);
m_element->setRectangle(rectangle);
m_element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
m_element->drawPage(painter, m_scene, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
}
const PDFPageContentElement* PDFCreatePCElementRectangleTool::getElement() const
@ -242,9 +243,10 @@ void PDFCreatePCElementLineTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
if (pageIndex != m_pickTool->getPageIndex() || !m_startPoint)
{
@ -262,7 +264,7 @@ void PDFCreatePCElementLineTool::drawPage(QPainter* painter,
m_element->setLine(line);
}
m_element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
m_element->drawPage(painter, m_scene, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
}
const PDFPageContentElement* PDFCreatePCElementLineTool::getElement() const
@ -335,13 +337,14 @@ PDFCreatePCElementImageTool::~PDFCreatePCElementImageTool()
}
void PDFCreatePCElementImageTool::drawPage(QPainter* painter,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
QList<PDFRenderError>& errors) const
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
if (pageIndex != m_pickTool->getPageIndex())
{
@ -361,12 +364,12 @@ void PDFCreatePCElementImageTool::drawPage(QPainter* painter,
PDFPainterStateGuard guard(painter);
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::DotLine);
painter->setPen(convertor.convert(QPen(Qt::DotLine)));
painter->setBrush(Qt::NoBrush);
painter->drawRect(rectangle);
}
m_element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
m_element->drawPage(painter, m_scene, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
}
const PDFPageContentElement* PDFCreatePCElementImageTool::getElement() const
@ -486,17 +489,18 @@ void PDFCreatePCElementDotTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
QPointF point = pagePointToDevicePointMatrix.inverted().map(m_pickTool->getSnappedPoint());
PDFPainterStateGuard guard(painter);
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(m_element->getPen());
painter->setBrush(m_element->getBrush());
painter->setPen(convertor.convert(m_element->getPen()));
painter->setBrush(convertor.convert(m_element->getBrush()));
painter->drawPoint(point);
}
@ -547,16 +551,17 @@ void PDFCreatePCElementFreehandCurveTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
if (pageIndex != m_element->getPageIndex() || m_element->isEmpty())
{
return;
}
m_element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
m_element->drawPage(painter, m_scene, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
}
const PDFPageContentElement* PDFCreatePCElementFreehandCurveTool::getElement() const
@ -691,9 +696,10 @@ void PDFCreatePCElementTextTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
if (pageIndex != m_element->getPageIndex())
{
@ -707,7 +713,7 @@ void PDFCreatePCElementTextTool::drawPage(QPainter* painter,
parameters.painter = painter;
parameters.boundingRectangle = m_element->getRectangle();
parameters.key.first = PDFAppeareanceStreams::Appearance::Normal;
parameters.colorConvertor = getProxy()->getCMSManager()->getColorConvertor();
parameters.colorConvertor = convertor;
PDFRenderer::applyFeaturesToColorConvertor(getProxy()->getFeatures(), parameters.colorConvertor);
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);

View File

@ -79,6 +79,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual const PDFPageContentElement* getElement() const override;
@ -113,6 +114,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual const PDFPageContentElement* getElement() const override;
@ -153,6 +155,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual const PDFPageContentElement* getElement() const override;
@ -187,6 +190,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual const PDFPageContentElement* getElement() const override;
@ -219,6 +223,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual const PDFPageContentElement* getElement() const override;
@ -257,6 +262,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual const PDFPageContentElement* getElement() const override;

View File

@ -85,6 +85,7 @@ PDFPageContentEditorWidget::PDFPageContentEditorWidget(QWidget* parent) :
connect(&m_actionMapper, &QSignalMapper::mappedObject, this, &PDFPageContentEditorWidget::onActionTriggerRequest);
connect(&m_operationMapper, &QSignalMapper::mappedInt, this, &PDFPageContentEditorWidget::operationTriggered);
connect(ui->itemsListWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &PDFPageContentEditorWidget::onItemSelectionChanged);
connect(ui->itemsListWidget, &QListWidget::itemDoubleClicked, this, &PDFPageContentEditorWidget::onItemDoubleClicked);
connect(m_settingsWidget, &PDFPageContentEditorStyleSettings::penChanged, this, &PDFPageContentEditorWidget::penChanged);
connect(m_settingsWidget, &PDFPageContentEditorStyleSettings::brushChanged, this, &PDFPageContentEditorWidget::brushChanged);
@ -225,6 +226,12 @@ void PDFPageContentEditorWidget::onItemSelectionChanged()
}
}
void PDFPageContentEditorWidget::onItemDoubleClicked(QListWidgetItem* item)
{
const PDFInteger elementId = item->data(Qt::UserRole).toLongLong();
Q_EMIT editElementRequest(elementId);
}
PDFPageContentScene* PDFPageContentEditorWidget::scene() const
{
return m_scene;

View File

@ -27,6 +27,7 @@
#include <set>
class QToolButton;
class QListWidgetItem;
namespace Ui
{
@ -74,11 +75,13 @@ signals:
void fontChanged(const QFont& font);
void alignmentChanged(Qt::Alignment alignment);
void textAngleChanged(pdf::PDFReal angle);
void editElementRequest(pdf::PDFInteger elementId);
private:
void onActionTriggerRequest(QObject* actionObject);
void onActionChanged();
void onItemSelectionChanged();
void onItemDoubleClicked(QListWidgetItem* item);
Ui::PDFPageContentEditorWidget* ui;
PDFPageContentEditorStyleSettings* m_settingsWidget;

View File

@ -21,6 +21,8 @@
#include "pdfdrawspacecontroller.h"
#include "pdfwidgetutils.h"
#include "pdfutils.h"
#include "pdfcms.h"
#include "pdfpagecontenteditorprocessor.h"
#include <QBuffer>
#include <QPainter>
@ -29,10 +31,16 @@
#include <QSvgRenderer>
#include <QApplication>
#include <QImageReader>
#include <QXmlStreamReader>
namespace pdf
{
PDFPageContentElement::~PDFPageContentElement()
{
}
PDFInteger PDFPageContentElement::getPageIndex() const
{
return m_pageIndex;
@ -61,6 +69,7 @@ Qt::CursorShape PDFPageContentElement::getCursorShapeForManipulationMode(uint mo
case Pt1:
case Pt2:
case Translate:
case Select:
return Qt::ArrowCursor;
case Top:
@ -154,6 +163,7 @@ void PDFPageContentElement::performRectangleManipulation(QRectF& rectangle,
switch (mode)
{
case None:
case Select:
break;
case Translate:
@ -267,15 +277,18 @@ void PDFPageContentElementRectangle::setRectangle(const QRectF& newRectangle)
}
void PDFPageContentElementRectangle::drawPage(QPainter* painter,
const pdf::PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(layoutGetter);
Q_UNUSED(errors);
Q_UNUSED(scene);
if (pageIndex != getPageIndex())
{
@ -284,8 +297,8 @@ void PDFPageContentElementRectangle::drawPage(QPainter* painter,
PDFPainterStateGuard guard(painter);
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
painter->setPen(getPen());
painter->setBrush(getBrush());
painter->setPen(convertor.convert(getPen()));
painter->setBrush(convertor.convert(getBrush()));
painter->setRenderHint(QPainter::Antialiasing);
QRectF rect = getRectangle();
@ -330,6 +343,7 @@ PDFPageContentScene::PDFPageContentScene(QObject* parent) :
QObject(parent),
m_firstFreeId(1),
m_isActive(false),
m_isPageContentDrawSuppressed(false),
m_widget(nullptr),
m_manipulator(this, nullptr)
{
@ -380,6 +394,7 @@ void PDFPageContentScene::clear()
{
m_manipulator.reset();
m_elements.clear();
m_firstFreeId = 1;
Q_EMIT sceneChanged(false);
}
}
@ -639,11 +654,17 @@ int PDFPageContentScene::getInputPriority() const
return ToolPriority + 1;
}
bool PDFPageContentScene::isPageContentDrawSuppressed() const
{
return isActive() && m_isPageContentDrawSuppressed;
}
void PDFPageContentScene::drawElements(QPainter* painter,
PDFInteger pageIndex,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFPrecompiledPage* compiledPage,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
for (const auto& element : m_elements)
@ -653,7 +674,7 @@ void PDFPageContentScene::drawElements(QPainter* painter,
continue;
}
element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
element->drawPage(painter, this, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
}
}
@ -662,6 +683,7 @@ void PDFPageContentScene::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
if (!m_isActive)
@ -669,8 +691,8 @@ void PDFPageContentScene::drawPage(QPainter* painter,
return;
}
drawElements(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix, compiledPage, errors);
m_manipulator.drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
drawElements(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix, compiledPage, convertor, errors);
m_manipulator.drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
}
PDFPageContentScene::MouseEventInfo PDFPageContentScene::getMouseEventInfo(QWidget* widget, QPoint point)
@ -820,6 +842,11 @@ void PDFPageContentScene::onSelectionChanged()
Q_EMIT selectionChanged();
}
void PDFPageContentScene::setIsPageContentDrawSuppressed(bool newIsPageContentDrawSuppressed)
{
m_isPageContentDrawSuppressed = newIsPageContentDrawSuppressed;
}
PDFWidget* PDFPageContentScene::widget() const
{
return m_widget;
@ -848,6 +875,7 @@ void PDFPageContentScene::setActive(bool newIsActive)
}
Q_EMIT sceneChanged(false);
Q_EMIT sceneActiveStateChanged(newIsActive);
}
}
@ -890,6 +918,18 @@ std::set<PDFInteger> PDFPageContentScene::getPageIndices() const
return result;
}
std::map<PDFInteger, std::vector<const PDFPageContentElement*>> PDFPageContentScene::getElementsByPage() const
{
std::map<PDFInteger, std::vector<const PDFPageContentElement*>> result;
for (const auto& elementHandle : m_elements)
{
result[elementHandle->getPageIndex()].push_back(elementHandle.get());
}
return result;
}
QRectF PDFPageContentScene::getBoundingBox(PDFInteger pageIndex) const
{
QRectF rect;
@ -950,15 +990,18 @@ PDFPageContentElementLine* PDFPageContentElementLine::clone() const
}
void PDFPageContentElementLine::drawPage(QPainter* painter,
const pdf::PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(layoutGetter);
Q_UNUSED(errors);
Q_UNUSED(scene);
if (pageIndex != getPageIndex())
{
@ -967,8 +1010,8 @@ void PDFPageContentElementLine::drawPage(QPainter* painter,
PDFPainterStateGuard guard(painter);
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
painter->setPen(getPen());
painter->setBrush(getBrush());
painter->setPen(convertor.convert(getPen()));
painter->setBrush(convertor.convert(getBrush()));
painter->setRenderHint(QPainter::Antialiasing);
painter->drawLine(getLine());
@ -1132,15 +1175,18 @@ PDFPageContentImageElement* PDFPageContentImageElement::clone() const
}
void PDFPageContentImageElement::drawPage(QPainter* painter,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
QList<PDFRenderError>& errors) const
const pdf::PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(layoutGetter);
Q_UNUSED(errors);
Q_UNUSED(scene);
if (pageIndex != getPageIndex() || !getRectangle().isValid())
{
@ -1185,7 +1231,8 @@ void PDFPageContentImageElement::drawPage(QPainter* painter,
painter->scale(1.0, -1.0);
targetRenderBox.moveTopLeft(QPointF(0, 0));
painter->drawImage(targetRenderBox, m_image);
QImage image = convertor.convert(image);
painter->drawImage(targetRenderBox, image);
}
}
@ -1224,7 +1271,22 @@ void PDFPageContentImageElement::setContent(const QByteArray& newContent)
if (m_content != newContent)
{
m_content = newContent;
if (!m_renderer->load(m_content))
m_renderer = std::make_unique<QSvgRenderer>();
QXmlStreamReader xml(m_content);
while (!xml.atEnd() && !xml.hasError())
{
xml.readNext();
}
bool isSvgLoaded = false;
if (!xml.hasError())
{
isSvgLoaded = m_renderer->load(m_content);
}
if (!isSvgLoaded)
{
QByteArray imageData = m_content;
QBuffer buffer(&imageData);
@ -1259,15 +1321,18 @@ PDFPageContentElementDot* PDFPageContentElementDot::clone() const
}
void PDFPageContentElementDot::drawPage(QPainter* painter,
const pdf::PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(layoutGetter);
Q_UNUSED(errors);
Q_UNUSED(scene);
if (pageIndex != getPageIndex())
{
@ -1277,8 +1342,8 @@ void PDFPageContentElementDot::drawPage(QPainter* painter,
PDFPainterStateGuard guard(painter);
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(getPen());
painter->setBrush(getBrush());
painter->setPen(convertor.convert(getPen()));
painter->setBrush(convertor.convert(getBrush()));
painter->drawPoint(m_point);
}
@ -1347,15 +1412,18 @@ PDFPageContentElementFreehandCurve* PDFPageContentElementFreehandCurve::clone()
}
void PDFPageContentElementFreehandCurve::drawPage(QPainter* painter,
const pdf::PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(layoutGetter);
Q_UNUSED(errors);
Q_UNUSED(scene);
if (pageIndex != getPageIndex())
{
@ -1364,8 +1432,8 @@ void PDFPageContentElementFreehandCurve::drawPage(QPainter* painter,
PDFPainterStateGuard guard(painter);
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
painter->setPen(getPen());
painter->setBrush(getBrush());
painter->setPen(convertor.convert(getPen()));
painter->setBrush(convertor.convert(getBrush()));
painter->setRenderHint(QPainter::Antialiasing);
painter->drawPath(getCurve());
@ -2266,6 +2334,7 @@ void PDFPageContentElementManipulator::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
// Draw selection
@ -2291,8 +2360,8 @@ void PDFPageContentElementManipulator::drawPage(QPainter* painter,
QBrush brush(Qt::SolidPattern);
brush.setColor(QColor::fromRgbF(1.0f, 1.0f, 0.0f, 0.2f));
painter->setPen(std::move(pen));
painter->setBrush(std::move(brush));
painter->setPen(convertor.convert(pen));
painter->setBrush(convertor.convert(brush));
selectionPath = pagePointToDevicePointMatrix.map(selectionPath);
painter->drawPath(selectionPath);
@ -2307,7 +2376,7 @@ void PDFPageContentElementManipulator::drawPage(QPainter* painter,
for (const auto& manipulatedElement : m_manipulatedElements)
{
manipulatedElement->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
manipulatedElement->drawPage(painter, m_scene, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
}
}
}
@ -2372,15 +2441,18 @@ PDFPageContentElementTextBox* PDFPageContentElementTextBox::clone() const
}
void PDFPageContentElementTextBox::drawPage(QPainter* painter,
const pdf::PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(layoutGetter);
Q_UNUSED(errors);
Q_UNUSED(scene);
if (pageIndex != getPageIndex())
{
@ -2397,8 +2469,8 @@ void PDFPageContentElementTextBox::drawPage(QPainter* painter,
PDFPainterStateGuard guard(painter);
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
painter->setPen(getPen());
painter->setBrush(getBrush());
painter->setPen(convertor.convert(getPen()));
painter->setBrush(convertor.convert(getBrush()));
painter->setFont(font);
painter->setRenderHint(QPainter::Antialiasing);
painter->setClipRect(rect, Qt::IntersectClip);
@ -2533,4 +2605,153 @@ void PDFPageContentElementTextBox::setAlignment(const Qt::Alignment& newAlignmen
m_alignment = newAlignment;
}
PDFPageContentElementEdited::PDFPageContentElementEdited(const PDFEditedPageContentElement* element) :
m_element(element->clone())
{
}
PDFPageContentElementEdited::~PDFPageContentElementEdited()
{
}
PDFPageContentElementEdited* PDFPageContentElementEdited::clone() const
{
PDFPageContentElementEdited* copy = new PDFPageContentElementEdited(m_element.get());
copy->setElementId(getElementId());
copy->setPageIndex(getPageIndex());
return copy;
}
void PDFPageContentElementEdited::drawPage(QPainter* painter,
const pdf::PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
PDFPainterStateGuard guard(painter);
Q_UNUSED(pageIndex);
Q_UNUSED(compiledPage);
Q_UNUSED(layoutGetter);
Q_UNUSED(errors);
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
painter->setPen(convertor.convert(QPen(Qt::SolidLine)));
painter->setBrush(Qt::NoBrush);
painter->setFont(QApplication::font());
painter->setRenderHint(QPainter::Antialiasing);
const pdf::PDFPage* page = scene->getDocument()->getCatalog()->getPage(pageIndex);
QRectF mediaBox = page->getMediaBox();
if (mediaBox.isValid())
{
QPainterPath path;
path.addPolygon(mediaBox);
painter->setClipPath(path, Qt::IntersectClip);
}
painter->setTransform(m_element->getTransform(), true);
if (const PDFEditedPageContentElementImage* imageElement = m_element->asImage())
{
QRectF rect(0, 0, 1, 1);
painter->translate(rect.bottomLeft());
painter->scale(1.0, -1.0);
QRect transformedRect(0.0, 0.0, rect.width(), rect.height());
QImage image = convertor.convert(imageElement->getImage());
painter->fillRect(transformedRect, Qt::white);
painter->drawImage(transformedRect, image);
}
if (const PDFEditedPageContentElementPath* pathElement = m_element->asPath())
{
const PDFPageContentProcessorState& state = m_element->getState();
QPen pen = convertor.convert(pdf::PDFPainterHelper::createPenFromState(&state, state.getAlphaStroking()));
QBrush brush = convertor.convert(pdf::PDFPainterHelper::createBrushFromState(&state, state.getAlphaFilling()));
painter->setPen(pathElement->getStrokePath() ? pen : QPen(Qt::NoPen));
painter->setBrush(pathElement->getFillPath() ? brush : QBrush(Qt::NoBrush));
painter->drawPath(pathElement->getPath());
}
if (const PDFEditedPageContentElementText* textElement = m_element->asText())
{
const PDFPageContentProcessorState& state = m_element->getState();
painter->setBrush(convertor.convert(pdf::PDFPainterHelper::createBrushFromState(&state, state.getAlphaFilling())));
painter->fillPath(textElement->getTextPath(), painter->brush());
}
}
uint PDFPageContentElementEdited::getManipulationMode(const QPointF& point, PDFReal snapPointDistanceThreshold) const
{
Q_UNUSED(point);
Q_UNUSED(snapPointDistanceThreshold);
if (getBoundingBox().contains(point))
{
return Translate;
}
return None;
}
void PDFPageContentElementEdited::performManipulation(uint mode, const QPointF& offset)
{
switch (mode)
{
case None:
break;
case Translate:
{
QTransform transform = m_element->getTransform();
QTransform updatedTransform(transform.m11(), transform.m12(), transform.m21(), transform.m22(), transform.dx() + offset.x(), transform.dy() + offset.y());
m_element->setTransform(updatedTransform);
break;
}
default:
Q_ASSERT(false);
break;
}
}
QRectF PDFPageContentElementEdited::getBoundingBox() const
{
return m_element->getBoundingBox();
}
void PDFPageContentElementEdited::setSize(QSizeF size)
{
Q_UNUSED(size);
}
QString PDFPageContentElementEdited::getDescription() const
{
if (m_element->asImage())
{
return formatDescription(PDFTranslationContext::tr("Image"));
}
if (m_element->asText())
{
return formatDescription(PDFTranslationContext::tr("Text"));
}
if (m_element->asPath())
{
return formatDescription(PDFTranslationContext::tr("Path"));
}
return formatDescription(PDFTranslationContext::tr("Unknown"));
}
} // namespace pdf

View File

@ -1,4 +1,4 @@
// Copyright (C) 2022 Jakub Melka
// Copyright (C) 2022-2024 Jakub Melka
//
// This file is part of PDF4QT.
//
@ -34,23 +34,34 @@ class QSvgRenderer;
namespace pdf
{
class PDFCMS;
class PDFWidget;
class PDFDocument;
class PDFPageContentScene;
class PDFEditedPageContentElement;
class PDFPageContentElementEdited;
class PDFPageContentElementRectangle;
class PDFPageContentElementLine;
class PDFPageContentElementDot;
class PDFPageContentElementFreehandCurve;
class PDFPageContentImageElement;
class PDFPageContentElementTextBox;
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFPageContentElement
{
public:
explicit PDFPageContentElement() = default;
virtual ~PDFPageContentElement() = default;
virtual ~PDFPageContentElement();
virtual PDFPageContentElement* clone() const = 0;
virtual void drawPage(QPainter* painter,
const PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const = 0;
/// Returns manipulation mode. If manipulation mode is zero, then element
@ -89,6 +100,7 @@ public:
enum ManipulationModes : uint
{
None = 0,
Select,
Translate,
Top,
Left,
@ -102,6 +114,14 @@ public:
Pt2
};
virtual const PDFPageContentElementEdited* asElementEdited() const { return nullptr; }
virtual const PDFPageContentElementRectangle* asElementRectangle() const { return nullptr; }
virtual const PDFPageContentElementLine* asElementLine() const { return nullptr; }
virtual const PDFPageContentElementDot* asElementDot() const { return nullptr ; }
virtual const PDFPageContentElementFreehandCurve* asElementFreehandCurve() const { return nullptr; }
virtual const PDFPageContentImageElement* asElementImage() const { return nullptr; }
virtual const PDFPageContentElementTextBox* asElementTextBox() const { return nullptr; }
protected:
uint getRectangleManipulationMode(const QRectF& rectangle,
const QPointF& point,
@ -150,10 +170,12 @@ public:
void setRectangle(const QRectF& newRectangle);
virtual void drawPage(QPainter* painter,
const PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual uint getManipulationMode(const QPointF& point,
@ -163,6 +185,7 @@ public:
virtual QRectF getBoundingBox() const override;
virtual void setSize(QSizeF size) override;
virtual QString getDescription() const override;
virtual const PDFPageContentElementRectangle* asElementRectangle() const override { return this; }
private:
bool m_rounded = false;
@ -184,10 +207,12 @@ public:
};
virtual void drawPage(QPainter* painter,
const PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual uint getManipulationMode(const QPointF& point,
@ -197,6 +222,7 @@ public:
virtual QRectF getBoundingBox() const override;
virtual void setSize(QSizeF size) override;
virtual QString getDescription() const override;
virtual const PDFPageContentElementLine* asElementLine() const override { return this; }
LineGeometry getGeometry() const;
void setGeometry(LineGeometry newGeometry);
@ -217,10 +243,12 @@ public:
virtual PDFPageContentElementDot* clone() const override;
virtual void drawPage(QPainter* painter,
const PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual uint getManipulationMode(const QPointF& point,
@ -230,6 +258,7 @@ public:
virtual QRectF getBoundingBox() const override;
virtual void setSize(QSizeF size) override;
virtual QString getDescription() const override;
virtual const PDFPageContentElementDot* asElementDot() const override { return this; }
QPointF getPoint() const;
void setPoint(QPointF newPoint);
@ -246,10 +275,12 @@ public:
virtual PDFPageContentElementFreehandCurve* clone() const override;
virtual void drawPage(QPainter* painter,
const PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual uint getManipulationMode(const QPointF& point,
@ -259,6 +290,7 @@ public:
virtual QRectF getBoundingBox() const override;
virtual void setSize(QSizeF size);
virtual QString getDescription() const override;
virtual const PDFPageContentElementFreehandCurve* asElementFreehandCurve() const override { return this; }
QPainterPath getCurve() const;
void setCurve(QPainterPath newCurve);
@ -281,10 +313,12 @@ public:
virtual PDFPageContentImageElement* clone() const override;
virtual void drawPage(QPainter* painter,
const PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual uint getManipulationMode(const QPointF& point,
@ -294,6 +328,7 @@ public:
virtual QRectF getBoundingBox() const override;
virtual void setSize(QSizeF size);
virtual QString getDescription() const override;
virtual const PDFPageContentImageElement* asElementImage() const override { return this; }
const QByteArray& getContent() const;
void setContent(const QByteArray& newContent);
@ -301,6 +336,9 @@ public:
const QRectF& getRectangle() const;
void setRectangle(const QRectF& newRectangle);
const QSvgRenderer* getRenderer() const { return m_renderer.get(); }
const QImage& getImage() const { return m_image; }
private:
QRectF m_rectangle;
QByteArray m_content;
@ -319,10 +357,12 @@ public:
void setRectangle(const QRectF& newRectangle) { m_rectangle = newRectangle; }
virtual void drawPage(QPainter* painter,
const PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual uint getManipulationMode(const QPointF& point,
@ -332,6 +372,7 @@ public:
virtual QRectF getBoundingBox() const override;
virtual void setSize(QSizeF size) override;
virtual QString getDescription() const override;
virtual const PDFPageContentElementTextBox* asElementTextBox() const override { return this; }
const QString& getText() const;
void setText(const QString& newText);
@ -353,6 +394,35 @@ private:
Qt::Alignment m_alignment = Qt::AlignCenter;
};
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFPageContentElementEdited : public PDFPageContentElement
{
public:
PDFPageContentElementEdited(const PDFEditedPageContentElement* element);
virtual ~PDFPageContentElementEdited();
virtual PDFPageContentElementEdited* clone() const override;
virtual void drawPage(QPainter* painter,
const PDFPageContentScene* scene,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual uint getManipulationMode(const QPointF& point, PDFReal snapPointDistanceThreshold) const override;
virtual void performManipulation(uint mode, const QPointF& offset) override;
virtual QRectF getBoundingBox() const override;
virtual void setSize(QSizeF size) override;
virtual QString getDescription() const override;
virtual const PDFPageContentElementEdited* asElementEdited() const { return this; }
const PDFEditedPageContentElement* getElement() const { return m_element.get(); }
PDFEditedPageContentElement* getElement() { return m_element.get(); }
private:
std::unique_ptr<PDFEditedPageContentElement> m_element;
};
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFPageContentElementManipulator : public QObject
{
Q_OBJECT
@ -442,6 +512,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const;
/// Returns bounding box of whole selection
@ -466,8 +537,8 @@ private:
};
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFPageContentScene : public QObject,
public IDocumentDrawInterface,
public IDrawWidgetInputInterface
public IDocumentDrawInterface,
public IDrawWidgetInputInterface
{
Q_OBJECT
@ -509,6 +580,8 @@ public:
/// Returns set of involved pages
std::set<PDFInteger> getPageIndices() const;
std::map<PDFInteger, std::vector<const PDFPageContentElement*>> getElementsByPage() const;
/// Returns bounding box of elements on page
QRectF getBoundingBox(PDFInteger pageIndex) const;
@ -538,12 +611,14 @@ 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,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
PDFWidget* widget() const;
@ -554,8 +629,11 @@ public:
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFPrecompiledPage* compiledPage,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const;
void setIsPageContentDrawSuppressed(bool newIsPageContentDrawSuppressed);
signals:
/// This signal is emitted when scene has changed (including graphics)
void sceneChanged(bool graphicsOnly);
@ -565,6 +643,8 @@ signals:
/// Request to edit the elements
void editElementRequest(const std::set<PDFInteger>& elements);
void sceneActiveStateChanged(bool activated);
private:
struct MouseEventInfo
@ -614,6 +694,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;

View File

@ -645,14 +645,14 @@ void PDFTextEditPseudowidget::draw(AnnotationDrawParameters& parameters, bool ed
if (edit)
{
pdf::PDFPainterStateGuard guard2(painter);
painter->setPen(parameters.colorConvertor.convert(Qt::black, false, true));
painter->setPen(parameters.colorConvertor.convert(QColor(Qt::black), false, true));
painter->setBrush(Qt::NoBrush);
painter->drawRect(parameters.boundingRectangle);
}
painter->setClipRect(parameters.boundingRectangle, Qt::IntersectClip);
painter->setWorldTransform(QTransform(createTextBoxTransformMatrix(edit)), true);
painter->setPen(parameters.colorConvertor.convert(Qt::black, false, true));
painter->setPen(parameters.colorConvertor.convert(QColor(Qt::black), false, true));
if (isComb())
{

View File

@ -1344,7 +1344,7 @@ void PDFFormFieldComboBoxEditor::draw(AnnotationDrawParameters& parameters, bool
AnnotationDrawParameters listBoxParameters = parameters;
listBoxParameters.boundingRectangle = m_listBoxPopupRectangle;
QColor color = parameters.colorConvertor.convert(Qt::white, true, false);
QColor color = parameters.colorConvertor.convert(QColor(Qt::white), true, false);
listBoxParameters.painter->fillRect(listBoxParameters.boundingRectangle, color);
m_listBox.draw(listBoxParameters, true);
@ -1751,7 +1751,7 @@ void PDFListBoxPseudowidget::draw(AnnotationDrawParameters& parameters, bool edi
if (edit)
{
pdf::PDFPainterStateGuard guard2(painter);
painter->setPen(parameters.colorConvertor.convert(Qt::black, false, true));
painter->setPen(parameters.colorConvertor.convert(QColor(Qt::black), false, true));
painter->setBrush(Qt::NoBrush);
painter->drawRect(parameters.boundingRectangle);
}

View File

@ -20,6 +20,7 @@
#include "pdfcompiler.h"
#include "pdfwidgetutils.h"
#include "pdfpainterutils.h"
#include "pdfcms.h"
#include <QLabel>
#include <QAction>
@ -346,6 +347,7 @@ void PDFFindTextTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
@ -353,7 +355,7 @@ void PDFFindTextTool::drawPage(QPainter* painter,
const pdf::PDFTextSelection& textSelection = getTextSelection();
pdf::PDFTextSelectionPainter textSelectionPainter(&textSelection);
textSelectionPainter.draw(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix);
textSelectionPainter.draw(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix, convertor);
}
void PDFFindTextTool::clearResults()
@ -713,13 +715,14 @@ void PDFSelectTextTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(errors);
pdf::PDFTextSelectionPainter textSelectionPainter(&m_textSelection);
textSelectionPainter.draw(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix);
textSelectionPainter.draw(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix, convertor);
}
void PDFSelectTextTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
@ -1305,6 +1308,7 @@ void PDFPickTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
@ -1330,14 +1334,14 @@ void PDFPickTool::drawPage(QPainter* painter,
QRect selectionRectangle(xMin, yMin, xMax - xMin, yMax - yMin);
if (selectionRectangle.isValid())
{
painter->fillRect(selectionRectangle, m_selectionRectangleColor);
painter->fillRect(selectionRectangle, convertor.convert(m_selectionRectangleColor, false, true));
}
}
if (m_mode == Mode::Images && m_snapper.getSnappedImage())
{
const PDFSnapper::ViewportSnapImage* snappedImage = m_snapper.getSnappedImage();
painter->fillPath(snappedImage->viewportPath, m_selectionRectangleColor);
painter->fillPath(snappedImage->viewportPath, convertor.convert(m_selectionRectangleColor, false, true));
}
}
@ -1644,9 +1648,10 @@ void PDFSelectTableTool::drawPage(QPainter* painter,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const
{
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, convertor, errors);
if (isTablePicked() && pageIndex == m_pageIndex)
{
@ -1658,8 +1663,8 @@ void PDFSelectTableTool::drawPage(QPainter* painter,
QPen pen(Qt::SolidLine);
pen.setWidthF(lineWidth);
painter->setPen(std::move(pen));
painter->setBrush(QBrush(color));
painter->setPen(convertor.convert(pen));
painter->setBrush(convertor.convert(QBrush(color)));
painter->drawRect(rectangle);
for (const PDFReal columnPosition : m_horizontalBreaks)

View File

@ -188,6 +188,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
protected:
@ -265,6 +266,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
@ -360,6 +362,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual void drawPostRendering(QPainter* painter, QRect rect) const override;
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
@ -428,6 +431,7 @@ public:
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
const PDFColorConvertor& convertor,
QList<PDFRenderError>& errors) const override;
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event) override;

View File

@ -120,7 +120,7 @@ int PDFToolInfoFonts::execute(const PDFToolOptions& options)
try
{
if (pdf::PDFFontPointer font = pdf::PDFFont::createFont(object, &document))
if (pdf::PDFFontPointer font = pdf::PDFFont::createFont(object, fontsDictionary->getKey(i).getString(), &document))
{
pdf::PDFRenderErrorReporterDummy dummyReporter;
pdf::PDFRealizedFontPointer realizedFont = pdf::PDFRealizedFont::createRealizedFont(font, 8.0, &dummyReporter);