I'm pretty new to C++/Qt and I'm trying to create an application with Visual Studio C++ and Qt (4.8.3). The application displays images using a QGraphicsView, I need to change the images at pixel level.
The basic code is (simplified):
QImage* img = new QImage(img_width,img_height,QImage::Format_RGB32);
while(do_some_stuff) {
img->setPixel(x,y,color);
}
QGraphicsPixmapItem* pm = new QGraphicsPixmapItem(QPixmap::fromImage(*img));
QGraphicsScene* sc = new QGraphicsScene;
sc->setSceneRect(0,0,img->width(),img->height());
sc->addItem(pm);
ui.graphicsView->setScene(sc);
This works well for images up to around 12000x6000 pixel. The weird thing happens beyond this size. When I set img_width=16000
and img_height=8000
, for example, the line img = new QImage(...)
returns a null image. The image data should be around 512,000,000 bytes, so it shouldn't be too large, even on a 32 bit system. Also, my machine (Win 7 64bit, 8 GB RAM) should be capable of holding the data.
I've also tried this version:
uchar* imgbuf = (uchar*) malloc(img_width*img_height*4);
QImage* img = new QImage(imgbuf,img_width,img_height,QImage::Format_RGB32);
At first, this works. The img pointer is valid and calling img->width()
for example returns the correct image width (instead of 0, in case the image pointer is null).
But as soon as I call img->setPixel()
, the pointer becomes null and img->width()
returns 0.
So what am I doing wrong? Or is there a better way of modifying large images on pixel level?
Regards, David
QImage supports a maximum of 32768x32768 px images (signed short). This follows from the condition: width * height * colordepth < INT_MAX (4 billion) -> 32768 * 32768 * 4 = 4 billion. The second condition is of course that malloc is able to allocate the requested memory.
If you really need bigger images you will have to use another wrapper or split into multiple QImage's.
I tracked down the problem. I just forgot to add the /LARGEADDRESSAWARE
flag to the Linker options.
I did also really appreciate Stephen Chu's answer with the scanLine() hint. First it saves some memory, second it's really a lot faster.
Now I can safely create images up to 32000x16000 pixel which was my desired aim.
Your second approach is the right way to go. The problem you are having with it is when you call setPixel()
, QImage
makes a copy of the external buffer you provided and runs out of memory for it.
Try changing the pixel value directly in the supplied buffer. You can use scanLine()
to get the pointer to the buffer of a line. I would not use setPixel()
anyway since it's really slow.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With