Skip to content

Instantly share code, notes, and snippets.

@davipatti
Created May 8, 2025 20:47
Show Gist options
  • Save davipatti/493292920365b9ef9a36195b980a3589 to your computer and use it in GitHub Desktop.
Save davipatti/493292920365b9ef9a36195b980a3589 to your computer and use it in GitHub Desktop.
Fetch a random image from an immich server that contains particular people, resize and pad that image, and return it in a fastapi response. Used for fetching and resizing images to display on a raspberry pi pico which an inky 7.3 e-ink screen.
#!/usr/bin/env python3
from typing import Annotated, Union
import io
import json
import requests
from fastapi import FastAPI, Query
from fastapi.responses import Response
from PIL import Image, ImageOps
import pillow_heif # pip install pillow-heif
URL = "http://ip:2283"
API_KEY = "xxx"
def search_person(name: str) -> requests.Response:
return requests.request(
"GET",
f"{URL}/api/search/person?name={name}",
headers={"Accept": "application/json", "x-api-key": API_KEY},
data={},
)
def get_person_id(name: str) -> str:
response = search_person(name)
data = response.json()
if len(data) == 1:
return data[0]["id"]
else:
raise ValueError(f"multiple matches for {name}")
def search_random(person_ids, n=1):
return requests.request(
"POST",
f"{URL}/api/search/random",
headers={
"Content-Type": "application/json",
"Accept": "application/json",
"x-api-key": API_KEY,
},
data=json.dumps(
{"personIds": person_ids, "type": "IMAGE", "withDeleted": False, "size": n}
),
)
def download_asset(id):
return requests.request(
"GET",
f"{URL}/api/assets/{id}/original",
headers={
"Accept": "application/octet-stream",
"x-api-key": API_KEY,
},
data={},
)
app = FastAPI()
@app.get("/immich/")
def get_immich(
names: Annotated[Union[list[str], None], Query()], width: int = 600, height: int = 448
) -> Response:
"""
Entry point that fetches a random image that contains at least one of the names
passed, resizes and pads it according to a width and height and then returns
it as a Response.
"""
person_ids = [get_person_id(name) for name in names]
# Fetch a random asset that contains these person_ids
random = search_random(person_ids=person_ids, n=1)
data = random.json()[0]
random_id = data["id"]
file_format = data["originalFileName"].split(".")[-1].lower()
download_resp = download_asset(random_id)
if file_format == "heic":
heif_file = pillow_heif.open_heif(io.BytesIO(download_resp.content))
img = Image.frombytes(
heif_file.mode,
heif_file.size,
heif_file.data,
"raw",
heif_file.mode,
heif_file.stride,
)
else:
img = Image.open(io.BytesIO(download_resp.content))
# Pad the image as requested
padded = ImageOps.pad(img, (width, height))
# Return the padded image as "image/jpeg" in a response
# Create a bytes buffer to hold the JPEG image data
img_byte_arr = io.BytesIO()
# Save the padded image as JPEG to the buffer
padded.save(img_byte_arr, format="JPEG")
# Seek to the beginning of the buffer
img_byte_arr.seek(0)
# Return the image as a response
return Response(content=img_byte_arr.getvalue(), media_type="image/jpeg")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=5678)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment