PerfectVector
Bởi Irene Kim10 phút đọc

Ảnh SVG trong WeasyPrint: sửa logo bị thiếu trong PDF

Khắc phục logo SVG bị thiếu trong PDF WeasyPrint bằng URL cơ sở đúng và kích thước CSS rõ ràng, rồi kiểm tra đường dẫn vector, tỷ lệ và hình trong PDF đã lưu.

Trên trang này

WeasyPrint có thể đưa SVG vào PDF thông qua phần tử ảnh HTML. Nếu logo biến mất khi bạn truyền HTML dưới dạng chuỗi, trước tiên hãy kiểm tra URL ảnh: đường dẫn tương đối cần URL cơ sở. Khi tệp đã tải được, đặt kích thước in bằng CSS và kiểm tra PDF đã lưu. Tài liệu API WeasyPrint hiện tại mô tả yêu cầu base_url này.

Ví dụ dưới đây tái hiện trường hợp ảnh bị thiếu bằng một logo hình khung tự tạo. Nó cũng kiểm tra rằng PDF sau khi sửa chứa hình học vẽ vector ở kích thước yêu cầu. Nếu đã có SVG, hãy bắt đầu với tệp đó. Vector hóa chỉ tham gia quy trình này khi hình nguồn tồn tại dưới dạng pixel.

Kiểm tra việc tải ảnh trước khi thay đổi hình

PDF vẫn có thể được tạo ngay cả khi thiếu logo. Kiểm tra cảnh báo tài nguyên, xử lý đường dẫn ảnh và hiển thị lại cùng SVG trước khi chỉnh sửa hình hoặc chuyển sang định dạng khác.

Tái hiện SVG bị thiếu bằng một tài liệu nhỏ

Chúng tôi thử nghiệm với Python 3.13.9 và WeasyPrint 70.0. Dùng môi trường riêng của dự án và cài phiên bản được cố định:

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

WeasyPrint cũng cần các thư viện native, bao gồm Pango. Làm theo hướng dẫn cài đặt cho hệ điều hành nếu lệnh import hoặc kiểm tra phiên bản thất bại. Thiếu thư viện native là vấn đề khác với thiếu logo.

Tạo cấu trúc thư mục này:

example/
  render.py
  assets/
    logo.svg

Lưu hình minh họa tự tạo này thành assets/logo.svg. Khoảng trống ở giữa cho bạn một chi tiết hữu ích để kiểm tra hơn hình chữ nhật đặc. Đây là hình học được viết thủ công, không phải kết quả chuyển đổi của 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>

Đưa nội dung sau vào 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")

Chạy python render.py. Trong PDF đầu tiên của chúng tôi, khung không xuất hiện và văn bản thay thế của ảnh hiện ra. Nhật ký chứa:

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

PDF thứ hai hiển thị khung xanh ngọc với khoảng trống còn nguyên. Cả hai lần gọi đều tạo một tệp, nên chỉ kiểm tra sự tồn tại của PDF không đủ để xác nhận thành công.

Cung cấp thư mục gốc ổn định cho đường dẫn tương đối

assets/logo.svg xác định một tệp tương đối với một vị trí khác. base_url trong lần gọi thứ hai cung cấp vị trí bắt đầu đó. root.as_uri() tạo URI tệp tuyệt đối; dấu gạch chéo ở cuối cho biết đây là cơ sở thư mục. Logo vẫn nằm trong cùng thư mục assets và nội dung SVG không thay đổi.

Dùng Path(__file__) cũng giúp ví dụ luôn gắn với thư mục chứa tập lệnh khi bạn chạy nó từ thư mục làm việc khác. Trong notebook, thay vào đó hãy dùng thư mục dự án được chỉ định rõ, vì thông thường không có __file__.

Minh họa hình SVG trong một thư mục được nối bằng mũi tên với cùng hình trên một trang tài liệu
Minh họa việc phân giải tài nguyên: tài liệu cần có đường tới tệp SVG trước khi đưa hình vào trang.

Có một phép thử đối chứng hữu ích khác. Lưu HTML thành invoice.html bên cạnh render.py và tải trực tiếp tệp đó:

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

WeasyPrint có thể suy ra cơ sở từ tên tệp hoặc URL đầu vào. Thử nghiệm dựa trên tệp của chúng tôi tạo cùng khung với trường hợp chỉ định cơ sở rõ ràng. Chuỗi HTML không có tên tệp tương ứng để suy ra điều đó. Các chế độ đầu vào và quy tắc phân giải cơ sở được mô tả trong hàm khởi tạo HTML.

Với ảnh được lưu ở nơi cần đăng nhập, URL đúng vẫn có thể chưa đủ. Tài liệu URL fetcher cho biết trình khách HTTP mặc định không cung cấp cookie hoặc xác thực. Dùng cơ chế lấy tài nguyên đã được ứng dụng của bạn phê duyệt và thử trong môi trường tạo PDF. Đừng cho rằng logo nhìn thấy trong trình duyệt đã đăng nhập cũng truy cập được từ tiến trình PDF.

Đặt kích thước ảnh riêng với kích thước trang PDF

Ví dụ dùng @page cho tờ A4 và lề, còn .logo đặt ảnh rộng 60 mm. Tỷ lệ nguồn 2:1 khiến ảnh cao 30 mm với height: auto. Trong PDF đã lưu của chúng tôi, khung đo được 60 × 30 mm và bắt đầu cách mép trên và mép trái trang 20 mm.

Ở đây hình vẽ phủ toàn bộ viewBox. Logo của bạn có thể có khoảng trống trong hình chữ nhật đó, nên một hộp ảnh rộng 60 mm có thể chứa logo nhìn hẹp hơn. Kiểm tra khung vẽ SVG trước khi bù bằng cách tăng chiều rộng CSS tùy ý. Hướng dẫn kích thước nhập SVG giải thích sự khác biệt này chi tiết hơn.

Giữ write_pdf() ở giá trị mặc định zoom=1 khi kiểm tra kích thước vật lý. Tài liệu đầu ra PDF của WeasyPrint cảnh báo rằng thay đổi zoom cũng thay đổi tỷ lệ của đơn vị CSS vật lý và các khổ trang có tên.

Hiện tượngKiểm tra đầu tiênBước tiếp theo
Văn bản thay thế hiện thay cho logoURL ảnh và nhật ký tài nguyênCung cấp URL cơ sở hợp lệ hoặc URL tuyệt đối có thể truy cập
Logo xuất hiện sai kích thướcChiều rộng CSS và tỷ lệ ảnh nguồnĐặt chiều rộng vật lý và kiểm tra khung vẽ SVG
Một phần hình bị thiếuGiới hạn nguồn và tính năng SVG cụ thểRút gọn thành ví dụ nhỏ có lỗi và so sánh PDF xuất ra
Hiển thị cục bộ được nhưng trên máy chủ thất bạiTệp, phông chữ và quyền truy cập URL sẵn cóThử với tài nguyên của tiến trình đã triển khai

Kiểm tra nội dung và diện mạo PDF

Tài liệu định dạng WeasyPrint hiện tại cho biết ảnh SVG được hiển thị dưới dạng vector trong PDF đầu ra. Điều đó không có nghĩa mọi tệp kết thúc bằng .svg đều hoàn toàn là hình vector: SVG có thể chứa bitmap nhúng. Khi kết quả vẫn trông vỡ pixel, hãy kiểm tra bằng hướng dẫn nhận diện ảnh nhúng.

Với mẫu thử đơn giản này, chúng tôi kiểm tra PDF đã lưu bằng PyMuPDF 1.26.7:

Trường hợp đầu vàoBản ghi hình vẽẢnh nhúngKhung nhìn thấy
Chuỗi HTML không có cơ sở00Bị thiếu; văn bản thay thế xuất hiện
Chuỗi HTML có cơ sở thư mục1060 × 30 mm, giữ khoảng trống
HTML được tải theo tên tệp10Giống kết quả của chuỗi đã phân giải

Các kết quả này áp dụng cho khung được cung cấp, không phải mọi tính năng SVG. Một đường dẫn ghép cũng không có nghĩa chỉ có một hình nhìn thấy: đường dẫn con bên trong xác định khoảng trống.

Để kiểm tra resolved.pdf, cài pymupdf==1.26.7 rồi chạy:

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)

Tài liệu page của PyMuPDF mô tả các phương thức kiểm tra hình vẽ và ảnh. Các số đếm này hỗ trợ chẩn đoán, không chứng nhận rằng hình gốc được tái hiện chính xác. Hãy mở PDF nữa: kiểm tra khoảng trống, màu, tỷ lệ và chữ ở kích thước bàn giao thực tế. Kiểm tra từng tính năng trong hình phức tạp và chạy lại các phép kiểm tra khi nâng cấp trình hiển thị.

Khi nào cần chuẩn bị SVG mới trước

Khi logo duy nhất có sẵn là PNG hoặc JPG, công cụ vector hóa logo của PerfectVector có thể chuẩn bị một bản SVG để kiểm tra trước khi bạn đưa vào tài liệu HTML. Kiểm tra đường bao, các lỗ nhỏ và chữ trong trình chỉnh sửa, rồi thử SVG qua cùng quy trình WeasyPrint. Hướng dẫn vector hóa ảnh giải thích điều gì thay đổi khi pixel trở thành đường dẫn.

Giữ SVG gốc có thể chỉnh sửa nếu có. Sửa tham chiếu tệp hoặc bố cục của nó thay vì đồ lại. Ảnh chụp có thể giữ dạng raster, và chữ thương hiệu cần chính xác có thể đòi hỏi phông chữ gốc hoặc vẽ lại thủ công. Vector hóa không sửa được tệp thiếu trên máy chủ, xác thực hay tính năng hiển thị không được hỗ trợ.

Nếu chỉ cần chuyển SVG thành một trang PDF riêng, quy trình xuất CairoSVG trình bày công việc nhỏ hơn đó. WeasyPrint phù hợp với trường hợp tài liệu HTML, khi hình nằm chung trang với nội dung khác.

Câu hỏi thường gặp

Vì sao WeasyPrint tạo PDF mà không có logo SVG của tôi? Lỗi tải ảnh có thể vẫn cho phép phần còn lại của tài liệu hiển thị. Kiểm tra nhật ký tài nguyên và URL ảnh. Trong thử nghiệm được cung cấp, chuỗi HTML có đường dẫn ảnh tương đối cần URL cơ sở được chỉ định rõ.

Tôi có cần chuyển SVG sang PNG trước không? Không. WeasyPrint nhận ảnh SVG. Giữ hình vector được hỗ trợ ở dạng SVG khi đó là đầu ra bạn muốn và kiểm tra PDF đã lưu. Xuất raster là phương án khác khi bạn chủ động ưu tiên diện mạo hơn hình học vector.

base_url có thay đổi kích thước in của logo không? Không. Nó cung cấp cơ sở để phân giải URL tài nguyên tương đối. Đặt kích thước bố trí của ảnh bằng CSS và kiểm tra riêng kích thước cùng viewBox của SVG.

Nguồn tham khảo

  1. Tài liệu API WeasyPrint — Mô tả đầu vào HTML, URL cơ sở, đầu ra SVG và hành vi zoom của PDF.
  2. WeasyPrint First Steps — Trình bày cài đặt và lấy tài nguyên, bao gồm giới hạn xác thực.
  3. Tài liệu Page của PyMuPDF — Mô tả các phương thức kiểm tra hình vẽ và ảnh nhúng dùng trong ví dụ.

Bạn chỉ có logo raster? Chuẩn bị SVG bằng PerfectVector, kiểm tra hình và chữ, rồi đưa vào HTML và xác minh diện mạo cùng kích thước vật lý trong PDF đã lưu.

Thêm từ blog

Bắt đầu với SVG gọn sạch hơn
và dễ chỉnh sửa hơn