1

I have a big image of 7589x5537 that I put in a scene as a QPixmapGraphicsItem.

If I scale the QGraphicsView to 14.2318 and rotate it -35 degrees, the render of the pixmap starts behaving weirdly; tearing or completely disappearing.

This happens also at other rotations and scales, but only if they are big scaling of more than 14.

I've read about X11 limitations but I'm on Windows.

I'm on Qt 5.5

I've tested changing the content of the image to a bucketfill of tree pattern, exactly the same behaviour. The image is indexed, but with a RGB I have the same issue.

Anybody has a clue why this happens and how to fix it? Is the problem reproducible?

The issue seems to be related to the maximum value of unsigned int, dimension independent if not rotated. Creating an untilted image of 1 million by 200 pixels, one can zoom up to 4384x. In my computer the size of unsigned int is 4 bytes, which can handle roughly values up to 4000 million.

I presume Qt doesn't crop the upscaled image to the view before scaling it, or something similar. It is weird, thought, that it tears it instead of crashing exhausting resources, failing to allocate contiguous memory or something else.

Those are suspicions since at the moment I don't know how QGraphicsView implements scaling.

#include <QtWidgets>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    unsigned int w = 7589;
    unsigned int h = 5537;

    QImage image(w, h, QImage::Format_ARGB32);
    for(unsigned int j = 0; j < h; j++)
    {
        for(unsigned int i = 0; i < w; i++)
        {
            QRgb rgb = qRgb(i%255,j%255,(i+j)%255);
            image.setPixel(i, j, rgb);
        }
    }

    QPixmap imagepm = QPixmap::fromImage(image);

    QGraphicsPixmapItem* item = new QGraphicsPixmapItem(imagepm);
    item->setTransformationMode(Qt::FastTransformation);
    QGraphicsScene* scene = new QGraphicsScene;
    scene->addItem(item);

    QGraphicsView* view = new QGraphicsView(scene);
    view->rotate(-35);
    view->scale(14.2318,14.2318);
    view->show();
    return a.exec();
}
quimnuss
  • 1,503
  • 2
  • 17
  • 37

1 Answers1

0

The fix requires cutting the image up into tiles, grouping them under a single parent item, and then proceeding as you did before. The tiles would be an implementation detail that you don't need to worry about.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • I'll see if tiling fixes the issue and get back to you. Could you elaborate on the reason of the tearing happening? What do you mean 'an implementation detail that you don't need to worry about'? Note that using QImage might be worse, i've checked the image viewer qt creator's example and un-limited the zoom in. The program crashes exhausting memory. – quimnuss May 03 '18 at 06:48
  • See my update. I have the strong suspicion the problem is in reality unrelated to the size of the image, and that if I have a scene bigger than the size of unsigned int I would have the same effect. I'll try to prove it with two one-pixel images set 4Gpixels apart. – quimnuss May 03 '18 at 10:20
  • Well, I was wrong. If the image is split the problem appears relative to the size of each piece, so zoom times width of piece value has to fit in a 4-byte unsigned int. – quimnuss May 03 '18 at 13:39
  • The scene coordinates are floating point, so the scene size doesn't matter. Image painting code uses integers for speed, so a zoom factor too big is not usable. Tiling is trivial though. – Kuba hasn't forgotten Monica May 03 '18 at 14:03
  • The tiles being an implementation detail means that the code that deals with the image as a whole still sees a single `QGraphicsItem`. The tiles are its children and are not much of a problem. – Kuba hasn't forgotten Monica May 03 '18 at 14:06
  • I don't know what happened on my first test, but tiling works. – quimnuss May 03 '18 at 14:46
  • Could you add the two comments to the answer? I think it helps understand what happens and why this fixes it. (maybe elaborate a little bit 'painting code uses integers for speed' ?) – quimnuss May 03 '18 at 14:59
  • How can I obtain the maximum scale value? I'm doing more tests and seems to happen as well assuming 2 bytes integer instead of 4 bytes integer under certain rotations and conditions. – quimnuss May 03 '18 at 15:36