I try to superpose 3 QImage but I have some warnings, for example :
QImage::pixelColor: coordinate (31,30) out of range
And the result of the blending is a black image.
Here my code :
QBrush MainWindow::blendLayer(int x, int y){
QImage blend(m_layer1_data[x][y]->background().textureImage());
QImage l2(m_layer2_data[x][y]->background().textureImage());
QImage l3(m_layer3_data[x][y]->background().textureImage());
for(int a = 0; a < blend.width(); a++){
for(int b = 0; b < blend.height(); b++ ){
blend.setPixelColor(a,b,blendColor(blend.pixelColor(a,b),l2.pixelColor(a,b),l3.pixelColor(a,b)));
}
}
QBrush brush(blend);
return brush;
}
QColor MainWindow::blendColor(QColor c2, QColor c1){
QColor c3;
c3.setRed(((c1.red()+c2.red())/2)%256);
c3.setGreen(((c1.green()+c2.green())/2)%256);
c3.setBlue(((c1.blue()+c2.blue())/2)%256);
c3.setAlpha(((c1.alpha()+c2.alpha())/2)%256);
return c3;
}
QColor MainWindow::blendColor(QColor c1, QColor c2, QColor c3){
return blendColor(c3,blendColor(c1,c2));
}
Is there an easy way to superposing some QImage ?
Thanks for your help
Like Kuba Ober mentioned in the comments, the best way is to simply use QPainter in a way like this:
//[...]
QPainter p(&myWidgetOrSurface);
p.setCompositionMode(QPainter::CompositionMode_Source);
p.drawRect(myWidgetOrSurface.size());
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.drawImage(image1);
p.end();
p.begin(image2);
p.drawImage(surface);
p.end();
//[...]
Here is the documentation for the different blend modes supported by Qt and QPainter.
Thanks a lot I've found a solution with QPainter
QBrush MainWindow::blendLayer(int x, int y){
QImage blend(m_layer1_data[x][y]->background().textureImage());
QImage l2(m_layer2_data[x][y]->background().textureImage());
QImage l3(m_layer3_data[x][y]->background().textureImage());
QImage im(QSize(32,32),QImage::Format_ARGB32);
QPainter painter(&im);
painter.drawImage(im.rect(),blend);
painter.drawImage(im.rect(),l2);
painter.drawImage(im.rect(),l3);
QBrush brush(im);
return brush;
}
Related
I have a robot that has a camera, which I use to capture image and view it on QT Application. The camera output is three [40][40] arrays for RGB colors respectively. I have tried QPaintEvent but it cannot be used as a slot and I found it like inventing the wheel.
gui::EpuckImage image = this->epuck->cameraShot();
int r[40][40],g[40][40],b[40][40];
for(int i=0;i<40;i++){
for(int j=0;j<40;j++){
image.getRGB(i,j,r[i][j],g[i][j],b[i][j]);
}
}
So, I have 40 x 40 RGB Pixels.
void MainWindow::paintEvent(QPaintEvent *event, int r[40][40], int g[40][40], int b[40][40]){
QPainter painter(this);
painter.setBrush(Qt::DiagCrossPattern);
QPen pen;
QColor color(100,0,0, 255);
pen.setColor(color);
pen.setWidth(5);
for(int i=0;i<40;i++){
for(int j=0;j<40;j++){
QColor color(r[i][j],g[i][j],b[i][j], 255);
pen.setColor(color);
painter.setPen(pen);
painter.drawPoint(i,j);
}
}
}
I need to use this code to draw the pixels on click
I have to merge some pixmaps and I want to add them first in a qlist and then merge them .While I know the procedure how to merge them I am confused about which one to use QList of pixmaps or Qlist of pointers to pixmaps and what is the difference and if it's possible to do the merging with a qlist of pointer of pixmaps .
GraphicsPixmapItem *pix =static_cast<QGraphicsPixmapItem *>(item1);
QGraphicsPixmapItem *pix2 =static_cast<QGraphicsPixmapItem *>(item2);
////////////////Merge Pixmaps/////////////////////
int pix_height=75;
int pix_width=50;
//use QList of pixmaps
QList <QPixmap> dragImages;
dragImages<<pix->pixmap()<<pix2->pixmap();//it works
QSize dragPixSize(pix_width*dragImages.size()+50,pix_height);
QPixmap dragpix(dragPixSize);
dragpix.fill(Qt::transparent);
QPainter painter;
painter.begin(&dragpix);
for(int i=0; i < dragImages.size(); ++i){
painter.drawPixmap(pix_width*i,0,pix_width,pix_height,dragImages.at(i));
}
painter.end();
//////////////////////////////////////////
//or use Qlist of pointers to pixmaps?
QList <QPixmap*> pix; //how do I add pix->pixmap() here?
A QPixmap is a cheap-to-copy value, thus you don't need to use pointers: you can use the values directly. If you don't know why you need to use QList: don't use it. It's deprecated in this case - use QVector.
First, let's extract the pixmaps from a vector of graphics items:
#include <QtWidgets>
#include <algorithm>
using QPixmapVector = QVector<QPixmap>;
QPixmapVector getPixmaps(const QVector<QGraphicsItem*> &items) {
QPixmapVector ret;
for (auto item : items) {
auto *pixItem = qgraphicsitem_cast<QGraphicsPixmapItem*>(item);
if (pixItem)
ret.push_back(pixItem->pixmap());
}
return ret;
}
Then, we can merge the pixmaps given in a vector, leaving some extra size at the right end of the strip:
QPixmap mergePixmaps(const QPixmapVector &pixmaps, const QSize &extraSize) {
auto size = extraSize;
for (auto &pix : pixmaps) {
size.setWidth(size.width() + pix.width());
size.setHeight(std::max(size.height(), pix.height()));
}
QPixmap ret(size);
ret.fill(Qt::transparent);
QPainter p(&ret);
int x = 0;
for (auto &pix : pixmaps) {
p.drawPixmap(x, 0, pix.width(), pix.height(), pix);
x += pix.width();
}
return ret;
}
The particular variant of the merge operation you wanted is, then:
QPixmap myMerge(QGraphicsItem *item1, QGraphicsItem *item2) {
auto pixmaps = getPixmaps({item1, item2});
return mergePixmaps(pixmaps, {50, 75});
}
QPainter p(this);
for (int i = 0; i < this->actions().count(); ++i)
{
QAction *action = this->actions().at(i);
QRect actionRect = ...........
QStyleOptionMenuItem opt;
initStyleOption(&opt, action);
opt.rect = actionRect;
QString strPicPath="/h/downloads/tableviewenabledBackGroundImageId.jpg";
QPixmap pic(strPicPath);
pic=pic.scaled(opt.rect.size());
opt.palette.setBrush(QPalette::Background,QBrush(pic));
p.fillRect(opt.rect,opt.palette.background());
style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this);
}
i need get actionRect of QMenu for paint selected menu Item with out Using Qt's Stylesheet.
thanks in advance
Try this->actionGeometry(QAction*), which should return the correct QRect.
I used this in one of my programs, where it worked quite well.
What is the proper way to draw thousands of rects in QT (around 100,000 or more)?
I tried:
Simple with paintEvent() of QWidget.
Drawing objects to QImage then this image to QWidget.
Using QGraphicsScene (maybe I didn't use it properly, I just added rects to scene)
Every time drawing was really slow and I don't have more ideas on how to do this (maybe with opengl/directx but this doesn't sound like a good idea). I know that there exist applications that do that so there should be some way.
EDIT:
I wonder how drawRects() work? Is there a chance that filling some uchar* array and passing it to QImage will be better?
The first trick is to do the drawing in a separate thread onto a QImage, then pass that into the main thread. This won't make it quicker, but it'll make it not block the GUI thread.
// https://github.com/KubaO/stackoverflown/tree/master/questions/threaded-paint-36748972
#include <QtWidgets>
#include <QtConcurrent>
class Widget : public QWidget {
Q_OBJECT
QImage m_image;
bool m_pendingRender { false };
Q_SIGNAL void hasNewRender(const QImage &);
// Must be thread-safe, we can't access the widget directly!
void paint() {
QImage image{2048, 2048, QImage::Format_ARGB32_Premultiplied};
image.fill(Qt::white);
QPainter p(&image);
for (int i = 0; i < 100000; ++i) {
QColor c{rand() % 256, rand() % 256, rand() % 256};
p.setBrush(c);
p.setPen(c);
p.drawRect(rand() % 2048, rand() % 2048, rand() % 100, rand() % 100);
}
emit hasNewRender(image);
}
void paintEvent(QPaintEvent *) {
QPainter p(this);
p.drawImage(0, 0, m_image);
}
public:
Widget(QWidget * parent = 0) : QWidget(parent) {
this->setAttribute(Qt::WA_OpaquePaintEvent);
setMinimumSize(200, 200);
connect(this, &Widget::hasNewRender, this, [this](const QImage & img) {
m_image = img;
m_pendingRender = false;
update();
});
refresh();
}
Q_SLOT void refresh() {
if (!m_pendingRender) {
m_pendingRender = true;
QtConcurrent::run([this] { paint(); });
}
}
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
Widget w;
QPushButton button{"Refresh", &w};
button.connect(&button, &QPushButton::clicked, &w, [&w]{ w.refresh(); });
w.show();
return app.exec();
}
#include "main.moc"
As a separate concern, you can then split the drawing across multiple parallel jobs, by clipping each job's painter to a sub-area of the shared image, and noting that fully clipped rectangle draws are no-ops, and partially clipped ones will only fill the pixels they affect.
Solution which I found:
Create array of uint32_t which can contain all pixels of widget, fill it using memcpy(). Create QImage with this array and use drawImage() to show it.
It can have some optimization like (for profiler) merging rects that are continues ( start time second is equal to end of first ). Don't draw rects that are out of time bounds. Maybe skip too small rects.
For drawing things like text, tool tips you can still use Qt functions.
For alpha blending in simplest case you can just take existing values, blend them in loop and write blended values or maybe use SIMD for this.
Of course for more complex shapes it will get harder to draw but still, I think, it will be faster than using Qt functions.
It's simple to draw line or ellipse just by using scene.addellipse(), etc.
QGraphicsScene scene(0,0,800,600);
QGraphicsView view(&scene);
scene.addText("Hello, world!");
QPen pen(Qt::green);
scene.addLine(0,0,200,200,pen);
scene.addEllipse(400,300,100,100,pen);
view.show();
now what should i do to set some pixel color? may i use a widget like qimage? by the way performance is an issue for me.thanks
I think that performing pixel manipulation on a QImage would slow down your application quite a lot. A good alternative is to subclasse QGraphicsItem in a new class, something like QGraphicsPixelItem, and implement the paint function like this:
// code untested
void QGraphicsPixelItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0)
{
painter->save();
foreach(const QPoint& p, pointList) {
// set your pen color etc.
painter->drawPoint(p);
}
painter->restore();
}
where pointList is some kind of container that you use to store the position of the pixels you want to draw.