1 /*******************************************************************************************************
2  nomacs is a fast and small image viewer with the capability of synchronizing multiple instances
3 
4  Copyright (C) 2011-2016 Markus Diem <markus@nomacs.org>
5  Copyright (C) 2011-2016 Stefan Fiel <stefan@nomacs.org>
6  Copyright (C) 2011-2016 Florian Kleber <florian@nomacs.org>
7 
8  This file is part of nomacs.
9 
10  nomacs is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  nomacs is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 
23  related links:
24  [1] https://nomacs.org/
25  [2] https://github.com/nomacs/
26  [3] http://download.nomacs.org
27  *******************************************************************************************************/
28 
29 #include "DkManipulatorsIpl.h"
30 
31 #include "DkImageStorage.h"
32 #include "DkMath.h"
33 
34 #pragma warning(push, 0)	// no warnings from includes
35 #include <QSharedPointer>
36 #include <QDebug>
37 #pragma warning(pop)
38 
39 namespace nmc {
40 
41 // DkGrayScaleManipulator --------------------------------------------------------------------
DkGrayScaleManipulator(QAction * action)42 DkGrayScaleManipulator::DkGrayScaleManipulator(QAction * action) : DkBaseManipulator(action) {
43 }
44 
apply(const QImage & img) const45 QImage DkGrayScaleManipulator::apply(const QImage& img) const {
46 
47 	if (img.isNull())
48 		return img;
49 
50 	return DkImage::grayscaleImage(img);
51 }
52 
errorMessage() const53 QString DkGrayScaleManipulator::errorMessage() const {
54 	return QObject::tr("Could not convert to grayscale");
55 }
56 
57 // DkAutoAdjustManipulator --------------------------------------------------------------------
DkAutoAdjustManipulator(QAction * action)58 DkAutoAdjustManipulator::DkAutoAdjustManipulator(QAction * action) : DkBaseManipulator(action) {
59 }
60 
apply(const QImage & img) const61 QImage DkAutoAdjustManipulator::apply(const QImage & img) const {
62 
63 	QImage imgR = img;
64 	if (DkImage::autoAdjustImage(imgR))
65 		return imgR;
66 
67 	return QImage();
68 }
69 
errorMessage() const70 QString DkAutoAdjustManipulator::errorMessage() const {
71 	return QString(QObject::tr("Cannot auto adjust"));
72 }
73 
74 // DkNormalizeManipulator --------------------------------------------------------------------
DkNormalizeManipulator(QAction * action)75 DkNormalizeManipulator::DkNormalizeManipulator(QAction * action) : DkBaseManipulator(action) {
76 }
77 
apply(const QImage & img) const78 QImage DkNormalizeManipulator::apply(const QImage & img) const {
79 
80 	QImage imgR = img;
81 	if (DkImage::normImage(imgR)) {
82 		return imgR;
83 	}
84 
85 	return QImage();
86 }
87 
errorMessage() const88 QString DkNormalizeManipulator::errorMessage() const {
89 	return QObject::tr("The Image is Already Normalized...");
90 }
91 
92 // DkInvertManipulator --------------------------------------------------------------------
DkInvertManipulator(QAction * action)93 DkInvertManipulator::DkInvertManipulator(QAction * action) : DkBaseManipulator(action) {
94 }
95 
apply(const QImage & img) const96 QImage DkInvertManipulator::apply(const QImage & img) const {
97 
98 	QImage imgR = img;
99 	imgR.invertPixels();
100 	return imgR;
101 }
102 
errorMessage() const103 QString DkInvertManipulator::errorMessage() const {
104 	return QObject::tr("Cannot invert image");
105 }
106 
107 // Flip Horizontally --------------------------------------------------------------------
DkFlipHManipulator(QAction * action)108 DkFlipHManipulator::DkFlipHManipulator(QAction * action) : DkBaseManipulator(action) {
109 }
110 
apply(const QImage & img) const111 QImage DkFlipHManipulator::apply(const QImage & img) const {
112 
113 	return img.mirrored(true, false);
114 }
115 
errorMessage() const116 QString DkFlipHManipulator::errorMessage() const {
117 	return QObject::tr("Cannot flip image");
118 }
119 
120 // Flip Vertically --------------------------------------------------------------------
DkFlipVManipulator(QAction * action)121 DkFlipVManipulator::DkFlipVManipulator(QAction * action) : DkBaseManipulator(action) {
122 }
123 
apply(const QImage & img) const124 QImage DkFlipVManipulator::apply(const QImage & img) const {
125 	return img.mirrored(false, true);
126 }
127 
errorMessage() const128 QString DkFlipVManipulator::errorMessage() const {
129 	return QObject::tr("Cannot flip image");
130 }
131 
132 // DkTinyPlanetManipulator --------------------------------------------------------------------
DkTinyPlanetManipulator(QAction * action)133 DkTinyPlanetManipulator::DkTinyPlanetManipulator(QAction * action) : DkBaseManipulatorExt(action) {
134 }
135 
apply(const QImage & img) const136 QImage DkTinyPlanetManipulator::apply(const QImage & img) const {
137 
138 #ifdef WITH_OPENCV
139 	int ms = qMax(img.width(), img.height());
140 	QSize s(ms, ms);
141 
142 	QImage imgR = img.copy();
143 	DkImage::tinyPlanet(imgR, size(), angle()*DK_DEG2RAD, s, inverted());
144 	return imgR;
145 #else
146 	Q_UNUSED(img);
147 	return QImage();	// trigger warning
148 #endif
149 }
150 
errorMessage() const151 QString DkTinyPlanetManipulator::errorMessage() const {
152 	return QObject::tr("Sorry, I could not create a tiny planet");
153 }
154 
setAngle(int angle)155 void DkTinyPlanetManipulator::setAngle(int angle) {
156 
157 	if (angle == mAngle)
158 		return;
159 
160 	mAngle = angle;
161 	action()->trigger();
162 }
163 
angle() const164 int DkTinyPlanetManipulator::angle() const {
165 	return mAngle;
166 }
167 
setSize(int size)168 void DkTinyPlanetManipulator::setSize(int size) {
169 
170 	if (mSize == size)
171 		return;
172 
173 	mSize = size;
174 	action()->trigger();
175 }
176 
size() const177 int DkTinyPlanetManipulator::size() const {
178 	return mSize;
179 }
180 
setInverted(bool inverted)181 void DkTinyPlanetManipulator::setInverted(bool inverted) {
182 
183 	if (mInverted == inverted)
184 		return;
185 
186 	mInverted = inverted;
187 	action()->trigger();
188 }
189 
inverted() const190 bool DkTinyPlanetManipulator::inverted() const {
191 	return mInverted;
192 }
193 
194 // DkUnsharpMaskManipulator --------------------------------------------------------------------
DkBlurManipulator(QAction * action)195 DkBlurManipulator::DkBlurManipulator(QAction* action) : DkBaseManipulatorExt(action) {
196 }
197 
apply(const QImage & img) const198 QImage DkBlurManipulator::apply(const QImage& img) const {
199 
200 	QImage imgC = img.copy();
201 	DkImage::gaussianBlur(imgC, (float)sigma());
202 	return imgC;
203 }
204 
errorMessage() const205 QString DkBlurManipulator::errorMessage() const {
206 
207 	// so give me coffee & TV
208 	return QObject::tr("Cannot blur image");
209 }
210 
setSigma(int sigma)211 void DkBlurManipulator::setSigma(int sigma) {
212 
213 	if (mSigma == sigma)
214 		return;
215 
216 	mSigma = sigma;
217 	action()->trigger();
218 }
219 
sigma() const220 int DkBlurManipulator::sigma() const {
221 	return mSigma;
222 }
223 
224 // DkUnsharpMaskManipulator --------------------------------------------------------------------
DkUnsharpMaskManipulator(QAction * action)225 DkUnsharpMaskManipulator::DkUnsharpMaskManipulator(QAction * action) : DkBaseManipulatorExt(action) {
226 }
227 
apply(const QImage & img) const228 QImage DkUnsharpMaskManipulator::apply(const QImage & img) const {
229 
230 	QImage imgC = img.copy();
231 	DkImage::unsharpMask(imgC, (float)sigma(), 1.0f+amount()/100.0f);
232 	return imgC;
233 }
234 
errorMessage() const235 QString DkUnsharpMaskManipulator::errorMessage() const {
236 	return QObject::tr("Cannot sharpen image");
237 }
238 
setSigma(int sigma)239 void DkUnsharpMaskManipulator::setSigma(int sigma) {
240 
241 	if (mSigma == sigma)
242 		return;
243 
244 	mSigma = sigma;
245 	action()->trigger();
246 }
247 
sigma() const248 int DkUnsharpMaskManipulator::sigma() const {
249 	return mSigma;
250 }
251 
setAmount(int amount)252 void DkUnsharpMaskManipulator::setAmount(int amount) {
253 
254 	if (mAmount == amount)
255 		return;
256 
257 	mAmount = amount;
258 	action()->trigger();
259 }
260 
amount() const261 int DkUnsharpMaskManipulator::amount() const {
262 	return mAmount;
263 }
264 
265 // Rotate Manipulator --------------------------------------------------------------------
DkRotateManipulator(QAction * action)266 DkRotateManipulator::DkRotateManipulator(QAction * action) : DkBaseManipulatorExt(action) {
267 }
268 
apply(const QImage & img) const269 QImage DkRotateManipulator::apply(const QImage & img) const {
270 	return DkImage::rotateImage(img, angle());
271 }
272 
errorMessage() const273 QString DkRotateManipulator::errorMessage() const {
274 	return QObject::tr("Cannot rotate image");
275 }
276 
setAngle(int angle)277 void DkRotateManipulator::setAngle(int angle) {
278 
279 	if (angle == mAngle)
280 		return;
281 
282 	mAngle = angle;
283 	action()->trigger();
284 }
285 
angle() const286 int DkRotateManipulator::angle() const {
287 	return mAngle;
288 }
289 
290 // -------------------------------------------------------------------- DkResizeManipulator
DkResizeManipulator(QAction * action)291 DkResizeManipulator::DkResizeManipulator(QAction * action) : DkBaseManipulatorExt(action) {
292 }
293 
apply(const QImage & img) const294 QImage DkResizeManipulator::apply(const QImage & img) const {
295 
296 	if (mScaleFactor == 1.0)
297 		return img;
298 
299 	return DkImage::resizeImage(img, QSize(), mScaleFactor, mInterpolation, mCorrectGamma);
300 }
301 
errorMessage() const302 QString DkResizeManipulator::errorMessage() const {
303 	return QObject::tr("Cannot resize image");
304 }
305 
setScaleFactor(double sf)306 void DkResizeManipulator::setScaleFactor(double sf) {
307 	mScaleFactor = sf;
308 	action()->trigger();
309 }
310 
scaleFactor() const311 double DkResizeManipulator::scaleFactor() const {
312 	return mScaleFactor;
313 }
314 
setInterpolation(int ipl)315 void DkResizeManipulator::setInterpolation(int ipl) {
316 	mInterpolation = ipl;
317 	action()->trigger();
318 }
319 
interpolation() const320 int DkResizeManipulator::interpolation() const {
321 	return mInterpolation;
322 }
323 
setCorrectGamma(bool cg)324 void DkResizeManipulator::setCorrectGamma(bool cg) {
325 	mCorrectGamma = cg;
326 	action()->trigger();
327 }
328 
correctGamma() const329 bool DkResizeManipulator::correctGamma() const {
330 	return mCorrectGamma;
331 }
332 
333 
334 // Rotate Manipulator --------------------------------------------------------------------
DkThresholdManipulator(QAction * action)335 DkThresholdManipulator::DkThresholdManipulator(QAction * action) : DkBaseManipulatorExt(action) {
336 }
337 
apply(const QImage & img) const338 QImage DkThresholdManipulator::apply(const QImage & img) const {
339 
340 	return DkImage::thresholdImage(img, threshold(), color());
341 }
342 
errorMessage() const343 QString DkThresholdManipulator::errorMessage() const {
344 	return QObject::tr("Cannot threshold image");
345 }
346 
setThreshold(int thr)347 void DkThresholdManipulator::setThreshold(int thr) {
348 
349 	if (thr == mThreshold)
350 		return;
351 
352 	mThreshold = thr;
353 	action()->trigger();
354 }
355 
threshold() const356 int DkThresholdManipulator::threshold() const {
357 	return mThreshold;
358 }
359 
setColor(bool col)360 void DkThresholdManipulator::setColor(bool col) {
361 
362 	if (col == mColor)
363 		return;
364 
365 	mColor = col;
366 	action()->trigger();
367 }
368 
color() const369 bool DkThresholdManipulator::color() const {
370 	return mColor;
371 }
372 
373 // DkHueManipulator --------------------------------------------------------------------
DkHueManipulator(QAction * action)374 DkHueManipulator::DkHueManipulator(QAction * action) : DkBaseManipulatorExt(action) {
375 }
376 
apply(const QImage & img) const377 QImage DkHueManipulator::apply(const QImage & img) const {
378 	return DkImage::hueSaturation(img, hue(), saturation(), value());
379 }
380 
errorMessage() const381 QString DkHueManipulator::errorMessage() const {
382 	return QObject::tr("Cannot change Hue/Saturation");
383 }
384 
setHue(int hue)385 void DkHueManipulator::setHue(int hue) {
386 
387 	if (mHue == hue)
388 		return;
389 
390 	mHue = hue;
391 	action()->trigger();
392 }
393 
hue() const394 int DkHueManipulator::hue() const {
395 	return mHue;
396 }
397 
setSaturation(int sat)398 void DkHueManipulator::setSaturation(int sat) {
399 
400 	if (mSat == sat)
401 		return;
402 
403 	mSat = sat;
404 	action()->trigger();
405 }
406 
saturation() const407 int DkHueManipulator::saturation() const {
408 	return mSat;
409 }
410 
setValue(int val)411 void DkHueManipulator::setValue(int val) {
412 
413 	if (mValue == val)
414 		return;
415 
416 	mValue = val;
417 	action()->trigger();
418 }
419 
value() const420 int DkHueManipulator::value() const {
421 	return mValue;
422 }
423 
DkExposureManipulator(QAction * action)424 DkExposureManipulator::DkExposureManipulator(QAction * action) : DkBaseManipulatorExt(action) {
425 }
426 
apply(const QImage & img) const427 QImage DkExposureManipulator::apply(const QImage & img) const {
428 	return DkImage::exposure(img, exposure(), offset(), gamma());
429 }
430 
errorMessage() const431 QString DkExposureManipulator::errorMessage() const {
432 	return QObject::tr("Cannot apply exposure");
433 }
434 
setExposure(double exposure)435 void DkExposureManipulator::setExposure(double exposure) {
436 
437 	if (mExposure == exposure)
438 		return;
439 
440 	mExposure = exposure;
441 	action()->trigger();
442 }
443 
exposure() const444 double DkExposureManipulator::exposure() const {
445 	return mExposure;
446 }
447 
setOffset(double offset)448 void DkExposureManipulator::setOffset(double offset) {
449 
450 	if (mOffset == offset)
451 		return;
452 
453 	mOffset = offset;
454 	action()->trigger();
455 }
456 
offset() const457 double DkExposureManipulator::offset() const {
458 	return mOffset;
459 }
460 
setGamma(double gamma)461 void DkExposureManipulator::setGamma(double gamma) {
462 
463 	if (mGamma == gamma)
464 		return;
465 
466 	mGamma = gamma;
467 	action()->trigger();
468 }
469 
gamma() const470 double DkExposureManipulator::gamma() const {
471 	return mGamma;
472 }
473 
474 // -------------------------------------------------------------------- DkColorManipulator
DkColorManipulator(QAction * action)475 DkColorManipulator::DkColorManipulator(QAction * action) : DkBaseManipulatorExt(action) {
476 }
477 
apply(const QImage & img) const478 QImage DkColorManipulator::apply(const QImage & img) const {
479 
480 	return DkImage::bgColor(img, color());
481 }
482 
errorMessage() const483 QString DkColorManipulator::errorMessage() const {
484 	return QObject::tr("Cannot draw background color");
485 }
486 
setColor(const QColor & col)487 void DkColorManipulator::setColor(const QColor & col) {
488 
489 	if (mColor == col)
490 		return;
491 
492 	mColor = col;
493 	action()->trigger();
494 }
495 
color() const496 QColor DkColorManipulator::color() const {
497 	return mColor;
498 }
499 
500 }