Spot color conversion

This commit is contained in:
Jakub Melka 2021-02-15 20:04:06 +01:00
parent e63d5aa242
commit 6844114397
3 changed files with 138 additions and 3 deletions

View File

@ -120,7 +120,7 @@ size_t PDFFloatBitmap::getPixelIndex(size_t x, size_t y) const
return (y * m_width + x) * m_pixelSize;
}
PDFFloatBitmap PDFFloatBitmap::extractProcessColors()
PDFFloatBitmap PDFFloatBitmap::extractProcessColors() const
{
PDFPixelFormat format = PDFPixelFormat::createFormat(m_format.getProcessColorChannelCount(), 0, false, m_format.hasProcessColorsSubtractive());
PDFFloatBitmap result(getWidth(), getHeight(), format);
@ -129,7 +129,7 @@ PDFFloatBitmap PDFFloatBitmap::extractProcessColors()
{
for (size_t y = 0; y < getHeight(); ++y)
{
PDFColorBuffer sourceProcessColorBuffer = getPixel(x, y);
PDFConstColorBuffer sourceProcessColorBuffer = getPixel(x, y);
PDFColorBuffer targetProcessColorBuffer = result.getPixel(x, y);
Q_ASSERT(sourceProcessColorBuffer.size() >= targetProcessColorBuffer.size());
@ -140,6 +140,29 @@ PDFFloatBitmap PDFFloatBitmap::extractProcessColors()
return result;
}
PDFFloatBitmap PDFFloatBitmap::extractSpotChannel(uint8_t channel) const
{
PDFPixelFormat format = PDFPixelFormat::createFormat(0, 1, false, m_format.hasProcessColorsSubtractive());
PDFFloatBitmap result(getWidth(), getHeight(), format);
Q_ASSERT(m_format.hasSpotColors());
Q_ASSERT(m_format.getSpotColorChannelIndexStart() <= channel);
Q_ASSERT(m_format.getSpotColorChannelIndexEnd() > channel);
for (size_t x = 0; x < getWidth(); ++x)
{
for (size_t y = 0; y < getHeight(); ++y)
{
PDFConstColorBuffer sourceProcessColorBuffer = getPixel(x, y);
PDFColorBuffer targetProcessColorBuffer = result.getPixel(x, y);
targetProcessColorBuffer[0] = sourceProcessColorBuffer[channel];
}
}
return result;
}
void PDFFloatBitmap::blend(const PDFFloatBitmap& source,
PDFFloatBitmap& target,
const PDFFloatBitmap& backdrop,
@ -455,6 +478,30 @@ void PDFFloatBitmap::blend(const PDFFloatBitmap& source,
}
}
void PDFFloatBitmap::blendConvertedSpots(const PDFFloatBitmap& convertedSpotColors)
{
Q_ASSERT(convertedSpotColors.getPixelFormat().getProcessColorChannelCount() == m_format.getProcessColorChannelCount());
const uint8_t processColorChannelStart = m_format.getProcessColorChannelIndexStart();
const uint8_t processColorChannelEnd = m_format.getProcessColorChannelIndexEnd();
const PDFColorComponent* sourcePixel = convertedSpotColors.begin();
for (PDFColorComponent* targetPixel = begin(); targetPixel != end(); targetPixel += m_pixelSize, sourcePixel+= convertedSpotColors.getPixelSize())
{
for (uint8_t i = processColorChannelStart; i < processColorChannelEnd; ++i)
{
if (m_format.hasProcessColorsSubtractive())
{
targetPixel[i] = PDFBlendFunction::blend_Union(targetPixel[i], sourcePixel[i]);
}
else
{
targetPixel[i] = targetPixel[i] * sourcePixel[i];
}
}
}
}
void PDFFloatBitmap::fillProcessColorChannels(PDFColorComponent value)
{
if (!m_format.hasProcessColors())
@ -644,6 +691,7 @@ void PDFTransparencyRenderer::beginPaint(QSize pixelSize)
m_transparencyGroupDataStack.back().filterColorsUsingMask = (m_settings.flags.testFlag(PDFTransparencyRendererSettings::ActiveColorMask) &&
m_settings.activeColorMask != PDFPixelFormat::getAllColorsMask());
m_transparencyGroupDataStack.back().activeColorMask = m_settings.activeColorMask;
m_transparencyGroupDataStack.back().transformSpotsToDevice = m_settings.flags.testFlag(PDFTransparencyRendererSettings::SeparationSimulation);
}
const PDFFloatBitmap& PDFTransparencyRenderer::endPaint()
@ -790,6 +838,48 @@ void PDFTransparencyRenderer::performPixelSampling(const PDFReal shape,
}
}
void PDFTransparencyRenderer::collapseSpotColorsToDeviceColors(PDFFloatBitmapWithColorSpace& bitmap)
{
PDFPixelFormat pixelFormat = bitmap.getPixelFormat();
if (!pixelFormat.hasSpotColors())
{
return;
}
const uint8_t spotColorIndexStart = pixelFormat.getSpotColorChannelIndexStart();
const uint8_t spotColorIndexEnd = pixelFormat.getSpotColorChannelIndexEnd();
for (uint8_t i = spotColorIndexStart; i < spotColorIndexEnd; ++i)
{
// Collapse spot color
PDFFloatBitmap spotColorBitmap = bitmap.extractSpotChannel(i);
const PDFInkMapper::ColorInfo* spotColor = m_inkMapper->getActiveSpotColor(i - spotColorIndexStart);
Q_ASSERT(spotColor);
switch (spotColor->colorSpace->getColorSpace())
{
case PDFAbstractColorSpace::ColorSpace::Separation:
{
PDFFloatBitmap processColorBitmap(spotColorBitmap.getWidth(), spotColorBitmap.getHeight(), PDFPixelFormat::createFormat(pixelFormat.getProcessColorChannelCount(), 0, false, pixelFormat.hasProcessColorsSubtractive()));
if (!PDFAbstractColorSpace::transform(spotColor->colorSpace.data(), bitmap.getColorSpace().data(), getCMS(), getGraphicState()->getRenderingIntent(), spotColorBitmap.getPixels(), processColorBitmap.getPixels(), this))
{
reportRenderError(RenderErrorType::Error, PDFTranslationContext::tr("Transformation of spot color to blend color space failed."));
}
bitmap.blendConvertedSpots(processColorBitmap);
break;
}
default:
reportRenderError(RenderErrorType::Error, PDFTranslationContext::tr("Transformation of spot color to blend color space failed."));
break;
}
}
}
void PDFTransparencyRenderer::performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule)
{
Q_UNUSED(fillRule);
@ -1118,6 +1208,12 @@ void PDFTransparencyRenderer::performEndTransparencyGroup(ProcessOrder order, co
}
}
// Collapse spot colors
if (sourceData.transformSpotsToDevice)
{
collapseSpotColorsToDeviceColors(sourceData.immediateBackdrop);
}
PDFTransparencyGroupPainterData& targetData = m_transparencyGroupDataStack.back();
sourceData.immediateBackdrop.convertToColorSpace(getCMS(), targetData.renderingIntent, targetData.blendColorSpace, this);
@ -1685,6 +1781,24 @@ const PDFInkMapper::ColorInfo* PDFInkMapper::getSpotColor(const QByteArray& colo
return nullptr;
}
const PDFInkMapper::ColorInfo* PDFInkMapper::getActiveSpotColor(size_t index) const
{
for (const ColorInfo& info : m_spotColors)
{
if (info.active)
{
if (index == 0)
{
return &info;
}
--index;
}
}
return nullptr;
}
void PDFInkMapper::setSpotColorsActive(bool active)
{
m_activeSpotColors = 0;

View File

@ -177,7 +177,11 @@ public:
size_t getPixelIndex(size_t x, size_t y) const;
/// Extract process colors into another bitmap
PDFFloatBitmap extractProcessColors();
PDFFloatBitmap extractProcessColors() const;
/// Extract spot channel
/// \param channel Channel
PDFFloatBitmap extractSpotChannel(uint8_t channel) const;
enum class OverprintMode
{
@ -216,6 +220,11 @@ public:
OverprintMode overprintMode,
QRect blendRegion);
/// Blends converted spot colors, which are in \p convertedSpotColors bitmap.
/// Process colors must match.
/// \param convertedSpotColors Bitmap with converted spot colors
void blendConvertedSpots(const PDFFloatBitmap& convertedSpotColors);
void fillProcessColorChannels(PDFColorComponent value);
void fillChannel(size_t channel, PDFColorComponent value);
@ -316,6 +325,12 @@ public:
/// \param colorName Color name
const ColorInfo* getSpotColor(const QByteArray& colorName) const;
/// Returns active spot color with given index. If index
/// of the spot color is invalid, or no active spot color
/// is found, then nullptr is returned.
/// \param index Active color index
const ColorInfo* getActiveSpotColor(size_t index) const;
/// Activates / deactivates spot colors
/// \param active Make spot colors active?
void setSpotColorsActive(bool active);
@ -577,6 +592,7 @@ private:
PDFColorSpacePointer blendColorSpace;
bool filterColorsUsingMask = false;
uint32_t activeColorMask = PDFPixelFormat::getAllColorsMask();
bool transformSpotsToDevice = false;
};
struct PDFTransparencyPainterState
@ -666,6 +682,10 @@ private:
const PDFPainterPathSampler& clipSampler,
const PDFPainterPathSampler& pathSampler);
/// Collapses spot colors to device colors
/// \param data Bitmap with data
void collapseSpotColorsToDeviceColors(PDFFloatBitmapWithColorSpace& bitmap);
PDFColorSpacePointer m_deviceColorSpace; ///< Device color space (color space for final result)
PDFColorSpacePointer m_processColorSpace; ///< Process color space (color space, in which is page graphic's blended)
std::unique_ptr<PDFTransparencyGroupGuard> m_pageTransparencyGroupGuard;

View File

@ -272,6 +272,7 @@ OutputPreviewDialog::RenderedImage OutputPreviewDialog::renderPage(const pdf::PD
#endif
settings.flags.setFlag(pdf::PDFTransparencyRendererSettings::ActiveColorMask, activeColorMask != pdf::PDFPixelFormat::getAllColorsMask());
settings.flags.setFlag(pdf::PDFTransparencyRendererSettings::SeparationSimulation, m_inkMapperForRendering.getActiveSpotColorCount() > 0);
settings.activeColorMask = activeColorMask;
QMatrix pagePointToDevicePoint = pdf::PDFRenderer::createPagePointToDevicePointMatrix(page, QRect(QPoint(0, 0), imageSize));