PerfectVector
Автор: Irene Kim7 мин чтения

SVG в WeasyPrint: верните пропавшие логотипы в PDF

Исправьте пропавшие SVG-логотипы в PDF WeasyPrint с помощью правильного базового URL и явных размеров CSS, затем проверьте контуры, пропорции и графику в сохраненном PDF.

На этой странице

WeasyPrint может поместить SVG в PDF через HTML-элемент изображения. Если логотип исчезает при передаче HTML строкой, сначала проверьте URL изображения: относительному пути нужен базовый URL. Когда файл загрузится, задайте его печатный размер в CSS и проверьте сохраненный PDF. Действующий справочник API WeasyPrint описывает это требование base_url.

Пример ниже воспроизводит исчезновение изображения на оригинальном логотипе в форме рамки. Он также проверяет, что исправленный PDF содержит векторную геометрию заданного размера. Если SVG уже есть, начните с него. Векторизация нужна в этом процессе только тогда, когда исходная графика существует в пикселях.

Проверьте загрузку, прежде чем менять графику

PDF может создаться даже без логотипа. Проверьте предупреждение о ресурсе, исправьте путь к изображению и повторите рендеринг того же SVG, прежде чем редактировать фигуры или конвертировать его в другой формат.

Воспроизведите пропавший SVG в небольшом документе

Мы проверяли с Python 3.13.9 и WeasyPrint 70.0. Используйте окружение проекта и установите закрепленную версию:

python -m pip install "weasyprint==70.0"
python -m weasyprint --info

WeasyPrint также нужны нативные библиотеки, включая Pango. Следуйте инструкциям установки для вашей ОС, если импорт или команда проверки версии завершаются ошибкой. Отсутствующая нативная библиотека — другая проблема, чем пропавший логотип.

Создайте следующую структуру папок:

example/
  render.py
  assets/
    logo.svg

Сохраните эту оригинальную демонстрационную графику как assets/logo.svg. Отверстие в середине дает более полезный объект для проверки, чем сплошной прямоугольник. Это вручную созданная геометрия, а не результат конвертации PerfectVector.

<svg xmlns="http://www.w3.org/2000/svg"
     width="120" height="60" viewBox="0 0 120 60">
  <path fill="#087f8c" fill-rule="evenodd"
        d="M0 0H120V60H0Z M20 15V45H100V15Z"/>
</svg>

Поместите следующий код в render.py:

from pathlib import Path
import logging
from weasyprint import HTML
 
logging.basicConfig(level=logging.WARNING)
root = Path(__file__).resolve().parent
 
html = """<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <style>
    @page { size: A4; margin: 20mm; }
    body { margin: 0; }
    .logo { display: block; width: 60mm; height: auto; }
  </style>
</head>
<body>
  <img class="logo" src="assets/logo.svg" alt="Frame logo">
</body>
</html>
"""
 
HTML(string=html).write_pdf(root / "missing-base.pdf")
 
HTML(
    string=html,
    base_url=root.as_uri() + "/",
).write_pdf(root / "resolved.pdf")

Запустите python render.py. В нашем первом PDF рамки не было, а вместо изображения появился альтернативный текст. Журнал содержал:

Relative URI reference without a base URI: assets/logo.svg

Во втором PDF появилась бирюзовая рамка с сохраненным отверстием. Оба вызова создали файл, поэтому само наличие PDF не было полезной проверкой успеха.

Задайте относительным путям постоянную начальную папку

assets/logo.svg указывает файл относительно другого расположения. base_url во втором вызове задает эту начальную точку. root.as_uri() создает абсолютный файловый URI; завершающий слеш указывает, что база — каталог. Логотип остается в той же папке assets, а содержимое SVG не меняется.

Использование Path(__file__) также привязывает пример к папке скрипта при запуске из другого рабочего каталога. В блокноте задайте папку проекта явно, поскольку __file__ обычно недоступен.

Иллюстрация: графика SVG в папке соединена стрелкой с той же графикой на странице документа
Иллюстрация разрешения ресурсов: документу нужен путь к файлу SVG, прежде чем он сможет разместить графику.

Есть еще полезная контрольная проверка. Сохраните HTML как invoice.html рядом с render.py и загрузите сам файл:

HTML(filename=str(root / "invoice.html")).write_pdf(
    root / "from-file.pdf"
)

WeasyPrint может определить базу по имени входного файла или URL. Наш тест с файлом дал ту же рамку, что и вариант с явной базой. У строки HTML нет соответствующего имени файла для такого вывода. Эти режимы ввода и правила определения базы описаны в конструкторе HTML.

Если изображение доступно только после входа, правильного URL может быть недостаточно. Документация URL fetcher сообщает, что HTTP-клиент по умолчанию не поддерживает cookies и аутентификацию. Используйте одобренный в вашем приложении механизм получения ресурсов и проверьте его в окружении генерации PDF. Не предполагайте, что логотип, видимый в браузере после входа, доступен процессу PDF.

Задавайте размер изображения отдельно от размера страницы PDF

В примере @page задает лист A4 и поля, а .logo — ширину изображения 60 мм. Исходное соотношение 2:1 дает высоту 30 мм при height: auto. В сохраненном PDF рамка имела размер 60 × 30 мм и начиналась в 20 мм от верхнего и левого краев страницы.

Здесь рисунок заполняет весь viewBox. У вашего логотипа внутри этого прямоугольника может быть пустое пространство, поэтому блок изображения шириной 60 мм может содержать визуально более узкий знак. Проверьте холст SVG, прежде чем компенсировать это произвольным увеличением ширины CSS. Руководство по размеру при импорте SVG подробнее объясняет различие.

При проверке физических размеров оставьте значение zoom=1 по умолчанию в write_pdf(). Справочник вывода PDF WeasyPrint предупреждает: изменение zoom также масштабирует физические единицы CSS и именованные размеры страниц.

Что вы видитеЧто проверить сначалаСледующий шаг
Вместо логотипа альтернативный текстURL изображения и журнал ресурсовЗадайте корректный базовый URL или доступный абсолютный URL
Логотип имеет неверный размерШирину CSS и исходные пропорцииЗадайте физическую ширину и проверьте холст SVG
Часть графики отсутствуетГраницы исходника и конкретную возможность SVGСведите проблему к небольшому примеру и сравните экспортированный PDF
Локально работает, на сервере — нетДоступные файлы, шрифты и доступ к URLПроверьте ресурсы развернутого процесса

Проверьте содержимое и внешний вид PDF

Действующая документация форматов WeasyPrint сообщает, что изображения SVG выводятся в PDF как векторы. Но не каждый файл с расширением .svg содержит только векторную графику: SVG может включать встроенный растр. Если результат все еще выглядит пикселизированным, проверьте это с помощью диагностики встроенных изображений.

Для этого простого теста мы проверили сохраненные PDF с PyMuPDF 1.26.7:

Вариант вводаЗаписи рисованияВстроенные изображенияВидимая рамка
Строка HTML без базы00Отсутствует; появился альтернативный текст
Строка HTML с базой папки1060 × 30 мм, отверстие сохранено
HTML, загруженный по имени файла10Тот же результат, что у строки с разрешенным путем

Эти результаты относятся к предоставленной рамке, а не ко всем возможностям SVG. Один составной контур также не означает одну видимую фигуру: его внутренний подконтур задает отверстие.

Чтобы проверить resolved.pdf, установите pymupdf==1.26.7 и запустите:

import pymupdf
 
with pymupdf.open("resolved.pdf") as document:
    page = document[0]
    print("Drawing records:", len(page.get_drawings()))
    print("Embedded images:", len(page.get_images()))
    for drawing in page.get_drawings():
        box = drawing["rect"]
        print("Bounds in mm:", box.width * 25.4 / 72,
              box.height * 25.4 / 72)

Справочник страниц PyMuPDF описывает методы проверки рисования и изображений. Эти количества служат диагностикой, а не сертификатом точности. Также откройте PDF: проверьте отверстие, цвета, пропорции и надписи в фактическом размере, в котором они будут использоваться. Проверяйте сложную графику по отдельным возможностям и повторяйте проверки при обновлении рендерера.

Когда сначала нужно подготовить новый SVG

Если доступный логотип существует только в PNG или JPG, векторизатор логотипов PerfectVector поможет подготовить SVG перед размещением в HTML-документе. Проверьте контуры, маленькие отверстия и надписи в редакторе, затем протестируйте SVG через тот же процесс WeasyPrint. Руководство по векторизации изображений объясняет, что меняется, когда пиксели становятся контурами.

Сохраняйте оригинальный редактируемый SVG, если он есть. Исправьте ссылку на файл или размещение вместо повторной трассировки. Фотографии могут оставаться растровыми, а для точных фирменных надписей может понадобиться исходный шрифт или ручная перерисовка. Векторизация не исправляет отсутствующие серверные файлы, аутентификацию или неподдерживаемые возможности рендеринга.

Если нужно только преобразовать SVG в отдельную страницу PDF, процесс экспорта CairoSVG описывает эту более узкую задачу. WeasyPrint подходит для HTML-документа, где графика находится на одной странице с другим содержимым.

FAQ

Почему WeasyPrint создает PDF без моего SVG-логотипа? Ошибка загрузки изображения может не мешать рендерингу остального документа. Проверьте журнал ресурсов и URL изображения. В приведенном тесте строке HTML с относительным путем изображения требовался явный базовый URL.

Нужно ли сначала конвертировать SVG в PNG? Нет. WeasyPrint принимает изображения SVG. Сохраняйте поддерживаемую векторную графику в SVG, если нужен именно такой результат, и проверяйте сохраненный PDF. Растровый экспорт — альтернатива, если вы сознательно выбираете внешний вид вместо векторной геометрии.

Меняет ли base_url печатный размер логотипа? Нет. Он задает базу для разрешения относительных URL ресурсов. Задайте размер размещения изображения через CSS и отдельно проверьте размеры и viewBox SVG.

Sources

  1. WeasyPrint API reference — Описывает ввод HTML, базовые URL, вывод SVG и поведение масштаба PDF.
  2. WeasyPrint First Steps — Описывает установку и получение ресурсов, включая ограничения аутентификации.
  3. PyMuPDF Page reference — Описывает методы проверки рисования и встроенных изображений, использованные в примере.

Есть только растровый логотип? Подготовьте SVG с PerfectVector, проверьте его фигуры и надписи, затем поместите в HTML и проверьте внешний вид и физические размеры в сохраненном PDF.

Ещё из блога

Начните с более чистого SVG,
который проще редактировать