Windows下Puppeteer生成PDF打印时宽大于高出现尺寸方向错误
问题描述
使用Puppeteer加载HTML文件转换为PDF后,通过Node.js调用打印机打印。当PDF宽度小于高度时打印正常,但宽度大于高度时,打印机输出的尺寸和方向均出现错误。
Node.js生成并打印PDF的代码
const puppeteer = require('puppeteer'); const fs = require('fs'); const path = require('path'); const express = require('express'); const expressWs = require('express-ws'); const printer = require('pdf-to-printer'); let browser; async function initializeBrowser() { if (!browser) { browser = await puppeteer.launch({ headless: 'new',//'new' }); } } async function printHtmlToCustomSize(page, htmlFilePath, outputPath, widthMM, heightMM, printerName) { await page.setViewport({ width: widthMM* 25.4, height: heightMM * 25.4, deviceScaleFactor: 2, }); const fileUrl = `file://${path.resolve(htmlFilePath)}`; console.log(fileUrl); await page.goto(fileUrl); await page.pdf({ path: outputPath, width: `${widthMM}mm`, height: `${heightMM}mm`, }); const printerOptions = { printer: printerName, }; await printer.print(outputPath, printerOptions); console.log(`PDF printed to ${printerName}`); } async function startServer() { const app = express(); expressWs(app); app.ws('/print', (ws, req) => { ws.on('message', async (message) => { const { htmlFilePath, outputPath, widthMM, heightMM, printerName } = JSON.parse(message); await initializeBrowser(); const page = await browser.newPage(); try { await printHtmlToCustomSize(page, htmlFilePath, outputPath, widthMM, heightMM, printerName); ws.send(JSON.stringify({ status: 'success' })); } finally { await page.close(); } }); }); app.listen(3000, () => { console.log('WebSocket server listening on port 3000'); }); } startServer();
使用设备
WP300B 4英寸热敏打印机
打印效果
- 实际打印:内容尺寸缩放错误,方向偏移,无法匹配设定的宽高
- 预期打印:内容完整贴合设定的宽高布局,位置准确
HTML标签代码
<meta charset="utf-8"> <style> @media print { body { -webkit-print-color-adjust:exact; } hr{ -webkit-print-color-adjust:exact; } body{ margin: 0 auto; } .preview-mode{ border: 0 !important; } } body{ line-height: 1.5; } .preview-body { margin: 0 auto; padding: 0; height: 100%; /* font-size: 14px;*/ font-family: Arial; } .table{ font-size:inherit; } @page{ margin: 0; } hr{ margin: 0; -webkit-print-color-adjust:exact; } .preview-border{ border: 1px solid #000000; /*width: 100%; height: 100%;*/ } .preview-mode .textarea, .preview-mode input { border: 0; resize: none; user-select: none; writing-mode: unset; cursor: default; outline: none; pointer-events: none; touch-action: none; font-size: 14px; } .preview-mode table { resize: none; user-select: none; writing-mode: unset; outline: none; border-collapse: collapse; } .preview-mode .draggable-table td .textarea { resize: none; user-select: none; writing-mode: unset; outline: none; width: 100%; height: 100%; overflow: hidden; box-sizing: border-box; border-collapse: collapse; } .preview-mode .draggable-table td{ position: relative; } .preview-mode .draggable-table .element{ top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; } .preview-mode .element { position: absolute; cursor: default; resize: none; } .preview-mode .delete-element, .preview-mode .duplicate-element, .preview-mode .rotate-element { display: none; } .preview-mode .textarea span { display: block !important; font-size: inherit; } .table-inside-border td { border: 1px solid black; } .table-inside-border tr:first-child td { border-top: 0; } .table-inside-border tr:last-child td { border-bottom: 0; } .table-inside-border tr td:first-child, .table-inside-border tr th:first-child { border-left: 0; } .table-inside-border tr td:last-child, .table-inside-border tr th:last-child { border-right: 0; } .table-full-border, .table-full-border tr, .table-full-border td { border: 1px solid black; } .table-outside-border { border: 1px solid #000; } .table-outside-border tr:first-child { border-top: 1px solid #000; } .table-outside-border tr+tr { border-top: 0; } .table-outside-border td { border: 0; border-left: 1px solid #000; } .table-outside-border td+td { border-left: 0; } .table-top-border tr:first-child { border-top: 1px solid #000; } .table-top-border tr, .table-top-border td { border: 0; } .table-bottom-border tr:last-child { border-bottom: 1px solid #000; } .table-bottom-border tr, .table-bottom-border td { border: 0; } .table-left-border tr td:first-child { border-left: 1px solid #000; } .table-left-border tr, .table-left-border td { border: 0; } .table-right-border tr td:last-child { border-right: 1px solid #000; } .table-right-border tr, .table-right-border td { border: 0; } </style> <input name="label_identifier" type="hidden" value="LB-65c49a6277c7f8.20063631"> <input name="width" type="hidden" value="264.566929137"> <input name="height" type="hidden" value="207.8740157505"> <div class="print-wrapper"> <table class="table table-bordered m-auto central-table preview-mode" style="position:relative;height:207.8740157505px; width: 264.566929137px"> <tbody> <tr class="central-table-row"> <td class="droppable ui-droppable"> <div class="draggable element draggable-text ui-draggable" id="droppable-1707383401662" data-id="text" style="z-index:1; top:-0.5px;left:-0.5px;" data-format-selected="1"><div class="element-child"><div contenteditable="true" class="textarea ui-resizable"><span>Text 1</span><div class="ui-resizable-handle ui-resizable-e" style="z-index: 90;"></div><div class="ui-resizable-handle ui-resizable-s" style="z-index: 90;"></div></div></div></div></td> <td class="droppable ui-droppable"> </td> <td class="droppable ui-droppable"> <div class="draggable element draggable-text ui-draggable" id="droppable-1707383410831" data-id="text" style="z-index: 1; top: 2.5px; left: 222.281px;" data-format-selected="1"><div class="element-child"><div contenteditable="true" class="textarea ui-resizable"><span>Text 2</span><div class="ui-resizable-handle ui-resizable-e" style="z-index: 90;"></div><div class="ui-resizable-handle ui-resizable-s" style="z-index: 90;"></div></div></div></div></td> <td class="droppable ui-droppable"> </td> </tr> <tr class="central-table-row"> <td class="droppable ui-droppable"> </td> <td class="droppable ui-droppable"> </td> <td class="droppable ui-droppable"> </td> <td class="droppable ui-droppable"> <div class="draggable element draggable-text ui-draggable" id="droppable-1707383429730" data-id="text" style="z-index: 1; top: 182.453px; left: 226.172px;" data-format-selected="1"><div class="element-child"><div contenteditable="true" class="textarea ui-resizable"><span>Text4</span><div class="ui-resizable-handle ui-resizable-e" style="z-index: 90;"></div><div class="ui-resizable-handle ui-resizable-s" style="z-index: 90;"></div></div></div></div></td> </tr> <tr class="central-table-row"> <td class="droppable ui-droppable"> <div class="draggable element draggable-text ui-draggable" id="droppable-1707383427788" data-id="text" style="z-index: 1; top: 182.906px; left: 2px;" data-format-selected="1"><div class="element-child"><div contenteditable="true" class="textarea ui-resizable"><span>Text3</span><div class="ui-resizable-handle ui-resizable-s" style="z-index: 90;"></div></div></div></div></td> <td class="droppable ui-droppable"> </td> <td class="droppable ui-droppable"> </td> <td class="droppable ui-droppable"> </td> </tr> </tbody> </table> </div> <script type="text/javascript"> if(document.getElementsByClassName('central-table')[0].classList.contains('preview-mode')){ document.getElementsByClassName('central-table')[0].classList.add('preview-border'); document.getElementsByTagName('body')[0].setAttribute( 'class', 'preview-body'); document.getElementsByTagName('html')[0].setAttribute( 'class', 'preview-body'); var elements=document.getElementsByClassName('ui-rotatable-handle'); while(elements.length > 0){ elements[0].parentNode.removeChild(elements[0]); } } </script>
WebSocket请求体格式
{ "htmlFilePath":"page.html", "outputPath":"./output.pdf", "widthMM":70, "heightMM":55, "printerName":"printerName" }
内容的提问来源于stack exchange,提问作者unkownDev
相关产品推荐
相关产品推荐

