Display JPEG Images From The Internet Using The Adafruit PyPortal

The PyPortal device is a new IoT device from Adafruit. It allows CircuitPython programs to connect to the Internet through its ESP32 coprocessor and also contains a 3.2″ 320 x 240 TFT display. My initial thought of a use for this device was for a web enabled photo frame which downloaded photos from the internet and displayed them on the device. A site that came to mind was ThisPersonDoesNotExist.com, a site recently in the news that generates JPEG pictures of non-existing people using AI. The current release of CircuitPython (4.0.0 Beta 4 as of this writing) does not natively support JPEG files. I expect that someday it will, but until then, I developed a solution to display JPEG images from the Internet using the PyPortal and CircuitPython.

A clue to the solution came from Adafruit’s Lady Ada herself, where she mentioned on GitHub that JPEG to BMP converters could be used for a workaround until JPEG images are officially supported. There are some commercial web sites that can convert JPEG files to BMP, however, they may require some human interaction in order to work and are not designed for an IoT device to use its service in the background. Also, scaling the image was needed to downsize large images onto the 320 x 240 screen size of the PyPortal. The solution I came up with was to write a small PHP program ( less than 10 lines of code) and run it from a web server. The PHP code reads the JPEG location from a URL request, reformats the JPEG to a BMP file at a specified image width and downloads it to the PyPortal. Fortunately, CircuitPython supports BMP files natively. The PHP program is copied to your web server (or a friend’s if you don’t have one) and a URL is called from the CircuitPython script requesting the image. The URL contains the location of the JPEG file and the desired width. For example:

 url = "{webserver}/jpeg2bmp.php?width={width}&url={url}"

Where {webserver} is the location of your webserver containing the jpeg2bmp.php script, {width} is the desired width of the image, and {url} is the location of the JPEG file. For my project I used this:

url = "{yourwebserver}/jpeg2bmp.php?width=320&url=https://ThisPersonDoesNotExist.com/image"

The code to convert and resize the JPEG image to BMP is actually quite small for the work it does (jpeg2bmp.php) :

header("Content-Type: image/bmp");

$width = @$_REQUEST['width'];
$img = imagecreatefromjpeg($_REQUEST['url']);
$img = imagescale($img, $width);


In less than 10 lines of code, the PHP program reads the URL and desired width of the image, requests the JPEG image from the supplied URL on the PyPortal’s behalf, scales down to fit on the PyPortal display, then converts it to BMP and sends it to the PyPortal.

The PyPortal code is a work in progress, but here is the workflow from the PyPortal viewpoint: the PyPortal code requests the JPEG file from the server, then downloads the now resized and converted BMP image to a micro SD card on the PyPortal. The CircuitPython code then takes the BMP file on the micro SD card and displays it. This process is repeated for an endless display of faces of people who do not exist. Of course JPEGs from other sites can be used with this. The site ThisCatDoesNotExist.com also provides AI created images, some a bit more creepy than the people images. Maybe I should work on displaying images of real people next?

AI generated image from ThisCatDoesNotExist.com