mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Ink management in output preview
This commit is contained in:
@@ -641,6 +641,9 @@ void PDFTransparencyRenderer::beginPaint(QSize pixelSize)
|
||||
}
|
||||
|
||||
m_pageTransparencyGroupGuard.reset(new PDFTransparencyGroupGuard(this, qMove(transparencyGroup)));
|
||||
m_transparencyGroupDataStack.back().filterColorsUsingMask = (m_settings.flags.testFlag(PDFTransparencyRendererSettings::ActiveColorMask) &&
|
||||
m_settings.activeColorMask != PDFPixelFormat::getAllColorsMask());
|
||||
m_transparencyGroupDataStack.back().activeColorMask = m_settings.activeColorMask;
|
||||
}
|
||||
|
||||
const PDFFloatBitmap& PDFTransparencyRenderer::endPaint()
|
||||
@@ -1093,6 +1096,28 @@ void PDFTransparencyRenderer::performEndTransparencyGroup(ProcessOrder order, co
|
||||
PDFTransparencyGroupPainterData sourceData = qMove(m_transparencyGroupDataStack.back());
|
||||
m_transparencyGroupDataStack.pop_back();
|
||||
|
||||
// Filter inactive colors - clear all colors in immediate mask,
|
||||
// which are set to inactive.
|
||||
if (sourceData.filterColorsUsingMask)
|
||||
{
|
||||
const PDFPixelFormat pixelFormat = sourceData.immediateBackdrop.getPixelFormat();
|
||||
const uint32_t colorChannelStart = pixelFormat.getColorChannelIndexStart();
|
||||
const uint32_t colorChannelEnd = pixelFormat.getColorChannelIndexEnd();
|
||||
const uint32_t processColorChannelEnd = pixelFormat.getProcessColorChannelIndexEnd();
|
||||
|
||||
for (uint32_t colorChannelIndex = colorChannelStart; colorChannelIndex < colorChannelEnd; ++colorChannelIndex)
|
||||
{
|
||||
const uint32_t flag = 1 << colorChannelIndex;
|
||||
if (!(sourceData.activeColorMask & flag))
|
||||
{
|
||||
const bool isProcessColor = colorChannelIndex < processColorChannelEnd;
|
||||
const bool isSubtractive = isProcessColor ? pixelFormat.hasProcessColorsSubtractive() : pixelFormat.hasSpotColorsSubtractive();
|
||||
|
||||
sourceData.immediateBackdrop.fillChannel(colorChannelIndex, isSubtractive ? 0.0f : 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PDFTransparencyGroupPainterData& targetData = m_transparencyGroupDataStack.back();
|
||||
sourceData.immediateBackdrop.convertToColorSpace(getCMS(), targetData.renderingIntent, targetData.blendColorSpace, this);
|
||||
|
||||
@@ -1429,6 +1454,118 @@ PDFInkMapper::PDFInkMapper(const PDFDocument* document) :
|
||||
|
||||
}
|
||||
|
||||
std::vector<PDFInkMapper::ColorInfo> PDFInkMapper::getSeparations(uint32_t processColorCount) const
|
||||
{
|
||||
std::vector<ColorInfo> result;
|
||||
result.reserve(getActiveSpotColorCount() + processColorCount);
|
||||
|
||||
switch (processColorCount)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
ColorInfo gray;
|
||||
gray.name = "Process Gray";
|
||||
gray.textName = PDFTranslationContext::tr("Process Gray");
|
||||
gray.canBeActive = true;
|
||||
gray.active = true;
|
||||
gray.isSpot = false;
|
||||
result.emplace_back(qMove(gray));
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
ColorInfo red;
|
||||
red.name = "Process Red";
|
||||
red.textName = PDFTranslationContext::tr("Process Red");
|
||||
red.canBeActive = true;
|
||||
red.active = true;
|
||||
red.isSpot = false;
|
||||
result.emplace_back(qMove(red));
|
||||
|
||||
ColorInfo green;
|
||||
green.name = "Process Green";
|
||||
green.textName = PDFTranslationContext::tr("Process Green");
|
||||
green.canBeActive = true;
|
||||
green.active = true;
|
||||
green.isSpot = false;
|
||||
result.emplace_back(qMove(green));
|
||||
|
||||
ColorInfo blue;
|
||||
blue.name = "Process Blue";
|
||||
blue.textName = PDFTranslationContext::tr("Process Blue");
|
||||
blue.canBeActive = true;
|
||||
blue.active = true;
|
||||
blue.isSpot = false;
|
||||
result.emplace_back(qMove(blue));
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
ColorInfo cyan;
|
||||
cyan.name = "Process Cyan";
|
||||
cyan.textName = PDFTranslationContext::tr("Process Cyan");
|
||||
cyan.canBeActive = true;
|
||||
cyan.active = true;
|
||||
cyan.isSpot = false;
|
||||
result.emplace_back(qMove(cyan));
|
||||
|
||||
ColorInfo magenta;
|
||||
magenta.name = "Process Magenta";
|
||||
magenta.textName = PDFTranslationContext::tr("Process Magenta");
|
||||
magenta.canBeActive = true;
|
||||
magenta.active = true;
|
||||
magenta.isSpot = false;
|
||||
result.emplace_back(qMove(magenta));
|
||||
|
||||
ColorInfo yellow;
|
||||
yellow.name = "Process Yellow";
|
||||
yellow.textName = PDFTranslationContext::tr("Process Yellow");
|
||||
yellow.canBeActive = true;
|
||||
yellow.active = true;
|
||||
yellow.isSpot = false;
|
||||
result.emplace_back(qMove(yellow));
|
||||
|
||||
ColorInfo black;
|
||||
black.name = "Process Black";
|
||||
black.textName = PDFTranslationContext::tr("Process Black");
|
||||
black.canBeActive = true;
|
||||
black.active = true;
|
||||
black.isSpot = false;
|
||||
result.emplace_back(qMove(black));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
for (uint32_t i = 0; i < processColorCount; ++i)
|
||||
{
|
||||
ColorInfo generic;
|
||||
generic.textName = PDFTranslationContext::tr("Process Generic%1").arg(i + 1);
|
||||
generic.name = generic.textName.toLatin1();
|
||||
generic.canBeActive = true;
|
||||
generic.active = true;
|
||||
generic.isSpot = false;
|
||||
result.emplace_back(qMove(generic));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& spotColor : m_spotColors)
|
||||
{
|
||||
if (!spotColor.active)
|
||||
{
|
||||
// Skip inactive spot colors
|
||||
continue;
|
||||
}
|
||||
|
||||
result.emplace_back(spotColor);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PDFInkMapper::createSpotColors(bool activate)
|
||||
{
|
||||
m_spotColors.clear();
|
||||
@@ -1477,8 +1614,9 @@ void PDFInkMapper::createSpotColors(bool activate)
|
||||
const QByteArray& colorName = separationColorSpace->getColorName();
|
||||
if (!containsSpotColor(colorName))
|
||||
{
|
||||
SpotColorInfo info;
|
||||
ColorInfo info;
|
||||
info.name = colorName;
|
||||
info.textName = PDFEncoding::convertTextString(info.name);
|
||||
info.colorSpace = colorSpacePointer;
|
||||
info.spotColorIndex = uint32_t(m_spotColors.size());
|
||||
m_spotColors.emplace_back(qMove(info));
|
||||
@@ -1500,8 +1638,9 @@ void PDFInkMapper::createSpotColors(bool activate)
|
||||
const PDFDeviceNColorSpace::ColorantInfo& colorantInfo = colorants[i];
|
||||
if (!containsSpotColor(colorantInfo.name))
|
||||
{
|
||||
SpotColorInfo info;
|
||||
ColorInfo info;
|
||||
info.name = colorantInfo.name;
|
||||
info.textName = PDFEncoding::convertTextString(info.name);
|
||||
info.colorSpaceIndex = uint32_t(i);
|
||||
info.colorSpace = colorSpacePointer;
|
||||
info.spotColorIndex = uint32_t(m_spotColors.size());
|
||||
@@ -1521,15 +1660,13 @@ void PDFInkMapper::createSpotColors(bool activate)
|
||||
}
|
||||
}
|
||||
|
||||
if (activate)
|
||||
size_t minIndex = qMin<uint32_t>(uint32_t(m_spotColors.size()), MAX_SPOT_COLOR_COMPONENTS);
|
||||
for (size_t i = 0; i < minIndex; ++i)
|
||||
{
|
||||
size_t minIndex = qMin<uint32_t>(uint32_t(m_spotColors.size()), MAX_SPOT_COLOR_COMPONENTS);
|
||||
for (size_t i = 0; i < minIndex; ++i)
|
||||
{
|
||||
m_spotColors[i].active = true;
|
||||
}
|
||||
m_activeSpotColors = minIndex;
|
||||
m_spotColors[i].canBeActive = true;
|
||||
}
|
||||
|
||||
setSpotColorsActive(activate);
|
||||
}
|
||||
|
||||
bool PDFInkMapper::containsSpotColor(const QByteArray& colorName) const
|
||||
@@ -1537,7 +1674,7 @@ bool PDFInkMapper::containsSpotColor(const QByteArray& colorName) const
|
||||
return getSpotColor(colorName) != nullptr;
|
||||
}
|
||||
|
||||
const PDFInkMapper::SpotColorInfo* PDFInkMapper::getSpotColor(const QByteArray& colorName) const
|
||||
const PDFInkMapper::ColorInfo* PDFInkMapper::getSpotColor(const QByteArray& colorName) const
|
||||
{
|
||||
auto it = std::find_if(m_spotColors.cbegin(), m_spotColors.cend(), [&colorName](const auto& info) { return info.name == colorName; });
|
||||
if (it != m_spotColors.cend())
|
||||
@@ -1548,6 +1685,30 @@ const PDFInkMapper::SpotColorInfo* PDFInkMapper::getSpotColor(const QByteArray&
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PDFInkMapper::setSpotColorsActive(bool active)
|
||||
{
|
||||
m_activeSpotColors = 0;
|
||||
|
||||
if (active)
|
||||
{
|
||||
for (auto& spotColor : m_spotColors)
|
||||
{
|
||||
if (spotColor.canBeActive)
|
||||
{
|
||||
spotColor.active = true;
|
||||
++m_activeSpotColors;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& spotColor : m_spotColors)
|
||||
{
|
||||
spotColor.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PDFInkMapping PDFInkMapper::createMapping(const PDFAbstractColorSpace* sourceColorSpace,
|
||||
const PDFAbstractColorSpace* targetColorSpace,
|
||||
PDFPixelFormat targetPixelFormat) const
|
||||
@@ -1590,7 +1751,7 @@ PDFInkMapping PDFInkMapper::createMapping(const PDFAbstractColorSpace* sourceCol
|
||||
else if (!separationColorSpace->isNone() && !separationColorSpace->getColorName().isEmpty())
|
||||
{
|
||||
const QByteArray& colorName = separationColorSpace->getColorName();
|
||||
const SpotColorInfo* info = getSpotColor(colorName);
|
||||
const ColorInfo* info = getSpotColor(colorName);
|
||||
if (info && info->active && targetPixelFormat.hasSpotColors() && info->spotColorIndex < targetPixelFormat.getSpotColorChannelCount())
|
||||
{
|
||||
mapping.map(0, uint8_t(targetPixelFormat.getSpotColorChannelIndexStart() + info->spotColorIndex));
|
||||
@@ -1610,7 +1771,7 @@ PDFInkMapping PDFInkMapper::createMapping(const PDFAbstractColorSpace* sourceCol
|
||||
for (size_t i = 0; i < colorants.size(); ++i)
|
||||
{
|
||||
const PDFDeviceNColorSpace::ColorantInfo& colorantInfo = colorants[i];
|
||||
const SpotColorInfo* info = getSpotColor(colorantInfo.name);
|
||||
const ColorInfo* info = getSpotColor(colorantInfo.name);
|
||||
|
||||
if (info && info->active && targetPixelFormat.hasSpotColors() && info->spotColorIndex < targetPixelFormat.getSpotColorChannelCount())
|
||||
{
|
||||
|
@@ -97,6 +97,8 @@ public:
|
||||
static constexpr PDFPixelFormat removeSpotColors(PDFPixelFormat format) { return PDFPixelFormat(format.getProcessColorChannelCount(), 0, format.getFlags()); }
|
||||
static constexpr PDFPixelFormat removeShapeAndOpacity(PDFPixelFormat format) { return PDFPixelFormat(format.getProcessColorChannelCount(), format.getSpotColorChannelCount(), format.hasProcessColorsSubtractive() ? FLAG_PROCESS_COLORS_SUBTRACTIVE : 0); }
|
||||
|
||||
static constexpr uint32_t getAllColorsMask() { return 0xFFFF; }
|
||||
|
||||
static constexpr PDFPixelFormat createFormat(uint8_t processColors, uint8_t spotColors, bool withShapeAndOpacity, bool processColorSubtractive)
|
||||
{
|
||||
return PDFPixelFormat(processColors, spotColors, (withShapeAndOpacity ? FLAG_HAS_SHAPE_CHANNEL + FLAG_HAS_OPACITY_CHANNEL : 0) + (processColorSubtractive ? FLAG_PROCESS_COLORS_SUBTRACTIVE : 0));
|
||||
@@ -277,19 +279,28 @@ class Pdf4QtLIBSHARED_EXPORT PDFInkMapper
|
||||
public:
|
||||
explicit PDFInkMapper(const PDFDocument* document);
|
||||
|
||||
struct SpotColorInfo
|
||||
struct ColorInfo
|
||||
{
|
||||
QByteArray name;
|
||||
QString textName;
|
||||
uint32_t spotColorIndex = 0; ///< Index of this spot color
|
||||
uint32_t colorSpaceIndex = 0; ///< Index into DeviceN color space (index of colorant)
|
||||
PDFColorSpacePointer colorSpace;
|
||||
bool canBeActive = false; ///< Can spot color be activated?
|
||||
bool active = false; ///< Is spot color active?
|
||||
bool isSpot = true;
|
||||
};
|
||||
|
||||
static constexpr const uint32_t MAX_COLOR_COMPONENTS = PDF_MAX_COLOR_COMPONENTS;
|
||||
static constexpr const uint32_t MAX_DEVICE_COLOR_COMPONENTS = 4;
|
||||
static constexpr const uint32_t MAX_SPOT_COLOR_COMPONENTS = MAX_COLOR_COMPONENTS - MAX_DEVICE_COLOR_COMPONENTS - 2;
|
||||
|
||||
/// Returns a vector of separations correspoding to the process colors
|
||||
/// and spot colors. Only active spot colors are added. Only 1, 3 and 4
|
||||
/// process colors are supported.
|
||||
/// \param processColorCount Process color count
|
||||
std::vector<ColorInfo> getSeparations(uint32_t processColorCount) const;
|
||||
|
||||
/// Scan document for spot colors and fills color info
|
||||
/// \param activate Set spot colors active?
|
||||
void createSpotColors(bool activate);
|
||||
@@ -303,7 +314,11 @@ public:
|
||||
|
||||
/// Returns spot color information (or nullptr, if spot color is not present)
|
||||
/// \param colorName Color name
|
||||
const SpotColorInfo* getSpotColor(const QByteArray& colorName) const;
|
||||
const ColorInfo* getSpotColor(const QByteArray& colorName) const;
|
||||
|
||||
/// Activates / deactivates spot colors
|
||||
/// \param active Make spot colors active?
|
||||
void setSpotColorsActive(bool active);
|
||||
|
||||
/// Creates color mapping from source color space to the target color space.
|
||||
/// If mapping cannot be created, then invalid mapping is returned. Target
|
||||
@@ -318,7 +333,7 @@ public:
|
||||
|
||||
private:
|
||||
const PDFDocument* m_document;
|
||||
std::vector<SpotColorInfo> m_spotColors;
|
||||
std::vector<ColorInfo> m_spotColors;
|
||||
size_t m_activeSpotColors = 0;
|
||||
};
|
||||
|
||||
@@ -456,13 +471,23 @@ struct PDFTransparencyRendererSettings
|
||||
|
||||
/// Use multithreading when painter paths are painted?
|
||||
/// Multithreading is used to
|
||||
MultithreadedPathSampler = 0x0002
|
||||
MultithreadedPathSampler = 0x0002,
|
||||
|
||||
/// When using CMYK process color space, transfer spot
|
||||
/// colors to the CMYK color space.
|
||||
SeparationSimulation = 0x0004,
|
||||
|
||||
/// Use active color mask
|
||||
ActiveColorMask = 0x0008
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
|
||||
/// Flags
|
||||
Flags flags = None;
|
||||
|
||||
/// Active color mask
|
||||
uint32_t activeColorMask = PDFPixelFormat::getAllColorsMask();
|
||||
};
|
||||
|
||||
/// Renders PDF pages with transparency, using 32-bit floating point precision.
|
||||
@@ -550,6 +575,8 @@ private:
|
||||
PDFFloatBitmapWithColorSpace immediateBackdrop; ///< Immediate backdrop
|
||||
PDFFloatBitmap softMask; ///< Soft mask for this group
|
||||
PDFColorSpacePointer blendColorSpace;
|
||||
bool filterColorsUsingMask = false;
|
||||
uint32_t activeColorMask = PDFPixelFormat::getAllColorsMask();
|
||||
};
|
||||
|
||||
struct PDFTransparencyPainterState
|
||||
|
Reference in New Issue
Block a user