diff --git a/assets/webui/index.html b/assets/webui/index.html index 77ee46d..96d959f 100644 --- a/assets/webui/index.html +++ b/assets/webui/index.html @@ -42,8 +42,9 @@
- - + + +
diff --git a/assets/webui/ofdgo.css b/assets/webui/ofdgo.css index 9a3ee4f..2c391b2 100644 --- a/assets/webui/ofdgo.css +++ b/assets/webui/ofdgo.css @@ -1073,10 +1073,6 @@ body[data-hide-meta] .meta-panel { min-width: 34px; } - #exportButton { - padding-inline: 8px; - } - .format-select { width: 52px; padding: 0 3px; @@ -1090,3 +1086,75 @@ body[data-hide-meta] .meta-panel { justify-content: flex-end; } } + +@media print { + @page { + margin: 0; + } + + html, + body { + width: auto; + height: auto; + min-width: 0; + overflow: visible; + background: #ffffff; + } + + .app { + display: block; + height: auto; + overflow: visible; + } + + .app-bar, + .app-footer, + .page-list-panel, + .meta-panel, + .empty-state, + .progress-panel, + .stamp-highlight { + display: none !important; + } + + .workspace, + .viewer-panel, + .page-frame, + .svg-host { + display: block; + width: auto; + min-width: 0; + min-height: 0; + height: auto; + margin: 0; + padding: 0; + overflow: visible; + background: #ffffff; + } + + .page-shell { + width: var(--page-width) !important; + height: var(--page-height) !important; + overflow: hidden; + border: 0; + box-shadow: none; + break-inside: avoid; + page-break-inside: avoid; + } + + .page-shell:not(:last-child) { + break-after: page; + page-break-after: always; + } + + .page-surface { + width: var(--page-width) !important; + height: var(--page-height) !important; + transform: none !important; + } + + .ofd-svg { + width: var(--page-width) !important; + height: var(--page-height) !important; + } +} diff --git a/assets/webui/ofdgo.js b/assets/webui/ofdgo.js index d10193c..7b335c2 100644 --- a/assets/webui/ofdgo.js +++ b/assets/webui/ofdgo.js @@ -27,6 +27,7 @@ const STATUS = { fonts: "正在匹配字体", exporting: "正在导出文档 PDF", pageExporting: "正在导出单页", + printing: "正在准备打印", }; const WASM_CALLBACKS = [ "ofdgoOpen", @@ -98,6 +99,7 @@ const el = { pageExportFormat: document.querySelector("#pageExportFormat"), exportPageButton: document.querySelector("#exportPageButton"), exportButton: document.querySelector("#exportButton"), + printButton: document.querySelector("#printButton"), emptyState: document.querySelector("#emptyState"), progressPanel: document.querySelector("#progressPanel"), progressLabel: document.querySelector("#progressLabel"), @@ -142,6 +144,7 @@ el.annotationButton.addEventListener("click", toggleAnnotations); el.renderDPI.addEventListener("change", changeDPI); el.exportPageButton.addEventListener("click", exportCurrentPage); el.exportButton.addEventListener("click", exportPDF); +el.printButton.addEventListener("click", printDocument); el.pageInput.addEventListener("change", () => { const page = Number.parseInt(el.pageInput.value, 10); if (Number.isFinite(page)) { @@ -1068,6 +1071,50 @@ async function exportCurrentPage() { } } +async function printDocument() { + if (!state.doc) { + return; + } + const openSeq = state.openSeq; + setExportControlsDisabled(true); + setBusy(true, "正在准备打印", 18, STATUS.printing); + try { + await renderPagesForPrint(openSeq); + if (openSeq !== state.openSeq) { + return; + } + setProgress("正在打开打印", 86); + await waitForPaint(); + if (openSeq !== state.openSeq) { + return; + } + setBusy(false); + updateControls(); + window.print(); + setStatus("已打开打印"); + } catch (err) { + if (openSeq === state.openSeq) { + showError(err, false); + } + } finally { + if (openSeq === state.openSeq) { + setBusy(false); + updateControls(); + } + } +} + +async function renderPagesForPrint(openSeq) { + const pages = state.doc?.pages || []; + for (let i = 0; i < pages.length; i += 1) { + if (openSeq !== state.openSeq) { + return; + } + setProgress(`正在渲染打印 ${i + 1}/${pages.length}`, 20 + Math.round(i / Math.max(1, pages.length) * 62), STATUS.printing); + await renderFlowPage(pages[i].index, { throwError: true, openSeq, priority: 0 }); + } +} + function renderPageFlow() { el.svgHost.replaceChildren(); if (!state.doc) { @@ -1409,6 +1456,8 @@ function layoutPages() { function layoutPageShell(shell, page) { const width = Math.max(1, page.width * MM_TO_PX); const height = Math.max(1, page.height * MM_TO_PX); + shell.style.setProperty("--page-width", `${width}px`); + shell.style.setProperty("--page-height", `${height}px`); shell.style.width = `${width * state.scale}px`; shell.style.height = `${height * state.scale}px`; const surface = shell.querySelector(".page-surface"); @@ -2103,6 +2152,7 @@ function updateControls() { el.pageExportFormat.disabled = !hasDoc || !state.exportFormats.length; el.exportPageButton.disabled = !hasDoc || !state.exportFormats.length; el.exportButton.disabled = !hasDoc; + el.printButton.disabled = !hasDoc; } function updateAnnotationButton() { @@ -2115,6 +2165,7 @@ function setExportControlsDisabled(disabled) { el.exportButton.disabled = disabled; el.exportPageButton.disabled = disabled; el.pageExportFormat.disabled = disabled; + el.printButton.disabled = disabled; } function callWASM(name, ...args) {