mirror of https://github.com/JakubMelka/PDF4QT.git
Ink coverage dialog
This commit is contained in:
parent
cfedca6f4f
commit
d8b5eed3a9
|
@ -1,4 +1,4 @@
|
|||
// Copyright (C) 2019-2020 Jakub Melka
|
||||
// Copyright (C) 2019-2021 Jakub Melka
|
||||
//
|
||||
// This file is part of Pdf4Qt.
|
||||
//
|
||||
|
@ -54,7 +54,7 @@ void PDFProgress::step()
|
|||
|
||||
if (emitSignal)
|
||||
{
|
||||
progressStep(newPercentage);
|
||||
emit progressStep(newPercentage);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3853,12 +3853,14 @@ PDFInkCoverageCalculator::PDFInkCoverageCalculator(const PDFDocument* document,
|
|||
const PDFCMSManager* cmsManager,
|
||||
const PDFOptionalContentActivity* optionalContentActivity,
|
||||
const PDFInkMapper* inkMapper,
|
||||
PDFProgress* progress,
|
||||
PDFTransparencyRendererSettings settings) :
|
||||
m_document(document),
|
||||
m_fontCache(fontCache),
|
||||
m_cmsManager(cmsManager),
|
||||
m_optionalContentActivity(optionalContentActivity),
|
||||
m_inkMapper(inkMapper),
|
||||
m_progress(progress),
|
||||
m_settings(settings)
|
||||
{
|
||||
Q_ASSERT(m_document);
|
||||
|
@ -3876,6 +3878,11 @@ void PDFInkCoverageCalculator::perform(QSize size, const std::vector<PDFInteger>
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_progress)
|
||||
{
|
||||
m_progress->start(pages.size(), ProgressStartupInfo());
|
||||
}
|
||||
|
||||
auto calculatePageCoverage = [this, size](PDFInteger pageIndex)
|
||||
{
|
||||
if (pageIndex >= PDFInteger(m_document->getCatalog()->getPageCount()))
|
||||
|
@ -3971,11 +3978,27 @@ void PDFInkCoverageCalculator::perform(QSize size, const std::vector<PDFInteger>
|
|||
results.emplace_back(qMove(info));
|
||||
}
|
||||
|
||||
if (m_progress)
|
||||
{
|
||||
m_progress->step();
|
||||
}
|
||||
|
||||
QMutexLocker lock(&m_mutex);
|
||||
m_inkCoverageResults[pageIndex] = qMove(results);
|
||||
};
|
||||
|
||||
PDFExecutionPolicy::execute(PDFExecutionPolicy::Scope::Page, pages.begin(), pages.end(), calculatePageCoverage);
|
||||
|
||||
if (m_progress)
|
||||
{
|
||||
m_progress->finish();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFInkCoverageCalculator::clear()
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
m_inkCoverageResults.clear();
|
||||
}
|
||||
|
||||
const std::vector<PDFInkCoverageCalculator::InkCoverageChannelInfo>* PDFInkCoverageCalculator::getInkCoverage(PDFInteger pageIndex) const
|
||||
|
@ -3990,4 +4013,27 @@ const std::vector<PDFInkCoverageCalculator::InkCoverageChannelInfo>* PDFInkCover
|
|||
return &dummy;
|
||||
}
|
||||
|
||||
const PDFInkCoverageCalculator::InkCoverageChannelInfo* PDFInkCoverageCalculator::findCoverageInfoByName(const std::vector<PDFInkCoverageCalculator::InkCoverageChannelInfo>& infos,
|
||||
const QByteArray& name)
|
||||
{
|
||||
auto it = std::find_if(infos.cbegin(), infos.cend(), [&name](const auto& info) { return info.name == name; });
|
||||
if (it != infos.cend())
|
||||
{
|
||||
return &*it;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PDFInkCoverageCalculator::InkCoverageChannelInfo* PDFInkCoverageCalculator::findCoverageInfoByName(std::vector<PDFInkCoverageCalculator::InkCoverageChannelInfo>& infos, const QByteArray& name)
|
||||
{
|
||||
auto it = std::find_if(infos.begin(), infos.end(), [&name](const auto& info) { return info.name == name; });
|
||||
if (it != infos.cend())
|
||||
{
|
||||
return &*it;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "pdfpagecontentprocessor.h"
|
||||
#include "pdfconstants.h"
|
||||
#include "pdfutils.h"
|
||||
#include "pdfprogress.h"
|
||||
|
||||
#include <QImage>
|
||||
|
||||
|
@ -934,6 +935,7 @@ public:
|
|||
const PDFCMSManager* cmsManager,
|
||||
const PDFOptionalContentActivity* optionalContentActivity,
|
||||
const PDFInkMapper* inkMapper,
|
||||
PDFProgress* progress,
|
||||
PDFTransparencyRendererSettings settings);
|
||||
|
||||
struct InkCoverageChannelInfo
|
||||
|
@ -953,17 +955,35 @@ public:
|
|||
/// \param pages Page indices
|
||||
void perform(QSize size, const std::vector<PDFInteger>& pages);
|
||||
|
||||
/// Clear all calculated ink coverage results
|
||||
void clear();
|
||||
|
||||
/// Clears calculated ink coverage for all pages. If ink coverage is not
|
||||
/// calculated for given page index, empty vector is returned.
|
||||
/// \param pageIndex Page index
|
||||
const std::vector<InkCoverageChannelInfo>* getInkCoverage(PDFInteger pageIndex) const;
|
||||
|
||||
/// Find coverage info in vector by colorant name. If coverage info with a given colorant
|
||||
/// name is not found, then nullptr is returned.
|
||||
/// \param infos Vector of coverage info
|
||||
/// \param name Colornant name
|
||||
/// \returns Info for a given colorant name, or nullptr, if it is not found
|
||||
static const InkCoverageChannelInfo* findCoverageInfoByName(const std::vector<InkCoverageChannelInfo>& infos, const QByteArray& name);
|
||||
|
||||
/// Find coverage info in vector by colorant name. If coverage info with a given colorant
|
||||
/// name is not found, then nullptr is returned.
|
||||
/// \param infos Vector of coverage info
|
||||
/// \param name Colornant name
|
||||
/// \returns Info for a given colorant name, or nullptr, if it is not found
|
||||
static InkCoverageChannelInfo* findCoverageInfoByName(std::vector<InkCoverageChannelInfo>& infos, const QByteArray& name);
|
||||
|
||||
private:
|
||||
const PDFDocument* m_document;
|
||||
const PDFFontCache* m_fontCache;
|
||||
const PDFCMSManager* m_cmsManager;
|
||||
const PDFOptionalContentActivity* m_optionalContentActivity;
|
||||
const PDFInkMapper* m_inkMapper;
|
||||
PDFProgress* m_progress;
|
||||
PDFTransparencyRendererSettings m_settings;
|
||||
|
||||
QMutex m_mutex;
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
"Author" : "Jakub Melka",
|
||||
"Version" : "1.0.0",
|
||||
"License" : "LGPL v3",
|
||||
"Description" : "View prepress output preview (overprint, spot colors, advanced transparency)."
|
||||
"Description" : "View prepress output preview (overprint, spot colors, advanced transparency). Measure ink coverage for process and spot colors for all pages."
|
||||
}
|
||||
|
|
|
@ -33,11 +33,13 @@ DESTDIR = $$OUT_PWD/../../pdfplugins
|
|||
CONFIG += c++11
|
||||
|
||||
SOURCES += \
|
||||
inkcoveragedialog.cpp \
|
||||
outputpreviewdialog.cpp \
|
||||
outputpreviewplugin.cpp \
|
||||
outputpreviewwidget.cpp
|
||||
|
||||
HEADERS += \
|
||||
inkcoveragedialog.h \
|
||||
outputpreviewdialog.h \
|
||||
outputpreviewplugin.h \
|
||||
outputpreviewwidget.h
|
||||
|
@ -51,4 +53,5 @@ RESOURCES += \
|
|||
icons.qrc
|
||||
|
||||
FORMS += \
|
||||
inkcoveragedialog.ui \
|
||||
outputpreviewdialog.ui
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<RCC>
|
||||
<qresource prefix="/pdfplugins/outputpreview">
|
||||
<file>preview.svg</file>
|
||||
<file>ink-coverage.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="30mm"
|
||||
height="30mm"
|
||||
viewBox="0 0 30 30"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="ink-coverage.svg"
|
||||
enable-background="new">
|
||||
<defs
|
||||
id="defs2">
|
||||
<inkscape:path-effect
|
||||
effect="spiro"
|
||||
id="path-effect831"
|
||||
is_visible="true" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="3.959798"
|
||||
inkscape:cx="353.90161"
|
||||
inkscape:cy="22.898892"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2035"
|
||||
inkscape:window-x="-13"
|
||||
inkscape:window-y="-13"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Melka</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Vrstva 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-267)">
|
||||
<rect
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.06046581;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
id="rect4534"
|
||||
width="23.724977"
|
||||
height="11.795169"
|
||||
x="3.0676022"
|
||||
y="281.75931"
|
||||
ry="0.0470865" />
|
||||
<path
|
||||
sodipodi:type="spiral"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.26458332"
|
||||
id="path4536"
|
||||
sodipodi:cx="6.8319197"
|
||||
sodipodi:cy="287.80103"
|
||||
sodipodi:expansion="1"
|
||||
sodipodi:revolution="3"
|
||||
sodipodi:radius="2.2576218"
|
||||
sodipodi:argument="-18.617268"
|
||||
sodipodi:t0="0"
|
||||
d="m 6.8319197,287.80103 c 0.1101534,0.026 0.01922,0.16134 -0.04331,0.18308 -0.1694529,0.0589 -0.3112585,-0.11718 -0.3228548,-0.2697 -0.020743,-0.27284 0.2420036,-0.46852 0.4960934,-0.46263 0.372887,0.009 0.6288465,0.36795 0.6024,0.72248 -0.035249,0.47254 -0.494221,0.79039 -0.9488772,0.74218 -0.5721383,-0.0607 -0.9525297,-0.62063 -0.8819452,-1.17527 0.085487,-0.67175 0.7471009,-1.11503 1.401661,-1.02172 0.7713764,0.10996 1.2777336,0.87362 1.1614904,1.62805 -0.1342073,0.87102 -1.0001713,1.44059 -1.8544448,1.30127 -0.9706798,-0.15832 -1.6035477,-1.12675 -1.4410356,-2.08084 0.1823141,-1.07035 1.2533288,-1.76658 2.3072286,-1.58081 1.1700285,0.20624 1.9296674,1.37993 1.7205808,2.53362"
|
||||
transform="matrix(1.5963587,0,0,1.64111,-3.4226782,-184.59737)" />
|
||||
<path
|
||||
sodipodi:type="spiral"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.26458332"
|
||||
id="path4536-3"
|
||||
sodipodi:cx="6.8319197"
|
||||
sodipodi:cy="287.80103"
|
||||
sodipodi:expansion="1"
|
||||
sodipodi:revolution="3"
|
||||
sodipodi:radius="2.2576218"
|
||||
sodipodi:argument="-18.617268"
|
||||
sodipodi:t0="0"
|
||||
d="m 6.8319197,287.80103 c 0.1101534,0.026 0.01922,0.16134 -0.04331,0.18308 -0.1694529,0.0589 -0.3112585,-0.11718 -0.3228548,-0.2697 -0.020743,-0.27284 0.2420036,-0.46852 0.4960934,-0.46263 0.372887,0.009 0.6288465,0.36795 0.6024,0.72248 -0.035249,0.47254 -0.494221,0.79039 -0.9488772,0.74218 -0.5721383,-0.0607 -0.9525297,-0.62063 -0.8819452,-1.17527 0.085487,-0.67175 0.7471009,-1.11503 1.401661,-1.02172 0.7713764,0.10996 1.2777336,0.87362 1.1614904,1.62805 -0.1342073,0.87102 -1.0001713,1.44059 -1.8544448,1.30127 -0.9706798,-0.15832 -1.6035477,-1.12675 -1.4410356,-2.08084 0.1823141,-1.07035 1.2533288,-1.76658 2.3072286,-1.58081 1.1700285,0.20624 1.9296674,1.37993 1.7205808,2.53362"
|
||||
transform="matrix(1.5963587,0,0,1.64111,4.1022508,-184.64367)" />
|
||||
<path
|
||||
sodipodi:type="spiral"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.26458332"
|
||||
id="path4536-6"
|
||||
sodipodi:cx="6.8319197"
|
||||
sodipodi:cy="287.80103"
|
||||
sodipodi:expansion="1"
|
||||
sodipodi:revolution="3"
|
||||
sodipodi:radius="2.2576218"
|
||||
sodipodi:argument="-18.617268"
|
||||
sodipodi:t0="0"
|
||||
d="m 6.8319197,287.80103 c 0.1101534,0.026 0.01922,0.16134 -0.04331,0.18308 -0.1694529,0.0589 -0.3112585,-0.11718 -0.3228548,-0.2697 -0.020743,-0.27284 0.2420036,-0.46852 0.4960934,-0.46263 0.372887,0.009 0.6288465,0.36795 0.6024,0.72248 -0.035249,0.47254 -0.494221,0.79039 -0.9488772,0.74218 -0.5721383,-0.0607 -0.9525297,-0.62063 -0.8819452,-1.17527 0.085487,-0.67175 0.7471009,-1.11503 1.401661,-1.02172 0.7713764,0.10996 1.2777336,0.87362 1.1614904,1.62805 -0.1342073,0.87102 -1.0001713,1.44059 -1.8544448,1.30127 -0.9706798,-0.15832 -1.6035477,-1.12675 -1.4410356,-2.08084 0.1823141,-1.07035 1.2533288,-1.76658 2.3072286,-1.58081 1.1700285,0.20624 1.9296674,1.37993 1.7205808,2.53362"
|
||||
transform="matrix(1.5963587,0,0,1.64111,11.378292,-184.69091)" />
|
||||
<rect
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
id="rect4559"
|
||||
width="10.924642"
|
||||
height="6.8821898"
|
||||
x="9.9223804"
|
||||
y="274.85004"
|
||||
ry="0.047246911" />
|
||||
<rect
|
||||
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
id="rect4561"
|
||||
width="15.167545"
|
||||
height="3.3742776"
|
||||
x="8.0849028"
|
||||
y="271.40894"
|
||||
ry="0.047246911" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.0 KiB |
|
@ -0,0 +1,381 @@
|
|||
// Copyright (C) 2021 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
|
||||
// (at your option) 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 "inkcoveragedialog.h"
|
||||
#include "ui_inkcoveragedialog.h"
|
||||
|
||||
#include "pdfdrawspacecontroller.h"
|
||||
#include "pdfwidgetutils.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
namespace pdfplugin
|
||||
{
|
||||
|
||||
InkCoverageDialog::InkCoverageDialog(const pdf::PDFDocument* document, pdf::PDFWidget* widget, QWidget* parent) :
|
||||
QDialog(parent, Qt::Dialog | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint),
|
||||
ui(new Ui::InkCoverageDialog),
|
||||
m_inkMapper(widget->getCMSManager(), document),
|
||||
m_document(document),
|
||||
m_widget(widget),
|
||||
m_model(nullptr),
|
||||
m_futureWatcher(nullptr)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_inkMapper.createSpotColors(true);
|
||||
|
||||
m_model = new InkCoverageStatisticsModel(this);
|
||||
ui->coverageTableView->setModel(m_model);
|
||||
ui->coverageTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
|
||||
setMinimumSize(pdf::PDFWidgetUtils::scaleDPI(this, QSize(800, 600)));
|
||||
updateInkCoverage();
|
||||
}
|
||||
|
||||
InkCoverageDialog::~InkCoverageDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void InkCoverageDialog::updateInkCoverage()
|
||||
{
|
||||
Q_ASSERT(!m_future.isRunning());
|
||||
Q_ASSERT(!m_futureWatcher);
|
||||
|
||||
auto calculateInkCoverage = [this]() -> InkCoverageResults
|
||||
{
|
||||
InkCoverageResults results;
|
||||
|
||||
pdf::PDFTransparencyRendererSettings settings;
|
||||
|
||||
// Jakub Melka: debug is very slow, use multithreading
|
||||
#ifdef QT_DEBUG
|
||||
settings.flags.setFlag(pdf::PDFTransparencyRendererSettings::MultithreadedPathSampler, true);
|
||||
#endif
|
||||
|
||||
settings.flags.setFlag(pdf::PDFTransparencyRendererSettings::ActiveColorMask, false);
|
||||
settings.flags.setFlag(pdf::PDFTransparencyRendererSettings::SeparationSimulation, m_inkMapper.getActiveSpotColorCount() > 0);
|
||||
settings.flags.setFlag(pdf::PDFTransparencyRendererSettings::SaveOriginalProcessImage, true);
|
||||
|
||||
pdf::PDFInkCoverageCalculator calculator(m_document,
|
||||
m_widget->getDrawWidgetProxy()->getFontCache(),
|
||||
m_widget->getCMSManager(),
|
||||
m_widget->getDrawWidgetProxy()->getOptionalContentActivity(),
|
||||
&m_inkMapper,
|
||||
m_widget->getDrawWidgetProxy()->getProgress(),
|
||||
settings);
|
||||
|
||||
std::vector<pdf::PDFInteger> pageIndices;
|
||||
pageIndices.resize(m_document->getCatalog()->getPageCount(), 0);
|
||||
std::iota(pageIndices.begin(), pageIndices.end(), 0);
|
||||
calculator.perform(QSize(RESOLUTION, RESOLUTION), pageIndices);
|
||||
|
||||
CoverageInfo coverageInfo;
|
||||
|
||||
for (const pdf::PDFInteger pageIndex : pageIndices)
|
||||
{
|
||||
const std::vector<pdf::PDFInkCoverageCalculator::InkCoverageChannelInfo>* coverage = calculator.getInkCoverage(pageIndex);
|
||||
|
||||
if (!coverage)
|
||||
{
|
||||
// Jakub Melka: Something bad happened?
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& info : *coverage)
|
||||
{
|
||||
if (!pdf::PDFInkCoverageCalculator::findCoverageInfoByName(coverageInfo, info.name))
|
||||
{
|
||||
coverageInfo.push_back(info);
|
||||
coverageInfo.back().coveredArea = 0.0;
|
||||
coverageInfo.back().ratio = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CoverageInfo templateInfo = coverageInfo;
|
||||
CoverageInfo sumInfo = coverageInfo;
|
||||
|
||||
for (const pdf::PDFInteger pageIndex : pageIndices)
|
||||
{
|
||||
const std::vector<pdf::PDFInkCoverageCalculator::InkCoverageChannelInfo>* coverage = calculator.getInkCoverage(pageIndex);
|
||||
results.pageInfo.push_back(templateInfo);
|
||||
|
||||
if (!coverage)
|
||||
{
|
||||
// Jakub Melka: Something bad happened?
|
||||
continue;
|
||||
}
|
||||
|
||||
CoverageInfo& currentInfo = results.pageInfo.back();
|
||||
|
||||
for (const auto& info : *coverage)
|
||||
{
|
||||
pdf::PDFInkCoverageCalculator::InkCoverageChannelInfo* channelInfo = pdf::PDFInkCoverageCalculator::findCoverageInfoByName(currentInfo, info.name);
|
||||
channelInfo->coveredArea = info.coveredArea;
|
||||
channelInfo->ratio = info.ratio;
|
||||
}
|
||||
}
|
||||
|
||||
results.sumInfo = qMove(sumInfo);
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
m_future = QtConcurrent::run(calculateInkCoverage);
|
||||
m_futureWatcher = new QFutureWatcher<InkCoverageResults>();
|
||||
connect(m_futureWatcher, &QFutureWatcher<InkCoverageResults>::finished, this, &InkCoverageDialog::onInkCoverageCalculated);
|
||||
m_futureWatcher->setFuture(m_future);
|
||||
}
|
||||
|
||||
void InkCoverageDialog::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
if (!isInkCoverageCalculated())
|
||||
{
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
BaseClass::closeEvent(event);
|
||||
}
|
||||
|
||||
void InkCoverageDialog::accept()
|
||||
{
|
||||
if (!isInkCoverageCalculated())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BaseClass::accept();
|
||||
}
|
||||
|
||||
void InkCoverageDialog::reject()
|
||||
{
|
||||
if (!isInkCoverageCalculated())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BaseClass::reject();
|
||||
}
|
||||
|
||||
void InkCoverageDialog::onInkCoverageCalculated()
|
||||
{
|
||||
Q_ASSERT(m_future.isFinished());
|
||||
InkCoverageResults results = m_future.result();
|
||||
m_model->setInkCoverageResults(qMove(results));
|
||||
}
|
||||
|
||||
bool InkCoverageDialog::isInkCoverageCalculated() const
|
||||
{
|
||||
return !(m_futureWatcher && m_futureWatcher->isRunning());
|
||||
}
|
||||
|
||||
InkCoverageStatisticsModel::InkCoverageStatisticsModel(QObject* parent) :
|
||||
BaseClass(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QModelIndex InkCoverageStatisticsModel::index(int row, int column, const QModelIndex& parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return createIndex(row, column, nullptr);
|
||||
}
|
||||
|
||||
QModelIndex InkCoverageStatisticsModel::parent(const QModelIndex& child) const
|
||||
{
|
||||
Q_UNUSED(child);
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int InkCoverageStatisticsModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
|
||||
if (m_inkCoverageResults.pageInfo.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return int(m_inkCoverageResults.pageInfo.size() + 1);
|
||||
}
|
||||
|
||||
int InkCoverageStatisticsModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return LastStandardColumn + getChannelCount() * LastChannelColumn;
|
||||
}
|
||||
|
||||
QVariant InkCoverageStatisticsModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
const int row = index.row();
|
||||
QLocale locale;
|
||||
|
||||
if (index.column() == StandardColumnPageIndex)
|
||||
{
|
||||
return locale.toString(row + 1);
|
||||
}
|
||||
|
||||
Q_ASSERT(index.column() >= LastStandardColumn);
|
||||
|
||||
const CoverageInfo* info = nullptr;
|
||||
if (row < m_inkCoverageResults.pageInfo.size())
|
||||
{
|
||||
info = &m_inkCoverageResults.pageInfo[row];
|
||||
}
|
||||
else
|
||||
{
|
||||
info = &m_inkCoverageResults.sumInfo;
|
||||
}
|
||||
|
||||
const int channelIndex = getChannelIndex(index.column());
|
||||
EChannelColumn channelColumn = getChannelColumn(index.column());
|
||||
ChannelCoverageInfo channelInfo = info->at(channelIndex);
|
||||
|
||||
switch (channelColumn)
|
||||
{
|
||||
case pdfplugin::InkCoverageStatisticsModel::ChannelColumnColorant:
|
||||
return channelInfo.coveredArea > 0.0 ? channelInfo.textName : QString();
|
||||
case pdfplugin::InkCoverageStatisticsModel::ChannelColumnCoverageArea:
|
||||
return locale.toString(channelInfo.coveredArea, 'f', 2);
|
||||
case pdfplugin::InkCoverageStatisticsModel::ChannelColumnCoverageRatio:
|
||||
return locale.toString(channelInfo.ratio * 100.0, 'f', 0);
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::TextAlignmentRole:
|
||||
{
|
||||
if (index.column() == StandardColumnPageIndex)
|
||||
{
|
||||
return int(Qt::AlignCenter);
|
||||
}
|
||||
|
||||
Q_ASSERT(index.column() >= LastStandardColumn);
|
||||
|
||||
EChannelColumn channelColumn = getChannelColumn(index.column());
|
||||
switch (channelColumn)
|
||||
{
|
||||
case pdfplugin::InkCoverageStatisticsModel::ChannelColumnColorant:
|
||||
return int(Qt::AlignLeft | Qt::AlignVCenter);
|
||||
|
||||
case pdfplugin::InkCoverageStatisticsModel::ChannelColumnCoverageArea:
|
||||
case pdfplugin::InkCoverageStatisticsModel::ChannelColumnCoverageRatio:
|
||||
return int(Qt::AlignRight | Qt::AlignVCenter);
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant InkCoverageStatisticsModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (section < LastStandardColumn)
|
||||
{
|
||||
Q_ASSERT(section == StandardColumnPageIndex);
|
||||
return tr("Page Index");
|
||||
}
|
||||
|
||||
const EChannelColumn channelColumn = getChannelColumn(section);
|
||||
|
||||
switch (channelColumn)
|
||||
{
|
||||
case ChannelColumnColorant:
|
||||
{
|
||||
const int channelIndex = getChannelIndex(section);
|
||||
return m_inkCoverageResults.sumInfo[channelIndex].textName;
|
||||
}
|
||||
|
||||
case ChannelColumnCoverageArea:
|
||||
return tr("[ mm² ]");
|
||||
|
||||
case ChannelColumnCoverageRatio:
|
||||
return tr("[ % ]");
|
||||
|
||||
case LastChannelColumn:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void InkCoverageStatisticsModel::setInkCoverageResults(InkCoverageResults inkCoverageResults)
|
||||
{
|
||||
beginResetModel();
|
||||
m_inkCoverageResults = qMove(inkCoverageResults);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int InkCoverageStatisticsModel::getChannelCount() const
|
||||
{
|
||||
return int(m_inkCoverageResults.sumInfo.size());
|
||||
}
|
||||
|
||||
InkCoverageStatisticsModel::EChannelColumn InkCoverageStatisticsModel::getChannelColumn(int index) const
|
||||
{
|
||||
Q_ASSERT(index >= LastStandardColumn);
|
||||
|
||||
index -= LastStandardColumn;
|
||||
return static_cast<EChannelColumn>(index % LastChannelColumn);
|
||||
}
|
||||
|
||||
int InkCoverageStatisticsModel::getChannelIndex(int index) const
|
||||
{
|
||||
Q_ASSERT(index >= LastStandardColumn);
|
||||
|
||||
index -= LastStandardColumn;
|
||||
return index / LastChannelColumn;
|
||||
}
|
||||
|
||||
} // pdfplugin
|
|
@ -0,0 +1,123 @@
|
|||
// Copyright (C) 2021 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
|
||||
// (at your option) 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 INKCOVERAGEDIALOG_H
|
||||
#define INKCOVERAGEDIALOG_H
|
||||
|
||||
#include "pdfdocument.h"
|
||||
#include "pdfdrawwidget.h"
|
||||
#include "pdftransparencyrenderer.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class InkCoverageDialog;
|
||||
}
|
||||
|
||||
namespace pdfplugin
|
||||
{
|
||||
class InkCoverageStatisticsModel;
|
||||
|
||||
using ChannelCoverageInfo = pdf::PDFInkCoverageCalculator::InkCoverageChannelInfo;
|
||||
using CoverageInfo = std::vector<ChannelCoverageInfo>;
|
||||
|
||||
struct InkCoverageResults
|
||||
{
|
||||
std::vector<CoverageInfo> pageInfo;
|
||||
CoverageInfo sumInfo;
|
||||
};
|
||||
|
||||
class InkCoverageDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = QDialog;
|
||||
|
||||
public:
|
||||
explicit InkCoverageDialog(const pdf::PDFDocument* document, pdf::PDFWidget* widget, QWidget* parent);
|
||||
virtual ~InkCoverageDialog() override;
|
||||
|
||||
void updateInkCoverage();
|
||||
|
||||
virtual void closeEvent(QCloseEvent* event) override;
|
||||
|
||||
virtual void accept() override;
|
||||
virtual void reject() override;
|
||||
|
||||
private:
|
||||
Ui::InkCoverageDialog* ui;
|
||||
|
||||
static constexpr int RESOLUTION = 1920;
|
||||
|
||||
void onInkCoverageCalculated();
|
||||
bool isInkCoverageCalculated() const;
|
||||
|
||||
pdf::PDFInkMapper m_inkMapper;
|
||||
const pdf::PDFDocument* m_document;
|
||||
pdf::PDFWidget* m_widget;
|
||||
InkCoverageStatisticsModel* m_model;
|
||||
|
||||
QFuture<InkCoverageResults> m_future;
|
||||
QFutureWatcher<InkCoverageResults>* m_futureWatcher;
|
||||
};
|
||||
|
||||
class InkCoverageStatisticsModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = QAbstractItemModel;
|
||||
|
||||
public:
|
||||
explicit InkCoverageStatisticsModel(QObject* parent);
|
||||
|
||||
enum EStandardColumn
|
||||
{
|
||||
StandardColumnPageIndex,
|
||||
LastStandardColumn
|
||||
};
|
||||
|
||||
enum EChannelColumn
|
||||
{
|
||||
ChannelColumnColorant,
|
||||
ChannelColumnCoverageArea,
|
||||
ChannelColumnCoverageRatio,
|
||||
LastChannelColumn
|
||||
};
|
||||
|
||||
virtual QModelIndex index(int row, int column, const QModelIndex& parent) const override;
|
||||
virtual QModelIndex parent(const QModelIndex& child) const override;
|
||||
virtual int rowCount(const QModelIndex& parent) const override;
|
||||
virtual int columnCount(const QModelIndex& parent) const override;
|
||||
virtual QVariant data(const QModelIndex& index, int role) const override;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
|
||||
void setInkCoverageResults(InkCoverageResults inkCoverageResults);
|
||||
int getChannelCount() const;
|
||||
EChannelColumn getChannelColumn(int index) const;
|
||||
int getChannelIndex(int index) const;
|
||||
|
||||
private:
|
||||
InkCoverageResults m_inkCoverageResults;
|
||||
};
|
||||
|
||||
} // namespace pdfplugin
|
||||
|
||||
#endif // INKCOVERAGEDIALOG_H
|
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>InkCoverageDialog</class>
|
||||
<widget class="QDialog" name="InkCoverageDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>715</width>
|
||||
<height>551</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Ink Coverage Calculator</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="coverageLabel">
|
||||
<property name="text">
|
||||
<string>Ink Coverage</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="coverageTableView">
|
||||
<attribute name="horizontalHeaderMinimumSectionSize">
|
||||
<number>40</number>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>InkCoverageDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>InkCoverageDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "outputpreviewplugin.h"
|
||||
#include "outputpreviewdialog.h"
|
||||
#include "inkcoveragedialog.h"
|
||||
#include "pdfdrawwidget.h"
|
||||
|
||||
#include <QAction>
|
||||
|
@ -26,7 +27,8 @@ namespace pdfplugin
|
|||
|
||||
OutputPreviewPlugin::OutputPreviewPlugin() :
|
||||
pdf::PDFPlugin(nullptr),
|
||||
m_outputPreviewAction(nullptr)
|
||||
m_outputPreviewAction(nullptr),
|
||||
m_inkCoverageAction(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -39,8 +41,11 @@ void OutputPreviewPlugin::setWidget(pdf::PDFWidget* widget)
|
|||
|
||||
m_outputPreviewAction = new QAction(QIcon(":/pdfplugins/outputpreview/preview.svg"), tr("Output Preview"), this);
|
||||
m_outputPreviewAction->setObjectName("actionOutputPreview_OutputPreview");
|
||||
m_inkCoverageAction = new QAction(QIcon(":/pdfplugins/outputpreview/ink-coverage.svg"), tr("Ink Coverage"), this);
|
||||
m_inkCoverageAction->setObjectName("actionOutputPreview_InkCoverage");
|
||||
|
||||
connect(m_outputPreviewAction, &QAction::triggered, this, &OutputPreviewPlugin::onOutputPreviewTriggered);
|
||||
connect(m_inkCoverageAction, &QAction::triggered, this, &OutputPreviewPlugin::onInkCoverageTriggered);
|
||||
|
||||
updateActions();
|
||||
}
|
||||
|
@ -57,7 +62,7 @@ void OutputPreviewPlugin::setDocument(const pdf::PDFModifiedDocument& document)
|
|||
|
||||
std::vector<QAction*> OutputPreviewPlugin::getActions() const
|
||||
{
|
||||
return { m_outputPreviewAction };
|
||||
return { m_outputPreviewAction, m_inkCoverageAction };
|
||||
}
|
||||
|
||||
void OutputPreviewPlugin::onOutputPreviewTriggered()
|
||||
|
@ -66,9 +71,16 @@ void OutputPreviewPlugin::onOutputPreviewTriggered()
|
|||
dialog.exec();
|
||||
}
|
||||
|
||||
void OutputPreviewPlugin::onInkCoverageTriggered()
|
||||
{
|
||||
InkCoverageDialog dialog(m_document, m_widget, m_widget);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void OutputPreviewPlugin::updateActions()
|
||||
{
|
||||
m_outputPreviewAction->setEnabled(m_widget && m_document);
|
||||
m_inkCoverageAction->setEnabled(m_widget && m_document);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,9 +42,11 @@ public:
|
|||
|
||||
private:
|
||||
void onOutputPreviewTriggered();
|
||||
void onInkCoverageTriggered();
|
||||
void updateActions();
|
||||
|
||||
QAction* m_outputPreviewAction;
|
||||
QAction* m_inkCoverageAction;
|
||||
};
|
||||
|
||||
} // namespace pdfplugin
|
||||
|
|
Loading…
Reference in New Issue