Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems with large QImage

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

like image 849
David Günzel Avatar asked Nov 26 '12 23:11

David Günzel


3 Answers

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.

like image 72
Alexander Nassian Avatar answered Nov 17 '22 11:11

Alexander Nassian


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.

like image 21
David Günzel Avatar answered Nov 17 '22 13:11

David Günzel


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.

like image 1
Stephen Chu Avatar answered Nov 17 '22 11:11

Stephen Chu