mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-01-27 23:59:23 +01:00
Color Warnings (ink coverage + rich black)
This commit is contained in:
parent
fb6de717f6
commit
7ca5942fb6
@ -74,6 +74,22 @@ PDFColorBuffer PDFFloatBitmap::getPixels()
|
||||
return PDFColorBuffer(m_data.data(), m_data.size());
|
||||
}
|
||||
|
||||
PDFColorComponent PDFFloatBitmap::getPixelInkCoverage(size_t x, size_t y) const
|
||||
{
|
||||
PDFConstColorBuffer buffer = getPixel(x, y);
|
||||
|
||||
const uint8_t colorChannelIndexStart = m_format.getColorChannelIndexStart();
|
||||
const uint8_t colorChannelIndexEnd = m_format.getColorChannelIndexEnd();
|
||||
|
||||
PDFColorComponent inkCoverage = 0.0;
|
||||
for (uint8_t i = colorChannelIndexStart; i < colorChannelIndexEnd; ++i)
|
||||
{
|
||||
inkCoverage += buffer[i];
|
||||
}
|
||||
|
||||
return inkCoverage;
|
||||
}
|
||||
|
||||
const PDFColorComponent* PDFFloatBitmap::begin() const
|
||||
{
|
||||
return m_data.data();
|
||||
|
@ -157,6 +157,9 @@ public:
|
||||
/// Returns buffer with all pixels
|
||||
PDFColorBuffer getPixels();
|
||||
|
||||
/// Returns ink coverage
|
||||
PDFColorComponent getPixelInkCoverage(size_t x, size_t y) const;
|
||||
|
||||
const PDFColorComponent* begin() const;
|
||||
const PDFColorComponent* end() const;
|
||||
|
||||
|
@ -69,11 +69,17 @@ OutputPreviewDialog::OutputPreviewDialog(const pdf::PDFDocument* document, pdf::
|
||||
connect(ui->displayVectorGraphicsCheckBox, &QCheckBox::clicked, this, &OutputPreviewDialog::updatePageImage);
|
||||
connect(ui->inksTreeWidget->model(), &QAbstractItemModel::dataChanged, this, &OutputPreviewDialog::onInksChanged);
|
||||
connect(ui->alarmColorButton, &QPushButton::clicked, this, &OutputPreviewDialog::onAlarmColorButtonClicked);
|
||||
connect(ui->displayModeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &OutputPreviewDialog::onDisplayModeChanged);
|
||||
connect(ui->inkCoverageLimitEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &OutputPreviewDialog::onInkCoverageLimitChanged);
|
||||
connect(ui->richBlackLimitEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &OutputPreviewDialog::onRichBlackLimtiChanged);
|
||||
|
||||
updatePageImage();
|
||||
updateInks();
|
||||
updatePaperColorWidgets();
|
||||
updateAlarmColorButtonIcon();
|
||||
onDisplayModeChanged();
|
||||
onInkCoverageLimitChanged(ui->inkCoverageLimitEdit->value());
|
||||
onRichBlackLimtiChanged(ui->richBlackLimitEdit->value());
|
||||
}
|
||||
|
||||
OutputPreviewDialog::~OutputPreviewDialog()
|
||||
@ -220,6 +226,11 @@ void OutputPreviewDialog::onSimulatePaperColorChecked(bool checked)
|
||||
updatePageImage();
|
||||
}
|
||||
|
||||
void OutputPreviewDialog::onDisplayModeChanged()
|
||||
{
|
||||
ui->imageWidget->setDisplayMode(OutputPreviewWidget::DisplayMode(ui->displayModeComboBox->currentData().toInt()));
|
||||
}
|
||||
|
||||
void OutputPreviewDialog::onInksChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles)
|
||||
{
|
||||
Q_UNUSED(topLeft);
|
||||
@ -231,6 +242,16 @@ void OutputPreviewDialog::onInksChanged(const QModelIndex& topLeft, const QModel
|
||||
}
|
||||
}
|
||||
|
||||
void OutputPreviewDialog::onInkCoverageLimitChanged(double value)
|
||||
{
|
||||
ui->imageWidget->setInkCoverageLimit(value / 100.0);
|
||||
}
|
||||
|
||||
void OutputPreviewDialog::onRichBlackLimtiChanged(double value)
|
||||
{
|
||||
ui->imageWidget->setRichBlackLimit(value / 100.0);
|
||||
}
|
||||
|
||||
void OutputPreviewDialog::updatePageImage()
|
||||
{
|
||||
if (!isRenderingDone())
|
||||
|
@ -59,7 +59,10 @@ private:
|
||||
void onAlarmColorButtonClicked();
|
||||
void onSimulateSeparationsChecked(bool checked);
|
||||
void onSimulatePaperColorChecked(bool checked);
|
||||
void onDisplayModeChanged();
|
||||
void onInksChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles);
|
||||
void onInkCoverageLimitChanged(double value);
|
||||
void onRichBlackLimtiChanged(double value);
|
||||
|
||||
struct RenderedImage
|
||||
{
|
||||
|
@ -30,7 +30,9 @@ OutputPreviewWidget::OutputPreviewWidget(QWidget* parent) :
|
||||
BaseClass(parent),
|
||||
m_inkMapper(nullptr),
|
||||
m_displayMode(Separations),
|
||||
m_alarmColor(Qt::red)
|
||||
m_alarmColor(Qt::red),
|
||||
m_inkCoverageLimit(3.0),
|
||||
m_richBlackLimit(1.0)
|
||||
{
|
||||
setMouseTracking(true);
|
||||
}
|
||||
@ -53,6 +55,8 @@ void OutputPreviewWidget::clear()
|
||||
m_infoBoxItems.clear();
|
||||
m_imagePointUnderCursor = std::nullopt;
|
||||
m_inkCoverageMM.dirty();
|
||||
m_alarmCoverageImage.dirty();
|
||||
m_alarmRichBlackImage.dirty();
|
||||
update();
|
||||
}
|
||||
|
||||
@ -72,6 +76,8 @@ void OutputPreviewWidget::setPageImage(QImage image, pdf::PDFFloatBitmapWithColo
|
||||
}
|
||||
|
||||
m_inkCoverageMM.dirty();
|
||||
m_alarmCoverageImage.dirty();
|
||||
m_alarmRichBlackImage.dirty();
|
||||
|
||||
buildInfoBoxItems();
|
||||
update();
|
||||
@ -89,12 +95,52 @@ void OutputPreviewWidget::paintEvent(QPaintEvent* event)
|
||||
QRect contentRect = getContentRect();
|
||||
QRect pageImageRect = getPageImageRect(contentRect);
|
||||
|
||||
if (pageImageRect.isValid() && !m_pageImage.isNull())
|
||||
if (pageImageRect.isValid())
|
||||
{
|
||||
painter.save();
|
||||
painter.setClipRect(pageImageRect, Qt::IntersectClip);
|
||||
painter.translate(0, (pageImageRect.height() - m_pageImage.height()) / 2);
|
||||
painter.drawImage(pageImageRect.topLeft(), m_pageImage);
|
||||
|
||||
switch (m_displayMode)
|
||||
{
|
||||
case Separations:
|
||||
{
|
||||
if (!m_pageImage.isNull())
|
||||
{
|
||||
painter.translate(0, (pageImageRect.height() - m_pageImage.height()) / 2);
|
||||
painter.drawImage(pageImageRect.topLeft(), m_pageImage);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ColorWarningInkCoverage:
|
||||
{
|
||||
const QImage& image = getAlarmCoverageImage();
|
||||
if (!image.isNull())
|
||||
{
|
||||
painter.translate(0, (pageImageRect.height() - image.height()) / 2);
|
||||
painter.drawImage(pageImageRect.topLeft(), image);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ColorWarningRichBlack:
|
||||
{
|
||||
const QImage& image = getAlarmRichBlackImage();
|
||||
if (!image.isNull())
|
||||
{
|
||||
painter.translate(0, (pageImageRect.height() - image.height()) / 2);
|
||||
painter.drawImage(pageImageRect.topLeft(), image);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case InkCoverage:
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
painter.restore();
|
||||
}
|
||||
|
||||
@ -411,6 +457,16 @@ const std::vector<pdf::PDFColorComponent>& OutputPreviewWidget::getInkCoverage()
|
||||
return m_inkCoverageMM.get(this, &OutputPreviewWidget::getInkCoverageImpl);
|
||||
}
|
||||
|
||||
const QImage& OutputPreviewWidget::getAlarmCoverageImage() const
|
||||
{
|
||||
return m_alarmCoverageImage.get(this, &OutputPreviewWidget::getAlarmCoverageImageImpl);
|
||||
}
|
||||
|
||||
const QImage& OutputPreviewWidget::getAlarmRichBlackImage() const
|
||||
{
|
||||
return m_alarmRichBlackImage.get(this, &OutputPreviewWidget::getAlarmRichBlackImageImpl);
|
||||
}
|
||||
|
||||
std::vector<pdf::PDFColorComponent> OutputPreviewWidget::getInkCoverageImpl() const
|
||||
{
|
||||
std::vector<pdf::PDFColorComponent> result;
|
||||
@ -447,6 +503,111 @@ std::vector<pdf::PDFColorComponent> OutputPreviewWidget::getInkCoverageImpl() co
|
||||
return result;
|
||||
}
|
||||
|
||||
QImage OutputPreviewWidget::getAlarmCoverageImageImpl() const
|
||||
{
|
||||
QImage alarmImage = m_pageImage;
|
||||
|
||||
const int width = alarmImage.width();
|
||||
const int height = alarmImage.height();
|
||||
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
for (int x = 0; x < width; ++x)
|
||||
{
|
||||
pdf::PDFColorComponent inkCoverage = m_originalProcessBitmap.getPixelInkCoverage(x, y);
|
||||
if (inkCoverage > m_inkCoverageLimit)
|
||||
{
|
||||
alarmImage.setPixelColor(x, y, m_alarmColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return alarmImage;
|
||||
}
|
||||
|
||||
QImage OutputPreviewWidget::getAlarmRichBlackImageImpl() const
|
||||
{
|
||||
QImage alarmImage = m_pageImage;
|
||||
|
||||
const pdf::PDFPixelFormat pixelFormat = m_originalProcessBitmap.getPixelFormat();
|
||||
if (pixelFormat.getProcessColorChannelCount() == 4)
|
||||
{
|
||||
const int width = alarmImage.width();
|
||||
const int height = alarmImage.height();
|
||||
|
||||
const uint8_t blackChannelIndex = pixelFormat.getProcessColorChannelIndexStart() + 3;
|
||||
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
for (int x = 0; x < width; ++x)
|
||||
{
|
||||
pdf::PDFConstColorBuffer buffer = m_originalProcessBitmap.getPixel(x, y);
|
||||
pdf::PDFColorComponent blackInk = buffer[blackChannelIndex];
|
||||
|
||||
if (blackInk > m_richBlackLimit)
|
||||
{
|
||||
pdf::PDFColorComponent inkCoverage = m_originalProcessBitmap.getPixelInkCoverage(x, y);
|
||||
pdf::PDFColorComponent inkCoverageWithoutBlack = inkCoverage - blackInk;
|
||||
|
||||
if (!qFuzzyIsNull(inkCoverageWithoutBlack))
|
||||
{
|
||||
alarmImage.setPixelColor(x, y, m_alarmColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return alarmImage;
|
||||
}
|
||||
|
||||
pdf::PDFColorComponent OutputPreviewWidget::getRichBlackLimit() const
|
||||
{
|
||||
return m_richBlackLimit;
|
||||
}
|
||||
|
||||
void OutputPreviewWidget::setRichBlackLimit(pdf::PDFColorComponent richBlackLimit)
|
||||
{
|
||||
if (m_richBlackLimit != richBlackLimit)
|
||||
{
|
||||
m_richBlackLimit = richBlackLimit;
|
||||
m_alarmRichBlackImage.dirty();
|
||||
buildInfoBoxItems();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
pdf::PDFColorComponent OutputPreviewWidget::getInkCoverageLimit() const
|
||||
{
|
||||
return m_inkCoverageLimit;
|
||||
}
|
||||
|
||||
void OutputPreviewWidget::setInkCoverageLimit(pdf::PDFColorComponent inkCoverageLimit)
|
||||
{
|
||||
if (m_inkCoverageLimit != inkCoverageLimit)
|
||||
{
|
||||
m_inkCoverageLimit = inkCoverageLimit;
|
||||
m_alarmCoverageImage.dirty();
|
||||
buildInfoBoxItems();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
OutputPreviewWidget::DisplayMode OutputPreviewWidget::getDisplayMode() const
|
||||
{
|
||||
return m_displayMode;
|
||||
}
|
||||
|
||||
void OutputPreviewWidget::setDisplayMode(const DisplayMode& displayMode)
|
||||
{
|
||||
if (m_displayMode != displayMode)
|
||||
{
|
||||
m_displayMode = displayMode;
|
||||
buildInfoBoxItems();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
QColor OutputPreviewWidget::getAlarmColor() const
|
||||
{
|
||||
return m_alarmColor;
|
||||
@ -454,7 +615,13 @@ QColor OutputPreviewWidget::getAlarmColor() const
|
||||
|
||||
void OutputPreviewWidget::setAlarmColor(const QColor& alarmColor)
|
||||
{
|
||||
m_alarmColor = alarmColor;
|
||||
if (m_alarmColor != alarmColor)
|
||||
{
|
||||
m_alarmColor = alarmColor;
|
||||
m_alarmCoverageImage.dirty();
|
||||
m_alarmRichBlackImage.dirty();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
const pdf::PDFInkMapper* OutputPreviewWidget::getInkMapper() const
|
||||
|
@ -61,6 +61,15 @@ public:
|
||||
QColor getAlarmColor() const;
|
||||
void setAlarmColor(const QColor& alarmColor);
|
||||
|
||||
DisplayMode getDisplayMode() const;
|
||||
void setDisplayMode(const DisplayMode& displayMode);
|
||||
|
||||
pdf::PDFColorComponent getInkCoverageLimit() const;
|
||||
void setInkCoverageLimit(pdf::PDFColorComponent inkCoverageLimit);
|
||||
|
||||
pdf::PDFColorComponent getRichBlackLimit() const;
|
||||
void setRichBlackLimit(pdf::PDFColorComponent richBlackLimit);
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent* event) override;
|
||||
virtual void mouseMoveEvent(QMouseEvent* event) override;
|
||||
@ -80,8 +89,12 @@ private:
|
||||
void addInfoBoxColoredRect(QColor color);
|
||||
|
||||
const std::vector<pdf::PDFColorComponent>& getInkCoverage() const;
|
||||
const QImage& getAlarmCoverageImage() const;
|
||||
const QImage& getAlarmRichBlackImage() const;
|
||||
|
||||
std::vector<pdf::PDFColorComponent> getInkCoverageImpl() const;
|
||||
QImage getAlarmCoverageImageImpl() const;
|
||||
QImage getAlarmRichBlackImageImpl() const;
|
||||
|
||||
enum InfoBoxStyle
|
||||
{
|
||||
@ -113,8 +126,12 @@ private:
|
||||
std::vector<InfoBoxItem> m_infoBoxItems;
|
||||
QColor m_alarmColor;
|
||||
std::optional<QPoint> m_imagePointUnderCursor;
|
||||
pdf::PDFColorComponent m_inkCoverageLimit;
|
||||
pdf::PDFColorComponent m_richBlackLimit;
|
||||
|
||||
mutable pdf::PDFCachedItem<std::vector<pdf::PDFColorComponent>> m_inkCoverageMM;
|
||||
mutable pdf::PDFCachedItem<QImage> m_alarmCoverageImage;
|
||||
mutable pdf::PDFCachedItem<QImage> m_alarmRichBlackImage;
|
||||
|
||||
QImage m_pageImage;
|
||||
pdf::PDFFloatBitmapWithColorSpace m_originalProcessBitmap;
|
||||
|
Loading…
x
Reference in New Issue
Block a user