PyQt: QImage() returns 一个 'Null'-图像
PyQt: QImage() returns a 'Null'-Image
我需要为我的项目截取网站截图。作为开发语言,我使用 Python 并使用 PyQt 中的 Webkit 来截取屏幕截图。下面的脚本是用于捕获网站的代码(它被部分修改但 most 仍然等于来自 webscraping.com 的原始代码)。
现在我的问题如下:
Most 的时候它工作没有任何问题,但是,不时发生以下异常。
QPainter::begin: Paint device returned engine == 0, type: QPainter::setRenderHint: Painter must be active to set rendering hints
QPainter::setBrush: Painter not active
QPainter::pen: Painter not active
QPainter::setPen: Painter not active
QPainter::end: Painter not active, aborted
我已经追踪到创建图像的问题
image = QImage(self.page().viewportSize(), QImage.Format_ARGB32)
此行返回的 QImage 有时为 Null - 我使用 QImage 的 .isNull() 方法检查了这一点。
根据 Qt 文档,如果没有足够的内存来分配新的 QImage,就会发生这种情况,但我仍然有足够的可用内存。
这种行为发生在 运行 和 windows 以及 linux 上,所以我认为它不应该依赖于某些 os 依赖的东西。我是 Qt 和 PyQt 的新手,所以我希望有人能帮助我。
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *
import sys
import time
# ############################################################# #
# This script is based on the following script: #
# https://webscraping.com/blog/Webpage-screenshots-with-webkit/ #
# ############################################################# #
class Screenshot(QWebView):
_instance = None
@staticmethod
def get_instance():
# TODO: Add a lock around the if including the creation!
if Screenshot._instance is None:
Screenshot._instance = Screenshot()
return Screenshot._instance
def __init__(self):
self.app = QApplication(sys.argv)
QWebView.__init__(self)
self._loaded = False
self.loadFinished.connect(self._loadFinished)
def capture(self, url, output_file):
self.load(QUrl(url))
self.wait_load()
# set to webpage size
frame = self.page().mainFrame()
self.page().setViewportSize(frame.contentsSize())
# render image
# creating the image. Here it happens that QImage returns a 'Null'-Image
image = QImage(self.page().viewportSize(), QImage.Format_ARGB32)
# check if there's no image allocated
if image.isNull():
print 'image.isNull() is True'
if image is None:
print 'image is None is True'
painter = QPainter(image)
frame.render(painter)
painter.end()
print 'saving', output_file
image.save(output_file)
def wait_load(self, delay=0):
# process app events until page loaded
while not self._loaded:
self.app.processEvents()
time.sleep(delay)
self._loaded = False
def _loadFinished(self, result):
self._loaded = True
if __name__ == '__main__':
# a simple way to get the exceptions is to try to create multiple screenshots
sc = Screenshot()
for i in range(0, 25):
sc.capture('http://google.de', str(i) + '.png')
for i in range(25, 50):
sc.capture('http://de.wikipedia.org', str(i) + '.png')
好的。我已经进一步跟踪了这个问题。看起来 QWebPages mainFrame 的 contentsSize 在读取以创建 QImage 时有时是 (0, 0)。
frame = self.page().mainFrame()
self.page().setViewportSize(frame.contentsSize()) # frame.contentsSize() = (0, 0)
image = QImage(self.page().viewportSize(), QImage.Format_ARGB32) # so we're creating here an Image with Width: 0 and Height: 0
所以基本上 QImage 似乎是 Null,因为它创建的大小是 (0, 0)。
这个问题可以通过检查 mainFrames contentsSize 是否为 (0, 0) 来解决。如果它是 (0, 0),则需要处理 QApplication 上的未完成事件,直到设置新的 contentsSize。我现在使用以下代码执行此操作:
if frame.contentsSize().width() == 0 or frame.contentsSize().height() == 0:
print 'ContentsSize = (w: {}, h: {})'.format(frame.contentsSize().width(), frame.contentsSize().height())
count = 0 # used so we're not starting an infinite loop
while (frame.contentsSize().width() == 0 or frame.contentsSize().height() == 0) and count < 5:
count += 1
self.app.processEvents()
time.sleep(1)
我需要为我的项目截取网站截图。作为开发语言,我使用 Python 并使用 PyQt 中的 Webkit 来截取屏幕截图。下面的脚本是用于捕获网站的代码(它被部分修改但 most 仍然等于来自 webscraping.com 的原始代码)。
现在我的问题如下:
Most 的时候它工作没有任何问题,但是,不时发生以下异常。
QPainter::begin: Paint device returned engine == 0, type: QPainter::setRenderHint: Painter must be active to set rendering hints
QPainter::setBrush: Painter not active
QPainter::pen: Painter not active
QPainter::setPen: Painter not active
QPainter::end: Painter not active, aborted
我已经追踪到创建图像的问题
image = QImage(self.page().viewportSize(), QImage.Format_ARGB32)
此行返回的 QImage 有时为 Null - 我使用 QImage 的 .isNull() 方法检查了这一点。
根据 Qt 文档,如果没有足够的内存来分配新的 QImage,就会发生这种情况,但我仍然有足够的可用内存。
这种行为发生在 运行 和 windows 以及 linux 上,所以我认为它不应该依赖于某些 os 依赖的东西。我是 Qt 和 PyQt 的新手,所以我希望有人能帮助我。
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *
import sys
import time
# ############################################################# #
# This script is based on the following script: #
# https://webscraping.com/blog/Webpage-screenshots-with-webkit/ #
# ############################################################# #
class Screenshot(QWebView):
_instance = None
@staticmethod
def get_instance():
# TODO: Add a lock around the if including the creation!
if Screenshot._instance is None:
Screenshot._instance = Screenshot()
return Screenshot._instance
def __init__(self):
self.app = QApplication(sys.argv)
QWebView.__init__(self)
self._loaded = False
self.loadFinished.connect(self._loadFinished)
def capture(self, url, output_file):
self.load(QUrl(url))
self.wait_load()
# set to webpage size
frame = self.page().mainFrame()
self.page().setViewportSize(frame.contentsSize())
# render image
# creating the image. Here it happens that QImage returns a 'Null'-Image
image = QImage(self.page().viewportSize(), QImage.Format_ARGB32)
# check if there's no image allocated
if image.isNull():
print 'image.isNull() is True'
if image is None:
print 'image is None is True'
painter = QPainter(image)
frame.render(painter)
painter.end()
print 'saving', output_file
image.save(output_file)
def wait_load(self, delay=0):
# process app events until page loaded
while not self._loaded:
self.app.processEvents()
time.sleep(delay)
self._loaded = False
def _loadFinished(self, result):
self._loaded = True
if __name__ == '__main__':
# a simple way to get the exceptions is to try to create multiple screenshots
sc = Screenshot()
for i in range(0, 25):
sc.capture('http://google.de', str(i) + '.png')
for i in range(25, 50):
sc.capture('http://de.wikipedia.org', str(i) + '.png')
好的。我已经进一步跟踪了这个问题。看起来 QWebPages mainFrame 的 contentsSize 在读取以创建 QImage 时有时是 (0, 0)。
frame = self.page().mainFrame()
self.page().setViewportSize(frame.contentsSize()) # frame.contentsSize() = (0, 0)
image = QImage(self.page().viewportSize(), QImage.Format_ARGB32) # so we're creating here an Image with Width: 0 and Height: 0
所以基本上 QImage 似乎是 Null,因为它创建的大小是 (0, 0)。
这个问题可以通过检查 mainFrames contentsSize 是否为 (0, 0) 来解决。如果它是 (0, 0),则需要处理 QApplication 上的未完成事件,直到设置新的 contentsSize。我现在使用以下代码执行此操作:
if frame.contentsSize().width() == 0 or frame.contentsSize().height() == 0:
print 'ContentsSize = (w: {}, h: {})'.format(frame.contentsSize().width(), frame.contentsSize().height())
count = 0 # used so we're not starting an infinite loop
while (frame.contentsSize().width() == 0 or frame.contentsSize().height() == 0) and count < 5:
count += 1
self.app.processEvents()
time.sleep(1)