Merge lp:~johbjo/qpdfview/invertlight into lp:qpdfview

Proposed by Johan
Status: Merged
Merged at revision: 2110
Proposed branch: lp:~johbjo/qpdfview/invertlight
Merge into: lp:qpdfview
Diff against target: 363 lines (+118/-4)
10 files modified
sources/documentview.cpp (+15/-1)
sources/documentview.h (+4/-0)
sources/mainwindow.cpp (+25/-1)
sources/mainwindow.h (+4/-0)
sources/pageitem.cpp (+5/-0)
sources/presentationview.cpp (+6/-1)
sources/renderparam.h (+5/-1)
sources/rendertask.cpp (+40/-0)
sources/settings.cpp (+10/-0)
sources/settings.h (+4/-0)
To merge this branch: bzr merge lp:~johbjo/qpdfview/invertlight
Reviewer Review Type Date Requested Status
Adam Reichold Approve
Review via email: mp+395618@code.launchpad.net

This proposal supersedes a proposal from 2020-12-26.

Description of the change

Changed named to "Invert lightness" and fixed tab indentations. There seems to exist various definition of "lightness" related to various colour spaces, but this transformation probably inverts it either way.

Here is the comment I wrote about how this works:

"This is a transformation in RGB space that mirrors the color coordinates about the plane that intersects the mid point of the cube (0.5, 0.5, 0.5) and is perpendicular to the diagonal vector (1,1,1).

"Each color-coordinate is moved along the (1,1,1)-vector twice its distance from this mid plane.

"Moving a color-coordinate along (1,1,1) preserves the "hue" but changes the "lightness" of the color."

The absolute differences between the components are preserved, which means the "hue" is preserved.

Here are the calculations:

The mid plane is: r + g + b = 1.5

To find the distance t for a given point (r,g,b), we can plug in: r+t + g+t + b+t = 1.5 => t = (1.5 - r - g - b) / 3

The mirrored point is then (r+2*t, g+2*t, b+2*t). When the range is 0-255, we have 1.5*255 = 382.5.

I simplified to: d = (382.5 - r - g - b) / 1.5

To post a comment you must log in.
Revision history for this message
Adam Reichold (adamreichold) wrote : Posted in a previous version of this proposal

Hello Johan,

thank you very much for your contribution!

I have to admit that I do not yet fully understand how this works. I am therefore also slightly uncomfortable with the name.

Is the idea to transform RGB into HSL and there invert the lightness component but keep hue and saturation intact? If so, wouldn't maybe "Invert lightness" be a more precise name?

Best regards,
Adam

Revision history for this message
Adam Reichold (adamreichold) wrote :

Hello again,

this looks good to me now. Thank you for taking the time to explain things.

One more thing I wonder is whether this should be locked against "Invert colors" so that one can either invert colors or lightness, but not both? Technically, chaining the transformations is not a problem, but I am not sure if the result is useful.

Best regards,
Adam

review: Approve
Revision history for this message
Adam Reichold (adamreichold) wrote :

Note that I had to change the keyboard shortcut as Ctrl+L is already used to focus the scale factor. I chose Ctrl+Shift+I instead which somewhat meshes with the other render flags modifiers...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'sources/documentview.cpp'
2--- sources/documentview.cpp 2020-12-15 20:53:35 +0000
3+++ sources/documentview.cpp 2020-12-26 16:15:31 +0000
4@@ -814,6 +814,11 @@
5 m_renderFlags |= InvertColors;
6 }
7
8+ if(s_settings->documentView().invertLightness())
9+ {
10+ m_renderFlags |= InvertLightness;
11+ }
12+
13 if(s_settings->documentView().convertToGrayscale())
14 {
15 m_renderFlags |= ConvertToGrayscale;
16@@ -1137,6 +1142,15 @@
17 s_settings->documentView().setInvertColors(invertColors());
18 }
19
20+ if(changedFlags.testFlag(InvertLightness))
21+ {
22+ prepareBackground();
23+
24+ emit invertLightnessChanged(invertLightness());
25+
26+ s_settings->documentView().setInvertLightness(invertLightness());
27+ }
28+
29 if(changedFlags.testFlag(ConvertToGrayscale))
30 {
31 emit convertToGrayscaleChanged(convertToGrayscale());
32@@ -2827,7 +2841,7 @@
33 {
34 backgroundColor = s_settings->pageItem().paperColor();
35
36- if(invertColors())
37+ if(invertColors() || invertLightness())
38 {
39 backgroundColor.setRgb(~backgroundColor.rgb());
40 }
41
42=== modified file 'sources/documentview.h'
43--- sources/documentview.h 2018-03-28 19:19:40 +0000
44+++ sources/documentview.h 2020-12-26 16:15:31 +0000
45@@ -112,6 +112,9 @@
46 bool invertColors() const { return m_renderFlags.testFlag(InvertColors); }
47 void setInvertColors(bool invertColors) { setRenderFlag(InvertColors, invertColors); }
48
49+ bool invertLightness() const { return m_renderFlags.testFlag(InvertLightness); }
50+ void setInvertLightness(bool invertLightness) { setRenderFlag(InvertLightness, invertLightness); }
51+
52 bool convertToGrayscale() const { return m_renderFlags.testFlag(ConvertToGrayscale); }
53 void setConvertToGrayscale(bool convertToGrayscale) { setRenderFlag(ConvertToGrayscale, convertToGrayscale); }
54
55@@ -193,6 +196,7 @@
56 void renderFlagsChanged(qpdfview::RenderFlags renderFlags);
57
58 void invertColorsChanged(bool invertColors);
59+ void invertLightnessChanged(bool invertLightness);
60 void convertToGrayscaleChanged(bool convertToGrayscale);
61 void trimMarginsChanged(bool trimMargins);
62
63
64=== modified file 'sources/mainwindow.cpp'
65--- sources/mainwindow.cpp 2020-01-03 18:40:18 +0000
66+++ sources/mainwindow.cpp 2020-12-26 16:15:31 +0000
67@@ -626,6 +626,7 @@
68 m_rotateRightAction->setEnabled(hasCurrent);
69
70 m_invertColorsAction->setEnabled(hasCurrent);
71+ m_invertLightnessAction->setEnabled(hasCurrent);
72 m_convertToGrayscaleAction->setEnabled(hasCurrent);
73 m_trimMarginsAction->setEnabled(hasCurrent);
74
75@@ -706,6 +707,7 @@
76 on_currentTab_scaleFactorChanged(tab->scaleFactor());
77
78 on_currentTab_invertColorsChanged(tab->invertColors());
79+ on_currentTab_invertLightnessChanged(tab->invertLightness());
80 on_currentTab_convertToGrayscaleChanged(tab->convertToGrayscale());
81 on_currentTab_trimMarginsChanged(tab->trimMargins());
82
83@@ -755,6 +757,7 @@
84 m_fitToPageWidthModeAction->setChecked(false);
85
86 m_invertColorsAction->setChecked(false);
87+ m_invertLightnessAction->setChecked(false);
88 m_convertToGrayscaleAction->setChecked(false);
89 m_trimMarginsAction->setChecked(false);
90
91@@ -1086,6 +1089,13 @@
92 m_invertColorsAction->setChecked(invertColors);
93 }
94
95+void MainWindow::on_currentTab_invertLightnessChanged(bool invertLightness)
96+{
97+ ONLY_IF_SENDER_IS_CURRENT_TAB
98+
99+ m_invertLightnessAction->setChecked(invertLightness);
100+}
101+
102 void MainWindow::on_currentTab_convertToGrayscaleChanged(bool convertToGrayscale)
103 {
104 ONLY_IF_SENDER_IS_CURRENT_TAB
105@@ -1770,6 +1780,11 @@
106 currentTab()->setInvertColors(checked);
107 }
108
109+void MainWindow::on_invertLightness_triggered(bool checked)
110+{
111+ currentTab()->setInvertLightness(checked);
112+}
113+
114 void MainWindow::on_convertToGrayscale_triggered(bool checked)
115 {
116 currentTab()->setConvertToGrayscale(checked);
117@@ -2783,6 +2798,7 @@
118 connect(tab, SIGNAL(renderFlagsChanged(qpdfview::RenderFlags)), SLOT(on_currentTab_renderFlagsChanged(qpdfview::RenderFlags)));
119
120 connect(tab, SIGNAL(invertColorsChanged(bool)), SLOT(on_currentTab_invertColorsChanged(bool)));
121+ connect(tab, SIGNAL(invertLightnessChanged(bool)), SLOT(on_currentTab_invertLightnessChanged(bool)));
122 connect(tab, SIGNAL(convertToGrayscaleChanged(bool)), SLOT(on_currentTab_convertToGrayscaleChanged(bool)));
123 connect(tab, SIGNAL(trimMarginsChanged(bool)), SLOT(on_currentTab_trimMarginsChanged(bool)));
124
125@@ -3213,6 +3229,7 @@
126 m_rotateRightAction = createAction(tr("Rotate &right"), QLatin1String("rotateRight"), QLatin1String("object-rotate-right"), ShortcutHandler::defaultRotateRight(), SLOT(on_rotateRight_triggered()));
127
128 m_invertColorsAction = createAction(tr("Invert colors"), QLatin1String("invertColors"), QIcon(), QKeySequence(Qt::CTRL + Qt::Key_I), SLOT(on_invertColors_triggered(bool)), true);
129+ m_invertLightnessAction = createAction(tr("Invert lightness"), QLatin1String("invertLightness"), QIcon(), QKeySequence(Qt::CTRL + Qt::Key_L), SLOT(on_invertLightness_triggered(bool)), true);
130 m_convertToGrayscaleAction = createAction(tr("Convert to grayscale"), QLatin1String("convertToGrayscale"), QIcon(), QKeySequence(Qt::CTRL + Qt::Key_U), SLOT(on_convertToGrayscale_triggered(bool)), true);
131 m_trimMarginsAction = createAction(tr("Trim margins"), QLatin1String("trimMargins"), QIcon(), QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_U), SLOT(on_trimMargins_triggered(bool)), true);
132
133@@ -3530,7 +3547,7 @@
134 m_viewMenu->addSeparator();
135 m_viewMenu->addActions(QList< QAction* >() << m_rotateLeftAction << m_rotateRightAction);
136 m_viewMenu->addSeparator();
137- m_viewMenu->addActions(QList< QAction* >() << m_invertColorsAction << m_convertToGrayscaleAction << m_trimMarginsAction);
138+ m_viewMenu->addActions(QList< QAction* >() << m_invertColorsAction << m_invertLightnessAction << m_convertToGrayscaleAction << m_trimMarginsAction);
139
140 m_compositionModeMenu = m_viewMenu->addMenu(tr("Composition"));
141 m_compositionModeMenu->addAction(m_darkenWithPaperColorAction);
142@@ -3789,6 +3806,13 @@
143 mainWindow()->on_invertColors_triggered(checked);
144 }
145
146+void MainWindowAdaptor::invertLightness(bool checked)
147+{
148+ ONLY_IF_CURRENT_TAB
149+
150+ mainWindow()->on_invertLightness_triggered(checked);
151+}
152+
153 void MainWindowAdaptor::convertToGrayscale(bool checked)
154 {
155 ONLY_IF_CURRENT_TAB
156
157=== modified file 'sources/mainwindow.h'
158--- sources/mainwindow.h 2018-03-29 18:56:40 +0000
159+++ sources/mainwindow.h 2020-12-26 16:15:31 +0000
160@@ -121,6 +121,7 @@
161 void on_currentTab_renderFlagsChanged(qpdfview::RenderFlags renderFlags);
162
163 void on_currentTab_invertColorsChanged(bool invertColors);
164+ void on_currentTab_invertLightnessChanged(bool invertLightness);
165 void on_currentTab_convertToGrayscaleChanged(bool convertToGrayscale);
166 void on_currentTab_trimMarginsChanged(bool trimMargins);
167
168@@ -206,6 +207,7 @@
169 void on_rotateRight_triggered();
170
171 void on_invertColors_triggered(bool checked);
172+ void on_invertLightness_triggered(bool checked);
173 void on_convertToGrayscale_triggered(bool checked);
174 void on_trimMargins_triggered(bool checked);
175 void on_darkenWithPaperColor_triggered(bool checked);
176@@ -405,6 +407,7 @@
177 QAction* m_rotateRightAction;
178
179 QAction* m_invertColorsAction;
180+ QAction* m_invertLightnessAction;
181 QAction* m_convertToGrayscaleAction;
182 QAction* m_trimMarginsAction;
183 QAction* m_darkenWithPaperColorAction;
184@@ -560,6 +563,7 @@
185 Q_NOREPLY void fitToPageSizeMode(bool checked);
186
187 Q_NOREPLY void invertColors(bool checked);
188+ Q_NOREPLY void invertLightness(bool checked);
189 Q_NOREPLY void convertToGrayscale(bool checked);
190 Q_NOREPLY void trimMargins(bool checked);
191
192
193=== modified file 'sources/pageitem.cpp'
194--- sources/pageitem.cpp 2020-01-01 08:54:36 +0000
195+++ sources/pageitem.cpp 2020-12-26 16:15:31 +0000
196@@ -1182,6 +1182,11 @@
197
198 QColor paperColor = s_settings->pageItem().paperColor();
199
200+ if(m_renderParam.invertLightness())
201+ {
202+ paperColor.setRgb(~paperColor.rgb());
203+ }
204+
205 if(m_renderParam.invertColors())
206 {
207 paperColor.setRgb(~paperColor.rgb());
208
209=== modified file 'sources/presentationview.cpp'
210--- sources/presentationview.cpp 2019-05-12 09:55:28 +0000
211+++ sources/presentationview.cpp 2020-12-26 16:15:31 +0000
212@@ -172,7 +172,7 @@
213 prepareScene();
214 prepareView();
215
216- if(changedFlags.testFlag(InvertColors))
217+ if(changedFlags.testFlag(InvertColors) || changedFlags.testFlag(InvertLightness))
218 {
219 prepareBackground();
220 }
221@@ -568,6 +568,11 @@
222 backgroundColor.setRgb(~backgroundColor.rgb());
223 }
224
225+ if(m_renderFlags.testFlag(InvertLightness))
226+ {
227+ backgroundColor.setRgb(~backgroundColor.rgb());
228+ }
229+
230 scene()->setBackgroundBrush(QBrush(backgroundColor));
231 }
232
233
234=== modified file 'sources/renderparam.h'
235--- sources/renderparam.h 2015-05-25 09:30:55 +0000
236+++ sources/renderparam.h 2020-12-26 16:15:31 +0000
237@@ -35,7 +35,8 @@
238 ConvertToGrayscale = 1 << 1,
239 TrimMargins = 1 << 2,
240 DarkenWithPaperColor = 1 << 3,
241- LightenWithPaperColor = 1 << 4
242+ LightenWithPaperColor = 1 << 4,
243+ InvertLightness = 1 << 5
244 };
245
246 Q_DECLARE_FLAGS(RenderFlags, RenderFlag)
247@@ -89,6 +90,9 @@
248 bool invertColors() const { return d->flags.testFlag(InvertColors); }
249 void setInvertColors(bool invertColors) { setFlag(InvertColors, invertColors); }
250
251+ bool invertLightness() const { return d->flags.testFlag(InvertLightness); }
252+ void setInvertLightness(bool invertLightness) { setFlag(InvertLightness, invertLightness); }
253+
254 bool convertToGrayscale() const { return d->flags.testFlag(ConvertToGrayscale); }
255 void setConvertToGrayscale(bool convertToGrayscale) { setFlag(ConvertToGrayscale, convertToGrayscale); }
256
257
258=== modified file 'sources/rendertask.cpp'
259--- sources/rendertask.cpp 2016-11-26 20:18:57 +0000
260+++ sources/rendertask.cpp 2020-12-26 16:15:31 +0000
261@@ -21,6 +21,7 @@
262
263 #include "rendertask.h"
264
265+#include <cmath>
266 #include <QApplication>
267 #include <qmath.h>
268 #include <QPainter>
269@@ -155,6 +156,38 @@
270 static_cast< qreal >(bottom - top) / height);
271 }
272
273+void invertLightness(QImage& image)
274+{
275+ QRgb* const begin = reinterpret_cast< QRgb* >(image.bits());
276+ QRgb* const end = reinterpret_cast< QRgb* >(image.bits() + image.byteCount());
277+
278+ // This is a transformation in RGB space that mirrors the color coordinates
279+ // about the plane that intersects the mid point of the cube (0.5, 0.5, 0.5)
280+ // and is perpendicular to the diagonal vector (1,1,1).
281+ //
282+ // Each color-coordinate is moved along the (1,1,1)-vector twice its
283+ // distance from this mid plane.
284+ //
285+ // Moving a color-coordinate along (1,1,1) preserves the "hue"
286+ // but changes the "lightness" of the color.
287+
288+ for(QRgb* pointer = begin; pointer != end; ++pointer)
289+ {
290+ const int alpha = qAlpha(*pointer);
291+ int r = qRed(*pointer);
292+ int g = qGreen(*pointer);
293+ int b = qBlue(*pointer);
294+ int d = (int) round((382.5 - r - g - b) / 1.5);
295+ r = r + d;
296+ g = g + d;
297+ b = b + d;
298+ r = qBound(0, r, 255);
299+ g = qBound(0, g, 255);
300+ b = qBound(0, b, 255);
301+ *pointer = qRgba(r, g, b, alpha);
302+ }
303+}
304+
305 void convertToGrayscale(QImage& image)
306 {
307 QRgb* const begin = reinterpret_cast< QRgb* >(image.bits());
308@@ -482,6 +515,13 @@
309 convertToGrayscale(image);
310 }
311
312+ if(m_renderParam.invertLightness())
313+ {
314+ CANCELLATION_POINT
315+
316+ invertLightness(image);
317+ }
318+
319 if(m_renderParam.invertColors())
320 {
321 CANCELLATION_POINT
322
323=== modified file 'sources/settings.cpp'
324--- sources/settings.cpp 2020-12-15 20:53:35 +0000
325+++ sources/settings.cpp 2020-12-26 16:15:31 +0000
326@@ -627,6 +627,16 @@
327 m_settings->setValue("documentView/invertColors", invertColors);
328 }
329
330+bool Settings::DocumentView::invertLightness() const
331+{
332+ return m_settings->value("documentView/invertLightness", Defaults::DocumentView::invertLightness()).toBool();
333+}
334+
335+void Settings::DocumentView::setInvertLightness(bool invertLightness)
336+{
337+ m_settings->setValue("documentView/invertLightness", invertLightness);
338+}
339+
340 bool Settings::DocumentView::convertToGrayscale() const
341 {
342 return m_settings->value("documentView/convertToGrayscale", Defaults::DocumentView::convertToGrayscale()).toBool();
343
344=== modified file 'sources/settings.h'
345--- sources/settings.h 2020-12-15 20:53:35 +0000
346+++ sources/settings.h 2020-12-26 16:15:31 +0000
347@@ -262,6 +262,9 @@
348 bool invertColors() const;
349 void setInvertColors(bool invertColors);
350
351+ bool invertLightness() const;
352+ void setInvertLightness(bool invertLightness);
353+
354 bool convertToGrayscale() const;
355 void setConvertToGrayscale(bool convertToGrayscale);
356
357@@ -606,6 +609,7 @@
358 static Rotation rotation() { return RotateBy0; }
359
360 static bool invertColors() { return false; }
361+ static bool invertLightness() { return false; }
362 static bool convertToGrayscale() { return false; }
363 static bool trimMargins() { return false; }
364

Subscribers

People subscribed via source and target branches

to all changes: