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 
9 ImageMaskEditor::ImageMaskEditor(QSize size, QWidget* parent) : QWidget(parent)
10 {
11  setMouseTracking(true);
12  resizeImage(size);
13 }
14 
15 ImageMaskEditor::ImageMaskEditor(int width, int height, QWidget* parent) :
16  ImageMaskEditor({width, height}, parent)
17 {
18 }
19 
20 bool
21 ImageMaskEditor::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 
32 bool
33 ImageMaskEditor::openBackgroundImage(const QString& fileName)
34 {
35  QImage loadedImage;
36  if (!loadedImage.load(fileName))
37  {
38  return false;
39  }
40  setBackgroundImage(loadedImage);
41  return true;
42 }
43 
44 bool
45 ImageMaskEditor::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 
57 bool
58 ImageMaskEditor::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 
70 const QColor&
72 {
73  return _penColor;
74 }
75 
76 const QColor&
78 {
79  return _maskTransparentColor;
80 }
81 
82 int
84 {
85  return _penWidth;
86 }
87 
88 const QImage&
90 {
91  return _backgroundImage;
92 }
93 
94 QImage
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 
117 QSize
119 {
120  return _backgroundImage.size();
121 }
122 
123 QSize
125 {
126  return imageSize();
127 }
128 
129 void
130 ImageMaskEditor::setMaskColor(const QColor& newColor)
131 {
132  _penColor = newColor;
133  _penColor.setAlpha(255); // prevent blending of masks
134 }
135 
136 void
137 ImageMaskEditor::setMaskColor(int r, int g, int b)
138 {
139  _penColor.setRed(r);
140  _penColor.setGreen(g);
141  _penColor.setBlue(b);
142  _penColor.setAlpha(255); // prevent blending of masks
143 }
144 
145 void
146 ImageMaskEditor::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 
154 void
156 {
157  _maskTransparentColor = newColor;
158  _maskTransparentColor.setAlpha(255); // prevent blending of masks
159 }
160 
161 void
163 {
164  _maskTransparentColor.setRed(r);
165  _maskTransparentColor.setGreen(g);
166  _maskTransparentColor.setBlue(b);
167  _maskTransparentColor.setAlpha(255); // prevent blending of masks
168 }
169 
170 void
171 ImageMaskEditor::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 
179 void
181 {
182  _maskImage.fill(qRgba(0, 0, 0, 0));
183  update();
184 }
185 
186 void
188 {
189  _penWidth = std::max(1, newWidth);
190 }
191 
192 void
194 {
195  _maskAlpha = std::max(1, std::min(255, newAlpha));
196  update();
197 }
198 
199 void
200 ImageMaskEditor::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 
213 void
214 ImageMaskEditor::resizeImage(QSize size, bool doNotShrink)
215 {
216  setImageSize(size, doNotShrink);
217 }
218 
219 void
221 {
222  _maskImage = i.copy();
223  resizeImage(i.size(), true);
224  update();
225 }
226 
227 void
229 {
230  _backgroundImage = i.copy();
231  resizeImage(i.size(), false);
232  _maskModified = true;
233  update();
234 }
235 
236 void
238 {
239  if (event->button() == Qt::LeftButton)
240  {
241  _lastPoint = event->pos();
242  drawOnMask(_lastPoint);
243  _drawing = true;
244  }
245 }
246 
247 void
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 
262 void
264 {
265  if (event->button() == Qt::LeftButton && _drawing)
266  {
267  drawOnMask(event->pos());
268  _drawing = false;
269  }
270 }
271 
272 void
273 ImageMaskEditor::paintEvent(QPaintEvent* event)
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 
334 void
335 ImageMaskEditor::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 
365 void
366 ImageMaskEditor::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 
380 void
382 {
383  _drawPenCircle = b;
384 }
ImageMaskEditor::imageSize
QSize imageSize() const
Definition: ImageMaskEditor.cpp:118
ImageMaskEditor::ImageMaskEditor
ImageMaskEditor(QSize size, QWidget *parent=nullptr)
Definition: ImageMaskEditor.cpp:9
ImageMaskEditor::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *event) override
Definition: ImageMaskEditor.cpp:263
ImageMaskEditor::backgroundImage
const QImage & backgroundImage() const
Definition: ImageMaskEditor.cpp:89
ImageMaskEditor::openMaskImage
bool openMaskImage(const QString &fileName)
Definition: ImageMaskEditor.cpp:21
ImageMaskEditor::maskColor
const QColor & maskColor() const
Definition: ImageMaskEditor.cpp:71
ImageMaskEditor.h
ImageMaskEditor::setPenWidth
void setPenWidth(int newWidth)
Definition: ImageMaskEditor.cpp:187
ImageMaskEditor::maskImage
QImage maskImage() const
Definition: ImageMaskEditor.cpp:95
ImageMaskEditor::setBackgroundImage
void setBackgroundImage(const QImage &i)
Definition: ImageMaskEditor.cpp:228
ImageMaskEditor::saveBackgroundImage
bool saveBackgroundImage(const QString &fileName, const char *fileFormat)
Definition: ImageMaskEditor.cpp:58
ImageMaskEditor::maskUpdateFinished
void maskUpdateFinished()
ImageMaskEditor::saveMaskImage
bool saveMaskImage(const QString &fileName, const char *fileFormat)
Definition: ImageMaskEditor.cpp:45
ImageMaskEditor::openBackgroundImage
bool openBackgroundImage(const QString &fileName)
Definition: ImageMaskEditor.cpp:33
armarx::navigation::algorithms::save
bool save(const Costmap &costmap, const std::filesystem::path &directory)
Definition: persistence.cpp:105
ImageMaskEditor::setMaskImage
void setMaskImage(const QImage &i)
Definition: ImageMaskEditor.cpp:220
ImageMaskEditor::clearMaskImage
void clearMaskImage()
Definition: ImageMaskEditor.cpp:180
ImageMaskEditor::setImageSize
void setImageSize(QSize size, bool doNotShrink=false)
Definition: ImageMaskEditor.cpp:200
ImageMaskEditor::transparentColor
const QColor & transparentColor() const
Definition: ImageMaskEditor.cpp:77
ImageMaskEditor::maskUpdated
void maskUpdated()
ImageMaskEditor
Definition: ImageMaskEditor.h:8
ImageMaskEditor::mouseMoveEvent
void mouseMoveEvent(QMouseEvent *event) override
Definition: ImageMaskEditor.cpp:248
ImageMaskEditor::resizeImage
void resizeImage(QSize size, bool doNotShrink=false)
Definition: ImageMaskEditor.cpp:214
max
T max(T t1, T t2)
Definition: gdiam.h:51
armarx::armem::server::ltm::util::mongodb::detail::update
bool update(mongocxx::collection &coll, const nlohmann::json &query, const nlohmann::json &update)
Definition: mongodb.cpp:68
ImageMaskEditor::setTransparentColor
void setTransparentColor(const QColor &newColor)
Definition: ImageMaskEditor.cpp:155
ImageMaskEditor::sizeHint
QSize sizeHint() const override
Definition: ImageMaskEditor.cpp:124
ImageMaskEditor::paintEvent
void paintEvent(QPaintEvent *event) override
Definition: ImageMaskEditor.cpp:273
ImageMaskEditor::setMaskColor
void setMaskColor(const QColor &newColor)
Definition: ImageMaskEditor.cpp:130
min
T min(T t1, T t2)
Definition: gdiam.h:44
ImageMaskEditor::setPenCircleVisible
void setPenCircleVisible(bool b=true)
Definition: ImageMaskEditor.cpp:381
ImageMaskEditor::penWidth
int penWidth() const
Definition: ImageMaskEditor.cpp:83
ImageMaskEditor::setMaskAlpha
void setMaskAlpha(int newAlpha)
Definition: ImageMaskEditor.cpp:193
ImageMaskEditor::mousePressEvent
void mousePressEvent(QMouseEvent *event) override
Definition: ImageMaskEditor.cpp:237