Я пытаюсь вывести этот SVG в pdf. SVG генерируетсяmermaid.js
Я нашел существующий ответ в стеке для преобразования SVG в PDF. В этом ответе определена функция, downloadPDF
которая преобразует SVG в PDF и запускает загрузку PDF.
Когда я запускаю эту функцию в приведенном ниже минимальном примере, я получаю вывод, но вывод выглядит серым. Может ли кто-нибудь помочь мне правильно вывести данный SVG в PDF?
Вот минимальный пример:
<!DOCTYPE html>
<html lang="en" style="height: auto;">
<head>
</head>
<body>
<div class="mermaid">
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
</div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/8.13.4/mermaid.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pdfkit@0.10.0/js/pdfkit.standalone.js"></script>
<script src="https://bundle.run/blob-stream@0.1.3"></script>
<script src="https://cdn.jsdelivr.net/npm/svg-to-pdfkit@0.1.8/source.js"></script>
<script>
mermaid.init({
flowchart: { useMaxWidth: false },
"theme": "default",
"themeVariables": {
"fontFamily": "Helvetica"
}
}, document.querySelectorAll(".mermaid"));
</script>
<script>
function downloadPDF(svg, outFileName) {
let doc = new PDFDocument({compress: false});
SVGtoPDF(doc, svg, 0, 0);
let stream = doc.pipe(blobStream());
stream.on('finish', () => {
let blob = stream.toBlob('application/pdf');
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = outFileName + ".pdf";
link.click();
});
doc.end();
}
var svg = document.querySelector('svg');
</script>
Чтобы создать PDF, вставьте это в консоль разработки браузера:downloadPDF(svg, "test")
Вот изображение svg, созданное на минимальном примере:
Вот вывод изображения из downloadPDF
функции (запускается downloadPDF(svg, "test")
в консоли разработки браузера):
Примечание. Такой же результат я получаю в браузерах Firefox и Edge.
Обновление: я отредактировал функцию загрузки PDF, и теперь я правильно получаю цвета, однако текст узла по-прежнему не отображается:
function downloadPDF(svg, outFileName) {
let doc = new PDFDocument({compress: false});
SVGtoPDF(doc, svg, 0, 0, {useCSS:true});
let stream = doc.pipe(blobStream());
stream.on('finish', () => {
let blob = stream.toBlob('application/pdf');
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = outFileName + ".pdf";
link.click();
});
doc.end();
}
Новый вывод в формате PDF без текста узла:
Если бы кто-нибудь мог помочь разобраться с текстовой частью узла, я был бы очень признателен!
Обновление 2: Итак, я заметил, что если я изменю ForeignObject в узлах svg на <text>
элементы и удалю div, я получу текст, но теперь проблема в том, что текст смещен, и я понятия не имею, сохранит ли это шрифты.
Ниже я беру каждый узел svg и использую replaceAll для изменения innerHTML узлов.
for(i = 0; i< svg.getElementsByClassName("node").length; i++){
svg.getElementsByClassName("node")[i].innerHTML = svg.getElementsByClassName("node")[i].innerHTML.replaceAll("<div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: inline-block; white-space: nowrap;\">", "").replaceAll("</div>", "").replaceAll("foreignObject", "text");
}
downloadPDF(svg, "test")
Решение проблемы
Я подозреваю, что в модуле рендеринга печати есть какая-то ошибка рендеринга, поскольку вызов SVG и ответ Mermaid кажутся идеальными, плюс встроенный SVG для чтения и печати также выглядит хорошо и правильно. Итак, ваш первоначальный код (с небольшой необходимой строкой @media) выглядит как PDF.
Точно так же образец Evo отлично визуализируется с использованием того же метода, но в этом случае допускается использование по умолчанию системной бумаги, например, 8,5x11 (Letter).
"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" --headless --run-all-compositor-stages-before-draw --print-to-pdf-no-header --print-to-pdf="C:\Users\WDAGUtilityAccount\desktop\svg-example.pdf" https://www.evopdf.com/DemoAppFiles/HTML_Files/SVG_Examples.html & timeout 5 & svg-example.pdf
Чтобы уменьшить размер носителя по умолчанию в Chrome, мне пришлось добавить в ваш<head>
<head>
<meta http-equiv="Content-Style-Type" content="text/css">
<style>@media print { @page { margin: 0; size: 125px 238px; } body { margin: 0; } }</style>
</head>
и вы заметите, что из-за небольшой ошибки округления в математике медиа размер должен быть немного больше, чем SVG viewBox="0 0 124.63749694824219 231.20001220703125" как ни странно в этом случае просто округлить ширину, но 6 дополнительных единиц в высоту!
Таким образом, я предлагаю заменить окончательный метод распечатки на более обычные методы JS, чтобы использовать встроенную функцию печати браузера, которая должна быть всего на несколько строк больше, чем мой однострочный метод.