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