Dustin IngramWriting — Speaking — Github — Twitter
VNC Screenshare over HTTP with Python and FlaskMay 29 2013
The Problem #
I recently found an interesting implementation of VNC over GIF in Node and wanted to try to quickly replicate the same thing in Python, using Flask as my web server. I quickly realized two things:
- Serving pieces of a GIF incrementally is not something that a micro-server like Flask is designed to handle
- While interesting, there are some inherent flaws with using a GIF image as the transport medium, namely that if you leave the screenshare open long enough, you’re going to have a massive GIF image in your cache and in memory.
Since I wanted to create something that was more functional than simply a proof-of-concept (how many times have you wanted to do a simple screenshare, but don’t want to install any applications, or boot up Skype, or install that Google Hangout plugin?) I decided to move away from a GIF image and instead implement a simple screenshare application in Python.
The script #
We use two important libraries:
flask for the web application and templating,
pyscreenshot as an abstraction to what is necessary to get a screenshot.
Note: your mileage may vary –
pyscreenshot might not work on your machine.
It can be installed as usual:
$ pip install pyscreenshot
pyscreenshot, you’ll also need to install at least one backend (if
they haven’t been installed already). This will likely be what limits your
pyscreenshot, but you should be able to get a backend installed for
The general idea here is to create the
flask app, and produce two routes: one
for the HTML of the page, and one for the actual image. The HTML will simply
route gets the screenshot from
pyscreenshot, performs some manipulations on
it in-memory, and uses the Flask
send_file method to hand it off. Here’s the
#!/usr/bin/python import pyscreenshot import flask from StringIO import StringIO app = flask.Flask(__name__) @app.route('/screen.png') def serve_pil_image(): img_io = StringIO() pyscreenshot.grab().save(img_io, 'PNG', quality=50) img_io.seek(0) return flask.send_file(img_io, mimetype='image/png') @app.route('/') def serve_img(): return flask.render_template('screen.html') if __name__ == "__main__": app.run(host= '0.0.0.0', debug=True)
The template #
Finally, we need a small HTML template to feed into flask to produce the screenshare page:
The script here refreshes the screen image once every half-second. As a cache-breaker, we append the current time (in milliseond) to the requested URI of the image.
Finally, start up the application:
$ python screen.py
Because we’ve set the host to
"0.0.0.0", the application will be accessible
on all hostnames your machine responds to on Flask’s default port 5000 –
including an external IP, if you have one – but it will be available at:
Here’s the whole project as a repo.