I would like to save web page as a PNG image using QtWebKit (pyQt).
I found following code on the internet, but as an output I get white image:
import sys
import signal
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import QWebPage
def onLoadFinished(result):
if not result:
print "Request failed"
sys.exit(1)
# Set the size of the (virtual) browser window
webpage.setViewportSize(QSize(640,480))
# Paint this frame into an image
image = QImage(QSize(640,480), QImage.Format_ARGB32)
paint = QPainter(image)
print webpage.mainFrame().toHtml()
webpage.mainFrame().render(paint)
paint.end()
image.save("output.png")
sys.exit(0)
app = QApplication(sys.argv)
signal.signal(signal.SIGINT, signal.SIG_DFL)
webpage = QWebPage()
webpage.connect(webpage, SIGNAL("loadFinished(bool)"), onLoadFinished)
webpage.mainFrame().load(QUrl("http://maps.googleapis.com/maps/api/streetview?size=640x480&location=50.073723,14.43037&pitch=-0.760&sensor=false&heading=-169.73968469794528"))
sys.exit(app.exec_())
It saves correctly other pages that I've tested, but can't handle Google Street View.
print webpage.mainFrame().toHtml()
shows that proper web page is loaded, but somehow it doesn't render it... Do you know why?
I use: PyQt4-4.10.2-gpl-Py2.7-Qt4.8.4-x64
Related
So let's say I have a URL that stores an image, let's say it's, "https://www.image.site/img.png"
I want to set the pygame icon to that image without downloading anything on my computer.
I am already familiar with the code to set the icon to a file on your computer
img = pygame.image.load('image')
pygame.display.set_icon(img)
But how can I set it to an online image, would just setting the argument in set_icon to the URL work, or do I have to do something more complicated?
Another way:
Use the requests library to download the image bytes
Use BytesIO to create a file stream in memory
Create a PIL.Image from the byte file stream
Use pygame.image.fromstring to convert the PIL image to a pygame image
Here's the code:
import pygame
from io import BytesIO
import requests
from PIL import Image
# create image from URL
rsp = requests.get('https://www.pygame.org/docs/_static/pygame_tiny.png')
pilimage = Image.open(BytesIO(rsp.content)).convert("RGBA")
pgimg = pygame.image.fromstring(pilimage.tobytes(), pilimage.size, pilimage.mode)
# show image
pygame.init()
display = pygame.display.set_mode((250,150))
display.fill((255,255,255))
display.blit(pgimg,((250 - pgimg.get_rect().width)/2,(150 - pgimg.get_rect().height)/2))
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); exit()
Output
I don't know why you'd do that, but I cooked something up for you.
It downloads the data of an image and then loads an image out of that data.
import requests
import io
import pygame
def surf_from_url(url):
data = io.BytesIO()
response = requests.get(url, stream=True)
if not response.ok:
print(response)
for block in response.iter_content(1024):
if not block:
break
data.write(block)
data.seek(0)
return pygame.image.load(data)
#demo
surf = surf_from_url("https://www.pygame.org/images/logo_lofi.png")
surf2 = surf_from_url("https://yt3.ggpht.com/a/AATXAJxybFq6Y8SFOuyvWqldJPcXbCps-gR_Qp2z4jKt=s100-c-k-c0xffffffff-no-rj-mo")
screen = pygame.display.set_mode([300,300])
pygame.display.set_icon(surf)
screen.fill((255,255,255))
screen.blit(surf, (0,0))
screen.blit(surf2, (20,100))
pygame.display.flip()
I am new to Python and I think I broke my python :(
I was trying Sentdex's PyQt4 YouTube tutorial right here.
I made the changes from PyQt4 to PyQt5. This is the code I was playing around. So I think, I messed up by printing the whole page on the console.
Now the output is:
Load finished
Look at you shinin!
Press any key to continue . . .
This is being shown for any code executed. That is python shows this code even if I try print("hello") in Visual code. I even tried to restart. Now like a virus, it is not clearing.
import bs4 as bs
import sys
import urllib.request
from PyQt5.QtWebEngineWidgets import QWebEnginePage
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
class Page(QWebEnginePage):
def __init__(self, url):
self.app = QApplication(sys.argv)
QWebEnginePage.__init__(self)
self.html = ''
self.loadFinished.connect(self._on_load_finished)
self.load(QUrl(url))
self.app.exec_()
def _on_load_finished(self):
self.html = self.toHtml(self.Callable)
print('Load finished')
def Callable(self, html_str):
self.html = html_str
self.app.quit()
def main():
page = Page('https://pythonprogramming.net/parsememcparseface/')
soup = bs.BeautifulSoup(page.html, 'html.parser')
js_test = soup.find('p', class_='jstest')
print js_test.text
print (soup)
#js_test = soup.find('div', class_='aqi-meter-panel')
#display.popen.terminate()
if __name__ == '__main__': main()
OK, so finally got the problem fixed..went manually inside the temp files in C:\Users\xxx\AppData\Local and started on a deletion rampage...removed many files and folder remotely related to python,vscode and conda...this gave an error warning first time I executed my program again...then on subsequent run...no issue...python back to its normal self...surprised that I was not able to find any solution on the net for this.
I am using a pixel based gym environment in my code. For some reasons, I need to modify the render function. Using pyglet, I have created my own class ShowRender with a render and a close function:
import cv2
import pyglet
from gym.envs.classic_control import rendering
class ShowRender(object):
def __init__(self):
self.viewer = rendering.SimpleImageViewer()
self.viewer.width = 512
self.viewer.height = 512
self.viewer.window = pyglet.window.Window(width=self.viewer.width, height=self.viewer.height,
display=self.viewer.display, vsync=False, resizable=True)
def render(self, observation):
self.viewer.imshow(observation)
def close(self):
self.viewer.close()
Function render works perfectly: a new window is created and displays the environment's pixels.
But when I use close function, the window stays open and does not disappear. Any advice to close it properly ? Thanks
Adding this so the question becomes marked as solved, after discussions in the comments above, the solution is pretty simple. calling .close() on the window object helped by doing self.viewer.window.close():
import cv2
import pyglet
from gym.envs.classic_control import rendering
class ShowRender(object):
def __init__(self):
self.viewer = rendering.SimpleImageViewer()
self.viewer.width = 512
self.viewer.height = 512
self.viewer.window = pyglet.window.Window(width=self.viewer.width, height=self.viewer.height,
display=self.viewer.display, vsync=False, resizable=True)
def render(self, observation):
self.viewer.imshow(observation)
def close(self):
self.viewer.window.close()
I'm trying to implement a slot method that will clear a matplotlib figure that is part of QtWidget. I have tried with both Python 3.6 and 3.5 on windows 7 and 10 and i get same behaviour.
My issue is that i can perfectly clear the figure when calling the wipe method from the main block of code or within the class drawing the figure. But whenever this very same method is called as a slot to a PyQT signal, slot is actually activated but the call to fig.clf() does not clear the figure.
The code below shows the issue :
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QApplication,QMainWindow, QSizePolicy,QWidget,QVBoxLayout, QPushButton
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
class GraphPopulate(FigureCanvas):
def __init__(self, parent=None):
self.fig = Figure(figsize=(6,4))
self.ax = self.fig.add_axes([0.07, 0.16, 0.95, 0.95]) # fraction of figure size #
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
x = [2000, 2001, 2002, 2003, 2004]
y = [10, 20, 30, 40, 50]
self.plt = self.ax.plot(x, y)
# self.wipe() # OK This one works as well
# self.plt.close(self.fig) # close the app, does not only clear figure
def wipe(self):
print('wipe start')
# del self.fig # close the app on second call, does not only clear figure !!
# self.plt.close(fig) # close the app, does not only clear figure
rc = self.fig.clf()
print('return code from clf() '+ str(rc))
print('wipe stop')
if __name__ == '__main__':
# create main window
app = QApplication(sys.argv)
MainWindow = QMainWindow()
MainWindow.resize(800, 600)
# create widget to be used by MathPlotlib
WidgetMatplot = QWidget(MainWindow)
WidgetMatplot.setGeometry(QRect(10, 40, 500, 500))
# create Push Button with clicked signal linked to GraphPopulate.wipe() slot
button = QPushButton(MainWindow)
button.setText("Push Me !")
# add widget to vertical box layout
hbox = QVBoxLayout(MainWindow)
hbox.addWidget(WidgetMatplot)
hbox.addWidget(button)
g = GraphPopulate(WidgetMatplot)
button.pyqtConfigure(clicked=g.wipe) # NOT OK !!!!!!! g.wipe is triggered as prints statements show
# on console but self.fig.clf() has no effect
MainWindow.show()
# g.wipe() # OK
sys.exit(app.exec_())
I've put comments on statements that if uncommented are actually clearing the figure or closing the whole app.
Looks like the "matplotlib context" is not the same when called from the signa-slot connect than from other calls.
May be i miss something trivial. If so sorry for that but i couldn't find any direction to investigate by myself...so i rely on you guys to spot it out.
Thanks - Thibault
In your code the figure is successfully cleared. You just don't see it because nobody told the figure that it needs to be redrawn.
If you redraw the figure, you'll see that it is indeed empty.
def wipe(self):
self.fig.clf()
self.fig.canvas.draw_idle()
I am working on a very simple interface to explore/graph csv files. My aim is ultimately to explore, not to build software as I am not a developer, more of a "desperate user" :-)
I am leveraging the code found in this example
These are my first steps both in Python and in GUI, so I tend to put print messages in my calls so that I can more or less track what is happening. And this is where I found a strange behavior if I run the code from within Spyder.
import sys
import os
from PyQt4 import QtGui
import pandas as pd
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
# QtGui.QDialog
class Window(QtGui.QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
# a figure instance to plot on
self.figure = plt.figure()
# this is the Canvas Widget that displays the `figure`
# it takes the `figure` instance as a parameter to __init__
self.canvas = FigureCanvas(self.figure)
# this is the Navigation widget
# it takes the Canvas widget and a parent
self.toolbar = NavigationToolbar(self.canvas, self)
# Just some extra button to mess around
self.button= QtGui.QPushButton('Push Me')
self.button.clicked.connect(self.do_print)
# set the layout
layout = QtGui.QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
layout.addWidget(self.button)
self.setLayout(layout)
def do_print(self):
print('Hello World!!')
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
main = Window()
main.show()
sys.exit(app.exec_())
The strange behavior is that if I push the button once, nothing happens on the Ipython console. By the second time I push, then two "Hello World!" printouts appear.
If, on the other hand, I just launch my script from within a Windows Shell:
python my_simple_test.py
Then everything works as expected.
What am I then doing wrong from within Spyder?
Thanks,
Michele
IPython buffers stdout a bit differently from a terminal. When something is printed, it looks at how long it has been since it last flushed the buffer, and if it's longer than some threshold, it flushes it again. So the second time you click the button, it flushes stdout, and you see both outputs.
You can force it to flush immediately like this:
print('Hello World!!')
sys.stdout.flush()