Reportlab cannot open resource when using Minio (S3) pre-signed link

I am using reportlab in a containerized Django project with django-minio-backend for storing user-uploaded images. I want to create a PDF that uses the uploaded image as the background.

This is the code used to render the PDF

from django_minio_backend import MinioBackendStatic
from reportlab.lib.utils import ImageReader

def render_pdf(data: dict, image_url: str) -> io.BytesIO:
    RGB_VAL = 50

    # Create a file-like buffer to receive PDF data.
    buffer = io.BytesIO()

    # Register the Open Sans Font
    font_file = MinioBackendStatic().open("/fonts/OpenSans-Regular.ttf")

    pdfmetrics.registerFont(TTFont("OpenSans", font_file))

    # Create the PDF object, using the buffer as its "file."
    p = canvas.Canvas(buffer, pagesize=landscape(A4))
    image = ImageReader(image_url) # <--------------- Problem Line!

    p.drawImage(image, 0, 0, width=A4[1], height=A4[0])
    
    # Other Draw operations
    ...    

    # Close the PDF object cleanly, and we're done.
    p.showPage()
    p.save()

    return buffer

The Minio storage backend is running in a different container and returns a URL for the resource something like this.

http://localhost:9000/media-root-storage/images/<My-Image-Name>.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credential>&X-Amz-Date=20250405T085308Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature>

This is the error that I get

Traceback (most recent call last):
  File "/usr/local/lib/python3.13/site-packages/reportlab/lib/utils.py", line 643, in __init__
    fp = open_for_read(fileName,'b')
  File "/usr/local/lib/python3.13/site-packages/reportlab/lib/utils.py", line 534, in open_for_read
    return open_for_read(name,mode)
  File "/usr/local/lib/python3.13/site-packages/reportlab/lib/utils.py", line 532, in open_for_read
    raise IOError('Cannot open resource "%s"' % name)
OSError: Cannot open resource "http://localhost:9000/media-root-storage/images/<My-Image-Name>.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credential>&X-Amz-Date=20250405T085308Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature>"

I even tried to replace the hostname from localhost:9000 to storage:9000 (which is the service name on which the minio server is running) but still the same issue persists.

Any help on this is greatly appreciated.

You're facing this issue because ReportLab's ImageReader doesn't support loading images from remote URLs directly (like your signed MinIO URL). It expects either-

  • A local file path

  • A file-like object (like a BytesIO)

  • Or a PIL image object

download image and pass a file-like object:

import io
import requests
from reportlab.lib.pagesizes import landscape, A4
from reportlab.lib.utils import ImageReader
from reportlab.pdfgen import canvas
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase import pdfmetrics
from django_minio_backend import MinioBackendStatic

def render_pdf(data: dict, image_url: str) -> io.BytesIO:
  # create a file-like buffer to receive PDF data
    buffer = io.BytesIO()

          # register the opensansfont
    font_file = MinioBackendStatic().open("/fonts/OpenSans-Regular.ttf")
    pdfmetrics.registerFont(TTFont("OpenSans", font_file))

    # craete pdf object
    p = canvas.Canvas(buffer, pagesize=landscape(A4))

    # download image
    response = requests.get(image_url)
    if response.status_code == 200:
        image_file = io.BytesIO(response.content)
        image = ImageReader(image_file)
        p.drawImage(image, 0, 0, width=A4[1], height=A4[0])
    else:
        raise Exception(f"Failed to load image from URL: {image_url}")

    # your other drawing operations
    # p.drawString(...)

    # finish the pdf
    p.showPage()
    p.save()

    buffer.seek(0)
    return buffer
Back to Top