mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-01-29 16:49:32 +01:00
Ink management in output preview
This commit is contained in:
parent
9da1efe4ef
commit
e63d5aa242
@ -641,6 +641,9 @@ void PDFTransparencyRenderer::beginPaint(QSize pixelSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_pageTransparencyGroupGuard.reset(new PDFTransparencyGroupGuard(this, qMove(transparencyGroup)));
|
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()
|
const PDFFloatBitmap& PDFTransparencyRenderer::endPaint()
|
||||||
@ -1093,6 +1096,28 @@ void PDFTransparencyRenderer::performEndTransparencyGroup(ProcessOrder order, co
|
|||||||
PDFTransparencyGroupPainterData sourceData = qMove(m_transparencyGroupDataStack.back());
|
PDFTransparencyGroupPainterData sourceData = qMove(m_transparencyGroupDataStack.back());
|
||||||
m_transparencyGroupDataStack.pop_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();
|
PDFTransparencyGroupPainterData& targetData = m_transparencyGroupDataStack.back();
|
||||||
sourceData.immediateBackdrop.convertToColorSpace(getCMS(), targetData.renderingIntent, targetData.blendColorSpace, this);
|
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)
|
void PDFInkMapper::createSpotColors(bool activate)
|
||||||
{
|
{
|
||||||
m_spotColors.clear();
|
m_spotColors.clear();
|
||||||
@ -1477,8 +1614,9 @@ void PDFInkMapper::createSpotColors(bool activate)
|
|||||||
const QByteArray& colorName = separationColorSpace->getColorName();
|
const QByteArray& colorName = separationColorSpace->getColorName();
|
||||||
if (!containsSpotColor(colorName))
|
if (!containsSpotColor(colorName))
|
||||||
{
|
{
|
||||||
SpotColorInfo info;
|
ColorInfo info;
|
||||||
info.name = colorName;
|
info.name = colorName;
|
||||||
|
info.textName = PDFEncoding::convertTextString(info.name);
|
||||||
info.colorSpace = colorSpacePointer;
|
info.colorSpace = colorSpacePointer;
|
||||||
info.spotColorIndex = uint32_t(m_spotColors.size());
|
info.spotColorIndex = uint32_t(m_spotColors.size());
|
||||||
m_spotColors.emplace_back(qMove(info));
|
m_spotColors.emplace_back(qMove(info));
|
||||||
@ -1500,8 +1638,9 @@ void PDFInkMapper::createSpotColors(bool activate)
|
|||||||
const PDFDeviceNColorSpace::ColorantInfo& colorantInfo = colorants[i];
|
const PDFDeviceNColorSpace::ColorantInfo& colorantInfo = colorants[i];
|
||||||
if (!containsSpotColor(colorantInfo.name))
|
if (!containsSpotColor(colorantInfo.name))
|
||||||
{
|
{
|
||||||
SpotColorInfo info;
|
ColorInfo info;
|
||||||
info.name = colorantInfo.name;
|
info.name = colorantInfo.name;
|
||||||
|
info.textName = PDFEncoding::convertTextString(info.name);
|
||||||
info.colorSpaceIndex = uint32_t(i);
|
info.colorSpaceIndex = uint32_t(i);
|
||||||
info.colorSpace = colorSpacePointer;
|
info.colorSpace = colorSpacePointer;
|
||||||
info.spotColorIndex = uint32_t(m_spotColors.size());
|
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);
|
m_spotColors[i].canBeActive = true;
|
||||||
for (size_t i = 0; i < minIndex; ++i)
|
|
||||||
{
|
|
||||||
m_spotColors[i].active = true;
|
|
||||||
}
|
|
||||||
m_activeSpotColors = minIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSpotColorsActive(activate);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PDFInkMapper::containsSpotColor(const QByteArray& colorName) const
|
bool PDFInkMapper::containsSpotColor(const QByteArray& colorName) const
|
||||||
@ -1537,7 +1674,7 @@ bool PDFInkMapper::containsSpotColor(const QByteArray& colorName) const
|
|||||||
return getSpotColor(colorName) != nullptr;
|
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; });
|
auto it = std::find_if(m_spotColors.cbegin(), m_spotColors.cend(), [&colorName](const auto& info) { return info.name == colorName; });
|
||||||
if (it != m_spotColors.cend())
|
if (it != m_spotColors.cend())
|
||||||
@ -1548,6 +1685,30 @@ const PDFInkMapper::SpotColorInfo* PDFInkMapper::getSpotColor(const QByteArray&
|
|||||||
return nullptr;
|
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,
|
PDFInkMapping PDFInkMapper::createMapping(const PDFAbstractColorSpace* sourceColorSpace,
|
||||||
const PDFAbstractColorSpace* targetColorSpace,
|
const PDFAbstractColorSpace* targetColorSpace,
|
||||||
PDFPixelFormat targetPixelFormat) const
|
PDFPixelFormat targetPixelFormat) const
|
||||||
@ -1590,7 +1751,7 @@ PDFInkMapping PDFInkMapper::createMapping(const PDFAbstractColorSpace* sourceCol
|
|||||||
else if (!separationColorSpace->isNone() && !separationColorSpace->getColorName().isEmpty())
|
else if (!separationColorSpace->isNone() && !separationColorSpace->getColorName().isEmpty())
|
||||||
{
|
{
|
||||||
const QByteArray& colorName = separationColorSpace->getColorName();
|
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())
|
if (info && info->active && targetPixelFormat.hasSpotColors() && info->spotColorIndex < targetPixelFormat.getSpotColorChannelCount())
|
||||||
{
|
{
|
||||||
mapping.map(0, uint8_t(targetPixelFormat.getSpotColorChannelIndexStart() + info->spotColorIndex));
|
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)
|
for (size_t i = 0; i < colorants.size(); ++i)
|
||||||
{
|
{
|
||||||
const PDFDeviceNColorSpace::ColorantInfo& colorantInfo = colorants[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())
|
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 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 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)
|
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));
|
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:
|
public:
|
||||||
explicit PDFInkMapper(const PDFDocument* document);
|
explicit PDFInkMapper(const PDFDocument* document);
|
||||||
|
|
||||||
struct SpotColorInfo
|
struct ColorInfo
|
||||||
{
|
{
|
||||||
QByteArray name;
|
QByteArray name;
|
||||||
|
QString textName;
|
||||||
uint32_t spotColorIndex = 0; ///< Index of this spot color
|
uint32_t spotColorIndex = 0; ///< Index of this spot color
|
||||||
uint32_t colorSpaceIndex = 0; ///< Index into DeviceN color space (index of colorant)
|
uint32_t colorSpaceIndex = 0; ///< Index into DeviceN color space (index of colorant)
|
||||||
PDFColorSpacePointer colorSpace;
|
PDFColorSpacePointer colorSpace;
|
||||||
|
bool canBeActive = false; ///< Can spot color be activated?
|
||||||
bool active = false; ///< Is spot color active?
|
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_COLOR_COMPONENTS = PDF_MAX_COLOR_COMPONENTS;
|
||||||
static constexpr const uint32_t MAX_DEVICE_COLOR_COMPONENTS = 4;
|
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;
|
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
|
/// Scan document for spot colors and fills color info
|
||||||
/// \param activate Set spot colors active?
|
/// \param activate Set spot colors active?
|
||||||
void createSpotColors(bool activate);
|
void createSpotColors(bool activate);
|
||||||
@ -303,7 +314,11 @@ public:
|
|||||||
|
|
||||||
/// Returns spot color information (or nullptr, if spot color is not present)
|
/// Returns spot color information (or nullptr, if spot color is not present)
|
||||||
/// \param colorName Color name
|
/// \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.
|
/// Creates color mapping from source color space to the target color space.
|
||||||
/// If mapping cannot be created, then invalid mapping is returned. Target
|
/// If mapping cannot be created, then invalid mapping is returned. Target
|
||||||
@ -318,7 +333,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const PDFDocument* m_document;
|
const PDFDocument* m_document;
|
||||||
std::vector<SpotColorInfo> m_spotColors;
|
std::vector<ColorInfo> m_spotColors;
|
||||||
size_t m_activeSpotColors = 0;
|
size_t m_activeSpotColors = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -456,13 +471,23 @@ struct PDFTransparencyRendererSettings
|
|||||||
|
|
||||||
/// Use multithreading when painter paths are painted?
|
/// Use multithreading when painter paths are painted?
|
||||||
/// Multithreading is used to
|
/// 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)
|
Q_DECLARE_FLAGS(Flags, Flag)
|
||||||
|
|
||||||
/// Flags
|
/// Flags
|
||||||
Flags flags = None;
|
Flags flags = None;
|
||||||
|
|
||||||
|
/// Active color mask
|
||||||
|
uint32_t activeColorMask = PDFPixelFormat::getAllColorsMask();
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Renders PDF pages with transparency, using 32-bit floating point precision.
|
/// Renders PDF pages with transparency, using 32-bit floating point precision.
|
||||||
@ -550,6 +575,8 @@ private:
|
|||||||
PDFFloatBitmapWithColorSpace immediateBackdrop; ///< Immediate backdrop
|
PDFFloatBitmapWithColorSpace immediateBackdrop; ///< Immediate backdrop
|
||||||
PDFFloatBitmap softMask; ///< Soft mask for this group
|
PDFFloatBitmap softMask; ///< Soft mask for this group
|
||||||
PDFColorSpacePointer blendColorSpace;
|
PDFColorSpacePointer blendColorSpace;
|
||||||
|
bool filterColorsUsingMask = false;
|
||||||
|
uint32_t activeColorMask = PDFPixelFormat::getAllColorsMask();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PDFTransparencyPainterState
|
struct PDFTransparencyPainterState
|
||||||
|
@ -32,6 +32,7 @@ OutputPreviewDialog::OutputPreviewDialog(const pdf::PDFDocument* document, pdf::
|
|||||||
QDialog(parent, Qt::Dialog | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint),
|
QDialog(parent, Qt::Dialog | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint),
|
||||||
ui(new Ui::OutputPreviewDialog),
|
ui(new Ui::OutputPreviewDialog),
|
||||||
m_inkMapper(document),
|
m_inkMapper(document),
|
||||||
|
m_inkMapperForRendering(document),
|
||||||
m_document(document),
|
m_document(document),
|
||||||
m_widget(widget),
|
m_widget(widget),
|
||||||
m_needUpdateImage(false),
|
m_needUpdateImage(false),
|
||||||
@ -43,8 +44,17 @@ OutputPreviewDialog::OutputPreviewDialog(const pdf::PDFDocument* document, pdf::
|
|||||||
ui->pageIndexScrollBar->setValue(1);
|
ui->pageIndexScrollBar->setValue(1);
|
||||||
ui->pageIndexScrollBar->setMaximum(int(document->getCatalog()->getPageCount()));
|
ui->pageIndexScrollBar->setMaximum(int(document->getCatalog()->getPageCount()));
|
||||||
|
|
||||||
m_inkMapper.createSpotColors(true);
|
m_inkMapper.createSpotColors(ui->simulateSeparationsCheckBox->isChecked());
|
||||||
|
connect(ui->simulateSeparationsCheckBox, &QCheckBox::clicked, this, &OutputPreviewDialog::onSimulateSeparationsChecked);
|
||||||
|
connect(ui->simulatePaperColorCheckBox, &QCheckBox::clicked, this, &OutputPreviewDialog::onSimulatePaperColorChecked);
|
||||||
|
connect(ui->redPaperColorEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &OutputPreviewDialog::onPaperColorChanged);
|
||||||
|
connect(ui->greenPaperColorEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &OutputPreviewDialog::onPaperColorChanged);
|
||||||
|
connect(ui->bluePaperColorEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &OutputPreviewDialog::onPaperColorChanged);
|
||||||
|
connect(ui->inksTreeWidget->model(), &QAbstractItemModel::dataChanged, this, &OutputPreviewDialog::onInksChanged);
|
||||||
|
|
||||||
updatePageImage();
|
updatePageImage();
|
||||||
|
updateInks();
|
||||||
|
updatePaperColorWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputPreviewDialog::~OutputPreviewDialog()
|
OutputPreviewDialog::~OutputPreviewDialog()
|
||||||
@ -73,6 +83,106 @@ void OutputPreviewDialog::showEvent(QShowEvent* event)
|
|||||||
updatePageImage();
|
updatePageImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OutputPreviewDialog::updateInks()
|
||||||
|
{
|
||||||
|
ui->inksTreeWidget->setUpdatesEnabled(false);
|
||||||
|
ui->inksTreeWidget->clear();
|
||||||
|
|
||||||
|
QTreeWidgetItem* processColorsRoot = new QTreeWidgetItem(ui->inksTreeWidget, QStringList(tr("Process Inks")));
|
||||||
|
QTreeWidgetItem* spotColorsRoot = new QTreeWidgetItem(ui->inksTreeWidget, QStringList(tr("Spot Inks")));
|
||||||
|
|
||||||
|
processColorsRoot->setFlags(processColorsRoot->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
processColorsRoot->setCheckState(0, Qt::Checked);
|
||||||
|
|
||||||
|
spotColorsRoot->setFlags(spotColorsRoot->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
spotColorsRoot->setCheckState(0, Qt::Checked);
|
||||||
|
|
||||||
|
int colorIndex = 0;
|
||||||
|
std::vector<pdf::PDFInkMapper::ColorInfo> separations = m_inkMapper.getSeparations(4);
|
||||||
|
for (const auto& colorInfo : separations)
|
||||||
|
{
|
||||||
|
QTreeWidgetItem* item = nullptr;
|
||||||
|
if (!colorInfo.isSpot)
|
||||||
|
{
|
||||||
|
// Process color (ink)
|
||||||
|
item = new QTreeWidgetItem(processColorsRoot, QStringList(colorInfo.textName));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Spot color (ink)
|
||||||
|
item = new QTreeWidgetItem(spotColorsRoot, QStringList(colorInfo.textName));
|
||||||
|
}
|
||||||
|
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(0, Qt::Checked);
|
||||||
|
item->setData(0, Qt::UserRole, colorIndex++);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (processColorsRoot->childCount() == 0)
|
||||||
|
{
|
||||||
|
delete processColorsRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spotColorsRoot->childCount() == 0)
|
||||||
|
{
|
||||||
|
delete spotColorsRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->inksTreeWidget->expandAll();
|
||||||
|
ui->inksTreeWidget->setUpdatesEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputPreviewDialog::updatePaperColorWidgets()
|
||||||
|
{
|
||||||
|
const bool isPaperColorEnabled = ui->simulatePaperColorCheckBox->isChecked();
|
||||||
|
|
||||||
|
ui->redPaperColorEdit->setEnabled(isPaperColorEnabled);
|
||||||
|
ui->greenPaperColorEdit->setEnabled(isPaperColorEnabled);
|
||||||
|
ui->bluePaperColorEdit->setEnabled(isPaperColorEnabled);
|
||||||
|
|
||||||
|
if (!isPaperColorEnabled)
|
||||||
|
{
|
||||||
|
ui->redPaperColorEdit->setValue(1.0);
|
||||||
|
ui->greenPaperColorEdit->setValue(1.0);
|
||||||
|
ui->bluePaperColorEdit->setValue(1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputPreviewDialog::onPaperColorChanged()
|
||||||
|
{
|
||||||
|
const bool isPaperColorEnabled = ui->simulatePaperColorCheckBox->isChecked();
|
||||||
|
if (isPaperColorEnabled)
|
||||||
|
{
|
||||||
|
updatePageImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputPreviewDialog::onSimulateSeparationsChecked(bool checked)
|
||||||
|
{
|
||||||
|
m_inkMapper.setSpotColorsActive(checked);
|
||||||
|
updateInks();
|
||||||
|
updatePageImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputPreviewDialog::onSimulatePaperColorChecked(bool checked)
|
||||||
|
{
|
||||||
|
Q_UNUSED(checked);
|
||||||
|
|
||||||
|
updatePaperColorWidgets();
|
||||||
|
updatePageImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputPreviewDialog::onInksChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles)
|
||||||
|
{
|
||||||
|
Q_UNUSED(topLeft);
|
||||||
|
Q_UNUSED(bottomRight);
|
||||||
|
|
||||||
|
if (roles.contains(Qt::CheckStateRole))
|
||||||
|
{
|
||||||
|
updatePageImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OutputPreviewDialog::updatePageImage()
|
void OutputPreviewDialog::updatePageImage()
|
||||||
{
|
{
|
||||||
if (!isRenderingDone())
|
if (!isRenderingDone())
|
||||||
@ -92,10 +202,46 @@ void OutputPreviewDialog::updatePageImage()
|
|||||||
|
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
|
|
||||||
QSize renderSize = ui->imageLabel->size();
|
pdf::PDFRGB paperColor = pdf::PDFRGB{ 1.0f, 1.0f, 1.0f };
|
||||||
auto renderImage = [this, page, renderSize]() -> RenderedImage
|
|
||||||
|
// Active color mask
|
||||||
|
uint32_t activeColorMask = pdf::PDFPixelFormat::getAllColorsMask();
|
||||||
|
|
||||||
|
const int itemCount = ui->inksTreeWidget->topLevelItemCount();
|
||||||
|
for (int i = 0; i < itemCount; ++i)
|
||||||
{
|
{
|
||||||
return renderPage(page, renderSize);
|
QTreeWidgetItem* rootItem = ui->inksTreeWidget->topLevelItem(i);
|
||||||
|
const bool isRootItemChecked = rootItem->data(0, Qt::CheckStateRole).toInt() == Qt::Checked;
|
||||||
|
|
||||||
|
const int childCount = rootItem->childCount();
|
||||||
|
for (int j = 0; j < childCount; ++j)
|
||||||
|
{
|
||||||
|
QTreeWidgetItem* childItem = rootItem->child(j);
|
||||||
|
const bool isChecked = childItem->data(0, Qt::CheckStateRole).toInt() == Qt::Checked;
|
||||||
|
const bool isEnabled = isRootItemChecked && isChecked;
|
||||||
|
|
||||||
|
if (!isEnabled)
|
||||||
|
{
|
||||||
|
uint32_t colorIndex = childItem->data(0, Qt::UserRole).toInt();
|
||||||
|
uint32_t colorFlags = 1 << colorIndex;
|
||||||
|
activeColorMask = activeColorMask & ~colorFlags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paper color
|
||||||
|
if (ui->simulatePaperColorCheckBox)
|
||||||
|
{
|
||||||
|
paperColor[0] = ui->redPaperColorEdit->value();
|
||||||
|
paperColor[1] = ui->greenPaperColorEdit->value();
|
||||||
|
paperColor[2] = ui->bluePaperColorEdit->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_inkMapperForRendering = m_inkMapper;
|
||||||
|
QSize renderSize = ui->imageLabel->size();
|
||||||
|
auto renderImage = [this, page, renderSize, paperColor, activeColorMask]() -> RenderedImage
|
||||||
|
{
|
||||||
|
return renderPage(page, renderSize, paperColor, activeColorMask);
|
||||||
};
|
};
|
||||||
|
|
||||||
m_future = QtConcurrent::run(renderImage);
|
m_future = QtConcurrent::run(renderImage);
|
||||||
@ -104,7 +250,7 @@ void OutputPreviewDialog::updatePageImage()
|
|||||||
m_futureWatcher->setFuture(m_future);
|
m_futureWatcher->setFuture(m_future);
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputPreviewDialog::RenderedImage OutputPreviewDialog::renderPage(const pdf::PDFPage* page, QSize renderSize)
|
OutputPreviewDialog::RenderedImage OutputPreviewDialog::renderPage(const pdf::PDFPage* page, QSize renderSize, pdf::PDFRGB paperColor, uint32_t activeColorMask)
|
||||||
{
|
{
|
||||||
RenderedImage result;
|
RenderedImage result;
|
||||||
|
|
||||||
@ -125,16 +271,20 @@ OutputPreviewDialog::RenderedImage OutputPreviewDialog::renderPage(const pdf::PD
|
|||||||
settings.flags.setFlag(pdf::PDFTransparencyRendererSettings::MultithreadedPathSampler, true);
|
settings.flags.setFlag(pdf::PDFTransparencyRendererSettings::MultithreadedPathSampler, true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
settings.flags.setFlag(pdf::PDFTransparencyRendererSettings::ActiveColorMask, activeColorMask != pdf::PDFPixelFormat::getAllColorsMask());
|
||||||
|
settings.activeColorMask = activeColorMask;
|
||||||
|
|
||||||
QMatrix pagePointToDevicePoint = pdf::PDFRenderer::createPagePointToDevicePointMatrix(page, QRect(QPoint(0, 0), imageSize));
|
QMatrix pagePointToDevicePoint = pdf::PDFRenderer::createPagePointToDevicePointMatrix(page, QRect(QPoint(0, 0), imageSize));
|
||||||
pdf::PDFDrawWidgetProxy* proxy = m_widget->getDrawWidgetProxy();
|
pdf::PDFDrawWidgetProxy* proxy = m_widget->getDrawWidgetProxy();
|
||||||
pdf::PDFCMSPointer cms = proxy->getCMSManager()->getCurrentCMS();
|
pdf::PDFCMSPointer cms = proxy->getCMSManager()->getCurrentCMS();
|
||||||
pdf::PDFTransparencyRenderer renderer(page, m_document, proxy->getFontCache(), cms.data(), proxy->getOptionalContentActivity(), &m_inkMapper, settings, pagePointToDevicePoint);
|
pdf::PDFTransparencyRenderer renderer(page, m_document, proxy->getFontCache(), cms.data(), proxy->getOptionalContentActivity(),
|
||||||
|
&m_inkMapperForRendering, settings, pagePointToDevicePoint);
|
||||||
|
|
||||||
renderer.beginPaint(imageSize);
|
renderer.beginPaint(imageSize);
|
||||||
renderer.processContents();
|
renderer.processContents();
|
||||||
renderer.endPaint();
|
renderer.endPaint();
|
||||||
|
|
||||||
QImage image = renderer.toImage(false, true, pdf::PDFRGB{ 1.0f, 1.0f, 1.0f });
|
QImage image = renderer.toImage(false, true, paperColor);
|
||||||
|
|
||||||
result.image = qMove(image);
|
result.image = qMove(image);
|
||||||
return result;
|
return result;
|
||||||
@ -162,4 +312,24 @@ bool OutputPreviewDialog::isRenderingDone() const
|
|||||||
return !(m_futureWatcher && m_futureWatcher->isRunning());
|
return !(m_futureWatcher && m_futureWatcher->isRunning());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OutputPreviewDialog::accept()
|
||||||
|
{
|
||||||
|
if (!isRenderingDone())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDialog::accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputPreviewDialog::reject()
|
||||||
|
{
|
||||||
|
if (!isRenderingDone())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDialog::reject();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdfplugin
|
} // namespace pdfplugin
|
||||||
|
@ -46,8 +46,19 @@ public:
|
|||||||
virtual void closeEvent(QCloseEvent* event) override;
|
virtual void closeEvent(QCloseEvent* event) override;
|
||||||
virtual void showEvent(QShowEvent* event) override;
|
virtual void showEvent(QShowEvent* event) override;
|
||||||
|
|
||||||
|
virtual void accept() override;
|
||||||
|
virtual void reject() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void updateInks();
|
||||||
|
void updatePaperColorWidgets();
|
||||||
|
|
||||||
|
void onPaperColorChanged();
|
||||||
|
void onSimulateSeparationsChecked(bool checked);
|
||||||
|
void onSimulatePaperColorChecked(bool checked);
|
||||||
|
void onInksChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles);
|
||||||
|
|
||||||
struct RenderedImage
|
struct RenderedImage
|
||||||
{
|
{
|
||||||
QImage image;
|
QImage image;
|
||||||
@ -55,11 +66,12 @@ private:
|
|||||||
|
|
||||||
void updatePageImage();
|
void updatePageImage();
|
||||||
void onPageImageRendered();
|
void onPageImageRendered();
|
||||||
RenderedImage renderPage(const pdf::PDFPage* page, QSize renderSize);
|
RenderedImage renderPage(const pdf::PDFPage* page, QSize renderSize, pdf::PDFRGB paperColor, uint32_t activeColorMask);
|
||||||
bool isRenderingDone() const;
|
bool isRenderingDone() const;
|
||||||
|
|
||||||
Ui::OutputPreviewDialog* ui;
|
Ui::OutputPreviewDialog* ui;
|
||||||
pdf::PDFInkMapper m_inkMapper;
|
pdf::PDFInkMapper m_inkMapper;
|
||||||
|
pdf::PDFInkMapper m_inkMapperForRendering;
|
||||||
const pdf::PDFDocument* m_document;
|
const pdf::PDFDocument* m_document;
|
||||||
pdf::PDFWidget* m_widget;
|
pdf::PDFWidget* m_widget;
|
||||||
bool m_needUpdateImage;
|
bool m_needUpdateImage;
|
||||||
|
@ -64,6 +64,85 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Settings</string>
|
<string>Settings</string>
|
||||||
</property>
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="redLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Red</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLabel" name="blueLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Blue</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="greenLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Green</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QCheckBox" name="simulateSeparationsCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Simulate separations</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QCheckBox" name="simulatePaperColorCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Simulate paper color</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QDoubleSpinBox" name="redPaperColorEdit">
|
||||||
|
<property name="maximum">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>0.100000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QDoubleSpinBox" name="greenPaperColorEdit">
|
||||||
|
<property name="maximum">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>0.100000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="2">
|
||||||
|
<widget class="QDoubleSpinBox" name="bluePaperColorEdit">
|
||||||
|
<property name="maximum">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>0.100000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -73,7 +152,16 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTreeView" name="treeView"/>
|
<widget class="QTreeWidget" name="inksTreeWidget">
|
||||||
|
<attribute name="headerVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">1</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user