PDA

View Full Version : Draw over an image, without replacing the pixels, save drawn image as standalone



Charvi
7th July 2015, 12:35
Hi,

1. I want to display a jpg.
2. Let user draw on the image.
3. I want to save the only user drawn image (and not the base image).

If I take two qlabels, one for background and another for foreground and display the one in foreground with transparency then the user drawing will not be visible too. But I want the background to be visible as well as the user drawing and also want to save the user drawing as a standalone png.

Please suggest something.

Thanks,
Charvi

anda_skoa
7th July 2015, 13:54
You don't necessarily need to widgets.

Just have one widget that paints the base image and a QPixmap on top of it into which you draw.

Cheers,
_

Charvi
8th July 2015, 04:08
Hi,

Thanks for response.

I did try something like that but I also want to be able to save only the user made drawing. For this I thought not to replace those pixels in the original image but overlay the user drawing on it.

wysota
8th July 2015, 07:31
I did try something like that
Great, so now use QPixmap::save() to save that extra pixmap.

anda_skoa
8th July 2015, 08:28
For this I thought not to replace those pixels in the original image but overlay the user drawing on it.

Which is exactly what I wrote, no?

Cheers,
_

Charvi
8th July 2015, 10:34
But if I make the overlay-ed pixmap transparent then user can't see what he draws ?
If I make it opaque then user can't see the base image ?

How to make the user see the overlay where he draws and background where he hasn't drawn ?

Thanks,
Charvi

^NyAw^
8th July 2015, 10:46
Hi,

The widget must not be transparent but the pixels on it must have the Alpha value to full transparency. When you draw on int you have to change the Alpha value and the RGB values to desired color.

wysota
8th July 2015, 13:17
But if I make the overlay-ed pixmap transparent then user can't see what he draws ?
If I make it opaque then user can't see the base image ?

How to make the user see the overlay where he draws and background where he hasn't drawn ?

Geez....


#include <QtWidgets>

class Widget : public QWidget {
public:
Widget(QWidget *parent = 0) : QWidget(parent) {}
void setImage(const QString &path) {
m_base = QPixmap(path);
m_mask = QImage(m_base.size(), QImage::Format_ARGB32);
if(!m_mask.isNull()) m_mask.fill(Qt::transparent);
updateGeometry();
}
QSize sizeHint() const { return m_base.size(); }
protected:
void mousePressEvent(QMouseEvent *e) {
if(!m_base.rect().contains(e->pos())) return;
m_mask.setPixel(e->pos(), qRgba(255, 0, 0, 255));
update();
}
void mouseMoveEvent(QMouseEvent *e) {
if(!m_base.rect().contains(e->pos())) return;
m_mask.setPixel(e->pos(), qRgba(255, 0, 0, 255));
update();
}
void paintEvent(QPaintEvent *pe) {
QPainter p(this);
p.drawPixmap(0, 0, m_base);
p.drawImage(0, 0, m_mask);
}
private:
QPixmap m_base;
QImage m_mask;
};

int main(int argc, char **argv) {
QApplication app(argc, argv);
Widget w;
w.setImage("/usr/share/icons/oxygen/256x256/apps/kword.png");
w.show();
return app.exec();
}

Charvi
18th July 2015, 11:30
Also, how would i construct QPen to erase the overlay ?

wysota
18th July 2015, 22:01
Why would you need a pen for that?

d_stranz
19th July 2015, 17:14
Also, how would i construct QPen to erase the overlay ?

You take the code wysota already wrote for you, and you replace the alpha value with 0 instead of 255 in the setPixel() calls.

You seem to be confused about the difference between the virtual "pen", "eraser" and other tools you might use in a drawing application and a QPen used by QPainter. Totally unrelated concepts.

Charvi
20th July 2015, 05:27
To get smooth drawing I used the following code taking reference from the Scribble example.


QPainter painter(&m_mask);
// if (eraseFlag == true)
// painter.setPen(QPen(QBrush(QColor(0, 0, 0, 0)), myPenWidth, Qt::SolidLine, Qt::RoundCap,
// Qt::RoundJoin));
// else
painter.setPen(QPen(myPenColor, myPenWidth, Qt::SolidLine, Qt::RoundCap,
Qt::RoundJoin));
painter.drawLine(lastPoint, endPoint);

int rad = (myPenWidth / 2) + 2;
update(QRect(lastPoint, endPoint).normalized()
.adjusted(-rad, -rad, +rad, +rad));
lastPoint = endPoint;

where


myPenWidth = 3;
myPenColor = Qt::red;

Trying to implement erasing in this.

Charvi
20th July 2015, 10:44
One more feature, sorry to extend in the same question but it's because the context has already been set.

In order to implement scaling on the wheel event I did the following:


void
LT_DrawingCanvas::wheelEvent(QWheelEvent *event)
{
QWidget::wheelEvent(event);
scaleFactor += ((float)event->delta()/1200.0);
update();
}


and in the paintEvent:


void
LT_DrawingCanvas::paintEvent(QPaintEvent *pe)
{
QPainter p(this);
p.scale(scaleFactor, scaleFactor);
p.drawPixmap(0, 0, m_base);
p.drawImage(0, 0, m_mask);
}


My widget hierarchy is as below:
Mainwindow
- Grid Layout
- Scrollarea
- MyCustomDrawing Canvas Widget (created just like the code wysota suggested above)

I am not getting the scrollbars on scaling the image. I realize I am drawing the scaled image again, instead of resizing the widget. I tried using resize on the widget but it didn't work. What I am doing wrong ?

wysota
21st July 2015, 11:51
Set the widgetResizable property of the scroll area to true.

Charvi
24th July 2015, 11:13
Okay so for erasing I did the following, may be this will be useful to someone.


QPainter painter(&m_mask);
painter.setCompositionMode(QPainter::CompositionMo de_Source);
painter.setPen(QPen(QBrush(Qt::transparent), myPenWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));


To understand the Composition Modes : http://doc.qt.io/qt-5/qpainter.html#CompositionMode-enum


Thanks.

P.S.: Still working on the scrollarea stuff. Once done will update here.

Kryzon
24th July 2015, 22:33
I think it might be faster to use composition mode CLEAR. It erases whatever pixels are there.