为什么从 QGraphicsScene 渲染的 PNG 图像偏移不正确?
我有一个程序可以将 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
发生的情况是,视图自动计算场景的矩形,然后将其自身集中在已添加的图形项上。根据物品的尺寸,有时可能会在边缘周围留下空白区域。
解决方案是显式地为场景设置一个矩形:
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: