ImageMaskEditor.cpp
Go to the documentation of this file.
1#include "ImageMaskEditor.h"
2
3#include <QBrush>
4#include <QMouseEvent>
5#include <QPainter>
6#include <QPen>
7#include <QWidget>
8
9ImageMaskEditor::ImageMaskEditor(QSize size, QWidget* parent) : QWidget(parent)
10{
11 setMouseTracking(true);
12 resizeImage(size);
13}
14
15ImageMaskEditor::ImageMaskEditor(int width, int height, QWidget* parent) :
16 ImageMaskEditor({width, height}, parent)
17{
18}
19
20bool
21ImageMaskEditor::openMaskImage(const QString& fileName)
22{
23 QImage loadedImage;
24 if (!loadedImage.load(fileName))
25 {
26 return false;
27 }
28 setMaskImage(loadedImage);
29 return true;
30}
31
32bool
34{
35 QImage loadedImage;
36 if (!loadedImage.load(fileName))
37 {
38 return false;
39 }
40 setBackgroundImage(loadedImage);
41 return true;
42}
43
44bool
45ImageMaskEditor::saveMaskImage(const QString& fileName, const char* fileFormat)
46{
47 if (maskImage().save(fileName, fileFormat))
48 {
49 return true;
50 }
51 else
52 {
53 return false;
54 }
55}
56
57bool
58ImageMaskEditor::saveBackgroundImage(const QString& fileName, const char* fileFormat)
59{
60 if (backgroundImage().save(fileName, fileFormat))
61 {
62 return true;
63 }
64 else
65 {
66 return false;
67 }
68}
69
70const QColor&
72{
73 return _penColor;
74}
75
76const QColor&
78{
79 return _maskTransparentColor;
80}
81
82int
84{
85 return _penWidth;
86}
87
88const QImage&
90{
91 return _backgroundImage;
92}
93
94QImage
96{
97 QImage i = _maskImage;
98 for (int x = 0; x < i.width(); ++x)
99 {
100 for (int y = 0; y < i.height(); ++y)
101 {
102 QColor color{i.pixel(x, y)};
103 if (color.alpha() == 0)
104 {
105 color = _maskTransparentColor;
106 }
107 else
108 {
109 color.setAlpha(255);
110 }
111 i.setPixel(x, y, color.rgba());
112 }
113 }
114 return i;
115}
116
117QSize
119{
120 return _backgroundImage.size();
121}
122
123QSize
125{
126 return imageSize();
127}
128
129void
130ImageMaskEditor::setMaskColor(const QColor& newColor)
131{
132 _penColor = newColor;
133 _penColor.setAlpha(255); // prevent blending of masks
134}
135
136void
138{
139 _penColor.setRed(r);
140 _penColor.setGreen(g);
141 _penColor.setBlue(b);
142 _penColor.setAlpha(255); // prevent blending of masks
143}
144
145void
146ImageMaskEditor::setMaskColor(qreal r, qreal g, qreal b)
147{
148 _penColor.setRedF(r);
149 _penColor.setGreenF(g);
150 _penColor.setBlueF(b);
151 _penColor.setAlpha(255); // prevent blending of masks
152}
153
154void
156{
157 _maskTransparentColor = newColor;
158 _maskTransparentColor.setAlpha(255); // prevent blending of masks
159}
160
161void
163{
164 _maskTransparentColor.setRed(r);
165 _maskTransparentColor.setGreen(g);
166 _maskTransparentColor.setBlue(b);
167 _maskTransparentColor.setAlpha(255); // prevent blending of masks
168}
169
170void
171ImageMaskEditor::setTransparentColor(qreal r, qreal g, qreal b)
172{
173 _maskTransparentColor.setRedF(r);
174 _maskTransparentColor.setGreenF(g);
175 _maskTransparentColor.setBlueF(b);
176 _maskTransparentColor.setAlpha(255); // prevent blending of masks
177}
178
179void
181{
182 _maskImage.fill(qRgba(0, 0, 0, 0));
183 update();
184}
185
186void
188{
189 _penWidth = std::max(1, newWidth);
190}
191
192void
194{
195 _maskAlpha = std::max(1, std::min(255, newAlpha));
196 update();
197}
198
199void
200ImageMaskEditor::setImageSize(QSize size, bool doNotShrink)
201{
202 if (doNotShrink)
203 {
204 size = imageSize().expandedTo(size);
205 }
206 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
207 setFixedSize(size);
208 resizeImage(&_backgroundImage, size, Qt::white);
209 resizeImage(&_maskImage, size, _maskTransparentColor);
210 update();
211}
212
213void
214ImageMaskEditor::resizeImage(QSize size, bool doNotShrink)
215{
216 setImageSize(size, doNotShrink);
217}
218
219void
221{
222 _maskImage = i.copy();
223 resizeImage(i.size(), true);
224 update();
225}
226
227void
229{
230 _backgroundImage = i.copy();
231 resizeImage(i.size(), false);
232 _maskModified = true;
233 update();
234}
235
236void
238{
239 if (event->button() == Qt::LeftButton)
240 {
241 _lastPoint = event->pos();
242 drawOnMask(_lastPoint);
243 _drawing = true;
244 }
245}
246
247void
249{
250 if ((event->buttons() & Qt::LeftButton) && _drawing)
251 {
252 drawOnMask(event->pos());
253 }
254 else if (_drawPenCircle)
255 {
256 int rad = (_penWidth / 2) + 2;
257 QPoint border{rad, rad};
258 update(QRect(event->pos() - border, event->pos() + border));
259 }
260}
261
262void
264{
265 if (event->button() == Qt::LeftButton && _drawing)
266 {
267 drawOnMask(event->pos());
268 _drawing = false;
269 }
270}
271
272void
274{
275 QPainter painter(this);
276 QRect dirtyRect = event->rect();
277 painter.drawImage(dirtyRect, _backgroundImage, dirtyRect);
278 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
279 for (int x = std::max(0, dirtyRect.x());
280 x < std::min(dirtyRect.x() + dirtyRect.width(), _maskImage.width());
281 ++x)
282 {
283 for (int y = std::max(0, dirtyRect.y());
284 y < std::min(dirtyRect.y() + dirtyRect.height(), _maskImage.height());
285 ++y)
286 {
287 QColor clr{_maskImage.pixel(x, y)};
288 if (clr.red() == _maskTransparentColor.red() &&
289 clr.green() == _maskTransparentColor.green() &&
290 clr.blue() == _maskTransparentColor.blue())
291 {
292 clr = QColor(0, 0, 0, 0);
293 }
294 else if (clr.alpha() != 0)
295 {
296 clr.setAlpha(_maskAlpha);
297 }
298 _maskImage.setPixel(x, y, clr.rgba());
299 }
300 }
301 painter.drawImage(dirtyRect, _maskImage, dirtyRect);
302 if (_maskModified)
303 {
304 _maskModified = false;
305 emit maskUpdated();
306 if (!_drawing)
307 {
308 emit maskUpdateFinished();
309 }
310 }
311 //draw brush circle
312 if (_drawPenCircle)
313 {
314 const auto pos = mapFromGlobal(QCursor::pos());
315 if (pos.x() >= 0 && pos.x() < width() && pos.y() >= 0 && pos.y() < height())
316 {
317 painter.setBrush(Qt::NoBrush);
318 {
319 QPen pen(Qt::white);
320 pen.setWidth(2);
321 painter.setPen(pen);
322 painter.drawEllipse(QPointF(pos), _penWidth / 2.0, _penWidth / 2.0);
323 }
324 {
325 QPen pen(Qt::black);
326 pen.setWidth(2);
327 painter.setPen(pen);
328 painter.drawEllipse(QPointF(pos), _penWidth / 2.0 - 2, _penWidth / 2.0 - 2);
329 }
330 }
331 }
332}
333
334void
335ImageMaskEditor::drawOnMask(const QPoint& endPoint)
336{
337 QPainter painter(&_maskImage);
338 if (_lastPoint == endPoint)
339 {
340 if (_penWidth > 1)
341 {
342 painter.setPen(Qt::NoPen);
343 painter.setBrush(_penColor);
344 const auto w = _penWidth / 2.0;
345 painter.drawEllipse(QPointF(_lastPoint), w, w);
346 }
347 else
348 {
349 painter.setPen(_penColor);
350 painter.drawPoint(_lastPoint); // fix for w = 1
351 }
352 }
353 else
354 {
355 painter.setPen(QPen(_penColor, _penWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
356 painter.drawLine(_lastPoint, endPoint);
357 }
358
359 int rad = (_penWidth / 2) + 2;
360 update(QRect(_lastPoint, endPoint).normalized().adjusted(-rad, -rad, +rad, +rad));
361 _lastPoint = endPoint;
362 _maskModified = true;
363}
364
365void
366ImageMaskEditor::resizeImage(QImage* image, const QSize& newSize, const QColor& fillcolor)
367{
368 if (image->size() == newSize)
369 {
370 return;
371 }
372
373 QImage newImage(newSize, QImage::Format_ARGB32);
374 newImage.fill(fillcolor);
375 QPainter painter(&newImage);
376 painter.drawImage(QPoint(0, 0), *image);
377 *image = newImage;
378}
379
380void
382{
383 _drawPenCircle = b;
384}
void maskUpdateFinished()
bool saveMaskImage(const QString &fileName, const char *fileFormat)
void setMaskAlpha(int newAlpha)
void setMaskColor(const QColor &newColor)
const QColor & transparentColor() const
QSize imageSize() const
QSize sizeHint() const override
void mouseReleaseEvent(QMouseEvent *event) override
QImage maskImage() const
void mouseMoveEvent(QMouseEvent *event) override
void setBackgroundImage(const QImage &i)
void setImageSize(QSize size, bool doNotShrink=false)
void mousePressEvent(QMouseEvent *event) override
void setMaskImage(const QImage &i)
void setPenWidth(int newWidth)
void setPenCircleVisible(bool b=true)
void paintEvent(QPaintEvent *event) override
void resizeImage(QSize size, bool doNotShrink=false)
bool openMaskImage(const QString &fileName)
const QImage & backgroundImage() const
bool saveBackgroundImage(const QString &fileName, const char *fileFormat)
ImageMaskEditor(QSize size, QWidget *parent=nullptr)
void setTransparentColor(const QColor &newColor)
bool openBackgroundImage(const QString &fileName)
const QColor & maskColor() const
bool update(mongocxx::collection &coll, const nlohmann::json &query, const nlohmann::json &update)
Definition mongodb.cpp:68
This file offers overloads of toIce() and fromIce() functions for STL container types.