diff --git a/Pdf4QtLib/sources/pdfutils.cpp b/Pdf4QtLib/sources/pdfutils.cpp index 89f8795..cc73211 100644 --- a/Pdf4QtLib/sources/pdfutils.cpp +++ b/Pdf4QtLib/sources/pdfutils.cpp @@ -518,6 +518,13 @@ QString PDFSysUtils::getUserName() return userName; } +PDFColorScale::PDFColorScale() : + m_min(0.0), + m_max(0.0) +{ + +} + PDFColorScale::PDFColorScale(PDFReal min, PDFReal max) : m_min(min), m_max(max) diff --git a/Pdf4QtLib/sources/pdfutils.h b/Pdf4QtLib/sources/pdfutils.h index 299c6c4..babb5aa 100644 --- a/Pdf4QtLib/sources/pdfutils.h +++ b/Pdf4QtLib/sources/pdfutils.h @@ -811,10 +811,27 @@ QDataStream& operator<<(QDataStream& stream, const std::set& set) class Pdf4QtLIBSHARED_EXPORT PDFColorScale { public: + explicit PDFColorScale(); + + /// Creates a new color scale for defined range + /// \param min Lower bound of a scale range + /// \param max Upper bound of a scale range explicit PDFColorScale(PDFReal min, PDFReal max); + /// Map value to the color. If value is outside of the range, it + /// is clamped to fit in the range. + /// \param value Value QColor map(PDFReal value) const; + /// Returns color values of the scale + const std::vector getColorScales() const { return m_colorScales; } + + PDFReal getMin() const { return m_min; } + PDFReal getMax() const { return m_max; } + + /// Returns true, if color scale is valid + bool isValid() const { return m_min < m_max && !m_colorScales.empty(); } + private: std::vector m_colorScales; PDFReal m_min; diff --git a/Pdf4QtViewerPlugins/OutputPreviewPlugin/outputpreviewwidget.cpp b/Pdf4QtViewerPlugins/OutputPreviewPlugin/outputpreviewwidget.cpp index 97ecd04..2717df2 100644 --- a/Pdf4QtViewerPlugins/OutputPreviewPlugin/outputpreviewwidget.cpp +++ b/Pdf4QtViewerPlugins/OutputPreviewPlugin/outputpreviewwidget.cpp @@ -235,7 +235,112 @@ void OutputPreviewWidget::paintEvent(QPaintEvent* event) 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(); + } + } } } @@ -649,7 +754,7 @@ OutputPreviewWidget::InkCoverageInfo OutputPreviewWidget::getInkCoverageInfoImpl } } - pdf::PDFColorScale colorScale(coverageInfo.minValue, 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) @@ -659,7 +764,7 @@ OutputPreviewWidget::InkCoverageInfo OutputPreviewWidget::getInkCoverageInfoImpl pdf::PDFColorBuffer buffer = inkCoverageBitmap.getPixel(x, y); const pdf::PDFColorComponent coverage = buffer[0]; - coverageInfo.image.setPixelColor(x, y, colorScale.map(coverage)); + coverageInfo.image.setPixelColor(x, y, coverageInfo.colorScale.map(coverage)); } } } diff --git a/Pdf4QtViewerPlugins/OutputPreviewPlugin/outputpreviewwidget.h b/Pdf4QtViewerPlugins/OutputPreviewPlugin/outputpreviewwidget.h index 72279e2..ea7c95a 100644 --- a/Pdf4QtViewerPlugins/OutputPreviewPlugin/outputpreviewwidget.h +++ b/Pdf4QtViewerPlugins/OutputPreviewPlugin/outputpreviewwidget.h @@ -100,6 +100,7 @@ private: QImage image; pdf::PDFColorComponent minValue = 0.0f; pdf::PDFColorComponent maxValue = 0.0f; + pdf::PDFColorScale colorScale; }; const std::vector& getInkCoverage() const;