mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Inverting colors feature
This commit is contained in:
@ -600,6 +600,10 @@ void PDFDrawWidgetProxy::draw(QPainter* painter, QRect rect)
|
|||||||
|
|
||||||
// Use current paper color (it can be a bit different from white)
|
// Use current paper color (it can be a bit different from white)
|
||||||
QColor paperColor = getCMSManager()->getCurrentCMS()->getPaperColor();
|
QColor paperColor = getCMSManager()->getCurrentCMS()->getPaperColor();
|
||||||
|
if (m_features.testFlag(PDFRenderer::InvertColors))
|
||||||
|
{
|
||||||
|
paperColor = invertColor(paperColor);
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate trough pages and display them on the painter device
|
// Iterate trough pages and display them on the painter device
|
||||||
for (const LayoutItem& item : m_layout.items)
|
for (const LayoutItem& item : m_layout.items)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "pdfpainter.h"
|
#include "pdfpainter.h"
|
||||||
#include "pdfpattern.h"
|
#include "pdfpattern.h"
|
||||||
|
#include "pdfcms.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
@ -389,6 +390,20 @@ void PDFPainter::setCompositionMode(QPainter::CompositionMode mode)
|
|||||||
m_painter->setCompositionMode(mode);
|
m_painter->setCompositionMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFPrecompiledPageGenerator::PDFPrecompiledPageGenerator(PDFPrecompiledPage* precompiledPage,
|
||||||
|
PDFRenderer::Features features,
|
||||||
|
const PDFPage* page,
|
||||||
|
const PDFDocument* document,
|
||||||
|
const PDFFontCache* fontCache,
|
||||||
|
const PDFCMS* cms,
|
||||||
|
const PDFOptionalContentActivity* optionalContentActivity,
|
||||||
|
const PDFMeshQualitySettings& meshQualitySettings) :
|
||||||
|
BaseClass(features, page, document, fontCache, cms, optionalContentActivity, QMatrix(), meshQualitySettings),
|
||||||
|
m_precompiledPage(precompiledPage)
|
||||||
|
{
|
||||||
|
m_precompiledPage->setPaperColor(cms->getPaperColor());
|
||||||
|
}
|
||||||
|
|
||||||
void PDFPrecompiledPageGenerator::performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule)
|
void PDFPrecompiledPageGenerator::performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule)
|
||||||
{
|
{
|
||||||
Q_ASSERT(stroke || fill);
|
Q_ASSERT(stroke || fill);
|
||||||
@ -632,6 +647,38 @@ void PDFPrecompiledPage::optimize()
|
|||||||
m_compositionModes.shrink_to_fit();
|
m_compositionModes.shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFPrecompiledPage::invertColors()
|
||||||
|
{
|
||||||
|
// Jakub Melka: we must invert colors in following areas:
|
||||||
|
// - painter paths
|
||||||
|
// - images
|
||||||
|
// - meshes
|
||||||
|
|
||||||
|
for (PathPaintData& pathData : m_paths)
|
||||||
|
{
|
||||||
|
if (pathData.pen.style() != Qt::NoPen)
|
||||||
|
{
|
||||||
|
pathData.pen.setColor(invertColor(pathData.pen.color()));
|
||||||
|
}
|
||||||
|
if (pathData.brush.style() == Qt::SolidPattern)
|
||||||
|
{
|
||||||
|
pathData.brush.setColor(invertColor(pathData.brush.color()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ImageData& imageData : m_images)
|
||||||
|
{
|
||||||
|
imageData.image.invertPixels(QImage::InvertRgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (MeshPaintData& meshPaintData : m_meshes)
|
||||||
|
{
|
||||||
|
meshPaintData.mesh.invertColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_paperColor = invertColor(m_paperColor);
|
||||||
|
}
|
||||||
|
|
||||||
void PDFPrecompiledPage::finalize(qint64 compilingTimeNS, QList<PDFRenderError> errors)
|
void PDFPrecompiledPage::finalize(qint64 compilingTimeNS, QList<PDFRenderError> errors)
|
||||||
{
|
{
|
||||||
m_compilingTimeNS = compilingTimeNS;
|
m_compilingTimeNS = compilingTimeNS;
|
||||||
|
@ -199,6 +199,9 @@ public:
|
|||||||
/// Optimizes page memory allocation to contain less space
|
/// Optimizes page memory allocation to contain less space
|
||||||
void optimize();
|
void optimize();
|
||||||
|
|
||||||
|
/// Inverts all colors
|
||||||
|
void invertColors();
|
||||||
|
|
||||||
/// Finalizes precompiled page
|
/// Finalizes precompiled page
|
||||||
/// \param compilingTimeNS Compiling time in nanoseconds
|
/// \param compilingTimeNS Compiling time in nanoseconds
|
||||||
/// \param errors List of rendering errors
|
/// \param errors List of rendering errors
|
||||||
@ -216,6 +219,10 @@ public:
|
|||||||
/// Returns memory consumption estimate
|
/// Returns memory consumption estimate
|
||||||
qint64 getMemoryConsumptionEstimate() const { return m_memoryConsumptionEstimate; }
|
qint64 getMemoryConsumptionEstimate() const { return m_memoryConsumptionEstimate; }
|
||||||
|
|
||||||
|
/// Returns paper color
|
||||||
|
QColor getPaperColor() const { return m_paperColor; }
|
||||||
|
void setPaperColor(QColor paperColor) { m_paperColor = paperColor; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct PathPaintData
|
struct PathPaintData
|
||||||
{
|
{
|
||||||
@ -275,6 +282,7 @@ private:
|
|||||||
|
|
||||||
qint64 m_compilingTimeNS = 0;
|
qint64 m_compilingTimeNS = 0;
|
||||||
qint64 m_memoryConsumptionEstimate = 0;
|
qint64 m_memoryConsumptionEstimate = 0;
|
||||||
|
QColor m_paperColor = QColor(Qt::white);
|
||||||
std::vector<Instruction> m_instructions;
|
std::vector<Instruction> m_instructions;
|
||||||
std::vector<PathPaintData> m_paths;
|
std::vector<PathPaintData> m_paths;
|
||||||
std::vector<ClipData> m_clips;
|
std::vector<ClipData> m_clips;
|
||||||
@ -287,7 +295,7 @@ private:
|
|||||||
|
|
||||||
/// Processor, which processes PDF's page commands and writes them to the precompiled page.
|
/// Processor, which processes PDF's page commands and writes them to the precompiled page.
|
||||||
/// Precompiled page then can be used to execute these commands on QPainter.
|
/// Precompiled page then can be used to execute these commands on QPainter.
|
||||||
class PDFPrecompiledPageGenerator : public PDFPainterBase
|
class PDFFORQTLIBSHARED_EXPORT PDFPrecompiledPageGenerator : public PDFPainterBase
|
||||||
{
|
{
|
||||||
using BaseClass = PDFPainterBase;
|
using BaseClass = PDFPainterBase;
|
||||||
|
|
||||||
@ -299,12 +307,7 @@ public:
|
|||||||
const PDFFontCache* fontCache,
|
const PDFFontCache* fontCache,
|
||||||
const PDFCMS* cms,
|
const PDFCMS* cms,
|
||||||
const PDFOptionalContentActivity* optionalContentActivity,
|
const PDFOptionalContentActivity* optionalContentActivity,
|
||||||
const PDFMeshQualitySettings& meshQualitySettings) :
|
const PDFMeshQualitySettings& meshQualitySettings);
|
||||||
BaseClass(features, page, document, fontCache, cms, optionalContentActivity, QMatrix(), meshQualitySettings),
|
|
||||||
m_precompiledPage(precompiledPage)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule) override;
|
virtual void performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule) override;
|
||||||
|
@ -1106,6 +1106,16 @@ qint64 PDFMesh::getMemoryConsumptionEstimate() const
|
|||||||
return memoryConsumption;
|
return memoryConsumption;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFMesh::invertColors()
|
||||||
|
{
|
||||||
|
for (Triangle& triangle : m_triangles)
|
||||||
|
{
|
||||||
|
triangle.color = 0x00FFFFFF - triangle.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_backgroundColor = invertColor(m_backgroundColor);
|
||||||
|
}
|
||||||
|
|
||||||
void PDFMeshQualitySettings::initResolution()
|
void PDFMeshQualitySettings::initResolution()
|
||||||
{
|
{
|
||||||
Q_ASSERT(deviceSpaceMeshingArea.isValid());
|
Q_ASSERT(deviceSpaceMeshingArea.isValid());
|
||||||
|
@ -143,6 +143,9 @@ public:
|
|||||||
/// Returns estimate of number of bytes, which this mesh occupies in memory
|
/// Returns estimate of number of bytes, which this mesh occupies in memory
|
||||||
qint64 getMemoryConsumptionEstimate() const;
|
qint64 getMemoryConsumptionEstimate() const;
|
||||||
|
|
||||||
|
/// Invert colors
|
||||||
|
void invertColors();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<QPointF> m_vertices;
|
std::vector<QPointF> m_vertices;
|
||||||
std::vector<Triangle> m_triangles;
|
std::vector<Triangle> m_triangles;
|
||||||
|
@ -144,6 +144,12 @@ void PDFRenderer::compile(PDFPrecompiledPage* precompiledPage, size_t pageIndex)
|
|||||||
|
|
||||||
PDFPrecompiledPageGenerator generator(precompiledPage, m_features, page, m_document, m_fontCache, m_cms, m_optionalContentActivity, m_meshQualitySettings);
|
PDFPrecompiledPageGenerator generator(precompiledPage, m_features, page, m_document, m_fontCache, m_cms, m_optionalContentActivity, m_meshQualitySettings);
|
||||||
QList<PDFRenderError> errors = generator.processContents();
|
QList<PDFRenderError> errors = generator.processContents();
|
||||||
|
|
||||||
|
if (m_features.testFlag(InvertColors))
|
||||||
|
{
|
||||||
|
precompiledPage->invertColors();
|
||||||
|
}
|
||||||
|
|
||||||
precompiledPage->optimize();
|
precompiledPage->optimize();
|
||||||
precompiledPage->finalize(timer.nsecsElapsed(), qMove(errors));
|
precompiledPage->finalize(timer.nsecsElapsed(), qMove(errors));
|
||||||
timer.invalidate();
|
timer.invalidate();
|
||||||
@ -214,7 +220,7 @@ QImage PDFRasterizer::render(const PDFPage* page, const PDFPrecompiledPage* comp
|
|||||||
{
|
{
|
||||||
QOpenGLPaintDevice device(size);
|
QOpenGLPaintDevice device(size);
|
||||||
QPainter painter(&device);
|
QPainter painter(&device);
|
||||||
painter.fillRect(QRect(QPoint(0, 0), size), Qt::white);
|
painter.fillRect(QRect(QPoint(0, 0), size), compiledPage->getPaperColor());
|
||||||
compiledPage->draw(&painter, page->getCropBox(), matrix, features);
|
compiledPage->draw(&painter, page->getCropBox(), matrix, features);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,8 @@ public:
|
|||||||
ClipToCropBox = 0x0010, ///< Clip page content to crop box (items outside crop box will not be visible)
|
ClipToCropBox = 0x0010, ///< Clip page content to crop box (items outside crop box will not be visible)
|
||||||
DisplayTimes = 0x0020, ///< Display page compile/draw time
|
DisplayTimes = 0x0020, ///< Display page compile/draw time
|
||||||
DebugTextBlocks = 0x0040, ///< Debug text block layout algorithm
|
DebugTextBlocks = 0x0040, ///< Debug text block layout algorithm
|
||||||
DebugTextLines = 0x0080 ///< Debug text line layout algorithm
|
DebugTextLines = 0x0080, ///< Debug text line layout algorithm
|
||||||
|
InvertColors = 0x0100, ///< Invert colors
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_FLAGS(Features, Feature)
|
Q_DECLARE_FLAGS(Features, Feature)
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "pdfglobal.h"
|
#include "pdfglobal.h"
|
||||||
|
|
||||||
#include <QRectF>
|
#include <QRectF>
|
||||||
|
#include <QColor>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
|
|
||||||
@ -429,6 +430,21 @@ constexpr bool isRectangleHorizontallyOverlapped(const QRectF& r1, const QRectF&
|
|||||||
return isIntervalOverlap(r1.left(), r1.right(), r2.left(), r2.right());
|
return isIntervalOverlap(r1.left(), r1.right(), r2.left(), r2.right());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline QColor invertColor(QColor color)
|
||||||
|
{
|
||||||
|
qreal r = 0.0;
|
||||||
|
qreal g = 0.0;
|
||||||
|
qreal b = 0.0;
|
||||||
|
qreal a = 0.0;
|
||||||
|
|
||||||
|
color.getRgbF(&r, &g, &b, &a);
|
||||||
|
|
||||||
|
r = 1.0 - r;
|
||||||
|
g = 1.0 - g;
|
||||||
|
b = 1.0 - b;
|
||||||
|
return QColor::fromRgbF(r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
#endif // PDFUTILS_H
|
#endif // PDFUTILS_H
|
||||||
|
@ -212,6 +212,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
|
|||||||
ui->actionRenderOptionTextAntialiasing->setData(pdf::PDFRenderer::TextAntialiasing);
|
ui->actionRenderOptionTextAntialiasing->setData(pdf::PDFRenderer::TextAntialiasing);
|
||||||
ui->actionRenderOptionSmoothPictures->setData(pdf::PDFRenderer::SmoothImages);
|
ui->actionRenderOptionSmoothPictures->setData(pdf::PDFRenderer::SmoothImages);
|
||||||
ui->actionRenderOptionIgnoreOptionalContentSettings->setData(pdf::PDFRenderer::IgnoreOptionalContent);
|
ui->actionRenderOptionIgnoreOptionalContentSettings->setData(pdf::PDFRenderer::IgnoreOptionalContent);
|
||||||
|
ui->actionInvertColors->setData(pdf::PDFRenderer::InvertColors);
|
||||||
ui->actionShow_Text_Blocks->setData(pdf::PDFRenderer::DebugTextBlocks);
|
ui->actionShow_Text_Blocks->setData(pdf::PDFRenderer::DebugTextBlocks);
|
||||||
ui->actionShow_Text_Lines->setData(pdf::PDFRenderer::DebugTextLines);
|
ui->actionShow_Text_Lines->setData(pdf::PDFRenderer::DebugTextLines);
|
||||||
|
|
||||||
@ -970,7 +971,8 @@ std::vector<QAction*> PDFViewerMainWindow::getRenderingOptionActions() const
|
|||||||
ui->actionRenderOptionSmoothPictures,
|
ui->actionRenderOptionSmoothPictures,
|
||||||
ui->actionRenderOptionIgnoreOptionalContentSettings,
|
ui->actionRenderOptionIgnoreOptionalContentSettings,
|
||||||
ui->actionShow_Text_Blocks,
|
ui->actionShow_Text_Blocks,
|
||||||
ui->actionShow_Text_Lines };
|
ui->actionShow_Text_Lines,
|
||||||
|
ui->actionInvertColors };
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> PDFViewerMainWindow::getActions() const
|
QList<QAction*> PDFViewerMainWindow::getActions() const
|
||||||
|
@ -74,6 +74,8 @@
|
|||||||
<addaction name="actionFitPage"/>
|
<addaction name="actionFitPage"/>
|
||||||
<addaction name="actionFitWidth"/>
|
<addaction name="actionFitWidth"/>
|
||||||
<addaction name="actionFitHeight"/>
|
<addaction name="actionFitHeight"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionInvertColors"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuTools">
|
<widget class="QMenu" name="menuTools">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@ -409,6 +411,14 @@
|
|||||||
<string>Copy text</string>
|
<string>Copy text</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionInvertColors">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Invert Colors</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<resources>
|
<resources>
|
||||||
|
Reference in New Issue
Block a user