From 6fdfc99e7d5b03d5dde0eb005cc6c5bc8be21201 Mon Sep 17 00:00:00 2001 From: Rodrigo Martins Date: Tue, 22 Apr 2025 14:44:00 -0300 Subject: [PATCH] tenta fix pdfservice.js --- src/server/services/PdfService.ts | 134 ++++++++++++++++++++++-------- 1 file changed, 99 insertions(+), 35 deletions(-) diff --git a/src/server/services/PdfService.ts b/src/server/services/PdfService.ts index 22c3169..347e8ef 100644 --- a/src/server/services/PdfService.ts +++ b/src/server/services/PdfService.ts @@ -377,6 +377,12 @@ export class PdfService { let currentLine: Array<{text: string, font: any, width: number}> = []; let currentLineWidth = 0; + // Verifica se o texto parece ser um título (todo em maiúsculas ou curto) + const isTitle = text.toUpperCase() === text || text.length < 50; + + // Se for título, centralizar independente do alinhamento fornecido + const effectiveAlign = isTitle ? 'center' : align; + // Processa texto com formatação - remover tags HTML e aplicar estilos let currentFont = normalFont; let boldActive = false; @@ -470,6 +476,17 @@ export class PdfService { return null; // Não há espaço suficiente para renderizar } + // Aumentar ligeiramente o espaçamento de linhas para títulos + const effectiveLineHeight = isTitle ? lineHeight * 1.3 : lineHeight; + + // Aumentar o tamanho da fonte para títulos + const effectiveFontSize = isTitle ? fontSize * 1.2 : fontSize; + + // Se for um título, adicionar um espaço extra antes + if (isTitle && y < startY) { + y -= lineHeight * 0.5; + } + // Agora, renderizar as palavras em linhas for (let i = 0; i < words.length; i++) { const word = words[i]; @@ -481,18 +498,23 @@ export class PdfService { currentLineWidth += word.width; } else { // Renderizar a linha atual - if (y - lineHeight < marginBottom) { + if (y - effectiveLineHeight < marginBottom) { return null; // Não há mais espaço na página } // Ajustar X baseado no alinhamento let lineX = x; - const spacingFactor = align === 'justify' && currentLine.length > 1 ? + + // Para justificado, calcular espaçamentos extras entre palavras + // Mas não justificar a última linha de um parágrafo ou títulos + const isLastLine = i === words.length - 1; + const shouldJustify = effectiveAlign === 'justify' && !isLastLine && !isTitle && currentLine.length > 1; + const extraSpacing = shouldJustify ? (maxWidth - currentLineWidth) / (currentLine.length - 1) : 0; - if (align === 'center') { + if (effectiveAlign === 'center') { lineX = x + (maxWidth - currentLineWidth) / 2; - } else if (align === 'right') { + } else if (effectiveAlign === 'right') { lineX = x + maxWidth - currentLineWidth; } @@ -500,11 +522,13 @@ export class PdfService { let posX = lineX; for (let j = 0; j < currentLine.length; j++) { const item = currentLine[j]; + const itemFontSize = isTitle ? effectiveFontSize : fontSize; + page.drawText(item.text, { x: posX, y: y, font: item.font, - size: fontSize, + size: itemFontSize, color }); @@ -512,18 +536,18 @@ export class PdfService { posX += item.width; // Adicionar espaço extra se for justificado (exceto no final da linha) - if (align === 'justify' && j < currentLine.length - 1) { - posX += spacingFactor; + if (shouldJustify && j < currentLine.length - 1) { + posX += extraSpacing; } } // Avançar para a próxima linha - y -= lineHeight; + y -= effectiveLineHeight; currentLine = [word]; currentLineWidth = word.width; // Verificar se ainda temos espaço - if (y - lineHeight < marginBottom) { + if (y - effectiveLineHeight < marginBottom) { return null; } } @@ -531,41 +555,37 @@ export class PdfService { // Renderizar a última linha, se houver if (currentLine.length > 0) { - // Ajustar X baseado no alinhamento (última linha nunca é justificada) + // Ajustar X baseado no alinhamento (última linha nunca é justificada, exceto se for curta) let lineX = x; - if (align === 'center') { + + // Se for título ou alinhado ao centro/direita, ajustar posição + if (effectiveAlign === 'center') { lineX = x + (maxWidth - currentLineWidth) / 2; - } else if (align === 'right') { + } else if (effectiveAlign === 'right') { lineX = x + maxWidth - currentLineWidth; } // Desenhar a linha let posX = lineX; for (const item of currentLine) { + const itemFontSize = isTitle ? effectiveFontSize : fontSize; + page.drawText(item.text, { x: posX, y: y, font: item.font, - size: fontSize, + size: itemFontSize, color }); posX += item.width; } - y -= lineHeight; + y -= effectiveLineHeight; } - // Se estiver em modo debug, desenhar uma caixa ao redor do texto - if (debug) { - page.drawRectangle({ - x, - y: y + lineHeight, - width: maxWidth, - height: startY - y, - borderColor: rgb(0.8, 0.8, 0.8), - borderWidth: 0.5, - opacity: 0.1 - }); + // Se for título, adicionar um espaço extra depois + if (isTitle) { + y -= lineHeight * 0.5; } return y; @@ -581,22 +601,49 @@ export class PdfService { const paragrafos = texto.split(/\n{2,}/).map(p => { let paragraph = p.trim(); if (!paragraph) return ''; + // Extrair informações de formatação - let align = 'left'; // padrão é justificado - const alignMatch = paragraph.match(/§§ALIGN=(center|right|justify)§§/); + let align = 'justify'; // Padrão agora é justificado para texto normal + + // Verifica se o texto parece ser um título por diversos critérios: + // 1. Começa com '#' (estilo markdown) + // 2. Todo em maiúsculas e relativamente curto + // 3. Começa com números seguidos de ponto (como "1. Título") + // 4. Termina com dois pontos e é curto (como "Considerando:") + const isTitle = + paragraph.startsWith('#') || + (paragraph.toUpperCase() === paragraph && paragraph.length < 100) || + /^\d+\.\s+\S+/.test(paragraph) || + (paragraph.endsWith(':') && paragraph.length < 70); + + // Se for um título, centraliza + if (isTitle) { + align = 'center'; + paragraph = paragraph.replace(/^#+\s*/, ''); // Remove marcadores de título estilo markdown + } + + // Processa alinhamentos explícitos (têm precedência) + const alignMatch = paragraph.match(/§§ALIGN=(center|right|justify|left)§§/); if (alignMatch) { align = alignMatch[1]; - paragraph = paragraph.replace(/§§ALIGN=(center|right|justify)§§/, ''); + paragraph = paragraph.replace(/§§ALIGN=(center|right|justify|left)§§/, ''); } + let indent = 0; - const indentMatch = paragraph.match(/§§INDENT=(\d+)(pt|px|em)§§/); + const indentMatch = paragraph.match(/§§INDENT=(\d+)(pt|px|em)?§§/); if (indentMatch) { indent = parseInt(indentMatch[1]); if (indentMatch[2] === 'em') indent *= 12; // Converter em para pontos aproximadamente - paragraph = paragraph.replace(/§§INDENT=\d+(pt|px|em)§§/, ''); + paragraph = paragraph.replace(/§§INDENT=\d+(pt|px|em)?§§/, ''); } - return { text: paragraph.trim(), align, indent }; - }).filter(Boolean); + + return { + text: paragraph.trim(), + align: align as 'left' | 'center' | 'right' | 'justify', + indent, + isTitle + }; + }).filter(p => p.text); let currentPar = 0; let pageIndex = 0; console.log(`Gerando PDF com ${paragrafos.length} parágrafos`); @@ -621,18 +668,35 @@ export class PdfService { while (currentPar < paragrafos.length) { const paraObj = paragrafos[currentPar]; const text = paraObj.text; - const align = paraObj.align || 'justify'; // Por padrão, justifica o texto + const align = paraObj.align; const indent = paraObj.indent || 0; + const isTitle = paraObj.isTitle || false; let x = margens.left + indent; let parWidth = MAX_WIDTH - indent; + // Se o texto for muito curto, avance para o próximo parágrafo if (text.length < 2) { currentPar++; processedAnyParagraph = true; continue; } - console.log(`Tentando renderizar parágrafo ${currentPar + 1} em y=${y} com alinhamento ${align}`); + + // Ajuste o tamanho da fonte para títulos + const fontSizeToUse = isTitle ? FONT_SIZE * 1.2 : FONT_SIZE; + + // Adicionar espaço extra antes de títulos (exceto para o primeiro parágrafo da página) + if (isTitle && processedAnyParagraph) { + y -= FONT_SIZE * 0.8; + + // Se não caber na página depois do espaço, vá para a próxima página + if (y < margens.bottom + fontSizeToUse * 2) { + break; + } + } + + console.log(`Tentando renderizar parágrafo ${currentPar + 1} em y=${y} com alinhamento ${align}${isTitle ? ' (título)' : ''}`); + let yAfter = renderInlineFormattedParagraph( page, text, @@ -642,7 +706,7 @@ export class PdfService { fontBold, fontItalic, fontBoldItalic, - FONT_SIZE, + fontSizeToUse, rgb(0, 0, 0), align, parWidth,