diff --git a/src/server/services/PdfService.ts b/src/server/services/PdfService.ts index 572468f..fc33479 100644 --- a/src/server/services/PdfService.ts +++ b/src/server/services/PdfService.ts @@ -347,46 +347,6 @@ export class PdfService { const fontItalic = await pdfDoc.embedFont(StandardFonts.TimesItalic); const fontBoldItalic = fontBold; // pdf-lib não tem TimesBoldItalic, usa bold - // Função para quebrar texto em linhas respeitando largura máxima e manter quebras de linha simples - function wrapTextStyled(text: string, font: any, fontBold: any, fontItalic: any, fontBoldItalic: any, fontSize: number, maxWidth: number, indent: boolean, align: string, bold: boolean, italic: boolean): { text: string, font: any, indent: boolean, align: string, bold: boolean, italic: boolean }[] { - // Mantém quebras de linha simples para espaçamento - const rawLines = text.split('\n'); - const lines: { text: string, font: any, indent: boolean, align: string, bold: boolean, italic: boolean }[] = []; - for (const rawLine of rawLines) { - let line = rawLine; - // Detecta negrito e itálico inline - let isBold = bold, isItalic = italic; - if (/^|^/.test(line)) { isBold = true; line = line.replace(/^|^/, ''); } - if (/^|^/.test(line)) { isItalic = true; line = line.replace(/^|^/, ''); } - if (/<\/b>$|<\/strong>$/.test(line)) { isBold = true; line = line.replace(/<\/b>$|<\/strong>$/, ''); } - if (/<\/i>$|<\/em>$/.test(line)) { isItalic = true; line = line.replace(/<\/i>$|<\/em>$/, ''); } - line = line.replace(/<\/?(b|strong|i|em)>/gi, ''); - - // Seleciona fonte correta - let usedFont = font; - if (isBold && isItalic && fontBoldItalic) usedFont = fontBoldItalic; - else if (isBold && fontBold) usedFont = fontBold; - else if (isItalic && fontItalic) usedFont = fontItalic; - - // Quebra em palavras para justificar - const words = line.split(' '); - let currentLine = ''; - for (let i = 0; i < words.length; i++) { - const word = words[i]; - const testLine = currentLine ? currentLine + ' ' + word : word; - const width = usedFont.widthOfTextAtSize(testLine, fontSize); - if (width > maxWidth && currentLine) { - lines.push({ text: currentLine, font: usedFont, indent, align, bold: isBold, italic: isItalic }); - currentLine = word; - } else { - currentLine = testLine; - } - } - if (currentLine) lines.push({ text: currentLine, font: usedFont, indent, align, bold: isBold, italic: isItalic }); - } - return lines; - } - // Quebrar o texto em páginas let currentPar = 0; let currentLine = 0; @@ -406,7 +366,6 @@ export class PdfService { let y = PAGE_HEIGHT - margens.top; let firstLine = true; while (currentPar < paragrafos.length) { - // Detecta recuo e alinhamento por marcação let indent = paragrafos[currentPar].startsWith('§§INDENT§§'); let center = paragrafos[currentPar].startsWith('§§CENTER§§'); let align = center ? 'center' : 'justify'; @@ -416,22 +375,45 @@ export class PdfService { let bold = /^|^/.test(text); let italic = /^|^/.test(text); - const styledLines = wrapTextStyled(text, font, fontBold, fontItalic, fontBoldItalic, FONT_SIZE, MAX_WIDTH - (indent ? FONT_SIZE * 2 : 0), indent, align, bold, italic); - let lineIdx = 0; - if (currentLine > 0) lineIdx = currentLine; - for (; lineIdx < styledLines.length; lineIdx++) { + // Remove tags de formatação para o texto puro + let cleanText = text.replace(/<\/?(b|strong|i|em)>/gi, ''); + + // Seleciona fonte correta + let usedFont = font; + if (bold && italic) usedFont = fontBoldItalic; + else if (bold) usedFont = fontBold; + else if (italic) usedFont = fontItalic; + + // Quebra em linhas respeitando largura máxima + const words = cleanText.split(' '); + let lines: string[] = []; + let current = ''; + for (let i = 0; i < words.length; i++) { + const word = words[i]; + const testLine = current ? current + ' ' + word : word; + const width = usedFont.widthOfTextAtSize(testLine, FONT_SIZE); + if (width > MAX_WIDTH - (indent ? FONT_SIZE * 2 : 0) && current) { + lines.push(current); + current = word; + } else { + current = testLine; + } + } + if (current) lines.push(current); + + for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) { if (y < margens.bottom + LINE_HEIGHT) { currentLine = lineIdx; break; } - let { text, font: usedFont, indent, align, bold, italic } = styledLines[lineIdx]; + let line = lines[lineIdx]; let x = margens.left + (indent ? FONT_SIZE * 2 : 0); // Centralizado if (align === 'center') { - const textWidth = usedFont.widthOfTextAtSize(text, FONT_SIZE); + const textWidth = usedFont.widthOfTextAtSize(line, FONT_SIZE); x = margens.left + ((MAX_WIDTH - (indent ? FONT_SIZE * 2 : 0) - textWidth) / 2) + (indent ? FONT_SIZE * 2 : 0); - page.drawText(text, { + page.drawText(line, { x, y, size: FONT_SIZE, @@ -440,39 +422,39 @@ export class PdfService { }); } // Justificado (exceto última linha do parágrafo e centralizado) - else if (text.trim().length > 0 && lineIdx < styledLines.length - 1 && align === 'justify') { - const words = text.split(' '); - if (words.length > 1) { - const textWidth = usedFont.widthOfTextAtSize(text, FONT_SIZE); + else if (line.trim().length > 0 && lineIdx < lines.length - 1 && align === 'justify') { + const lineWords = line.split(' '); + if (lineWords.length > 1) { + const textWidth = usedFont.widthOfTextAtSize(line, FONT_SIZE); const spaceWidth = usedFont.widthOfTextAtSize(' ', FONT_SIZE); - const totalSpaces = words.length - 1; + const totalSpaces = lineWords.length - 1; const extraSpace = (MAX_WIDTH - (indent ? FONT_SIZE * 2 : 0) - textWidth) / totalSpaces; let cursor = x; - for (let w = 0; w < words.length; w++) { - page.drawText(words[w], { + for (let w = 0; w < lineWords.length; w++) { + page.drawText(lineWords[w], { x: cursor, y, size: FONT_SIZE, font: usedFont }); - if (w < words.length - 1) { - cursor += usedFont.widthOfTextAtSize(words[w], FONT_SIZE) + spaceWidth + extraSpace; + if (w < lineWords.length - 1) { + cursor += usedFont.widthOfTextAtSize(lineWords[w], FONT_SIZE) + spaceWidth + extraSpace; } } } else { - page.drawText(text, { x, y, size: FONT_SIZE, font: usedFont }); + page.drawText(line, { x, y, size: FONT_SIZE, font: usedFont }); } } else { - page.drawText(text, { x, y, size: FONT_SIZE, font: usedFont }); + page.drawText(line, { x, y, size: FONT_SIZE, font: usedFont }); } y -= FONT_SIZE * 1.25; // espaçamento entre linhas 1,25 currentLine = 0; firstLine = false; } - if (lineIdx >= styledLines.length) { + if (lines.length > 0) { y -= FONT_SIZE * 0.5; } - if (lineIdx < styledLines.length) { + if (currentLine > 0) { break; } currentPar++;