mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Issue #10: Ability to cancel the operation
This commit is contained in:
@ -142,6 +142,7 @@ HEADERS += \
|
||||
sources/pdfobjecteditorwidget.h \
|
||||
sources/pdfobjecteditorwidget_impl.h \
|
||||
sources/pdfobjectutils.h \
|
||||
sources/pdfoperationcontrol.h \
|
||||
sources/pdfoptimizer.h \
|
||||
sources/pdfoptionalcontent.h \
|
||||
sources/pdfoutline.h \
|
||||
|
@ -218,7 +218,8 @@ QImage PDFAbstractColorSpace::getImage(const PDFImageData& imageData,
|
||||
const PDFImageData& softMask,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter) const
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const
|
||||
{
|
||||
if (imageData.isValid())
|
||||
{
|
||||
@ -249,6 +250,12 @@ QImage PDFAbstractColorSpace::getImage(const PDFImageData& imageData,
|
||||
|
||||
auto transformPixelLine = [&](unsigned int i)
|
||||
{
|
||||
// Is operation being cancelled?
|
||||
if (PDFOperationControl::isOperationCancelled(operationControl))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
PDFBitReader reader(&imageData.getData(), imageData.getBitsPerComponent());
|
||||
@ -260,23 +267,29 @@ QImage PDFAbstractColorSpace::getImage(const PDFImageData& imageData,
|
||||
|
||||
std::vector<float> inputColors(imageWidth * componentCount, 0.0f);
|
||||
auto itInputColor = inputColors.begin();
|
||||
|
||||
if (!decode.empty())
|
||||
{
|
||||
// Interpolate value
|
||||
for (unsigned int j = 0; j < imageData.getWidth(); ++j)
|
||||
{
|
||||
for (unsigned int k = 0; k < componentCount; ++k)
|
||||
{
|
||||
PDFReal value = reader.read();
|
||||
|
||||
// Interpolate value, if it is not empty
|
||||
if (!decode.empty())
|
||||
{
|
||||
*itInputColor++ = interpolate(value, 0.0, max, decode[2 * k], decode[2 * k + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just read all values and multiply them with coefficient
|
||||
const unsigned int pixelCount = imageData.getWidth() * componentCount;
|
||||
for (unsigned int j = 0; j < pixelCount; ++j)
|
||||
{
|
||||
PDFReal value = reader.read();
|
||||
*itInputColor++ = value * coefficient;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fillRGBBuffer(inputColors, outputLine, intent, cms, reporter);
|
||||
}
|
||||
@ -334,6 +347,12 @@ QImage PDFAbstractColorSpace::getImage(const PDFImageData& imageData,
|
||||
|
||||
auto transformPixelLine = [&](unsigned int i)
|
||||
{
|
||||
// Is operation being cancelled?
|
||||
if (PDFOperationControl::isOperationCancelled(operationControl))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
PDFBitReader reader(&imageData.getData(), imageData.getBitsPerComponent());
|
||||
@ -1872,7 +1891,8 @@ QImage PDFIndexedColorSpace::getImage(const PDFImageData& imageData,
|
||||
const PDFImageData& softMask,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter) const
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const
|
||||
{
|
||||
if (imageData.isValid())
|
||||
{
|
||||
@ -1898,6 +1918,12 @@ QImage PDFIndexedColorSpace::getImage(const PDFImageData& imageData,
|
||||
|
||||
for (unsigned int i = 0, rowCount = imageData.getHeight(); i < rowCount; ++i)
|
||||
{
|
||||
// Is operation being cancelled?
|
||||
if (PDFOperationControl::isOperationCancelled(operationControl))
|
||||
{
|
||||
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Operation cancelled!"));
|
||||
}
|
||||
|
||||
reader.seek(i * imageData.getStride());
|
||||
unsigned char* outputLine = image.scanLine(i);
|
||||
|
||||
@ -1945,6 +1971,12 @@ QImage PDFIndexedColorSpace::getImage(const PDFImageData& imageData,
|
||||
|
||||
for (unsigned int i = 0, rowCount = imageData.getHeight(); i < rowCount; ++i)
|
||||
{
|
||||
// Is operation being cancelled?
|
||||
if (PDFOperationControl::isOperationCancelled(operationControl))
|
||||
{
|
||||
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Operation cancelled!"));
|
||||
}
|
||||
|
||||
reader.seek(i * imageData.getStride());
|
||||
unsigned char* outputLine = image.scanLine(i);
|
||||
unsigned char* alphaLine = alphaMask.scanLine(i);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "pdfflatarray.h"
|
||||
#include "pdffunction.h"
|
||||
#include "pdfutils.h"
|
||||
#include "pdfoperationcontrol.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QImage>
|
||||
@ -365,11 +366,13 @@ public:
|
||||
/// \param cms Color management system
|
||||
/// \param intent Rendering intent
|
||||
/// \param reporter Error reporter
|
||||
/// \param operationControl Operation control
|
||||
virtual QImage getImage(const PDFImageData& imageData,
|
||||
const PDFImageData& softMask,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter) const;
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const;
|
||||
|
||||
/// Fills RGB buffer using colors from \p colors. Colors are transformed
|
||||
/// by this color space (or color management system is used). Buffer
|
||||
@ -755,7 +758,8 @@ public:
|
||||
const PDFImageData& softMask,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter) const override;
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const override;
|
||||
|
||||
/// Creates indexed color space from provided values.
|
||||
/// \param colorSpaceDictionary Color space dictionary
|
||||
|
@ -64,11 +64,12 @@ void PDFAsynchronousPageCompilerWorkerThread::run()
|
||||
auto proxy = m_compiler->getProxy();
|
||||
proxy->getFontCache()->setCacheShrinkEnabled(this, false);
|
||||
|
||||
auto compilePage = [proxy](PDFAsynchronousPageCompiler::CompileTask& task) -> PDFPrecompiledPage
|
||||
auto compilePage = [this, proxy](PDFAsynchronousPageCompiler::CompileTask& task) -> PDFPrecompiledPage
|
||||
{
|
||||
PDFPrecompiledPage compiledPage;
|
||||
PDFCMSPointer cms = proxy->getCMSManager()->getCurrentCMS();
|
||||
PDFRenderer renderer(proxy->getDocument(), proxy->getFontCache(), cms.data(), proxy->getOptionalContentActivity(), proxy->getFeatures(), proxy->getMeshQualitySettings());
|
||||
renderer.setOperationControl(m_compiler);
|
||||
renderer.compile(&task.precompiledPage, task.pageIndex);
|
||||
task.finished = true;
|
||||
return compiledPage;
|
||||
@ -122,6 +123,11 @@ PDFAsynchronousPageCompiler::~PDFAsynchronousPageCompiler()
|
||||
stop(true);
|
||||
}
|
||||
|
||||
bool PDFAsynchronousPageCompiler::isOperationCancelled() const
|
||||
{
|
||||
return m_state == State::Stopping;
|
||||
}
|
||||
|
||||
void PDFAsynchronousPageCompiler::start()
|
||||
{
|
||||
switch (m_state)
|
||||
|
@ -54,7 +54,7 @@ private:
|
||||
/// Asynchronous page compiler compiles pages asynchronously, and stores them in the
|
||||
/// cache. Cache size can be set. This object is designed to cooperate with
|
||||
/// draw widget proxy.
|
||||
class PDFAsynchronousPageCompiler : public QObject
|
||||
class PDFAsynchronousPageCompiler : public QObject, public PDFOperationControl
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -106,6 +106,9 @@ public:
|
||||
/// \param compile Compile the page, if it is not found in the cache
|
||||
const PDFPrecompiledPage* getCompiledPage(PDFInteger pageIndex, bool compile);
|
||||
|
||||
/// Is operation being cancelled?
|
||||
virtual bool isOperationCancelled() const override;
|
||||
|
||||
signals:
|
||||
void pageImageChanged(bool all, const std::vector<pdf::PDFInteger>& pages);
|
||||
void renderingError(pdf::PDFInteger pageIndex, const QList<pdf::PDFRenderError>& errors);
|
||||
|
@ -745,12 +745,14 @@ PDFImage PDFImage::createImage(const PDFDocument* document,
|
||||
return image;
|
||||
}
|
||||
|
||||
QImage PDFImage::getImage(const PDFCMS* cms, PDFRenderErrorReporter* reporter) const
|
||||
QImage PDFImage::getImage(const PDFCMS* cms,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const
|
||||
{
|
||||
const bool isImageMask = m_imageData.getMaskingType() == PDFImageData::MaskingType::ImageMask;
|
||||
if (m_colorSpace && !isImageMask)
|
||||
{
|
||||
return m_colorSpace->getImage(m_imageData, m_softMask, cms, m_renderingIntent, reporter);
|
||||
return m_colorSpace->getImage(m_imageData, m_softMask, cms, m_renderingIntent, reporter, operationControl);
|
||||
}
|
||||
else if (isImageMask)
|
||||
{
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "pdfobject.h"
|
||||
#include "pdfcolorspaces.h"
|
||||
#include "pdfoperationcontrol.h"
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
@ -73,7 +74,9 @@ public:
|
||||
PDFRenderErrorReporter* errorReporter);
|
||||
|
||||
/// Returns image transformed from image data and color space
|
||||
QImage getImage(const PDFCMS* cms, PDFRenderErrorReporter* reporter) const;
|
||||
QImage getImage(const PDFCMS* cms,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const;
|
||||
|
||||
/// Returns rendering intent of the image
|
||||
RenderingIntent getRenderingIntent() const { return m_renderingIntent; }
|
||||
|
51
Pdf4QtLib/sources/pdfoperationcontrol.h
Normal file
51
Pdf4QtLib/sources/pdfoperationcontrol.h
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright (C) 2022 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 PDFOPERATIONCONTROL_H
|
||||
#define PDFOPERATIONCONTROL_H
|
||||
|
||||
#include "pdfglobal.h"
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
/// Operation controller. This interface can be used for
|
||||
/// long operation interruption - so operation is cancelled
|
||||
/// immediately.
|
||||
class PDFOperationControl
|
||||
{
|
||||
public:
|
||||
constexpr PDFOperationControl() = default;
|
||||
virtual ~PDFOperationControl() = default;
|
||||
|
||||
/// Returns true, if operation is cancelled and
|
||||
/// processed data should be abandoned. It is safe
|
||||
/// to call this function in another thread, implementators
|
||||
/// of this interface must ensure thread safety.
|
||||
/// If this function returns true, it must return true until
|
||||
/// all operations are stopped and correctly handled.
|
||||
virtual bool isOperationCancelled() const = 0;
|
||||
|
||||
static inline bool isOperationCancelled(const PDFOperationControl* operationControl)
|
||||
{
|
||||
return operationControl && operationControl->isOperationCancelled();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // PDFOPERATIONCONTROL_H
|
@ -232,6 +232,7 @@ PDFPageContentProcessor::PDFPageContentProcessor(const PDFPage* page,
|
||||
m_fontCache(fontCache),
|
||||
m_CMS(CMS),
|
||||
m_optionalContentActivity(optionalContentActivity),
|
||||
m_operationControl(nullptr),
|
||||
m_colorSpaceDictionary(nullptr),
|
||||
m_fontDictionary(nullptr),
|
||||
m_xobjectDictionary(nullptr),
|
||||
@ -311,6 +312,12 @@ QList<PDFRenderError> PDFPageContentProcessor::processContents()
|
||||
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
if (isProcessingCancelled())
|
||||
{
|
||||
// Break, if processing is being cancelled
|
||||
break;
|
||||
}
|
||||
|
||||
const PDFObject& streamObject = m_document->getObject(array->getItem(i));
|
||||
if (streamObject.isStream())
|
||||
{
|
||||
@ -523,7 +530,7 @@ void PDFPageContentProcessor::processContent(const QByteArray& content)
|
||||
{
|
||||
PDFLexicalAnalyzer parser(content.constBegin(), content.constEnd());
|
||||
|
||||
while (!parser.isAtEnd())
|
||||
while (!parser.isAtEnd() && !isProcessingCancelled())
|
||||
{
|
||||
bool tokenFetched = false;
|
||||
PDFInteger oldParserPosition = parser.pos();
|
||||
@ -844,7 +851,7 @@ void PDFPageContentProcessor::processPathPainting(const QPainterPath& path, bool
|
||||
|
||||
if (!performPathPaintingUsingShading(path, false, true, shadingPattern))
|
||||
{
|
||||
PDFMesh mesh = shadingPattern->createMesh(settings, m_CMS, m_graphicState.getRenderingIntent(), this);
|
||||
PDFMesh mesh = shadingPattern->createMesh(settings, m_CMS, m_graphicState.getRenderingIntent(), this, m_operationControl);
|
||||
|
||||
// Now, merge the current path to the mesh clipping path
|
||||
QPainterPath boundingPath = mesh.getBoundingPath();
|
||||
@ -961,7 +968,7 @@ void PDFPageContentProcessor::processPathPainting(const QPainterPath& path, bool
|
||||
|
||||
if (!performPathPaintingUsingShading(strokedPath, true, false, shadingPattern))
|
||||
{
|
||||
PDFMesh mesh = shadingPattern->createMesh(settings, m_CMS, m_graphicState.getRenderingIntent(), this);
|
||||
PDFMesh mesh = shadingPattern->createMesh(settings, m_CMS, m_graphicState.getRenderingIntent(), this, m_operationControl);
|
||||
|
||||
QPainterPath boundingPath = mesh.getBoundingPath();
|
||||
if (boundingPath.isEmpty())
|
||||
@ -1095,6 +1102,16 @@ void PDFPageContentProcessor::processTillingPatternPainting(const PDFTilingPatte
|
||||
|
||||
performClipping(boundingPath, boundingPath.fillRule());
|
||||
processContent(content);
|
||||
|
||||
if (isProcessingCancelled())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isProcessingCancelled())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1831,6 +1848,16 @@ void PDFPageContentProcessor::finishMarkedContent()
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentProcessor::setOperationControl(const PDFOperationControl* newOperationControl)
|
||||
{
|
||||
m_operationControl = newOperationControl;
|
||||
}
|
||||
|
||||
bool PDFPageContentProcessor::isProcessingCancelled() const
|
||||
{
|
||||
return m_operationControl && m_operationControl->isOperationCancelled();
|
||||
}
|
||||
|
||||
void PDFPageContentProcessor::reportRenderErrorOnce(RenderErrorType type, QString message)
|
||||
{
|
||||
if (!m_onceReportedErrors.count(message))
|
||||
@ -2952,8 +2979,10 @@ void PDFPageContentProcessor::paintXObjectImage(const PDFStream* stream)
|
||||
|
||||
if (!performOriginalImagePainting(pdfImage))
|
||||
{
|
||||
QImage image = pdfImage.getImage(m_CMS, this);
|
||||
QImage image = pdfImage.getImage(m_CMS, this, m_operationControl);
|
||||
|
||||
if (!isProcessingCancelled())
|
||||
{
|
||||
if (image.format() == QImage::Format_Alpha8)
|
||||
{
|
||||
QSize size = image.size();
|
||||
@ -2972,6 +3001,7 @@ void PDFPageContentProcessor::paintXObjectImage(const PDFStream* stream)
|
||||
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Can't decode the image."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentProcessor::reportWarningAboutColorOperatorsInUTP()
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "pdfmeshqualitysettings.h"
|
||||
#include "pdfblendfunction.h"
|
||||
#include "pdftextlayout.h"
|
||||
#include "pdfoperationcontrol.h"
|
||||
|
||||
#include <QMatrix>
|
||||
#include <QPainterPath>
|
||||
@ -237,6 +238,15 @@ public:
|
||||
/// or true, if it is suppressed.
|
||||
virtual bool isContentSuppressedByOC(PDFObjectReference ocgOrOcmd);
|
||||
|
||||
/// Sets operation control object which can decide, if operation should
|
||||
/// be cancelled. If this is the case, page content processor stops
|
||||
/// processing page contents.
|
||||
/// \param newOperationControl Operation control object
|
||||
void setOperationControl(const PDFOperationControl* newOperationControl);
|
||||
|
||||
/// Returns true, if page content processing is being cancelled
|
||||
bool isProcessingCancelled() const;
|
||||
|
||||
protected:
|
||||
|
||||
struct PDFTransparencyGroup
|
||||
@ -1009,6 +1019,7 @@ private:
|
||||
const PDFFontCache* m_fontCache;
|
||||
const PDFCMS* m_CMS;
|
||||
const PDFOptionalContentActivity* m_optionalContentActivity;
|
||||
const PDFOperationControl* m_operationControl;
|
||||
const PDFDictionary* m_colorSpaceDictionary;
|
||||
const PDFDictionary* m_fontDictionary;
|
||||
const PDFDictionary* m_xobjectDictionary;
|
||||
|
@ -608,10 +608,16 @@ ShadingType PDFFunctionShading::getShadingType() const
|
||||
return ShadingType::Function;
|
||||
}
|
||||
|
||||
PDFMesh PDFFunctionShading::createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
PDFMesh PDFFunctionShading::createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const
|
||||
{
|
||||
PDFMesh mesh;
|
||||
|
||||
Q_UNUSED(operationControl);
|
||||
|
||||
QMatrix patternSpaceToDeviceSpaceMatrix = getPatternSpaceToDeviceSpaceMatrix(settings);
|
||||
QMatrix domainToDeviceSpaceMatrix = m_domainToTargetTransform * patternSpaceToDeviceSpaceMatrix;
|
||||
QLineF topLine(m_domain.topLeft(), m_domain.topRight());
|
||||
@ -916,10 +922,16 @@ PDFShadingSampler* PDFFunctionShading::createSampler(QMatrix userSpaceToDeviceSp
|
||||
return new PDFFunctionShadingSampler(this, userSpaceToDeviceSpaceMatrix);
|
||||
}
|
||||
|
||||
PDFMesh PDFAxialShading::createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
PDFMesh PDFAxialShading::createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const
|
||||
{
|
||||
PDFMesh mesh;
|
||||
|
||||
Q_UNUSED(operationControl);
|
||||
|
||||
QMatrix patternSpaceToDeviceSpaceMatrix = getPatternSpaceToDeviceSpaceMatrix(settings);
|
||||
QPointF p1 = patternSpaceToDeviceSpaceMatrix.map(m_startPoint);
|
||||
QPointF p2 = patternSpaceToDeviceSpaceMatrix.map(m_endPoint);
|
||||
@ -1423,10 +1435,16 @@ ShadingType PDFRadialShading::getShadingType() const
|
||||
return ShadingType::Radial;
|
||||
}
|
||||
|
||||
PDFMesh PDFRadialShading::createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
PDFMesh PDFRadialShading::createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const
|
||||
{
|
||||
PDFMesh mesh;
|
||||
|
||||
Q_UNUSED(operationControl);
|
||||
|
||||
QMatrix patternSpaceToDeviceSpaceMatrix = getPatternSpaceToDeviceSpaceMatrix(settings);
|
||||
QPointF p1 = patternSpaceToDeviceSpaceMatrix.map(m_startPoint);
|
||||
QPointF p2 = patternSpaceToDeviceSpaceMatrix.map(m_endPoint);
|
||||
@ -2239,10 +2257,16 @@ bool PDFFreeFormGouradTriangleShading::processTriangles(InitializeFunction initi
|
||||
return true;
|
||||
}
|
||||
|
||||
PDFMesh PDFFreeFormGouradTriangleShading::createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
PDFMesh PDFFreeFormGouradTriangleShading::createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const
|
||||
{
|
||||
PDFMesh mesh;
|
||||
|
||||
Q_UNUSED(operationControl);
|
||||
|
||||
auto addTriangle = [this, &settings, &mesh, cms, intent, reporter](const VertexData* va, const VertexData* vb, const VertexData* vc)
|
||||
{
|
||||
const uint32_t via = va->index;
|
||||
@ -2401,10 +2425,16 @@ bool PDFLatticeFormGouradTriangleShading::processTriangles(InitializeFunction in
|
||||
return true;
|
||||
}
|
||||
|
||||
PDFMesh PDFLatticeFormGouradTriangleShading::createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
PDFMesh PDFLatticeFormGouradTriangleShading::createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const
|
||||
{
|
||||
PDFMesh mesh;
|
||||
|
||||
Q_UNUSED(operationControl);
|
||||
|
||||
auto addTriangle = [this, &settings, &mesh, cms, intent, reporter](const VertexData* va, const VertexData* vb, const VertexData* vc)
|
||||
{
|
||||
const uint32_t via = va->index;
|
||||
@ -3071,7 +3101,11 @@ PDFTensorPatches PDFTensorProductPatchShading::createPatches(QMatrix userSpaceTo
|
||||
return patches;
|
||||
}
|
||||
|
||||
PDFMesh PDFTensorProductPatchShading::createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
PDFMesh PDFTensorProductPatchShading::createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const
|
||||
{
|
||||
PDFMesh mesh;
|
||||
|
||||
@ -3082,7 +3116,7 @@ PDFMesh PDFTensorProductPatchShading::createMesh(const PDFMeshQualitySettings& s
|
||||
throw PDFException(PDFTranslationContext::tr("Invalid data in tensor product patch shading."));
|
||||
}
|
||||
|
||||
fillMesh(mesh, getPatternSpaceToDeviceSpaceMatrix(settings.userSpaceToDeviceSpaceMatrix), settings, patches, cms, intent, reporter);
|
||||
fillMesh(mesh, getPatternSpaceToDeviceSpaceMatrix(settings.userSpaceToDeviceSpaceMatrix), settings, patches, cms, intent, reporter, operationControl);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
@ -3228,7 +3262,8 @@ void PDFTensorProductPatchShadingBase::fillMesh(PDFMesh& mesh,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
bool fastAlgorithm) const
|
||||
bool fastAlgorithm,
|
||||
const PDFOperationControl* operationControl) const
|
||||
{
|
||||
// We implement algorithm similar to Ruppert's algorithm (see https://en.wikipedia.org/wiki/Ruppert%27s_algorithm), but
|
||||
// we do not need a mesh for FEM calculation, so we do not care about quality of the triangles (we can have triangles with
|
||||
@ -3301,6 +3336,13 @@ void PDFTensorProductPatchShadingBase::fillMesh(PDFMesh& mesh,
|
||||
|
||||
while (!unfinishedTriangles.empty())
|
||||
{
|
||||
// Mesh generation is cancelled
|
||||
if (PDFOperationControl::isOperationCancelled(operationControl))
|
||||
{
|
||||
mesh = PDFMesh();
|
||||
return;
|
||||
}
|
||||
|
||||
Triangle triangle = unfinishedTriangles.back();
|
||||
unfinishedTriangles.pop_back();
|
||||
|
||||
@ -3417,12 +3459,13 @@ void PDFTensorProductPatchShadingBase::fillMesh(PDFMesh& mesh,
|
||||
const PDFTensorPatches& patches,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter) const
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const
|
||||
{
|
||||
const bool fastAlgorithm = patches.size() > 16;
|
||||
for (const auto& patch : patches)
|
||||
{
|
||||
fillMesh(mesh, settings, patch, cms, intent, reporter, fastAlgorithm);
|
||||
fillMesh(mesh, settings, patch, cms, intent, reporter, fastAlgorithm, operationControl);
|
||||
}
|
||||
|
||||
// Create bounding path
|
||||
@ -3655,7 +3698,11 @@ PDFTensorPatches PDFCoonsPatchShading::createPatches(QMatrix userSpaceToDeviceSp
|
||||
return patches;
|
||||
}
|
||||
|
||||
PDFMesh PDFCoonsPatchShading::createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
PDFMesh PDFCoonsPatchShading::createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const
|
||||
{
|
||||
PDFMesh mesh;
|
||||
PDFTensorPatches patches = createPatches(settings.userSpaceToDeviceSpaceMatrix, true);
|
||||
@ -3665,7 +3712,7 @@ PDFMesh PDFCoonsPatchShading::createMesh(const PDFMeshQualitySettings& settings,
|
||||
throw PDFException(PDFTranslationContext::tr("Invalid data in coons patch shading."));
|
||||
}
|
||||
|
||||
fillMesh(mesh, getPatternSpaceToDeviceSpaceMatrix(settings), settings, patches, cms, intent, reporter);
|
||||
fillMesh(mesh, getPatternSpaceToDeviceSpaceMatrix(settings), settings, patches, cms, intent, reporter, operationControl);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
@ -311,7 +311,11 @@ public:
|
||||
/// \param cms Color management system
|
||||
/// \param intent Rendering intent
|
||||
/// \param reporter Error reporter
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const = 0;
|
||||
/// \param operationControl Operation control
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms, RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const = 0;
|
||||
|
||||
/// Returns patterns graphic state. This state must be applied before
|
||||
/// the shading pattern is painted to the target device.
|
||||
@ -386,7 +390,11 @@ public:
|
||||
explicit PDFFunctionShading() = default;
|
||||
|
||||
virtual ShadingType getShadingType() const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const override;
|
||||
virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override;
|
||||
|
||||
const QRectF& getDomain() const { return m_domain; }
|
||||
@ -407,7 +415,11 @@ public:
|
||||
explicit PDFAxialShading() = default;
|
||||
|
||||
virtual ShadingType getShadingType() const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const override;
|
||||
virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override;
|
||||
|
||||
private:
|
||||
@ -420,7 +432,11 @@ public:
|
||||
explicit PDFRadialShading() = default;
|
||||
|
||||
virtual ShadingType getShadingType() const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const override;
|
||||
virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override;
|
||||
|
||||
PDFReal getR0() const { return m_r0; }
|
||||
@ -480,7 +496,11 @@ public:
|
||||
explicit PDFFreeFormGouradTriangleShading() = default;
|
||||
|
||||
virtual ShadingType getShadingType() const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const override;
|
||||
virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override;
|
||||
|
||||
private:
|
||||
@ -509,7 +529,11 @@ public:
|
||||
explicit PDFLatticeFormGouradTriangleShading() = default;
|
||||
|
||||
virtual ShadingType getShadingType() const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const override;
|
||||
virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override;
|
||||
|
||||
private:
|
||||
@ -675,8 +699,8 @@ public:
|
||||
protected:
|
||||
struct Triangle;
|
||||
|
||||
void fillMesh(PDFMesh& mesh, const PDFMeshQualitySettings& settings, const PDFTensorPatch& patch, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool fastAlgorithm) const;
|
||||
void fillMesh(PDFMesh& mesh, const QMatrix& patternSpaceToDeviceSpaceMatrix, const PDFMeshQualitySettings& settings, const PDFTensorPatches& patches, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const;
|
||||
void fillMesh(PDFMesh& mesh, const PDFMeshQualitySettings& settings, const PDFTensorPatch& patch, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool fastAlgorithm, const PDFOperationControl* operationControl) const;
|
||||
void fillMesh(PDFMesh& mesh, const QMatrix& patternSpaceToDeviceSpaceMatrix, const PDFMeshQualitySettings& settings, const PDFTensorPatches& patches, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, const PDFOperationControl* operationControl) const;
|
||||
static void addTriangle(std::vector<Triangle>& triangles, const PDFTensorPatch& patch, std::array<QPointF, 3> uvCoordinates);
|
||||
|
||||
private:
|
||||
@ -689,7 +713,11 @@ public:
|
||||
explicit PDFCoonsPatchShading() = default;
|
||||
|
||||
virtual ShadingType getShadingType() const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const override;
|
||||
virtual PDFTensorPatches createPatches(QMatrix userSpaceToDeviceSpaceMatrix, bool transformColor) const override;
|
||||
|
||||
private:
|
||||
@ -702,7 +730,11 @@ public:
|
||||
explicit PDFTensorProductPatchShading() = default;
|
||||
|
||||
virtual ShadingType getShadingType() const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter,
|
||||
const PDFOperationControl* operationControl) const override;
|
||||
virtual PDFTensorPatches createPatches(QMatrix userSpaceToDeviceSpaceMatrix, bool transformColor) const override;
|
||||
|
||||
private:
|
||||
|
@ -43,6 +43,7 @@ PDFRenderer::PDFRenderer(const PDFDocument* document,
|
||||
m_fontCache(fontCache),
|
||||
m_cms(cms),
|
||||
m_optionalContentActivity(optionalContentActivity),
|
||||
m_operationControl(nullptr),
|
||||
m_features(features),
|
||||
m_meshQualitySettings(meshQualitySettings)
|
||||
{
|
||||
@ -107,6 +108,16 @@ QMatrix PDFRenderer::createMediaBoxToDevicePointMatrix(const QRectF& mediaBox,
|
||||
return matrix;
|
||||
}
|
||||
|
||||
const PDFOperationControl* PDFRenderer::getOperationControl() const
|
||||
{
|
||||
return m_operationControl;
|
||||
}
|
||||
|
||||
void PDFRenderer::setOperationControl(const PDFOperationControl* newOperationControl)
|
||||
{
|
||||
m_operationControl = newOperationControl;
|
||||
}
|
||||
|
||||
QList<PDFRenderError> PDFRenderer::render(QPainter* painter, const QRectF& rectangle, size_t pageIndex) const
|
||||
{
|
||||
const PDFCatalog* catalog = m_document->getCatalog();
|
||||
@ -122,6 +133,7 @@ QList<PDFRenderError> PDFRenderer::render(QPainter* painter, const QRectF& recta
|
||||
QMatrix matrix = createPagePointToDevicePointMatrix(page, rectangle);
|
||||
|
||||
PDFPainter processor(painter, m_features, matrix, page, m_document, m_fontCache, m_cms, m_optionalContentActivity, m_meshQualitySettings);
|
||||
processor.setOperationControl(m_operationControl);
|
||||
return processor.processContents();
|
||||
}
|
||||
|
||||
@ -138,6 +150,7 @@ QList<PDFRenderError> PDFRenderer::render(QPainter* painter, const QMatrix& matr
|
||||
Q_ASSERT(page);
|
||||
|
||||
PDFPainter processor(painter, m_features, matrix, page, m_document, m_fontCache, m_cms, m_optionalContentActivity, m_meshQualitySettings);
|
||||
processor.setOperationControl(m_operationControl);
|
||||
return processor.processContents();
|
||||
}
|
||||
|
||||
@ -158,6 +171,7 @@ void PDFRenderer::compile(PDFPrecompiledPage* precompiledPage, size_t pageIndex)
|
||||
timer.start();
|
||||
|
||||
PDFPrecompiledPageGenerator generator(precompiledPage, m_features, page, m_document, m_fontCache, m_cms, m_optionalContentActivity, m_meshQualitySettings);
|
||||
generator.setOperationControl(m_operationControl);
|
||||
QList<PDFRenderError> errors = generator.processContents();
|
||||
|
||||
if (m_features.testFlag(InvertColors))
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "pdfpage.h"
|
||||
#include "pdfexception.h"
|
||||
#include "pdfoperationcontrol.h"
|
||||
#include "pdfmeshqualitysettings.h"
|
||||
|
||||
#include <QMutex>
|
||||
@ -113,11 +114,15 @@ public:
|
||||
/// Returns default renderer features
|
||||
static constexpr Features getDefaultFeatures() { return Features(Antialiasing | TextAntialiasing | ClipToCropBox | DisplayAnnotations); }
|
||||
|
||||
const PDFOperationControl* getOperationControl() const;
|
||||
void setOperationControl(const PDFOperationControl* newOperationControl);
|
||||
|
||||
private:
|
||||
const PDFDocument* m_document;
|
||||
const PDFFontCache* m_fontCache;
|
||||
const PDFCMS* m_cms;
|
||||
const PDFOptionalContentActivity* m_optionalContentActivity;
|
||||
const PDFOperationControl* m_operationControl;
|
||||
Features m_features;
|
||||
PDFMeshQualitySettings m_meshQualitySettings;
|
||||
};
|
||||
|
@ -228,7 +228,7 @@ void ObjectViewerWidget::updateUi()
|
||||
|
||||
pdf::PDFRenderErrorReporterDummy dummyErrorReporter;
|
||||
pdf::PDFImage pdfImage = pdf::PDFImage::createImage(m_document, stream, qMove(colorSpace), false, pdf::RenderingIntent::Perceptual, &dummyErrorReporter);
|
||||
QImage image = pdfImage.getImage(m_cms, &dummyErrorReporter);
|
||||
QImage image = pdfImage.getImage(m_cms, &dummyErrorReporter, nullptr);
|
||||
ui->stackedWidget->setCurrentWidget(ui->imageBrowserPage);
|
||||
ui->imageBrowser->setPixmap(QPixmap::fromImage(image));
|
||||
|
||||
|
Reference in New Issue
Block a user