Untitled
unknown
javascript
2 months ago
6.0 kB
5
Indexable
import { jsPDF } from "jspdf"
import html2canvas from "html2canvas"
interface PrintHtmlProps {
htmlString: string
}
export const printHtml = ({ htmlString }: PrintHtmlProps): Promise<void> => {
return new Promise((resolve, reject) => {
try {
const iframe = document.createElement("iframe")
iframe.style.position = "fixed"
iframe.style.right = "0"
iframe.style.bottom = "0"
iframe.style.width = "0"
iframe.style.height = "0"
iframe.style.border = "0"
document.body.appendChild(iframe)
const iframeWindow = iframe.contentWindow
if (!iframeWindow) {
document.body.removeChild(iframe)
// Rejeita a Promise se o navegador bloquear o acesso ao iframe
return reject(
new Error(
"Não foi possível acessar a janela do iframe para impressão."
)
)
}
const iframeDocument = iframeWindow.document
const style = iframeDocument.createElement("style")
style.textContent = `
@page { margin: 0; }
body {
margin: 0;
padding: 0;
width: 100vw;
}
.scale-container {
width: fit-content;
/* margin: 0 auto; */
}
`
iframeDocument.head.appendChild(style)
const container = iframeDocument.createElement("div")
container.className = "scale-container"
container.innerHTML = htmlString
iframeDocument.body.appendChild(container)
// Timeout 1: Aguarda a renderização inicial para podermos medir
setTimeout(() => {
const apiWidth = container.scrollWidth
if (apiWidth > 0) {
container.style.zoom = `calc(100vw / ${apiWidth})`
}
// Timeout 2: Aguarda o zoom ser aplicado antes de focar e imprimir
setTimeout(() => {
iframeWindow.focus()
// Abre a caixa de impressão. A execução do JS pausa aqui na maioria dos navegadores
// até que a caixa seja fechada (seja por confirmar ou cancelar).
iframeWindow.print()
// Timeout 3: Limpeza do DOM e resolução da Promise
setTimeout(() => {
document.body.removeChild(iframe)
resolve() // Sucesso! O processo de impressão terminou.
}, 1000)
}, 150)
}, 100)
} catch (error) {
// Captura qualquer erro inesperado durante a execução
reject(error)
}
})
}
type GeneratePdfOptions = {
htmlString: string | string[]
pageWidthMm?: number
pageHeightMm?: number
containerWidthPx?: number
}
export const generatePdfFromHtml = async ({
htmlString,
pageWidthMm = 80,
pageHeightMm = 80,
containerWidthPx = 464
}: GeneratePdfOptions): Promise<string> => {
const htmlStrings = Array.isArray(htmlString) ? htmlString : [htmlString]
// 1. Configurações centrais do PDF (mm)
const doc = new jsPDF({
unit: "mm",
format: [pageWidthMm, pageHeightMm],
orientation: "portrait",
compress: true
})
/**
* Helper para envolver o HTML em um container padronizado que evita cortes
* e garante que o fundo seja branco durante a captura.
*/
const wrapContent = (content: string) => `
<div style="
width: ${containerWidthPx}px;
padding: 8px 16px;
box-sizing: border-box;
background: white;
word-wrap: break-word;
font-smoothing: antialiased;
-webkit-font-smoothing: antialiased;
">
${content}
</div>
`
// 2. Construção progressiva do PDF
// Ao usar html2canvas diretamente, evitamos a criação de iframes, o que limpa os erros de console.
for (let i = 0; i < htmlStrings.length; i++) {
// Adicionamos uma página nova se não for a primeira
if (i > 0) {
doc.addPage([pageWidthMm, pageHeightMm], "p")
}
// Criamos um elemento temporário no nosso DOM para captura direta
const container = document.body.appendChild(document.createElement("div"))
container.style.position = "absolute"
container.style.left = "-9999px"
container.style.top = "0"
container.innerHTML = wrapContent(htmlStrings[i])
try {
const canvas = await html2canvas(container, {
scale: 4, // Alta qualidade
useCORS: true,
logging: false,
backgroundColor: "white",
width: containerWidthPx,
windowWidth: containerWidthPx + 32 // Evita cortes laterais
})
const imgData = canvas.toDataURL("image/png", 1.0)
// Ajusta a imagem para preencher a largura total da página respeitando a proporção
const imgWidth = pageWidthMm
const imgHeight = (canvas.height * imgWidth) / canvas.width
doc.addImage(imgData, "PNG", 0, 0, imgWidth, imgHeight)
} finally {
// Limpeza imediata do elemento após a captura
document.body.removeChild(container)
}
}
// 3. Finalização e retorno do Base64
return doc.output("datauristring")
}
export function printPdf(pdfBase64: string) {
if (!pdfBase64) return
const cleanedBase64 = pdfBase64.replace(
"data:application/pdf;filename=generated.pdf;base64,",
""
)
const byteCharacters = atob(cleanedBase64)
const byteNumbers = Array.from(byteCharacters, char => char.charCodeAt(0))
const byteArray = new Uint8Array(byteNumbers)
const blob = new Blob([byteArray], { type: "application/pdf" })
const blobUrl = URL.createObjectURL(blob)
const iframe = document.createElement("iframe")
iframe.style.position = "fixed"
iframe.style.right = "0"
iframe.style.bottom = "0"
iframe.style.width = "0"
iframe.style.height = "0"
iframe.style.border = "0"
iframe.src = blobUrl
iframe.onload = () => {
iframe.contentWindow?.focus()
iframe.contentWindow?.print()
}
document.body.appendChild(iframe)
}
Editor is loading...
Leave a Comment