为什么从 QGraphicsScene 渲染的 PNG 图像偏移不正确?

发布于 2024-12-19 07:32:41 字数 3896 浏览 2 评论 0原文

我有一个程序可以将 QGraphicsScene 的内容绘制到 PNG 图像。我发现在某些情况下 PNG 图像无法正确创建。生成的图像似乎存在一定量的“偏移”,因为 QGraphicsScene 的左上角不在 PNG 图像中的 (0,0) 处。

下面的代码演示了这个问题。 createImage 函数创建一个给定宽度和高度的 QGraphicsScene,在坐标 (0, 0) 处绘制与场景宽度和高度相同的实心红色矩形,渲染将此场景转换为图像并将图像写入文件。我相信这个函数应该总是写出一个纯红色的图像,无论它给出的宽度和高度如何。然而,这里是一个示例输出图像,它表明这不是案件。

testImage 函数(依赖于 PIL)读取图像并检查最右边的列和底行。如果图像被错误地“偏移”,它将在底行或最右列内的某处找到一个白色像素。如果图像已正确生成,则底行和最右列将仅包含红色像素。 (PIL 不是这里问题的一部分;我只是用它来自动测试输出图像。)

#!/usr/bin/env python

import sys
import Image        # Requires PIL
from PyQt4.QtCore import Qt, QRect, QRectF
from PyQt4.QtGui import QPen, QBrush, QGraphicsScene, QGraphicsView, QGraphicsRectItem, QPixmap, QPainter, QApplication

whitebrush = QBrush(Qt.white)
redbrush = QBrush(Qt.red)

RED = (255, 0, 0)

def createImage(width, height):
    scene = QGraphicsScene(0, 0, width, height)
    scene.setBackgroundBrush(whitebrush)

    rectangle = QGraphicsRectItem(0, 0, width, height)
    rectangle.setPen(QPen(Qt.NoPen))
    rectangle.setBrush(redbrush)
    rectangle.show()
    scene.addItem(rectangle)

    view = QGraphicsView()
    view.setScene(scene)

    outputimg = QPixmap(width, height)
    painter = QPainter(outputimg)
    targetrect = QRectF(0, 0, width, height)
    sourcerect = QRect(0, 0, width, height)
    view.render(painter, targetrect, sourcerect)
    outputimg.save("output.png", "PNG")

    painter.end()

def testImage(width, height):
    image = Image.open("output.png")
    ok = True

    for x in range(width):
        if image.getpixel((x, height - 1)) == RED:
            if x > 0:
                print "First red pixel on bottom row is at x = %d" % x
                ok = False

            break
    else:
        print "No red pixels found on bottom row"
        ok = False

    for y in range(height):
        if image.getpixel((width - 1, y)) == RED:
            if y > 0:
                print "First red pixel in rightmost column is at y = %d" % y
                ok = False

            break
    else:
        print "No red pixels found in rightmost column"
        ok = False

    if ok:
        print "Image OK"

def doTest(width, height):
    createImage(width, height)
    testImage(width, height)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    doTest(int(sys.argv[1]), int(sys.argv[2]))

以下是一些运行示例:

$ ./qgraphicssceneimagetest.py 200 200
No red pixels found on bottom row
No red pixels found in rightmost column

在这种情况下,“偏移”的影响是如此剧烈,以至于整个输出图像为白色。

$ ./qgraphicssceneimagetest.py 400 400
First red pixel on bottom row is at x = 117
First red pixel in rightmost column is at y = 37

这就是生成我上面链接的示例图像的情况。

$ ./qgraphicssceneimagetest.py 500 500
First red pixel on bottom row is at x = 55

此时,图像现在已正确垂直偏移,但红色矩形仍绘制得离右侧太远 55 像素。

$ ./qgraphicssceneimagetest.py 600 600
First red pixel on bottom row is at x = 5

现在几乎正确了...

$ ./qgraphicssceneimagetest.py 700 700
Image OK

因此,如果图像足够大,代码似乎可以正确生成输出图像。

碰巧的是,我有一个解决这个问题的方法。 我可以使用 createImage 函数来正确创建图像

    sourcerect = QRect(0, 0, width, height)

如果我将该行替换为“

    xoff = 0
    yoff = 0

    if width <= 634 and height <= 474:
        xoff = (634 - width) // 2
        yoff = (474 - height) // 2
    elif width < 610:
        xoff = (610 - width) // 2
    elif height < 450:
        yoff = (450 - height) // 2

    sourcerect = QRect(xoff, yoff, width, height)

我不知道此代码中“魔术”数字的意义是什么”, 。但是,我已经使用此解决方法运行了大量测试,并验证它们都生成了正确的纯红色图像。

有了这个解决方法就可以了,但我想了解为什么这些图像没有正确创建。有什么我错过或忘记做的事情吗?

I have a program that draws the contents of a QGraphicsScene to a PNG image. I have found that in some circumstances the PNG image is not being created correctly. The image generated appears to be 'offset' by some amount, in that the top-left corner of the QGraphicsScene isn't at (0,0) in the PNG image.

The code below demonstrates the problem. The createImage function creates a QGraphicsScene of a given width and height, draws at coordinates (0, 0) a solid red rectangle of the same width and height as the scene, renders this scene to an image and writes the image out to a file. I believe that this function should always write out an image that is solid red, regardless of the width and height it is given. However, here is one example output image which demonstrates that this is not the case.

The testImage function (which relies on PIL) reads in the image and inspects the rightmost column and bottom row. If the image has been incorrectly 'offset', it will find a white pixel somewhere within the bottom row or rightmost column. If the image has been generated correctly, the bottom row and rightmost column will contain only red pixels. (PIL isn't part of the problem here; I'm just using it to automate the testing of the output images.)

#!/usr/bin/env python

import sys
import Image        # Requires PIL
from PyQt4.QtCore import Qt, QRect, QRectF
from PyQt4.QtGui import QPen, QBrush, QGraphicsScene, QGraphicsView, QGraphicsRectItem, QPixmap, QPainter, QApplication

whitebrush = QBrush(Qt.white)
redbrush = QBrush(Qt.red)

RED = (255, 0, 0)

def createImage(width, height):
    scene = QGraphicsScene(0, 0, width, height)
    scene.setBackgroundBrush(whitebrush)

    rectangle = QGraphicsRectItem(0, 0, width, height)
    rectangle.setPen(QPen(Qt.NoPen))
    rectangle.setBrush(redbrush)
    rectangle.show()
    scene.addItem(rectangle)

    view = QGraphicsView()
    view.setScene(scene)

    outputimg = QPixmap(width, height)
    painter = QPainter(outputimg)
    targetrect = QRectF(0, 0, width, height)
    sourcerect = QRect(0, 0, width, height)
    view.render(painter, targetrect, sourcerect)
    outputimg.save("output.png", "PNG")

    painter.end()

def testImage(width, height):
    image = Image.open("output.png")
    ok = True

    for x in range(width):
        if image.getpixel((x, height - 1)) == RED:
            if x > 0:
                print "First red pixel on bottom row is at x = %d" % x
                ok = False

            break
    else:
        print "No red pixels found on bottom row"
        ok = False

    for y in range(height):
        if image.getpixel((width - 1, y)) == RED:
            if y > 0:
                print "First red pixel in rightmost column is at y = %d" % y
                ok = False

            break
    else:
        print "No red pixels found in rightmost column"
        ok = False

    if ok:
        print "Image OK"

def doTest(width, height):
    createImage(width, height)
    testImage(width, height)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    doTest(int(sys.argv[1]), int(sys.argv[2]))

Here are a few example runs:

$ ./qgraphicssceneimagetest.py 200 200
No red pixels found on bottom row
No red pixels found in rightmost column

In this case the effect of the 'offsetting' is so drastic that the entire output image is white.

$ ./qgraphicssceneimagetest.py 400 400
First red pixel on bottom row is at x = 117
First red pixel in rightmost column is at y = 37

This is the case that generated the sample image I linked to above.

$ ./qgraphicssceneimagetest.py 500 500
First red pixel on bottom row is at x = 55

At this point, the image is now correctly offset vertically, but the red rectangle is still being drawn 55 pixels too far to the right.

$ ./qgraphicssceneimagetest.py 600 600
First red pixel on bottom row is at x = 5

Nearly correct now...

$ ./qgraphicssceneimagetest.py 700 700
Image OK

So it seems that the code can generate an output image correctly if the image is large enough.

As it happens, I have a workaround for this problem. I can get the createImage function to create the images correctly if I replace the line

    sourcerect = QRect(0, 0, width, height)

with

    xoff = 0
    yoff = 0

    if width <= 634 and height <= 474:
        xoff = (634 - width) // 2
        yoff = (474 - height) // 2
    elif width < 610:
        xoff = (610 - width) // 2
    elif height < 450:
        yoff = (450 - height) // 2

    sourcerect = QRect(xoff, yoff, width, height)

I do not know what the significance of the 'magic' numbers in this code is. However, I have run numerous tests with this workaround in place and have verified that they all generated a correct solid red image.

Having this workaround is all right, but I'd like to understand why these images aren't being created correctly. Is there something I've missed or forgotten to do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

就是爱搞怪 2024-12-26 07:32:41

发生的情况是,视图自动计算场景的矩形,然后将其自身集中在已添加的图形项上。根据物品的尺寸,有时可能会在边缘周围留下空白区域。

解决方案是显式地为场景设置一个矩形:

view = QGraphicsView()
view.setScene(scene)
view.setSceneRect(QRectF(view.viewport().rect()))

What is happening, is that the view is automatically calculating a rect for the scene and then centring itself on the graphics items that have been added. Depending on the dimensions of the items, this may sometimes leave blank areas around the edges.

The solution is to explicitly set a rect for the scene:

view = QGraphicsView()
view.setScene(scene)
view.setSceneRect(QRectF(view.viewport().rect()))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文