CMS optimization, some bugfixing

This commit is contained in:
Jakub Melka 2021-07-01 19:40:50 +02:00
parent e89a26790e
commit f759585870
2 changed files with 163 additions and 1 deletions

View File

@ -26,6 +26,7 @@
#pragma warning(disable:5033) #pragma warning(disable:5033)
#define CMS_NO_REGISTER_KEYWORD #define CMS_NO_REGISTER_KEYWORD
#include <lcms2.h> #include <lcms2.h>
#include <lcms2_plugin.h>
#pragma warning(pop) #pragma warning(pop)
#include <unordered_map> #include <unordered_map>
@ -56,6 +57,14 @@ public:
private: private:
void init(); void init();
static int installCmsPlugins();
static cmsBool optimizePipeline(cmsPipeline** Lut,
cmsUInt32Number Intent,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
cmsUInt32Number* dwFlags);
enum Profile enum Profile
{ {
Output, Output,
@ -415,6 +424,9 @@ PDFLittleCMS::PDFLittleCMS(const PDFCMSManager* manager, const PDFCMSSettings& s
m_paperColor(Qt::white), m_paperColor(Qt::white),
m_profiles() m_profiles()
{ {
static const int installed = installCmsPlugins();
Q_UNUSED(installed);
init(); init();
} }
@ -700,6 +712,145 @@ void PDFLittleCMS::init()
m_transformationCache.reserve(64); m_transformationCache.reserve(64);
} }
int PDFLittleCMS::installCmsPlugins()
{
static cmsPluginOptimization optimizationPlugin = { };
optimizationPlugin.base.Magic = cmsPluginMagicNumber;
optimizationPlugin.base.Type = cmsPluginOptimizationSig;
optimizationPlugin.base.Next = nullptr;
optimizationPlugin.base.ExpectedVersion = LCMS_VERSION;
optimizationPlugin.OptimizePtr = &PDFLittleCMS::optimizePipeline;
cmsPlugin(&optimizationPlugin);
return 0;
}
cmsBool PDFLittleCMS::optimizePipeline(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
{
if (*dwFlags & cmsFLAGS_HIGHRESPRECALC)
{
// Do not optimize
return FALSE;
}
Q_UNUSED(Intent);
// We will find, if we can optimize...
bool shouldOptimize = false;
for (auto stage = cmsPipelineGetPtrToFirstStage(*Lut); stage; stage = cmsStageNext(stage))
{
if (cmsStageType(stage) == cmsSigCurveSetElemType)
{
_cmsStageToneCurvesData* data = reinterpret_cast<_cmsStageToneCurvesData*>(cmsStageData(stage));
for (cmsUInt32Number i = 0; i < data->nCurves; ++i)
{
const cmsToneCurve* curve = data->TheCurves[i];
const cmsInt32Number type = cmsGetToneCurveParametricType(curve);
if (type != 0 && !cmsIsToneCurveMultisegment(curve))
{
shouldOptimize = true;
}
}
}
}
if (shouldOptimize)
{
cmsContext contextId = cmsGetPipelineContextID(*Lut);
cmsPipeline* pipeline = cmsPipelineAlloc(contextId, T_CHANNELS(*InputFormat), T_CHANNELS(*OutputFormat));
if (!pipeline)
{
return FALSE;
}
for (auto stage = cmsPipelineGetPtrToFirstStage(*Lut); stage; stage = cmsStageNext(stage))
{
if (cmsStageType(stage) == cmsSigCurveSetElemType)
{
_cmsStageToneCurvesData* data = reinterpret_cast<_cmsStageToneCurvesData*>(cmsStageData(stage));
std::vector<cmsToneCurve*> curves(data->nCurves, nullptr);
for (cmsUInt32Number i = 0; i < data->nCurves; ++i)
{
const cmsToneCurve* curve = data->TheCurves[i];
const cmsInt32Number type = cmsGetToneCurveParametricType(curve);
if (type != 0 && !cmsIsToneCurveMultisegment(curve))
{
std::array<cmsCurveSegment, 3> segments = { };
const cmsFloat64Number* params = cmsGetToneCurveParams(curve);
cmsCurveSegment& s1 = segments[0];
cmsCurveSegment& s2 = segments[1];
cmsCurveSegment& s3 = segments[2];
const cmsFloat32Number eps = cmsFloat32Number(1e-5);
const cmsFloat32Number low = 0.0f - eps;
const cmsFloat32Number high = 1.0f + eps;
s1.Type = type;
s1.nGridPoints = 0;
s1.SampledPoints = nullptr;
std::copy(params, params + (sizeof(s1.Params) / sizeof(*s1.Params)), s1.Params);
s1.x0 = std::numeric_limits<cmsFloat32Number>::min();
s1.x1 = low;
const cmsUInt32Number gridPoints = 1024;
const cmsFloat32Number factor = 1.0f / cmsFloat32Number(gridPoints - 1);
s2.Type = 0;
s2.nGridPoints = gridPoints;
s2.SampledPoints = static_cast<cmsFloat32Number*>(_cmsCalloc(contextId, gridPoints, sizeof(*s2.SampledPoints)));
std::copy(params, params + (sizeof(s2.Params) / sizeof(*s2.Params)), s2.Params);
s2.x0 = low;
s2.x1 = high;
for (cmsUInt32Number i = 0; i < gridPoints; ++i)
{
const cmsFloat32Number x = i * factor;
s2.SampledPoints[i] = cmsEvalToneCurveFloat(curve, x);
}
s3.Type = type;
s3.nGridPoints = 0;
s3.SampledPoints = nullptr;
std::copy(params, params + (sizeof(s3.Params) / sizeof(*s3.Params)), s3.Params);
s3.x0 = high;
s3.x1 = std::numeric_limits<cmsFloat32Number>::max();
curves[i] = cmsBuildSegmentedToneCurve(contextId, cmsUInt32Number(segments.size()), segments.data());
_cmsFree(contextId, s2.SampledPoints);
}
else
{
curves[i] = cmsDupToneCurve(curve);
}
}
cmsStageAllocToneCurves(contextId, cmsFloat32Number(curves.size()), curves.data());
for (cmsToneCurve* curve : curves)
{
cmsFreeToneCurve(curve);
}
}
else
{
cmsPipelineInsertStage(pipeline, cmsAT_END, cmsStageDup(stage));
}
}
cmsPipelineFree(*Lut);
*Lut = pipeline;
}
return FALSE;
}
bool PDFLittleCMS::isSoftProofing() const bool PDFLittleCMS::isSoftProofing() const
{ {
return (m_settings.isSoftProofing || m_settings.isGamutChecking) && m_profiles[SoftProofing]; return (m_settings.isSoftProofing || m_settings.isGamutChecking) && m_profiles[SoftProofing];

View File

@ -49,6 +49,7 @@ PDFRenderToImagesDialog::PDFRenderToImagesDialog(const pdf::PDFDocument* documen
ui->setupUi(this); ui->setupUi(this);
qRegisterMetaType<pdf::PDFRenderError>("PDFRenderError"); qRegisterMetaType<pdf::PDFRenderError>("PDFRenderError");
qRegisterMetaType<pdf::PDFInteger>("PDFInteger");
// Load image formats // Load image formats
for (const QByteArray& format : m_imageWriterSettings.getFormats()) for (const QByteArray& format : m_imageWriterSettings.getFormats())
@ -245,7 +246,17 @@ void PDFRenderToImagesDialog::onProgressiveScanWriteChanged(bool value)
void PDFRenderToImagesDialog::onRenderError(pdf::PDFInteger pageIndex, pdf::PDFRenderError error) void PDFRenderToImagesDialog::onRenderError(pdf::PDFInteger pageIndex, pdf::PDFRenderError error)
{ {
ui->progressMessagesEdit->setPlainText(QString("%1\n%2").arg(ui->progressMessagesEdit->toPlainText()).arg(tr("Page %1: %2").arg(pageIndex + 1).arg(error.message))); QString text;
if (pageIndex != pdf::PDFCatalog::INVALID_PAGE_INDEX)
{
text = tr("%1\nPage %2: %3").arg(ui->progressMessagesEdit->toPlainText(), QString::number(pageIndex + 1), error.message);
}
else
{
text = QString("%1\n%2").arg(ui->progressMessagesEdit->toPlainText(), error.message);
}
ui->progressMessagesEdit->setPlainText(text);
} }
void PDFRenderToImagesDialog::onRenderingFinished() void PDFRenderToImagesDialog::onRenderingFinished()