Convert html to pdf using pyqt5 without showing a screen - python-3.x

I am trying to render html to pdf using QtWebEngineWidgets using the following code.
import sys
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
from tempfile import gettempdir
from pathlib import Path
def printhtmltopdf(html_in, callback):
tfile =Path(gettempdir(), 'printhtmltopdf.html')
with open(tfile, 'wb') as tempf:
tempf.write(html_in)
app = QtWidgets.QApplication(sys.argv)
loader = QtWebEngineWidgets.QWebEngineView()
loader.setZoomFactor(1)
loader.page().pdfPrintingFinished.connect(
lambda *args: print('finished:', args))
loader.load(QtCore.QUrl().fromLocalFile(str(tfile)))
def emit_pdf(finished):
loader.page().printToPdf(callback)
app.exit(0)
loader.loadFinished.connect(emit_pdf)
app.exec()
However the callback is never triggered. When I omit the app.exit(0) it works, but it will wait for user interaction which I do not want. In fact I would prefer to execute the routine without the eventloop at all.

You have to use a QWebEnginePage, also it is not necessary to create temporary files but you can load the HTML directly:
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
def printhtmltopdf(html_in, pdf_filename):
app = QtWidgets.QApplication([])
page = QtWebEngineWidgets.QWebEnginePage()
def handle_pdfPrintingFinished(*args):
print("finished: ", args)
app.quit()
def handle_loadFinished(finished):
page.printToPdf(pdf_filename)
page.pdfPrintingFinished.connect(handle_pdfPrintingFinished)
page.loadFinished.connect(handle_loadFinished)
page.setZoomFactor(1)
page.setHtml(html_in)
app.exec()
printhtmltopdf(
"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello!</title>
</head>
<body>
<h1>Hello World!</h1>
<p>This is a simple paragraph.</p>
</body>
</html>""",
"test.pdf",
)

Related

Flask with opencv-python: Keep camera running before accessingg #app.route and take image when GET request sent

I am trying to initialize the camera and start the video feed and then open the #app.route function and the frame should only be saved when i recieve a URL from GET request.
My code is :
from flask import Flask, jsonify
from flask import request
from flask_restful import Resource, Api, reqparse
from datetime import datetime
import time
import numpy as np
import glob
import os
import sys
import cv2
# initialize the flask application
app = Flask(__name__)
# initialize the camera and grab a reference to the raw camera capture
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# Our operations on the frame come here
#gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Display the resulting frame
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
#RESTAPI for image
#app.route('/take_image')
def image():
start_time = time.time()
jobnummer = request.args.get('JOB') #if key doesn't exist, returns None
#save the frame when GET Request is sentt
if jobnummer:
cv2.imwrite('test.jpg', frame)
end_time = time.time()
time_tot = end_time-start_time
res = {"jobnummer" : jobnummer,
"time":time_tot
}
return jsonify(res) , 200
if __name__ == "__main__":
# run flask application in debug mode
app.run(debug=True,port=5000,host='0.0.0.0')
But when i run this, due to the while loop, i can not enter the #app.route function. Is there any way to keep the video feel running then access the #app.route?
Here is a demo which solves the problem:
from flask import Flask, render_template, Response
import cv2
app = Flask(__name__)
'''
for ip camera use - rtsp://username:password#ip_address:554/user=username_password='password'_channel=channel_number_stream=0.sdp'
for local webcam use cv2.VideoCapture(0)
'''
camera = cv2.VideoCapture(0)
def gen_frames():
while True:
success, frame = camera.read() # read the camera frame
if not success:
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
#app.route('/')
def index():
return render_template('index.html')
#app.route('/video_feed')
def video_feed():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == "__main__":
app.run(debug=True)
index.html (uses bootstrap but not necesssary)
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<title>Live Streaming Demonstration</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 offset-lg-2">
<h3 class="mt-5">Live Streaming</h3>
<img src="{{ url_for('video_feed') }}" width="100%">
</div>
</div>
</div>
</body>
</html>
Adapted from here with code here

How to fix ```<function Render.__getattr__.<locals>.template at 0x7f1dafac8400>``` error in python3 web.py

I'm using web.py for python3. And gets an error.
Error:
function Render.getattr..template at 0x7fcf15a43840
main.py
import web
from web.template import render
urls = (
'/', 'Home'
)
render = web.template.render('Views/Templates/', base='MainLayout')
app = web.application(urls, globals())
#routes
class Home:
def GET(self):
return render.Home
if __name__ == '__main__':
app.run()
Views/Templates/MainLayout.html
def with (page)
<html>
<head>
<title> Title </title>
</head>
<body>
<div id='app'>
$:page
</div>
</body>
</html>
Views/Templates/Home.html
<h1> Hello World!</h1>

Flask-socketio sending payloads one at a time

I have the following Python script which is using Flask-socketio
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
from time import sleep
app = Flask(__name__)
app.config['SECRET_KEY'] = 'P#ssw0rd'
socketio = SocketIO(app)
#app.route('/')
def index():
return render_template('index.html')
#socketio.on('connect')
def on_connect():
payload1 = 'Connected!!!'
payload2 = 'Doing thing 1'
payload3 = 'Doing thing 2'
emit('send_thing', payload1, broadcast=True)
sleep(2)
emit('send_thing', payload2, broadcast=True)
sleep(2)
emit('send_thing', payload3, broadcast=True)
if __name__ == '__main__':
socketio.run(app)
And here is the corresponding index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SocketIO Python</title>
</head>
<body>
<div id="my-div"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.4.5/socket.io.js"></script>
<script>
(function init() {
var socket = io()
var divElement = document.getElementById('my-div')
socket.on('send_thing', function(payload) {
var dataElement = document.createElement('inner')
dataElement.innerHTML = payload
divElement.appendChild(dataElement)
})
})()
</script>
</body>
</html>
What I am trying to achieve is that when a client connects, it first says 'Connected!!!' and then 2 seconds later a new 'inner' element appears that says 'Doing thing 1' followed by 2 seconds later a new 'inner' element appears that says 'Doing thing 2' etc.
But what is happening is that when a client connects, it sends all 3 lines at the same time (after 4 seconds which is both sleep statements). This is the first time using SocketIO so I'm sure I've done something wrong.
When you use eventlet or gevent, the time.sleep() function is blocking, it does not allow any other tasks to run.
Three ways to address this problem:
Use socketio.sleep() instead of time.sleep().
Use eventlet.sleep() or gevent.sleep().
Monkey patch the Python standard library so that time.sleep() becomes async-friendly.

Unable to Stop Python from Flask GUI

I am trying to create a GUI where I will have 2 buttons. Start button will trigger my python script and display the moving graph. When I press the stop button, the graph should exit and python should stop.
when I click on start button, I am getting the desired result. But it goes to infinite loop and the stop button does not exit the code.Clicking on stop button does not take the code to the decorator and my function stop() is not executed.
Below is the snippet :
from flask import Flask, request, flash, url_for, redirect, render_template, session
from flask import render_template
import numpy as np
import matplotlib.pyplot as plt
import io
import threading
import base64
from IPython import get_ipython
from sys import exit
app = Flask(__name__)
#app.route('/')
def home():
return render_template('home.html')
#app.route('/plot' , methods = ['GET', 'POST'])
def build_plot():
img = io.BytesIO()
global running
x = np.linspace(-180, 180,1000)
y = np.sin(x)
global j
fig, ax = plt.subplots()
plt.plot(x[0:200], y[0:200])
#plt.plot(x,y)
for i in range(200, len(y)):
plt.scatter(x[i], y[i])
plt.pause(0.0005)
return(get_ipython().run_line_magic('matplotlib', 'inline'))
#app.route('/stop' , methods = ['GET', 'POST'])
def stop():
#stop_ind='N'
#exit()
return render_template('home.html')
if __name__ == '__main__':
app.debug = True
app.run()
The function where I want to exit is not getting called.
Below is my HTML :
<!DOCTYPE html>
<html>
<title>HOME PAGE..</title>
<body>
<h1>Home Page..!!</h1>
<form action="/plot" method="POST">
<input type="number" name="Number" ><br>
<br>
<input type="submit" value="Start" >
</form>
<form action="/stop" method="POST">
<br>
<input type="submit" value="Stop" >
</form>
</body>
</html>
</form>
</body>
</html>
Your Flask app can not respond to your input because it is busy in your loop.
You will need to put the calculation of your results in a separate Thread or Coroutine in order to stop it from blocking your main Flask Thread.
Also you can use Websockets to communicate with your Frontend. Have a look at Flask-SocketIO. It uses Websockets to communicate between Flask and your Frontend.

TypeError: can't convert return value to desired type

When I run my python script I get the following console output:
TypeError: can't convert return value to desired type
The script does what I except and I have no clue where this message comes from. How can I find out which line contains the code that triggers the message in order to isolate the cause?
EDIT:
A minimal example:
#!/usr/bin/python
import gi
import os
import urllib
import urllib.parse
import getopt
import sys
from gi.repository import Gtk,WebKit
#resolve the file url
fileUri = 'test.html'
fileUri = os.path.realpath(fileUri)
fileUri = urllib.parse.ParseResult('file', '', fileUri, '', '', '')
fileUri = urllib.parse.urlunparse(fileUri)
def navrequest(thisview, frame, networkRequest):
address = networkRequest.get_uri()
if not fileUri in address:
md = Gtk.MessageDialog(win,0,Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE, "Not allowed to leave the site!")
md.run()
md.destroy()
view.open(fileUri)
view = WebKit.WebView()
view.connect("navigation-requested", navrequest)
sw = Gtk.ScrolledWindow()
sw.add(view)
vbox = Gtk.VBox()
vbox.add(sw)
win = Gtk.Window()
win.set_size_request(800, 600)
win.connect("destroy", Gtk.main_quit)
win.set_title("TypeErrortest")
win.add(vbox)
win.show_all()
view.open(fileUri)
Gtk.main()
test.hmtml:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title of the document</title>
</head>
<body>
<h1>Test</h1>
</body>
</html>
The complete console output:
[me ~]$ ./testTypeError.py
TypeError: can't convert return value to desired type
[me ~]$
Operating System: Arch Linux
Version: Python 3.4.2
The return value of the function handling the signal was the problem. Adding a return 0 to the navrequest function made the message disappear.

Resources