Tldraw/apps/examples/src/examples/pdf-editor/ExportPdfButton.tsx

90 wiersze
2.2 KiB
TypeScript

import { PDFDocument } from 'pdf-lib'
import { useState } from 'react'
import { Editor, assert, exportToBlob, useEditor } from 'tldraw'
import { Pdf } from './PdfPicker'
export function ExportPdfButton({ pdf }: { pdf: Pdf }) {
const [exportProgress, setExportProgress] = useState<number | null>(null)
const editor = useEditor()
return (
<button
className="ExportPdfButton"
onClick={async () => {
setExportProgress(0)
try {
await exportPdf(editor, pdf, setExportProgress)
} finally {
setExportProgress(null)
}
}}
>
{exportProgress ? `Exporting... ${Math.round(exportProgress * 100)}%` : 'Export PDF'}
</button>
)
}
async function exportPdf(
editor: Editor,
{ name, source, pages }: Pdf,
onProgress: (progress: number) => void
) {
const totalThings = pages.length * 2 + 2
let progressCount = 0
const tickProgress = () => {
progressCount++
onProgress(progressCount / totalThings)
}
const pdf = await PDFDocument.load(source)
tickProgress()
const pdfPages = pdf.getPages()
assert(pdfPages.length === pages.length, 'PDF page count mismatch')
const pageShapeIds = new Set(pages.map((page) => page.shapeId))
const allIds = Array.from(editor.getCurrentPageShapeIds()).filter((id) => !pageShapeIds.has(id))
for (let i = 0; i < pages.length; i++) {
const page = pages[i]
const pdfPage = pdfPages[i]
const bounds = page.bounds
const shapesInBounds = allIds.filter((id) => {
const shapePageBounds = editor.getShapePageBounds(id)
if (!shapePageBounds) return false
return shapePageBounds.collides(bounds)
})
if (shapesInBounds.length === 0) {
tickProgress()
tickProgress()
continue
}
const exportedPng = await exportToBlob({
editor,
ids: allIds,
format: 'png',
opts: { background: false, bounds: page.bounds, padding: 0, scale: 2 },
})
tickProgress()
pdfPage.drawImage(await pdf.embedPng(await exportedPng.arrayBuffer()), {
x: 0,
y: 0,
width: pdfPage.getWidth(),
height: pdfPage.getHeight(),
})
tickProgress()
}
const url = URL.createObjectURL(new Blob([await pdf.save()], { type: 'application/pdf' }))
tickProgress()
const a = document.createElement('a')
a.href = url
a.download = name
a.click()
URL.revokeObjectURL(url)
}