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 --infoWeasyPrint также нужны нативные библиотеки, включая 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__ обычно недоступен.

Есть еще полезная контрольная проверка. Сохраните 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 без базы | 0 | 0 | Отсутствует; появился альтернативный текст |
| Строка HTML с базой папки | 1 | 0 | 60 × 30 мм, отверстие сохранено |
| HTML, загруженный по имени файла | 1 | 0 | Тот же результат, что у строки с разрешенным путем |
Эти результаты относятся к предоставленной рамке, а не ко всем возможностям 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
- WeasyPrint API reference — Описывает ввод HTML, базовые URL, вывод SVG и поведение масштаба PDF.
- WeasyPrint First Steps — Описывает установку и получение ресурсов, включая ограничения аутентификации.
- PyMuPDF Page reference — Описывает методы проверки рисования и встроенных изображений, использованные в примере.
Есть только растровый логотип? Подготовьте SVG с PerfectVector, проверьте его фигуры и надписи, затем поместите в HTML и проверьте внешний вид и физические размеры в сохраненном PDF.
Ещё из блога

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

SVG в Matplotlib: график и логотип в виде контуров
Экспортируйте график Matplotlib в SVG, добавьте отдельные контуры логотипа через svgutils и проверьте итоговый файл на встроенные пиксели, размещение и изменения шрифтов.