PyScript: Get image from API and display on webpage

Question:

this is my first question on SO. Please give me directions if the question is not clear.

I am trying to get an image from a public API and write it on a webpage using PyScript.

However, I am not able to get the image to display on the webpage. I tried different packages to read the image (PIL, matplotlib, imageio) and different methods to display the output (Setting "output" at the beginning of pyscript, using pyscript.write() ). Below you can find a full (non-working) example.

img is formatted as a Numpy array with uint8 values.

UPDATE: The data is obtained correctly from the API. If I treat the data as Numpy array I can see all the pixel values. However, I am not able to display the image on the webpage afterwards.

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
        <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
        <py-env>
            - matplotlib
            - imageio
        </py-env>
    </head>
    <body>
        <h1>PyScript - images from API</h1>
        <div>
            <p>
                This webpage fetches a cat image from <a href="https://cataas.com/#/", target="_blank">cataas</a> and displays it below.
            </p>
        </div>
        <div id="image"></div>

    <py-script output="image">
from pyodide.http import pyfetch
import asyncio
from io import BytesIO
import matplotlib.pyplot as plt
import imageio.v3 as iio


response = await pyfetch(url="https://cataas.com/cat", method="GET")

img = iio.imread(BytesIO(await response.bytes()), index=None)

imgplot = plt.imshow(img)

imgplot
    </py-script>
    </body>
</html>

I tested on both Chrome and Firefox, but the image is never displayed.

Thanks in advance!

Asked By: Luigi Palumbo

||

Answers:

you need to assign the output image to some element in HTML document. Inside pyscript node add something like:

document.querySelector("img").setAttribute("src", img)

will display the image in tag:
<img id ="img" src="src">
Use id="img" for .CSS

And, I dont know how your code for downloading the images works but I googled a lot (dont remember the source, most likely this: https://www.jhanley.com/pyscript-loading-python-code-in-the-browser/) and created two functions:

async def download(url):
            filename = Path(url).name
            response = await pyfetch(url)
            if response.status == 200:
                status = response.status
                with open(filename, mode="wb") as file:
                    file.write(await response.bytes())
                return filename, status
            else:
                status = response.status
                filename = None
                return filename, status

async def process_response(url):
            response_content = await loop.run_until_complete(
                download(url)
                )
            if response_content[1] == 200:
                data = base64.b64encode(open(response_content[0], "rb").read()).decode("utf-8")
                src = f"data:image/png;base64,{data}"
                return src
            else:
                src = None
                return src

img = await process_response("url")
document.querySelector("img").setAttribute("src", img)
Answered By: Johnny R.

I add this answer as complement of the accepted answer from @Johnny R., as I took some time to figure out how to import the Path element he used in his function.
The full working code is below.

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
        <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
        <py-env>
            - matplotlib
            - imageio
        </py-env>
    </head>
    <body>
        <h1>PyScript - images from API</h1>
        <div>
            <p>
                This webpage fetches a cat image from <a href="https://cataas.com/#/", target="_blank">cataas</a> and displays it below.
            </p>
        </div>
        <div><img id ="img" src="src"></div>

    <py-script>
from pyodide.http import pyfetch
import asyncio
from js import document
import base64
from pathlib import Path

async def download(url):
            filename = Path(url).name
            response = await pyfetch(url, method="GET")
            if response.status == 200:
                status = response.status
                with open(filename, mode="wb") as file:
                    file.write(await response.bytes())
                return filename, status
            else:
                status = response.status
                filename = None
                return filename, status

async def process_response(url):
            response_content = await loop.run_until_complete(
                download(url)
                )
            if response_content[1] == 200:
                data = base64.b64encode(open(response_content[0], "rb").read()).decode("utf-8")
                src = f"data:image/png;base64,{data}"
                return src
            else:
                src = None
                return src

img = await process_response("https://cataas.com/cat")
document.querySelector("img").setAttribute("src", img)
    </py-script>
    </body>
</html>
Answered By: Luigi Palumbo
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.