我正在嘗試將此 SVG 輸出為 pdf。SVG 由mermaid.js
我在堆疊上找到了將 SVG 轉換為 PDF 的現有
這是downloadPDF函式的影像輸出(downloadPDF(svg, "test")在瀏覽器開發控制臺中運行):

注意:我在 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")
更新
使用瀏覽器列印功能變得非常簡單
我稍微修改了我在
同樣,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方法來使用瀏覽器原生列印功能,應該只比我的一行方法多幾行。
uj5u.com熱心網友回復:
更新:
您可以通過將引數設定為 false來啟用<text>元素標簽 :htmlLabels
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/[email protected]/js/pdfkit.standalone.js"></script>
<script src="https://bundle.run/[email protected]"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/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 不支持這個元素。
不支持
- 過濾器
- 文本屬性:font-variant、writing-mode、unicode-bidi
- 矢量效果(#113)
- 外國物件 (#37)
- 其他我什至不知道它們存在的東西
一種解決方法可能是使用可以像這樣注冊的網路字體:
doc.registerFont('Fira-Sans-Regular', arrayBuffer)
doc.font('Fira-Sans-Regular')
關于布局/垂直對齊,您可以為替換添加一個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/[email protected]/js/pdfkit.standalone.js"></script>
<script src="https://bundle.run/[email protected]"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/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>
請注意字體系列名稱的連字符表示法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/475354.html
標籤:javascript html svg 美人鱼
