将 SVG 转换为 PDF 时出现奇怪的输出 javascript mermaid.js 示例
Strange output when converting SVG to PDF javascript mermaid.js example
我正在尝试将此 SVG 输出为 pdf。 SVG 由 mermaid.js
生成
我在堆栈上找到了一个现有的 answer 用于将 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;
C[Action 1 </br> Can code preserve line breaks?];
</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")
在broswer开发控制台):
注意:我在 Firefox 和 Edge 浏览器中得到了同样的输出。
更新:我编辑了函数 downloadPDF,现在我得到了正确的颜色,但是,节点文本仍然没有显示:
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:
所以我注意到,如果我将 svg 节点中的 foreignObject 更改为 <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")
更新
浏览器打印功能变得非常简单
我稍微修改了我在 this answer 中找到的这个函数。
var printSVG = function()
{
var popUpAndPrint = function()
{
var container = $('.mermaid')[0];
var width = Math.max(1000, parseFloat(svg.getAttribute("width")))
var height = Math.max(1000, parseFloat(svg.getAttribute("height")))
var printWindow = window.open('', 'PrintMap',
'width=' + width + ',height=' + height);
printWindow.document.writeln($(container).html());
printWindow.document.close();
printWindow.print();
printWindow.close();
};
setTimeout(popUpAndPrint, 500);
};
感谢大家的帮助!
我怀疑打印渲染模块中存在一些渲染错误,因为 SVG 调用和美人鱼响应看起来很完美,而且本机读取和打印 SVG 看起来也不错,而且合适。所以你的初始代码(带有一小段必要的@media 行看起来像这样的 PDF。
同样,Evo 示例使用相同的方法完美呈现,但在这种情况下允许系统纸张的媒体默认值,例如8.5x11(信纸)
"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方法以使用浏览器原生打印功能,应该只比我的一行方法多几行。
更新:
您可以通过配置将 htmlLabels
参数设置为 false 来启用 <text>
元素标签:
var config = {
startOnLoad:true,
flowchart:{
useMaxWidth:false,
htmlLabels:false
} };
mermaid.initialize(config);
但你仍然需要一些消毒,因为美人鱼会添加一个 xml:space
属性 svg-to-pdf-kit 不喜欢
示例:渲染 <text>
标签 (codepen)
var config = {
startOnLoad: true,
flowchart: {
useMaxWidth: false,
htmlLabels: false
}
};
mermaid.initialize(config);
//example font fira Sans
let fontUrl = 'https://fonts.gstatic.com/s/firasans/v16/va9E4kDNxMZdWfMOD5Vvl4jO.ttf';
async function downloadPDF(outFileName) {
let svg = document.querySelector('.mermaid svg');
// sanitize
sanitizeSVG();
// load font and register
const font = await fetch(fontUrl)
const arrayBuffer = await font.arrayBuffer()
let doc = new PDFDocument({
compress: false
});
doc.registerFont('Fira-Sans-Regular', arrayBuffer)
doc.font('Fira-Sans-Regular')
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();
}
function sanitizeSVG() {
let svg = document.querySelector('.mermaid svg');
let tspans = svg.querySelectorAll('tspan');
tspans.forEach(function(tspan, i) {
tspan.removeAttribute('xml:space');
});
}
@font-face {
font-family: 'Fira-Sans-Regular';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/firasans/v16/va9E4kDNxMZdWfMOD5Vvl4jO.ttf) format('truetype');
}
text {
font-family: 'Fira-Sans-Regular';
line-height: 18px;
}
<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>
<button type="button" onclick="downloadPDF( 'mermaid')">Download PDF</button>
<button type="button" onclick="sanitizeSVG()">sanitize</button>
<div class="mermaid">
graph TD; A-->B; A-->C; B-->D; C-->D; C[Action 1 </br> Can code preserve line breaks?];
</div>
转换 <foreignObject>
元素当然是个好主意,因为 svg-to-pdfkit 不支持此元素。
- filters
- text attributes: font-variant, writing-mode, unicode-bidi
- vector-effect (#113)
- foreignObject (#37)
- other things I don't even know they exist
解决方法可能是使用可以像这样注册的网络字体:
doc.registerFont('Fira-Sans-Regular', arrayBuffer)
doc.font('Fira-Sans-Regular')
关于 layout/vertical 对齐,您可以将 dy
属性添加到 <text>
替换。
示例:转换 <foreignObject>
(参见 codepen)
mermaid.init({
flowchart: {
useMaxWidth: false
},
"theme": "default",
"themeVariables": {
"fontFamily": "Fira-Sans-Regular",
}
}, document.querySelectorAll(".mermaid"));
const svg = document.querySelector('.mermaid svg');
//example font fira Sans
let fontUrl = 'https://fonts.gstatic.com/s/firasans/v16/va9E4kDNxMZdWfMOD5Vvl4jO.ttf';
async function downloadPDF(svg, outFileName) {
// convert foreignObjects
convertForeignObjects(svg);
// load font and register
const font = await fetch(fontUrl)
const arrayBuffer = await font.arrayBuffer()
let doc = new PDFDocument({
compress: false
});
doc.registerFont('Fira-Sans-Regular', arrayBuffer)
doc.font('Fira-Sans-Regular')
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();
}
function convertForeignObjects(svg) {
//replace font-family in css
svg.innerHTML = svg.innerHTML.replaceAll('"trebuchet ms"', 'Fira-Sans-Regular')
let foreignObjects = svg.querySelectorAll('foreignObject');
foreignObjects.forEach(function(el, i) {
let text = el.querySelector('div');
//split newlines
let contentHTML = text.innerHTML;
contentHTML = contentHTML.replaceAll('</br>', ' || ').replaceAll('<br>', ' || ');
text.innerHTML = contentHTML;
let content = text.textContent;
let contentLines = content.split(' || ');
let newTextEl = document.createElementNS('http://www.w3.org/2000/svg', 'text');
newTextEl.setAttribute('x', '0');
newTextEl.setAttribute('y', '-0.2em');
newTextEl.setAttribute('style', 'font-family:"Fira-Sans-Regular"!important;');
if(contentLines.length){
contentLines.forEach(function(line){
let newLine = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
newLine.textContent = line;
newLine.setAttribute('x', '0');
newLine.setAttribute('dy', '1.2em');
newTextEl.appendChild(newLine);
});
}
el.parentNode.appendChild(newTextEl);
el.remove();
})
}
@font-face {
font-family: 'Fira-Sans-Regular';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/firasans/v16/va9E4kDNxMZdWfMOD5Vvl4jO.ttf) format('truetype');
}
text {
font-family: 'Fira-Sans-Regular';
line-height: 18px;
}
<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>
<button type="button" onclick="downloadPDF(svg, 'mermaid')">Convert and download PDF</button>
<button type="button" onclick="convertForeignObjects(svg)">Convert foreign objects</button>
<div class="mermaid">
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
C[Action 1 <br> Can code preserve line breaks?];
</div>
注意 font-family 个名称的连字符符号。
我正在尝试将此 SVG 输出为 pdf。 SVG 由 mermaid.js
我在堆栈上找到了一个现有的 answer 用于将 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;
C[Action 1 </br> Can code preserve line breaks?];
</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")
在broswer开发控制台):
注意:我在 Firefox 和 Edge 浏览器中得到了同样的输出。
更新:我编辑了函数 downloadPDF,现在我得到了正确的颜色,但是,节点文本仍然没有显示:
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:
所以我注意到,如果我将 svg 节点中的 foreignObject 更改为 <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")
更新
浏览器打印功能变得非常简单
我稍微修改了我在 this answer 中找到的这个函数。
var printSVG = function()
{
var popUpAndPrint = function()
{
var container = $('.mermaid')[0];
var width = Math.max(1000, parseFloat(svg.getAttribute("width")))
var height = Math.max(1000, parseFloat(svg.getAttribute("height")))
var printWindow = window.open('', 'PrintMap',
'width=' + width + ',height=' + height);
printWindow.document.writeln($(container).html());
printWindow.document.close();
printWindow.print();
printWindow.close();
};
setTimeout(popUpAndPrint, 500);
};
感谢大家的帮助!
我怀疑打印渲染模块中存在一些渲染错误,因为 SVG 调用和美人鱼响应看起来很完美,而且本机读取和打印 SVG 看起来也不错,而且合适。所以你的初始代码(带有一小段必要的@media 行看起来像这样的 PDF。
同样,Evo 示例使用相同的方法完美呈现,但在这种情况下允许系统纸张的媒体默认值,例如8.5x11(信纸)
"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方法以使用浏览器原生打印功能,应该只比我的一行方法多几行。
更新:
您可以通过配置将 htmlLabels
参数设置为 false 来启用 <text>
元素标签:
var config = {
startOnLoad:true,
flowchart:{
useMaxWidth:false,
htmlLabels:false
} };
mermaid.initialize(config);
但你仍然需要一些消毒,因为美人鱼会添加一个 xml:space
属性 svg-to-pdf-kit 不喜欢
示例:渲染 <text>
标签 (codepen)
var config = {
startOnLoad: true,
flowchart: {
useMaxWidth: false,
htmlLabels: false
}
};
mermaid.initialize(config);
//example font fira Sans
let fontUrl = 'https://fonts.gstatic.com/s/firasans/v16/va9E4kDNxMZdWfMOD5Vvl4jO.ttf';
async function downloadPDF(outFileName) {
let svg = document.querySelector('.mermaid svg');
// sanitize
sanitizeSVG();
// load font and register
const font = await fetch(fontUrl)
const arrayBuffer = await font.arrayBuffer()
let doc = new PDFDocument({
compress: false
});
doc.registerFont('Fira-Sans-Regular', arrayBuffer)
doc.font('Fira-Sans-Regular')
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();
}
function sanitizeSVG() {
let svg = document.querySelector('.mermaid svg');
let tspans = svg.querySelectorAll('tspan');
tspans.forEach(function(tspan, i) {
tspan.removeAttribute('xml:space');
});
}
@font-face {
font-family: 'Fira-Sans-Regular';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/firasans/v16/va9E4kDNxMZdWfMOD5Vvl4jO.ttf) format('truetype');
}
text {
font-family: 'Fira-Sans-Regular';
line-height: 18px;
}
<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>
<button type="button" onclick="downloadPDF( 'mermaid')">Download PDF</button>
<button type="button" onclick="sanitizeSVG()">sanitize</button>
<div class="mermaid">
graph TD; A-->B; A-->C; B-->D; C-->D; C[Action 1 </br> Can code preserve line breaks?];
</div>
转换 <foreignObject>
元素当然是个好主意,因为 svg-to-pdfkit 不支持此元素。
- filters
- text attributes: font-variant, writing-mode, unicode-bidi
- vector-effect (#113)
- foreignObject (#37)
- other things I don't even know they exist
解决方法可能是使用可以像这样注册的网络字体:
doc.registerFont('Fira-Sans-Regular', arrayBuffer)
doc.font('Fira-Sans-Regular')
关于 layout/vertical 对齐,您可以将 dy
属性添加到 <text>
替换。
示例:转换 <foreignObject>
(参见 codepen)
mermaid.init({
flowchart: {
useMaxWidth: false
},
"theme": "default",
"themeVariables": {
"fontFamily": "Fira-Sans-Regular",
}
}, document.querySelectorAll(".mermaid"));
const svg = document.querySelector('.mermaid svg');
//example font fira Sans
let fontUrl = 'https://fonts.gstatic.com/s/firasans/v16/va9E4kDNxMZdWfMOD5Vvl4jO.ttf';
async function downloadPDF(svg, outFileName) {
// convert foreignObjects
convertForeignObjects(svg);
// load font and register
const font = await fetch(fontUrl)
const arrayBuffer = await font.arrayBuffer()
let doc = new PDFDocument({
compress: false
});
doc.registerFont('Fira-Sans-Regular', arrayBuffer)
doc.font('Fira-Sans-Regular')
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();
}
function convertForeignObjects(svg) {
//replace font-family in css
svg.innerHTML = svg.innerHTML.replaceAll('"trebuchet ms"', 'Fira-Sans-Regular')
let foreignObjects = svg.querySelectorAll('foreignObject');
foreignObjects.forEach(function(el, i) {
let text = el.querySelector('div');
//split newlines
let contentHTML = text.innerHTML;
contentHTML = contentHTML.replaceAll('</br>', ' || ').replaceAll('<br>', ' || ');
text.innerHTML = contentHTML;
let content = text.textContent;
let contentLines = content.split(' || ');
let newTextEl = document.createElementNS('http://www.w3.org/2000/svg', 'text');
newTextEl.setAttribute('x', '0');
newTextEl.setAttribute('y', '-0.2em');
newTextEl.setAttribute('style', 'font-family:"Fira-Sans-Regular"!important;');
if(contentLines.length){
contentLines.forEach(function(line){
let newLine = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
newLine.textContent = line;
newLine.setAttribute('x', '0');
newLine.setAttribute('dy', '1.2em');
newTextEl.appendChild(newLine);
});
}
el.parentNode.appendChild(newTextEl);
el.remove();
})
}
@font-face {
font-family: 'Fira-Sans-Regular';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/firasans/v16/va9E4kDNxMZdWfMOD5Vvl4jO.ttf) format('truetype');
}
text {
font-family: 'Fira-Sans-Regular';
line-height: 18px;
}
<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>
<button type="button" onclick="downloadPDF(svg, 'mermaid')">Convert and download PDF</button>
<button type="button" onclick="convertForeignObjects(svg)">Convert foreign objects</button>
<div class="mermaid">
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
C[Action 1 <br> Can code preserve line breaks?];
</div>
注意 font-family 个名称的连字符符号。