diff --git a/src/server/services/PdfService.ts b/src/server/services/PdfService.ts index 44189b9..3241437 100644 --- a/src/server/services/PdfService.ts +++ b/src/server/services/PdfService.ts @@ -396,24 +396,10 @@ export class PdfService { let currentTokens: { text: string, font: any, underline: boolean, bold: boolean, italic: boolean }[] = []; let currentWidth = 0; for (const [i, word] of words.entries()) { - // Aplica recuo de parágrafo na primeira linha (apenas se alinhamento for justify ou left) - let recuo = 0; - // Detecta se é uma linha de lista (ex: "1. ", "a) ", "1) ") e NÃO aplica recuo - const isLista = /^\s*((\d+\.|[a-zA-Z]\)|\d+\)))\s+/.test( - lines.length === 0 && currentTokens.length === 0 ? word.text : '' - ); - if ( - indent && - lines.length === 0 && - currentTokens.length === 0 && - (align === 'justify' || align === 'left') && - !isLista - ) { - recuo = fontSize * 2; - } const wordWidth = word.font.widthOfTextAtSize(word.text, fontSize); - if (currentTokens.length === 0) { - if (currentWidth + wordWidth + recuo > maxWidth && currentTokens.length > 0) { + // Corrige o cálculo de recuo apenas na primeira palavra da primeira linha + if (lines.length === 0 && currentTokens.length === 0 && recuo > 0) { + if (wordWidth + recuo > maxWidth) { lines.push({ tokens: currentTokens }); currentTokens = [word]; currentWidth = wordWidth; @@ -453,7 +439,50 @@ export class PdfService { drawX += recuo; } - // Alinhamento à esquerda (ou última linha justificada) + // Alinhamento + if (align === 'center') { + drawX = x + (maxWidth - totalWidth) / 2; + } else if (align === 'right') { + drawX = x + (maxWidth - totalWidth); + } else if (align === 'justify' && i !== lines.length - 1 && line.tokens.length > 1) { + // Justify: distribui espaço entre palavras (menos na última linha) + const wordsOnly = line.tokens.filter(t => t.text.trim() !== ''); + const spaces = line.tokens.filter(t => /^\s+$/.test(t.text)); + const numSpaces = spaces.length; + const lineTextWidth = line.tokens.reduce((acc, t) => acc + t.font.widthOfTextAtSize(t.text, fontSize), 0); + const extraSpace = maxWidth - lineTextWidth; + let spaceWidth = 0; + if (numSpaces > 0) { + spaceWidth = extraSpace / numSpaces; + } + for (const t of line.tokens) { + page.drawText(t.text, { + x: drawX, + y, + size: fontSize, + font: t.font, + color + }); + if (t.underline && t.text.trim() !== '') { + const underlineY = y - 1.5; + page.drawLine({ + start: { x: drawX, y: underlineY }, + end: { x: drawX + t.font.widthOfTextAtSize(t.text, fontSize), y: underlineY }, + thickness: 0.75, + color + }); + } + if (/^\s+$/.test(t.text) && spaceWidth > 0) { + drawX += t.font.widthOfTextAtSize(t.text, fontSize) + spaceWidth; + } else { + drawX += t.font.widthOfTextAtSize(t.text, fontSize); + } + } + y -= fontSize * 1.5; + continue; + } + + // Alinhamento padrão (esquerda, centro, direita) for (const t of line.tokens) { page.drawText(t.text, { x: drawX,