[Development] What is the correct way to use QTransform to rotate a QImage by the Y axis?

Eirik Aavitsland eirik.aavitsland at qt.io
Wed Jul 20 17:25:04 CEST 2022


Ok as far as I can see, this does not have anything to do with image 
transformations as such. Using the same transform to to map just a 
QRect/QRectF shows the same issue.

As I understand it, the issue here is that when doing perspective 
transformation calculations, one needs to know how far away the "camera" 
is. In the simplified world of QTransform, that distance is hardcoded to 
be 1024. Now as the projection of the closest edge of a rect gets 
"close" to the camera (or even extends "behind" it), its projected size 
grows exponentially, as one would expect. Hence, the required image size 
quickly exceeds the max allowed size of a QImage. The result is then a 
null QImage, and that error case is (somewhat confusingly) reported as 
an out of memory situation.

func2() works, IIUC, because it effectively changes the camera distance 
to be image.width(). Since the image is rotated around its center, it 
never gets closer to the camera than half its width, and so the huge 
projection effect never happens. So that is then a good workaround if 
one needs image transformations of this kind. QMatrix4x4::toTransform() 
can probably also be used, it takes a camera distance parameter.

It should be noted that if one just paints (with transformation) the 
rectangle/image instead of transforming it, one does not run into the 
problem, since the huge coordinates simply get clipped.

I have no idea if this whole thing is in any way related to QTBUG-75954, 
though :)

- Eirik Aa.

On 7/20/22 07:48, JiDe Zhang wrote:
> I want to rotate the image to 45 degrees by Y axis, what should I do?
> 
> bool func1()
> {
>      QImage image(3840, 2160, QImage::Format_ARGB32_Premultiplied);
>      image.fill(Qt::red);
> 
>      QTransform t;
>      t.translate(image.width() / 2.0, image.height() / 2.0);
>      t.rotate(-45, Qt::YAxis);
>      t.translate(-image.width() / 2.0, -image.height() / 2.0);
>      image = image.transformed(t);
> 
>      return image.save("/tmp/func1.png");
> }
> 
> The func1 is output the "QImage: out of memory, returning null image" 
> error message and return false. This behavior is related to the size of 
> the image. If it is a 1000x1000 image, it can be successful. But the 
> rotated image is different as use GIMP, is this a Qt bug?
> 
> bool func2()
> {
>      QImage image(3840, 2160, QImage::Format_ARGB32_Premultiplied);
>      image.fill(Qt::red);
> 
>      QTransform t;
>      t.translate(image.width() / 2.0, image.height() / 2.0);
> 
>      qreal b = qDegreesToRadians(-45);
>      qreal sina = qSin(b);
>      qreal cosa = qCos(b);
>      QTransform tmp(cosa, 0, -sina / image.width(), // There is "-sina / 
> 1024" in QTransform::rotate
>                     0, 1, 0,
>                     0, 0, 1);
> 
>      t = tmp * t;
>      t.translate(-image.width() / 2.0, -image.height() / 2.0);
>      image = image.transformed(t);
> 
>      return image.save("/tmp/func2.png");
> }
> 
> The func2 is return true. I can't understand the QTransform::rotate, 
> What is the "inv_dist_to_plane"? Why is its value 1/1024?
> 
> _______________________________________________
> Development mailing list
> Development at qt-project.org
> https://lists.qt-project.org/listinfo/development



More information about the Development mailing list