MauiKit Image Tools

imagedocument.cpp
1/*
2 * SPDX-FileCopyrightText: (C) 2020 Carl Schwan <carl@carlschwan.eu>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6
7#include "imagedocument.h"
8
9#include "commands/cropcommand.h"
10#include "commands/mirrorcommand.h"
11#include "commands/resizecommand.h"
12#include "commands/rotatecommand.h"
13#include "commands/transformcommand.h"
14
15#include <QDebug>
16
17ImageDocument::ImageDocument(QObject *parent)
18 : QObject(parent)
19{
20 m_changesApplied = true;
21
22 connect(this, &ImageDocument::pathChanged, this, [this](const QUrl &url) {
23 m_image = QImage(url.isLocalFile() ? url.toLocalFile() : url.toString());
24 m_originalImage = m_image;
25 m_edited = false;
26 Q_EMIT editedChanged();
27 Q_EMIT imageChanged();
28 });
29}
30
32{
33 while (!m_undos.empty()) {
34 const auto command = m_undos.pop();
35 if(m_undos.isEmpty())
36 m_image = command->undo(m_image);
37 delete command;
38 }
39
40 resetValues();
41 setEdited(false);
42 Q_EMIT imageChanged();
43}
44
45QImage ImageDocument::image() const
46{
47 return m_image;
48}
49
50bool ImageDocument::edited() const
51{
52 return m_edited;
53}
54
56{
57 if(m_undos.empty())
58 {
59 qDebug() << "No more commands to undo";
60 return;
61 }
62
63 const auto command = m_undos.pop();
64 m_image = command->undo();
65 m_originalImage = m_image;
66 delete command;
67 Q_EMIT imageChanged();
68 if (m_undos.empty()) {
69 setEdited(false);
70 }
71}
72
73void ImageDocument::crop(int x, int y, int width, int height)
74{
75 const auto command = new CropCommand(QRect(x, y, width, height));
76 m_image = command->redo(m_image);
77 m_undos.append(command);
78 setEdited(true);
79 Q_EMIT imageChanged();
80}
81
82void ImageDocument::resize(int width, int height)
83{
84 const auto command = new ResizeCommand(QSize(width, height));
85 m_image = command->redo(m_image);
86 m_undos.append(command);
87 setEdited(true);
88 Q_EMIT imageChanged();
89}
90
91void ImageDocument::mirror(bool horizontal, bool vertical)
92{
93 const auto command = new MirrorCommand(horizontal, vertical);
94 m_image = command->redo(m_image);
95
96 m_undos.append(command);
97 setEdited(true);
98 Q_EMIT imageChanged();
99}
100
102{
103 QTransform transform;
104 transform.rotate(angle);
105 const auto command = new RotateCommand(transform);
106 m_image = command->redo(m_image);
107 m_undos.append(command);
108 setEdited(true);
109 Q_EMIT imageChanged();
110}
111
113{
114 m_changesApplied = !value;
115 Q_EMIT changesAppliedChanged();
116
117 if (m_edited == value) {
118 return;
119 }
120 m_edited = value;
121 Q_EMIT editedChanged();
122}
123
125{
126 applyChanges();
127 return m_originalImage.save(m_path.isLocalFile() ? m_path.toLocalFile() : m_path.toString());
128}
129
130bool ImageDocument::saveAs(const QUrl &location)
131{
132 return m_originalImage.save(location.isLocalFile() ? location.toLocalFile() : location.toString());
133}
134
135void ImageDocument::adjustBrightness(int value)
136{
137 if(value == m_brightness)
138 return;
139
140 auto oldValue = m_brightness;
141 m_brightness = value;
142
143 auto transformation = [val = m_brightness](QImage &ref) -> QImage
144 {
145 return Trans::adjustBrightness(ref, val);
146 };
147
148 auto undoCallback = [this, oldValue]()
149 {
150 this->m_brightness = oldValue;
151 Q_EMIT brightnessChanged();
152 };
153
154 const auto command = new TransformCommand(m_image, transformation, undoCallback);
155
156 m_image = command->redo(m_originalImage);
157 m_undos.append(command);
158 Q_EMIT brightnessChanged();
159 setEdited(true);
160 Q_EMIT imageChanged();
161}
162
163void ImageDocument::adjustContrast(int value)
164{
165 if(value == m_contrast)
166 return;
167
168 auto oldValue = m_contrast;
169 m_contrast = value;
170
171 auto transformation = [val = m_contrast](QImage &ref) -> QImage
172 {
173 return Trans::adjustContrast(ref, val);
174 };
175
176 auto undoCallback = [this, oldValue]()
177 {
178 this->m_contrast = oldValue;
179 Q_EMIT contrastChanged();
180 };
181
182 const auto command = new TransformCommand(m_image, transformation, undoCallback);
183
184 m_image = command->redo(m_originalImage);
185 m_undos.append(command);
186 setEdited(true);
187 Q_EMIT contrastChanged();
188 Q_EMIT imageChanged();
189}
190
191void ImageDocument::adjustSaturation(int value)
192{
193 if(m_image.isGrayscale())
194 return;
195
196 if(value == m_saturation)
197 return;
198
199 auto oldValue = m_saturation;
200 m_saturation = value;
201
202 auto transformation = [val = m_saturation](QImage &ref) -> QImage
203 {
204 return Trans::adjustSaturation(ref, val);
205 };
206
207 auto undoCallback = [this, oldValue]()
208 {
209 this->m_saturation = oldValue;
210 Q_EMIT saturationChanged();
211 };
212
213 const auto command = new TransformCommand(m_image, transformation, undoCallback);
214
215 m_image = command->redo(m_originalImage);
216 m_undos.append(command);
217 setEdited(true);
218 Q_EMIT imageChanged();
219 Q_EMIT saturationChanged();
220}
221
222void ImageDocument::adjustHue(int value)
223{
224 qDebug() << "adjust HUE DOCUMENT" << value;
225 if(value == m_hue)
226 return;
227
228 if(m_image.isGrayscale())
229 return;
230
231 auto oldValue = m_hue;
232 m_hue = value;
233
234 auto transformation = [val = m_hue](QImage &ref) -> QImage
235 {
236 return Trans::adjustHue(ref, val);
237 };
238
239 auto undoCallback = [this, oldValue]()
240 {
241 this->m_hue = oldValue;
242 Q_EMIT hueChanged();
243 };
244
245 const auto command = new TransformCommand(m_image, transformation, undoCallback);
246
247 m_image = command->redo(m_originalImage);
248 m_undos.append(command);
249 setEdited(true);
250 Q_EMIT imageChanged();
251 Q_EMIT hueChanged();
252}
253
254void ImageDocument::adjustGamma(int value)
255{
256 qDebug() << "adjust GAMMA DOCUMENT" << value;
257 // if(m_image.isGrayscale())
258 // return;
259
260 if(value == m_gamma)
261 return;
262
263 auto oldValue = m_gamma;
264 m_gamma = value;
265
266 auto transformation = [val = m_gamma](QImage &ref) -> QImage
267 {
268 return Trans::adjustGamma(ref, val);
269 };
270
271 auto undoCallback = [this, oldValue]()
272 {
273 this->m_gamma = oldValue;
274 Q_EMIT gammaChanged();
275 };
276
277 const auto command = new TransformCommand(m_image, transformation, undoCallback);
278
279 m_image = command->redo(m_originalImage);
280 m_undos.append(command);
281 setEdited(true);
282 Q_EMIT imageChanged();
283 Q_EMIT gammaChanged();
284}
285
286void ImageDocument::adjustSharpness(int value)
287{
288 qDebug() << "adjust SHARPNESS DOCUMENT" << value;
289 // if(m_image.isGrayscale())
290 // return;
291
292 if(value == m_sharpness)
293 return;
294
295 auto oldValue = m_sharpness;
296 m_sharpness = value;
297
298 auto transformation = [val = m_sharpness](QImage &ref) -> QImage
299 {
300 return Trans::adjustSharpness(ref, val);
301 };
302
303 auto undoCallback = [this, oldValue]()
304 {
305 this->m_sharpness = oldValue;
306 Q_EMIT sharpnessChanged();
307 };
308
309 const auto command = new TransformCommand(m_image, transformation, undoCallback);
310
311 m_image = command->redo(m_originalImage);
312 m_undos.append(command);
313 setEdited(true);
314 Q_EMIT imageChanged();
315 Q_EMIT sharpnessChanged();
316}
317
318void ImageDocument::adjustThreshold(int value)
319{
320 qDebug() << "adjust threshold DOCUMENT" << value;
321 // if(m_image.isGrayscale())
322 // return;
323
324 if(value == m_threshold)
325 return;
326
327 auto oldValue = m_threshold;
328 m_threshold = value;
329
330 auto transformation = [val = m_threshold](QImage &ref) -> QImage
331 {
332 return Trans::adjustThreshold(ref, val);
333 };
334
335 auto undoCallback = [this, oldValue]()
336 {
337 this->m_threshold = oldValue;
338 Q_EMIT thresholdChanged();
339 };
340
341 const auto command = new TransformCommand(m_image, transformation, undoCallback);
342
343 m_image = command->redo(m_originalImage);
344 m_undos.append(command);
345 setEdited(true);
346 Q_EMIT imageChanged();
347 Q_EMIT thresholdChanged();
348}
349
350void ImageDocument::adjustGaussianBlur(int value)
351{
352 if(value == m_gaussianBlur)
353 return;
354
355 auto oldValue = m_gaussianBlur;
356 m_gaussianBlur = value;
357 auto transformation = [val = m_gaussianBlur](QImage &ref) -> QImage
358 {
359 qDebug() << "SXetting gaussian blur" << val;
360 return Trans::adjustGaussianBlur(ref, val);
361 };
362
363 auto undoCallback = [this, oldValue]()
364 {
365 this->m_gaussianBlur = oldValue;
366 Q_EMIT gaussianBlurChanged();
367 };
368
369 const auto command = new TransformCommand(m_image, transformation, undoCallback);
370 m_image = command->redo(m_originalImage);
371 m_undos.append(command);
372 setEdited(true);
373 Q_EMIT imageChanged();
374 Q_EMIT gaussianBlurChanged();
375}
376
377void ImageDocument::toGray()
378{
379 const auto command = new TransformCommand(m_image, &Trans::toGray, nullptr);
380
381 m_image = command->redo(m_originalImage);
382 m_undos.append(command);
383 setEdited(true);
384 Q_EMIT imageChanged();
385}
386
387void ImageDocument::toSketch()
388{
389 const auto command = new TransformCommand(m_image, &Trans::sketch, nullptr);
390
391 m_image = command->redo(m_originalImage);
392 m_undos.append(command);
393 setEdited(true);
394 Q_EMIT imageChanged();
395}
396
397void ImageDocument::addVignette()
398{
399 const auto command = new TransformCommand(m_image, &Trans::vignette, nullptr);
400
401 m_image = command->redo(m_originalImage);
402 m_undos.append(command);
403 setEdited(true);
404 Q_EMIT imageChanged();
405}
406
407void ImageDocument::applyChanges()
408{
409 resetValues();
410
411 m_originalImage = m_image;
412 m_changesApplied = true;
413 Q_EMIT changesAppliedChanged();
414}
415
416int ImageDocument::brightness() const
417{
418 return m_brightness;
419}
420
421int ImageDocument::contrast() const
422{
423 return m_contrast;
424}
425
426int ImageDocument::saturation() const
427{
428 return m_saturation;
429}
430
431int ImageDocument::hue() const
432{
433 return m_hue;
434}
435
436int ImageDocument::gamma() const
437{
438 return m_gamma;
439}
440
441int ImageDocument::sharpness() const
442{
443 return m_sharpness;
444}
445
446int ImageDocument::threshold() const
447{
448 return m_threshold;
449}
450
451int ImageDocument::gaussianBlur() const
452{
453 return m_gaussianBlur;
454}
455
456QUrl ImageDocument::path() const
457{
458 return m_path;
459}
460
461void ImageDocument::setPath(const QUrl &path)
462{
463 m_path = path;
464 Q_EMIT pathChanged(path);
465}
466
467QRectF ImageDocument::area() const
468{
469 return m_area;
470}
471
472void ImageDocument::setArea(const QRectF &newArea)
473{
474 if (m_area == newArea)
475 return;
476 m_area = newArea;
477 Q_EMIT areaChanged();
478}
479
480void ImageDocument::resetArea()
481{
482 setArea({}); // TODO: Adapt to use your actual default value
483}
484
485void ImageDocument::resetValues()
486{
487 m_contrast = 0;
488 m_brightness = 0;
489 m_saturation = 0;
490 m_hue = 0;
491 m_gamma = 0;
492 m_sharpness = 0;
493 m_threshold = 0;
494 Q_EMIT hueChanged();
495 Q_EMIT saturationChanged();
496 Q_EMIT brightnessChanged();
497 Q_EMIT contrastChanged();
498 Q_EMIT gammaChanged();
499 Q_EMIT thresholdChanged();
500 Q_EMIT sharpnessChanged();
501}
502
503bool ImageDocument::changesApplied() const
504{
505 return m_changesApplied;
506}
CropCommand that crop the current image.
Definition cropcommand.h:18
Q_INVOKABLE void undo()
Undo the last edit on the images.
Q_INVOKABLE void rotate(int angle)
Rotate the image.
Q_INVOKABLE bool saveAs(const QUrl &location)
Save current edited image as a new image.
Q_INVOKABLE bool save()
Save current edited image in place.
Q_INVOKABLE void mirror(bool horizontal, bool vertical)
Mirror the image.
Q_INVOKABLE void crop(int x, int y, int width, int height)
Crop the image.
Q_INVOKABLE void cancel()
Cancel all the edit.
void setEdited(bool value)
Change the edited value.
Q_INVOKABLE void resize(int width, int height)
Resize the image.
MirrorCommand that mirror an image horizontally or vertically.
ResizeCommand that resizes the current image.
RotateCommand that rotates the current image.
Q_EMITQ_EMIT
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool isLocalFile() const const
QString toLocalFile() const const
QString toString(FormattingOptions options) const const
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 18 2025 12:10:54 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.