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
Вернуться на верх