import html2canvas from 'html2canvas'; import jsPDF from 'jspdf'; export const generateProfessionalPDF = async (elementId: string, filename: string) => { try { const element = document.getElementById(elementId); if (!element) { throw new Error('Elemento não encontrado para gerar PDF'); } // Aguardar um pouco para garantir que o elemento esteja completamente renderizado await new Promise(resolve => setTimeout(resolve, 200)); // Garantir que o elemento esteja visível e com dimensões corretas const originalDisplay = element.style.display; const originalVisibility = element.style.visibility; const originalPosition = element.style.position; element.style.display = 'block'; element.style.visibility = 'visible'; element.style.position = 'relative'; // Forçar um reflow element.offsetHeight; // Aguardar mais um pouco após forçar o reflow await new Promise(resolve => setTimeout(resolve, 300)); console.log('Gerando PDF para elemento:', elementId); console.log('Dimensões do elemento:', { width: element.offsetWidth, height: element.offsetHeight, scrollWidth: element.scrollWidth, scrollHeight: element.scrollHeight }); // Se o elemento não tem dimensões, isso pode causar PDF em branco if (element.offsetWidth === 0 || element.offsetHeight === 0) { throw new Error('Elemento tem dimensões zero - não é possível gerar PDF'); } // Configurações otimizadas para html2canvas const canvas = await html2canvas(element, { scale: 2, useCORS: true, allowTaint: false, backgroundColor: '#ffffff', width: element.scrollWidth, height: element.scrollHeight, scrollX: 0, scrollY: 0, windowWidth: Math.max(element.scrollWidth, 1200), windowHeight: Math.max(element.scrollHeight, 800), foreignObjectRendering: false, removeContainer: false, imageTimeout: 10000, logging: false }); console.log('Canvas criado com sucesso:', { width: canvas.width, height: canvas.height }); // Verificar se o canvas foi criado corretamente if (canvas.width === 0 || canvas.height === 0) { throw new Error('Canvas criado com dimensões zero'); } // Restaurar estilos originais element.style.display = originalDisplay; element.style.visibility = originalVisibility; element.style.position = originalPosition; // Criar PDF com configurações otimizadas const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4', compress: true }); // Dimensões A4 em mm const pageWidth = 210; const pageHeight = 297; // Margens adequadas const marginTop = 15; const marginBottom = 15; const marginLeft = 15; const marginRight = 15; // Área útil para conteúdo const contentWidth = pageWidth - marginLeft - marginRight; const contentHeight = pageHeight - marginTop - marginBottom; // Calcular proporções mantendo aspect ratio const imgWidth = contentWidth; const imgHeight = (canvas.height * contentWidth) / canvas.width; // Converter canvas para imagem const imgData = canvas.toDataURL('image/png', 1.0); console.log('Adicionando imagem ao PDF:', { imgWidth, imgHeight, contentHeight, totalPages: Math.ceil(imgHeight / contentHeight) }); // Verificar se os dados da imagem foram gerados if (!imgData || imgData === 'data:,') { throw new Error('Falha ao gerar dados da imagem do canvas'); } // Sistema de paginação let currentY = 0; let pageNumber = 1; const totalPages = Math.ceil(imgHeight / contentHeight); // Função para adicionar rodapé com numeração const addFooter = (pageNum: number, totalPages: number) => { pdf.setFontSize(8); pdf.setTextColor(100, 100, 100); const footerText = `Página ${pageNum} de ${totalPages}`; const textWidth = pdf.getTextWidth(footerText); const footerX = (pageWidth - textWidth) / 2; const footerY = pageHeight - 8; pdf.text(footerText, footerX, footerY); }; // Primeira página if (imgHeight <= contentHeight) { // Conteúdo cabe em uma página pdf.addImage(imgData, 'PNG', marginLeft, marginTop, imgWidth, imgHeight); addFooter(1, 1); } else { // Conteúdo precisa de múltiplas páginas while (currentY < imgHeight) { if (pageNumber > 1) { pdf.addPage(); } // Calcular a altura restante do conteúdo const remainingHeight = imgHeight - currentY; const currentPageHeight = Math.min(contentHeight, remainingHeight); // Criar um canvas temporário para a seção atual const tempCanvas = document.createElement('canvas'); const tempCtx = tempCanvas.getContext('2d'); if (tempCtx) { tempCanvas.width = canvas.width; tempCanvas.height = (currentPageHeight * canvas.width) / imgWidth; // Desenhar a seção atual do canvas original tempCtx.drawImage( canvas, 0, (currentY * canvas.width) / imgWidth, canvas.width, tempCanvas.height, 0, 0, canvas.width, tempCanvas.height ); // Converter para dados de imagem const tempImgData = tempCanvas.toDataURL('image/png', 1.0); // Adicionar a seção ao PDF pdf.addImage(tempImgData, 'PNG', marginLeft, marginTop, imgWidth, currentPageHeight); } // Adicionar rodapé addFooter(pageNumber, totalPages); // Preparar para próxima página currentY += contentHeight; pageNumber++; } } // Forçar o download do PDF console.log('Iniciando download do PDF:', filename); pdf.save(filename); // Aguardar um momento para garantir que o download seja iniciado await new Promise(resolve => setTimeout(resolve, 500)); console.log('PDF salvo com sucesso:', filename); return true; } catch (error) { console.error('Erro detalhado ao gerar PDF:', error); throw new Error(`Erro ao gerar PDF: ${error.message}`); } }; export const printProfessionalPDF = async (elementId: string) => { try { const element = document.getElementById(elementId); if (!element) { throw new Error('Elemento não encontrado'); } // Criar nova janela para impressão const printWindow = window.open('', '_blank'); if (!printWindow) { throw new Error('Não foi possível abrir janela de impressão'); } // Obter estilos do documento atual const styleSheets = Array.from(document.styleSheets); let allStyles = ''; try { styleSheets.forEach(sheet => { try { if (sheet.cssRules) { Array.from(sheet.cssRules).forEach(rule => { allStyles += rule.cssText + '\n'; }); } } catch (e) { // Ignorar erros de CORS } }); } catch (e) { console.warn('Não foi possível obter alguns estilos', e); } // HTML otimizado para impressão sem áreas vazias const printContent = `