mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Ink coverage calculator
This commit is contained in:
@ -3848,4 +3848,146 @@ void PDFTransparencyRenderer::PDFTransparencySoftMask::makeOpaque()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFInkCoverageCalculator::PDFInkCoverageCalculator(const PDFDocument* document,
|
||||||
|
const PDFFontCache* fontCache,
|
||||||
|
const PDFCMSManager* cmsManager,
|
||||||
|
const PDFOptionalContentActivity* optionalContentActivity,
|
||||||
|
const PDFInkMapper* inkMapper,
|
||||||
|
PDFTransparencyRendererSettings settings) :
|
||||||
|
m_document(document),
|
||||||
|
m_fontCache(fontCache),
|
||||||
|
m_cmsManager(cmsManager),
|
||||||
|
m_optionalContentActivity(optionalContentActivity),
|
||||||
|
m_inkMapper(inkMapper),
|
||||||
|
m_settings(settings)
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_document);
|
||||||
|
Q_ASSERT(m_fontCache);
|
||||||
|
Q_ASSERT(m_cmsManager);
|
||||||
|
Q_ASSERT(m_optionalContentActivity);
|
||||||
|
Q_ASSERT(m_inkMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFInkCoverageCalculator::perform(QSize size, const std::vector<PDFInteger>& pages)
|
||||||
|
{
|
||||||
|
if (pages.empty())
|
||||||
|
{
|
||||||
|
// Nothing to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto calculatePageCoverage = [this, size](PDFInteger pageIndex)
|
||||||
|
{
|
||||||
|
if (pageIndex >= PDFInteger(m_document->getCatalog()->getPageCount()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PDFPage* page = m_document->getCatalog()->getPage(pageIndex);
|
||||||
|
if (!page)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF pageRect = page->getRotatedMediaBox();
|
||||||
|
QSizeF pageSize = pageRect.size();
|
||||||
|
pageSize.scale(size.width(), size.height(), Qt::KeepAspectRatio);
|
||||||
|
QSize imageSize = pageSize.toSize();
|
||||||
|
|
||||||
|
if (!imageSize.isValid())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdf::PDFTransparencyRendererSettings settings;
|
||||||
|
settings.flags.setFlag(PDFTransparencyRendererSettings::SaveOriginalProcessImage, true);
|
||||||
|
|
||||||
|
// Jakub Melka: debug is very slow, use multithreading
|
||||||
|
#ifdef QT_DEBUG
|
||||||
|
settings.flags.setFlag(PDFTransparencyRendererSettings::MultithreadedPathSampler, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
settings.flags.setFlag(PDFTransparencyRendererSettings::ActiveColorMask, false);
|
||||||
|
settings.flags.setFlag(PDFTransparencyRendererSettings::SeparationSimulation, true);
|
||||||
|
settings.activeColorMask = PDFPixelFormat::getAllColorsMask();
|
||||||
|
|
||||||
|
QMatrix pagePointToDevicePoint = pdf::PDFRenderer::createPagePointToDevicePointMatrix(page, QRect(QPoint(0, 0), imageSize));
|
||||||
|
pdf::PDFCMSPointer cms = m_cmsManager->getCurrentCMS();
|
||||||
|
pdf::PDFTransparencyRenderer renderer(page, m_document, m_fontCache, cms.data(), m_optionalContentActivity,
|
||||||
|
m_inkMapper, settings, pagePointToDevicePoint);
|
||||||
|
|
||||||
|
renderer.beginPaint(imageSize);
|
||||||
|
renderer.processContents();
|
||||||
|
renderer.endPaint();
|
||||||
|
|
||||||
|
PDFFloatBitmapWithColorSpace originalProcessImage = renderer.getOriginalProcessBitmap();
|
||||||
|
QSizeF pageSizeMM = page->getRotatedMediaBoxMM().size();
|
||||||
|
|
||||||
|
pdf::PDFPixelFormat pixelFormat = originalProcessImage.getPixelFormat();
|
||||||
|
pdf::PDFColorComponent totalArea = pageSizeMM.width() * pageSizeMM.height();
|
||||||
|
pdf::PDFColorComponent pixelArea = totalArea / pdf::PDFColorComponent(originalProcessImage.getWidth() * originalProcessImage.getHeight());
|
||||||
|
|
||||||
|
std::vector<PDFColorComponent> pageCoverage;
|
||||||
|
const uint8_t colorChannelCount = pixelFormat.getColorChannelCount();
|
||||||
|
pageCoverage.resize(colorChannelCount, 0.0f);
|
||||||
|
|
||||||
|
for (size_t y = 0; y < originalProcessImage.getHeight(); ++y)
|
||||||
|
{
|
||||||
|
for (size_t x = 0; x < originalProcessImage.getWidth(); ++x)
|
||||||
|
{
|
||||||
|
const pdf::PDFColorBuffer buffer = originalProcessImage.getPixel(x, y);
|
||||||
|
const pdf::PDFColorComponent alpha = pixelFormat.hasOpacityChannel() ? buffer[pixelFormat.getOpacityChannelIndex()] : 1.0f;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < colorChannelCount; ++i)
|
||||||
|
{
|
||||||
|
pageCoverage[i] += buffer[i] * alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<PDFColorComponent> pageRatioCoverage = pageCoverage;
|
||||||
|
for (uint8_t i = 0; i < colorChannelCount; ++i)
|
||||||
|
{
|
||||||
|
pageCoverage[i] *= pixelArea;
|
||||||
|
pageRatioCoverage[i] *= pixelArea / totalArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<PDFInkMapper::ColorInfo> separations = m_inkMapper->getSeparations(pixelFormat.getProcessColorChannelCount());
|
||||||
|
Q_ASSERT(pixelFormat.getColorChannelCount() == separations.size());
|
||||||
|
|
||||||
|
std::vector<InkCoverageChannelInfo> results;
|
||||||
|
results.reserve(separations.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < separations.size(); ++i)
|
||||||
|
{
|
||||||
|
const PDFInkMapper::ColorInfo& colorInfo = separations[i];
|
||||||
|
|
||||||
|
InkCoverageChannelInfo info;
|
||||||
|
info.color = colorInfo.color;
|
||||||
|
info.name = colorInfo.name;
|
||||||
|
info.textName = colorInfo.textName;
|
||||||
|
info.isSpot = colorInfo.isSpot;
|
||||||
|
info.coveredArea = pageCoverage[i];
|
||||||
|
results.emplace_back(qMove(info));
|
||||||
|
}
|
||||||
|
|
||||||
|
QMutexLocker lock(&m_mutex);
|
||||||
|
m_inkCoverageResults[pageIndex] = qMove(results);
|
||||||
|
};
|
||||||
|
|
||||||
|
PDFExecutionPolicy::execute(PDFExecutionPolicy::Scope::Page, pages.begin(), pages.end(), calculatePageCoverage);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<PDFInkCoverageCalculator::InkCoverageChannelInfo>* PDFInkCoverageCalculator::getInkCoverage(PDFInteger pageIndex) const
|
||||||
|
{
|
||||||
|
auto it = m_inkCoverageResults.find(pageIndex);
|
||||||
|
if (it != m_inkCoverageResults.end())
|
||||||
|
{
|
||||||
|
return &it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const std::vector<PDFInkCoverageCalculator::InkCoverageChannelInfo> dummy;
|
||||||
|
return &dummy;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -924,6 +924,52 @@ private:
|
|||||||
PDFFloatBitmapWithColorSpace m_originalProcessBitmap;
|
PDFFloatBitmapWithColorSpace m_originalProcessBitmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Ink coverage calculator. Calculates ink coverage for a given
|
||||||
|
/// page range. Calculates ink coverage of both cmyk colors and spot colors.
|
||||||
|
class Pdf4QtLIBSHARED_EXPORT PDFInkCoverageCalculator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PDFInkCoverageCalculator(const PDFDocument* document,
|
||||||
|
const PDFFontCache* fontCache,
|
||||||
|
const PDFCMSManager* cmsManager,
|
||||||
|
const PDFOptionalContentActivity* optionalContentActivity,
|
||||||
|
const PDFInkMapper* inkMapper,
|
||||||
|
PDFTransparencyRendererSettings settings);
|
||||||
|
|
||||||
|
struct InkCoverageChannelInfo
|
||||||
|
{
|
||||||
|
QByteArray name;
|
||||||
|
QString textName;
|
||||||
|
bool isSpot = true;
|
||||||
|
QColor color;
|
||||||
|
PDFColorComponent coveredArea = 0.0f;
|
||||||
|
PDFColorComponent ratio = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Perform ink coverage calculations on given pages. Results are stored
|
||||||
|
/// in this object. Page images are rendered using \p size resolution,
|
||||||
|
/// and in this resolution, ink coverage is calculated.
|
||||||
|
/// \param size Resolution size (for ink coverage calculation)
|
||||||
|
/// \param pages Page indices
|
||||||
|
void perform(QSize size, const std::vector<PDFInteger>& pages);
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const PDFDocument* m_document;
|
||||||
|
const PDFFontCache* m_fontCache;
|
||||||
|
const PDFCMSManager* m_cmsManager;
|
||||||
|
const PDFOptionalContentActivity* m_optionalContentActivity;
|
||||||
|
const PDFInkMapper* m_inkMapper;
|
||||||
|
PDFTransparencyRendererSettings m_settings;
|
||||||
|
|
||||||
|
QMutex m_mutex;
|
||||||
|
std::map<pdf::PDFInteger, std::vector<InkCoverageChannelInfo>> m_inkCoverageResults;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
#endif // PDFTRANSPARENCYRENDERER_H
|
#endif // PDFTRANSPARENCYRENDERER_H
|
||||||
|
Reference in New Issue
Block a user