2025, Dec 07 21:01
Обрезка SVG из PDF в PyMuPDF по границам рисунка
Показываем, как обрезать экспорт SVG из PDF в PyMuPDF по границам векторных элементов: объединить bbox рисунков, задать cropbox и сохранить безрамочный SVG.
Извлекая линейные схемы из PDF и конвертируя их в SVG, часто получаешь слишком большой холст с лишними полями. Если цель — компактный, безрамочный SVG, сфокусированный на самом векторном содержимом, экспорт всей страницы оказывается избыточным и неудобным.
Постановка задачи
У вас уже есть рабочий экспорт в SVG с помощью PyMuPDF (fitz), но он захватывает всю страницу и сохраняет поля по краям в исходном масштабе. Задача — обрезать по границам диаграммы и сохранить в SVG только эту область.
Минимальный пример, воспроизводящий проблему
import fitz
pdf_obj = fitz.open(pdf_path)
first_page = pdf_obj[0]
svg_data = first_page.get_svg_image(matrix=fitz.Matrix(1, 1))
Так получается SVG на всю страницу, включая лишние поля по краям.
Почему SVG выходит с лишним полем
Экспорт опирается на текущий холст страницы. Если не менять видимую область, SVG покрывает всё внутри исходного прямоугольника страницы, включая пустые поля и рамочную графику. Чтобы убрать это лишнее пространство, перед экспортом область страницы нужно сузить до объединения всех векторных рисунков на странице.
Решение: обрезать по объединённым границам векторных элементов и экспортировать
Подход простой: собрать объекты-рисунки со страницы, объединить их ограничивающие прямоугольники, слегка расширить границы, чтобы избежать среза, задать область обрезки этим прямоугольником и затем экспортировать в SVG.
import fitz
def make_svg_trimmed(src_pdf, out_svg, pg_idx=0):
doc_obj = fitz.open(src_pdf)
pg = doc_obj[pg_idx]
draw_items = pg.get_drawings()
rects = [itm["rect"] for itm in draw_items if itm["rect"].is_valid]
if not rects:
print("No vector drawings found")
return
union_box = rects[0]
for bx in rects[1:]:
union_box |= bx
union_box = union_box + (-2, -2, 2, 2)
pg.set_cropbox(union_box)
svg_txt = pg.get_svg_image(matrix=fitz.Matrix(1, 1))
with open(out_svg, "w", encoding="utf-8") as out_f:
out_f.write(svg_txt)
print(f"SVG saved to {out_svg}")
Так страница обрезается по фактическому векторному содержимому, а эффект рамки исчезает: холст ограничивается объединёнными границами рисунков с небольшим запасом.
Зачем это нужно
С векторными схемами аккуратно и плотно обрезанные SVG проще использовать дальше, они не отвлекают полями и соответствуют нужной видимой области. Экспорт фокусируется на самой диаграмме, а не на полном макете исходного PDF.
Итог
Если при экспорте SVG берётся вся PDF-страница, соберите векторные рисунки страницы, вычислите их общий ограничивающий прямоугольник, задайте область обрезки по нему и отрендерьте SVG. Так холст сужается до диаграммы, и исчезает масштаб полей, который иначе засоряет результат.