Reportlab не может открыть ресурс при использовании предварительно подписанной ссылки Minio (S3)
Я использую reportlab
в контейнерном Django-проекте с django-minio-backend
для хранения загруженных пользователем изображений. Я хочу создать PDF, который использует загруженное изображение в качестве фона.
Этот код используется для рендеринга 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
Бэкэнд хранилища Minio работает в другом контейнере и возвращает URL для ресурса примерно так.
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>
Вот ошибка, которую я получаю
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>"
Я даже попытался заменить имя хоста с localhost:9000
на storage:9000
(это имя службы, на которой запущен сервер minio), но все равно та же проблема сохраняется.
Любая помощь по этому вопросу будет высоко оценена.
Вы столкнулись с этой проблемой, потому что ReportLab
в ImageReader
не поддерживается загрузка изображений напрямую с удаленных URL-адресов (например, с вашего подписанного мини-URL). Ожидается, что либо-
Путь к локальному файлу
Файлообразный объект (например,
BytesIO
)Или объект изображения PIL
загрузите изображение и передайте объект, похожий на файл:
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