// Copyright (C) 2021 Jakub Melka // // This file is part of Pdf4Qt. // // Pdf4Qt is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Pdf4Qt is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with Pdf4Qt. If not, see . #include "outputpreviewwidget.h" #include "pdfwidgetutils.h" #include #include #include namespace pdfplugin { OutputPreviewWidget::OutputPreviewWidget(QWidget* parent) : BaseClass(parent), m_inkMapper(nullptr), m_displayMode(Separations), m_alarmColor(Qt::red), m_inkCoverageLimit(3.0), m_richBlackLimit(1.0) { setMouseTracking(true); } QSize OutputPreviewWidget::sizeHint() const { return pdf::PDFWidgetUtils::scaleDPI(this, QSize(500, 300)); } QSize OutputPreviewWidget::minimumSizeHint() const { return pdf::PDFWidgetUtils::scaleDPI(this, QSize(400, 300)); } void OutputPreviewWidget::clear() { m_pageImage = QImage(); m_originalProcessBitmap = pdf::PDFFloatBitmapWithColorSpace(); m_pageSizeMM = QSizeF(); m_infoBoxItems.clear(); m_imagePointUnderCursor = std::nullopt; m_inkCoverageMM.dirty(); m_alarmCoverageImage.dirty(); m_alarmRichBlackImage.dirty(); m_inkCoverageImage.dirty(); m_shapeMask.dirty(); m_opacityMask.dirty(); update(); } void OutputPreviewWidget::setPageImage(QImage image, pdf::PDFFloatBitmapWithColorSpace originalProcessBitmap, QSizeF pageSizeMM) { m_pageImage = qMove(image); m_originalProcessBitmap = qMove(originalProcessBitmap); m_pageSizeMM = pageSizeMM; if (m_imagePointUnderCursor.has_value()) { QPoint point = m_imagePointUnderCursor.value(); if (point.x() >= image.width() || point.y() >= image.height()) { m_imagePointUnderCursor = std::nullopt; } } m_inkCoverageMM.dirty(); m_alarmCoverageImage.dirty(); m_alarmRichBlackImage.dirty(); m_inkCoverageImage.dirty(); m_shapeMask.dirty(); m_opacityMask.dirty(); buildInfoBoxItems(); update(); } void OutputPreviewWidget::paintEvent(QPaintEvent* event) { QPainter painter(this); Q_UNUSED(event); QRect rect = this->rect(); painter.fillRect(rect, Qt::gray); QRect contentRect = getContentRect(); QRect pageImageRect = getPageImageRect(contentRect); if (pageImageRect.isValid()) { painter.save(); painter.setClipRect(pageImageRect, Qt::IntersectClip); 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 AlarmImageInfo& alarmImage = getAlarmCoverageImage(); if (!alarmImage.image.isNull()) { painter.translate(0, (pageImageRect.height() - alarmImage.image.height()) / 2); painter.drawImage(pageImageRect.topLeft(), alarmImage.image); } break; } case ColorWarningRichBlack: { const AlarmImageInfo& image = getAlarmRichBlackImage(); if (!image.image.isNull()) { painter.translate(0, (pageImageRect.height() - image.image.height()) / 2); painter.drawImage(pageImageRect.topLeft(), image.image); } break; } case InkCoverage: { const InkCoverageInfo& image = getInkCoverageInfo(); if (!image.image.isNull()) { painter.translate(0, (pageImageRect.height() - image.image.height()) / 2); painter.drawImage(pageImageRect.topLeft(), image.image); } break; } case ShapeChannel: { const QImage& image = getShapeImage(); if (!image.isNull()) { painter.translate(0, (pageImageRect.height() - image.height()) / 2); painter.drawImage(pageImageRect.topLeft(), image); } break; } case OpacityChannel: { const QImage& image = getOpacityImage(); if (!image.isNull()) { painter.translate(0, (pageImageRect.height() - image.height()) / 2); painter.drawImage(pageImageRect.topLeft(), image); } break; } default: Q_ASSERT(false); } painter.restore(); } if (!m_infoBoxItems.empty()) { painter.save(); int infoBoxWidth = getInfoBoxWidth(); int itemHorizontalMargin = getInfoBoxContentHorizontalMargin(); QRect infoBoxRect = contentRect; infoBoxRect.setLeft(infoBoxRect.right() - infoBoxWidth); painter.setPen(Qt::black); painter.setBrush(QBrush(Qt::white)); painter.drawRect(infoBoxRect); painter.setClipRect(infoBoxRect, Qt::IntersectClip); painter.setBrush(Qt::NoBrush); QFontMetrics fontMetrics(painter.font(), painter.device()); QRect rowRect = infoBoxRect; rowRect.setHeight(fontMetrics.lineSpacing()); for (const auto& infoBoxItem : m_infoBoxItems) { switch (infoBoxItem.style) { case pdfplugin::OutputPreviewWidget::Header: { painter.save(); QFont font = painter.font(); font.setBold(true); painter.setFont(font); painter.drawText(rowRect, Qt::AlignCenter | Qt::TextSingleLine, infoBoxItem.caption); painter.restore(); break; } case pdfplugin::OutputPreviewWidget::Separator: break; case pdfplugin::OutputPreviewWidget::ColoredItem: { QRect cellRect = rowRect.marginsRemoved(QMargins(itemHorizontalMargin, 0, itemHorizontalMargin, 0)); if (infoBoxItem.color.isValid()) { QRect ellipseRect = cellRect; ellipseRect.setWidth(ellipseRect.height()); cellRect.setLeft(ellipseRect.right() + 1); painter.save(); painter.setPen(Qt::NoPen); painter.setBrush(QBrush(infoBoxItem.color)); painter.drawEllipse(ellipseRect); painter.restore(); } painter.drawText(cellRect, Qt::AlignVCenter | Qt::AlignLeft | Qt::TextSingleLine, infoBoxItem.caption); painter.drawText(cellRect, Qt::AlignVCenter | Qt::AlignRight | Qt::TextSingleLine, infoBoxItem.value); break; } case pdfplugin::OutputPreviewWidget::ColorOnly: { QRect cellRect = rowRect.marginsRemoved(QMargins(itemHorizontalMargin, 0, itemHorizontalMargin, 0)); QPoint center = cellRect.center(); cellRect.setWidth(cellRect.width() / 4); cellRect.moveCenter(center); painter.fillRect(cellRect, infoBoxItem.color); break; } default: Q_ASSERT(false); break; } rowRect.translate(0, rowRect.height()); } rowRect.translate(0, rowRect.height()); painter.restore(); if (m_displayMode == InkCoverage) { const InkCoverageInfo& info = getInkCoverageInfo(); if (info.colorScale.isValid()) { painter.save(); int rowHeight = rowRect.height(); QRect colorScaleRect = rowRect; colorScaleRect.setBottom(contentRect.bottom()); const int maxRows = colorScaleRect.height() / rowHeight; int rows = maxRows; if (rows > 6) { painter.save(); QFont font = painter.font(); font.setBold(true); painter.setFont(font); painter.drawText(rowRect, Qt::AlignCenter | Qt::TextSingleLine, tr("Distribution")); rowRect.translate(0, rowRect.height()); colorScaleRect.setTop(rowRect.top()); painter.restore(); --rows; const pdf::PDFColorScale& colorScale = info.colorScale; pdf::PDFLinearInterpolation interpolation(0, rows - 1, colorScale.getMax(), colorScale.getMin()); QRect colorRect = colorScaleRect; colorRect.setLeft(colorScaleRect.left() + colorScaleRect.width() / 3); colorRect.setWidth(colorScaleRect.width() / 3); colorRect.setHeight(rowHeight); colorRect.translate(0, rowHeight / 2); QRect textRect = rowRect; textRect.setLeft(colorRect.right() + colorRect.height() / 2); QLocale locale; qreal colorScaleTop = colorRect.top(); qreal colorScaleBottom = colorRect.bottom(); for (int i = 0; i < rows; ++i) { if (i < rows - 1) { QLinearGradient gradient(0, colorRect.top(), 0, colorRect.bottom()); gradient.setColorAt(0, colorScale.map(interpolation(i))); gradient.setColorAt(1, colorScale.map(interpolation(i + 1))); painter.setPen(Qt::NoPen); painter.setBrush(QBrush(gradient)); painter.drawRect(colorRect); colorScaleBottom = colorRect.bottom(); } pdf::PDFReal value = interpolation(i) * 100.0; QPointF point2 = (textRect.topLeft() + textRect.bottomLeft()) * 0.5; point2.rx() -= rowHeight / 4; QPointF point1 = point2; point1.rx() -= rowHeight / 4; painter.setPen(Qt::black); painter.drawLine(point1, point2); painter.drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft | Qt::TextSingleLine, QString("%1 %").arg(locale.toString(value, 'f', 2))); colorRect.translate(0, colorRect.height()); textRect.translate(0, textRect.height()); } if (m_imagePointUnderCursor.has_value()) { pdf::PDFLinearInterpolation inverseInterpolation(colorScale.getMax(), colorScale.getMin(), colorScaleTop, colorScaleBottom); pdf::PDFColorComponent coverage = m_originalProcessBitmap.getPixelInkCoverage(m_imagePointUnderCursor->x(), m_imagePointUnderCursor->y()); qreal yCoordinate = inverseInterpolation(coverage); const int triangleRight = colorRect.left(); const int triangleLeft = triangleRight - colorRect.height(); const int halfHeight = (triangleRight - triangleLeft) * 0.5; QPolygonF triangle; triangle << QPointF(triangleLeft, yCoordinate - halfHeight); triangle << QPointF(triangleRight, yCoordinate); triangle << QPointF(triangleLeft, yCoordinate + halfHeight); painter.setPen(Qt::NoPen); painter.setBrush(QBrush(Qt::red)); painter.drawConvexPolygon(triangle); QString textCoverage = QString("%1 %").arg(locale.toString(coverage * 100.0, 'f', 2)); const int textRight = triangleLeft - rowHeight / 4; const int textWidth = painter.fontMetrics().width(textCoverage); const int textStart = textRight - textWidth; QRect textRect(textStart, yCoordinate - halfHeight, textWidth + 1, rowHeight); painter.setPen(Qt::black); painter.drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft | Qt::TextSingleLine, textCoverage); } } painter.restore(); } } } } QMargins OutputPreviewWidget::getDrawMargins() const { const int horizontalMargin = pdf::PDFWidgetUtils::scaleDPI_x(this, 5); const int verticalMargin = pdf::PDFWidgetUtils::scaleDPI_y(this, 5); return QMargins(horizontalMargin, verticalMargin, horizontalMargin, verticalMargin); } QRect OutputPreviewWidget::getContentRect() const { QRect rect = this->rect(); QRect contentRect = rect.marginsRemoved(getDrawMargins()); return contentRect; } QRect OutputPreviewWidget::getPageImageRect(QRect contentRect) const { int infoBoxWidth = getInfoBoxWidth(); if (infoBoxWidth > 0) { infoBoxWidth += pdf::PDFWidgetUtils::scaleDPI_x(this, 5); } contentRect.setRight(contentRect.right() - infoBoxWidth); return contentRect; } int OutputPreviewWidget::getInfoBoxWidth() const { if (m_infoBoxItems.empty()) { return 0; } return pdf::PDFWidgetUtils::scaleDPI_x(this, 200); } int OutputPreviewWidget::getInfoBoxContentHorizontalMargin() const { return pdf::PDFWidgetUtils::scaleDPI_x(this, 5); } void OutputPreviewWidget::buildInfoBoxItems() { m_infoBoxItems.clear(); QColor sampleColor; switch (m_displayMode) { case Separations: case ColorWarningInkCoverage: case ColorWarningRichBlack: case InkCoverage: { if (m_originalProcessBitmap.getWidth() > 0 && m_originalProcessBitmap.getHeight() > 0) { const pdf::PDFPixelFormat pixelFormat = m_originalProcessBitmap.getPixelFormat(); std::vector separations = m_inkMapper->getSeparations(pixelFormat.getProcessColorChannelCount(), true); QStringList colorValues; colorValues.reserve(pixelFormat.getColorChannelCount()); Q_ASSERT(pixelFormat.getColorChannelCount() == separations.size()); std::vector inkColors; if (m_imagePointUnderCursor.has_value()) { QPoint point = m_imagePointUnderCursor.value(); Q_ASSERT(point.x() >= 0); Q_ASSERT(point.x() < m_originalProcessBitmap.getWidth()); Q_ASSERT(point.y() >= 0); Q_ASSERT(point.y() < m_originalProcessBitmap.getHeight()); pdf::PDFColorBuffer buffer = m_originalProcessBitmap.getPixel(point.x(), point.y()); for (int i = 0; i < pixelFormat.getColorChannelCount(); ++i) { const pdf::PDFColorComponent color = buffer[i] * 100.0f; const int percent = qRound(color); colorValues << QString("%1 %").arg(percent); QColor inkColor = separations[i].color; if (inkColor.isValid()) { inkColor.setAlphaF(buffer[i]); inkColors.push_back(inkColor); } } Q_ASSERT(point.x() >= 0); Q_ASSERT(point.x() < m_pageImage.width()); Q_ASSERT(point.y() >= 0); Q_ASSERT(point.y() < m_pageImage.height()); sampleColor = m_pageImage.pixelColor(point); } else { for (int i = 0; i < pixelFormat.getColorChannelCount(); ++i) { colorValues << QString(); } } // Count process/spot inks int processInks = 0; int spotInks = 0; for (const auto& colorInfo : separations) { if (!colorInfo.isSpot) { ++processInks; } else { ++spotInks; } } int colorValueIndex = 0; if (processInks > 0) { addInfoBoxSeparator(); addInfoBoxHeader(tr("Process Inks")); for (const auto& colorInfo : separations) { if (colorInfo.isSpot) { continue; } addInfoBoxColoredItem(colorInfo.color, colorInfo.textName, colorValues[colorValueIndex++]); } } if (spotInks > 0) { addInfoBoxSeparator(); addInfoBoxHeader(tr("Spot Inks")); for (const auto& colorInfo : separations) { if (!colorInfo.isSpot) { continue; } addInfoBoxColoredItem(colorInfo.color, colorInfo.textName, colorValues[colorValueIndex++]); } } } break; } case ShapeChannel: case OpacityChannel: break; default: Q_ASSERT(false); break; } if (m_displayMode == ColorWarningInkCoverage) { addInfoBoxSeparator(); addInfoBoxHeader(tr("Warning | Ink Coverage")); QLocale locale; const auto& alarmImage = getAlarmCoverageImage(); addInfoBoxColoredItem(Qt::green, tr("OK"), QString("%1 mm²").arg(locale.toString(alarmImage.areaValid, 'f', 2))); addInfoBoxColoredItem(Qt::red, tr("Failure"), QString("%1 mm²").arg(locale.toString(alarmImage.areaInvalid, 'f', 2))); } if (m_displayMode == ColorWarningRichBlack) { addInfoBoxSeparator(); addInfoBoxHeader(tr("Warning | Rich Black")); QLocale locale; const auto& alarmImage = getAlarmRichBlackImage(); addInfoBoxColoredItem(Qt::green, tr("OK"), QString("%1 mm²").arg(locale.toString(alarmImage.areaValid, 'f', 2))); addInfoBoxColoredItem(Qt::red, tr("Failure"), QString("%1 mm²").arg(locale.toString(alarmImage.areaInvalid, 'f', 2))); } if (m_displayMode == Separations || m_displayMode == InkCoverage) { if (m_originalProcessBitmap.getWidth() > 0 && m_originalProcessBitmap.getHeight() > 0) { const pdf::PDFPixelFormat pixelFormat = m_originalProcessBitmap.getPixelFormat(); std::vector separations = m_inkMapper->getSeparations(pixelFormat.getProcessColorChannelCount(), true); const std::vector& inkCoverage = getInkCoverage(); if (!inkCoverage.empty() && inkCoverage.size() == separations.size()) { addInfoBoxSeparator(); addInfoBoxHeader(tr("Ink Coverage")); QLocale locale; for (size_t i = 0; i < inkCoverage.size(); ++i) { const pdf::PDFColorComponent area = inkCoverage[i]; const QColor separationColor = separations[i].color; const QString& name = separations[i].textName; addInfoBoxColoredItem(separationColor, name, QString("%1 mm²").arg(locale.toString(area, 'f', 2))); } } } } if (m_displayMode == ShapeChannel || m_displayMode == OpacityChannel) { addInfoBoxSeparator(); addInfoBoxHeader(tr("Shape/Opacity")); } if (sampleColor.isValid()) { addInfoBoxSeparator(); addInfoBoxHeader(tr("Sample Color")); addInfoBoxColoredRect(sampleColor); } } void OutputPreviewWidget::addInfoBoxHeader(QString caption) { m_infoBoxItems.push_back(InfoBoxItem(Header, QColor(), caption, QString())); } void OutputPreviewWidget::addInfoBoxSeparator() { if (!m_infoBoxItems.empty()) { m_infoBoxItems.push_back(InfoBoxItem(Separator, QColor(), QString(), QString())); } } void OutputPreviewWidget::addInfoBoxColoredItem(QColor color, QString caption, QString value) { m_infoBoxItems.push_back(InfoBoxItem(ColoredItem, color, caption, value)); } void OutputPreviewWidget::addInfoBoxColoredRect(QColor color) { m_infoBoxItems.push_back(InfoBoxItem(ColorOnly, color, QString(), QString())); } const std::vector& OutputPreviewWidget::getInkCoverage() const { return m_inkCoverageMM.get(this, &OutputPreviewWidget::getInkCoverageImpl); } const OutputPreviewWidget::AlarmImageInfo& OutputPreviewWidget::getAlarmCoverageImage() const { return m_alarmCoverageImage.get(this, &OutputPreviewWidget::getAlarmCoverageImageImpl); } const OutputPreviewWidget::AlarmImageInfo& OutputPreviewWidget::getAlarmRichBlackImage() const { return m_alarmRichBlackImage.get(this, &OutputPreviewWidget::getAlarmRichBlackImageImpl); } const OutputPreviewWidget::InkCoverageInfo& OutputPreviewWidget::getInkCoverageInfo() const { return m_inkCoverageImage.get(this, &OutputPreviewWidget::getInkCoverageInfoImpl); } const QImage& OutputPreviewWidget::getShapeImage() const { return m_shapeMask.get(this, &OutputPreviewWidget::getShapeImageImpl); } const QImage& OutputPreviewWidget::getOpacityImage() const { return m_opacityMask.get(this, &OutputPreviewWidget::getOpacityImageImpl); } std::vector OutputPreviewWidget::getInkCoverageImpl() const { std::vector result; if (m_originalProcessBitmap.getWidth() > 0 && m_originalProcessBitmap.getHeight() > 0) { pdf::PDFPixelFormat pixelFormat = m_originalProcessBitmap.getPixelFormat(); pdf::PDFColorComponent totalArea = m_pageSizeMM.width() * m_pageSizeMM.height(); pdf::PDFColorComponent pixelArea = totalArea / pdf::PDFColorComponent(m_originalProcessBitmap.getWidth() * m_originalProcessBitmap.getHeight()); const uint8_t colorChannelCount = pixelFormat.getColorChannelCount(); result.resize(colorChannelCount, 0.0f); for (size_t y = 0; y < m_originalProcessBitmap.getHeight(); ++y) { for (size_t x = 0; x < m_originalProcessBitmap.getWidth(); ++x) { const pdf::PDFConstColorBuffer buffer = m_originalProcessBitmap.getPixel(x, y); const pdf::PDFColorComponent alpha = pixelFormat.hasOpacityChannel() ? buffer[pixelFormat.getOpacityChannelIndex()] : 1.0f; for (uint8_t i = 0; i < colorChannelCount; ++i) { result[i] += buffer[i] * alpha; } } } for (uint8_t i = 0; i < colorChannelCount; ++i) { result[i] *= pixelArea; } } return result; } OutputPreviewWidget::AlarmImageInfo OutputPreviewWidget::getAlarmCoverageImageImpl() const { AlarmImageInfo alarmImage; alarmImage.image = m_pageImage; alarmImage.areaValid = 0.0f; alarmImage.areaInvalid = 0.0f; const int width = alarmImage.image.width(); const int height = alarmImage.image.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.areaInvalid += 1.0f; alarmImage.image.setPixelColor(x, y, m_alarmColor); } else if (!qFuzzyIsNull(inkCoverage)) { alarmImage.areaValid += 1.0f; } } } if (width > 0 && height > 0) { const pdf::PDFColorComponent factor = m_pageSizeMM.width() * m_pageSizeMM.height() / (pdf::PDFColorComponent(width) * pdf::PDFColorComponent(height)); alarmImage.areaValid *= factor; alarmImage.areaInvalid *= factor; } return alarmImage; } OutputPreviewWidget::AlarmImageInfo OutputPreviewWidget::getAlarmRichBlackImageImpl() const { AlarmImageInfo alarmImage; alarmImage.image = m_pageImage; alarmImage.areaValid = 0.0f; alarmImage.areaInvalid = 0.0f; const pdf::PDFPixelFormat pixelFormat = m_originalProcessBitmap.getPixelFormat(); if (pixelFormat.getProcessColorChannelCount() == 4) { const int width = alarmImage.image.width(); const int height = alarmImage.image.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]; pdf::PDFColorComponent inkCoverage = m_originalProcessBitmap.getPixelInkCoverage(x, y); pdf::PDFColorComponent inkCoverageWithoutBlack = inkCoverage - blackInk; if (blackInk > m_richBlackLimit && !qFuzzyIsNull(inkCoverageWithoutBlack)) { alarmImage.areaInvalid += 1.0f; alarmImage.image.setPixelColor(x, y, m_alarmColor); } else if (!qFuzzyIsNull(inkCoverage)) { alarmImage.areaValid += 1.0f; } } } if (width > 0 && height > 0) { const pdf::PDFColorComponent factor = m_pageSizeMM.width() * m_pageSizeMM.height() / (pdf::PDFColorComponent(width) * pdf::PDFColorComponent(height)); alarmImage.areaValid *= factor; alarmImage.areaInvalid *= factor; } } return alarmImage; } OutputPreviewWidget::InkCoverageInfo OutputPreviewWidget::getInkCoverageInfoImpl() const { InkCoverageInfo coverageInfo; coverageInfo.minValue = 0.0f; coverageInfo.maxValue = 1.0f; pdf::PDFFloatBitmap inkCoverageBitmap = m_originalProcessBitmap.getInkCoverageBitmap(); int width = int(inkCoverageBitmap.getWidth()); int height = int(inkCoverageBitmap.getHeight()); if (width > 0 && height > 0) { for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { pdf::PDFColorBuffer buffer = inkCoverageBitmap.getPixel(x, y); const pdf::PDFColorComponent coverage = buffer[0]; coverageInfo.maxValue = qMax(coverage, coverageInfo.maxValue); } } coverageInfo.colorScale = pdf::PDFColorScale(coverageInfo.minValue, coverageInfo.maxValue); coverageInfo.image = QImage(width, height, QImage::Format_RGBX8888); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { pdf::PDFColorBuffer buffer = inkCoverageBitmap.getPixel(x, y); const pdf::PDFColorComponent coverage = buffer[0]; coverageInfo.image.setPixelColor(x, y, coverageInfo.colorScale.map(coverage)); } } } return coverageInfo; } QImage OutputPreviewWidget::getShapeImageImpl() const { if (!m_originalProcessBitmap.getPixelFormat().hasShapeChannel()) { return QImage(); } return m_originalProcessBitmap.getChannelImage(m_originalProcessBitmap.getPixelFormat().getShapeChannelIndex()); } QImage OutputPreviewWidget::getOpacityImageImpl() const { if (!m_originalProcessBitmap.getPixelFormat().hasOpacityChannel()) { return QImage(); } return m_originalProcessBitmap.getChannelImage(m_originalProcessBitmap.getPixelFormat().getOpacityChannelIndex()); } 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; } void OutputPreviewWidget::setAlarmColor(const QColor& alarmColor) { if (m_alarmColor != alarmColor) { m_alarmColor = alarmColor; m_alarmCoverageImage.dirty(); m_alarmRichBlackImage.dirty(); update(); } } const pdf::PDFInkMapper* OutputPreviewWidget::getInkMapper() const { return m_inkMapper; } void OutputPreviewWidget::setInkMapper(const pdf::PDFInkMapper* inkMapper) { m_inkMapper = inkMapper; } QSize OutputPreviewWidget::getPageImageSizeHint() const { return getPageImageRect(getContentRect()).size(); } void OutputPreviewWidget::mouseMoveEvent(QMouseEvent* event) { m_imagePointUnderCursor = std::nullopt; if (m_pageImage.isNull()) { // Nothing to do... return; } QPoint position = event->pos(); QRect rect = getPageImageRect(getContentRect()); if (rect.contains(position)) { int verticalImageOffset = (rect.height() - m_pageImage.height()) / 2; QPoint imagePoint = position - rect.topLeft() - QPoint(0, verticalImageOffset); if (imagePoint.x() >= 0 && imagePoint.x() < m_pageImage.width() && imagePoint.y() >= 0 && imagePoint.y() < m_pageImage.height()) { m_imagePointUnderCursor = imagePoint; } } buildInfoBoxItems(); update(); } } // pdfplugin