Maxime Chéramy
Maxime Chéramy

Reputation: 18821

Draw an image too big to fit into a QImage

I need to display a chart that can be very large, for example the image resolution could be 100 000 x 1000. However, it seems like I am limited to 32768 x 32768 by the QImage.

I can't reasonably redraw directly the chart at every paintEvent so I need to store it into a QImage (it could be a QPixmap that won't change anything). But then, it doesn't fit.

My first idea was:

The first and last points have been done quite easily. But the second point is more complex. I'm quite confident that my approach would work but it requires to overload the basic paint methods (draw rectangle, circles, etc.) in order to be able to paint on multiple images.

So, before going any further, I would like to know what could be the other options.

Upvotes: 1

Views: 825

Answers (3)

You do realize that a 100,000 x 1000 RGBA QImage is 400MBytes? There's no point in wasting all that memory. Really, none.

Just paint it every time, one request, in the paintEvent. Be clever about it so that you only paint what needs to be shown. I'd think one should focus on optimizing the painting process and your data structures so that it can be painted effectively.

At small scales (zoomed out), a lot can be gained by approximating/decimating/interpolating the data so that it looks the same, but you don't waste time painting the same pixel too many times.

Upvotes: 0

Pavel Strakhov
Pavel Strakhov

Reputation: 40492

You can use the Qt Graphics View Framework. Create a QGraphicsView and a QGraphicsScene for it. Add items using QGraphicsScene::addPixmap (that returns QGraphicsPixmapItem which is derived from QGraphicsItem) and adjust their positions using QGraphicsItem::setPos. QGraphicsView will effectively draw your scene and handle scrolling and zooming if necessary.

Upvotes: 1

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275370

You probably do not want to display more than one QImage of data at a time. Few screens are more than 32k pixels wide or tall.

So you want an abstract type that produces QImages on request for reading, at offsets and possibly at different zoom factors.

The next problem is modifying this abstract type. An easy to use, not maximally performance version consists of letting users blit QImages into your internal storage (whatever that is).

The user still has to "tile" their efforts, but can tile their efforts in ways that is convenient for them.

A higher performance version exposes some of the underlying implementation, which we have not yet mentioned.

A traditional implementation for large images is a tiled image. You have a grid of image tiles that abut each other. When someone asks for a blit from your image, you produce a temporary QImage, and blit the appropriate tiles onto it. And when someone blits to you, you figure out what the appropriate tiles are, and write parts of that source QImage over parts of them.

The higher performance interface exposes these tiles.

A low level interface lets the outside know where your tiles are, and lets them ask for them. This is a poor interface.

A better interface exposes a sub tile iterator. They ask for a region, and you return a pair of iterators that describe the region. The data in the iterators consists of either a tile and a region in that tile as well as the location this region is in the "full image", or a sub-tile object (with linestride, line length, etc) and the location of the sub-tile object.

Another good interface is a foreach style interface. Again, the user of the big image class passes in a region they want to work with, but a callback as well. That callback something similar to either one of the above results of the iterator dereference.

This approach has two large advantages over the iterator approach. First, you can implement parallel image processing algorithms within your large image class. Second, it is much easier to write than rolling your own iterator.

Once you have either of these, drawing is relatively easy. Determine the region you are drawing on (be generous). Iterate over the resulting tiles. On each tile, draw after applying the offset of the tile to the drawing.

Upvotes: 2

Related Questions