tenta fix pdfservice.js

This commit is contained in:
rodrigo committed 2025-04-21 22:04:31 -03:00
1 parent bd67cf49cc
commit 287ed34abf
1 file changed
+70 -55
+70 -55
View File
@@ -329,14 +329,11 @@ export class PdfService {
.replace(/<!--[\s\S]*?-->/g, ''); .replace(/<!--[\s\S]*?-->/g, '');
} }
// Função para renderizar texto com formatação inline (negrito, itálico, ambos) // Função para renderizar texto com formatação inline (negrito, itálico, ambos) e controle de quebra de linha
function renderInlineFormattedText(page, text: string, x: number, y: number, font, fontBold, fontItalic, fontBoldItalic, fontSize: number, color, align: string, maxWidth: number) { function renderInlineFormattedParagraph(page, text: string, x: number, y: number, font, fontBold, fontItalic, fontBoldItalic, fontSize: number, color, align: string, maxWidth: number) {
// Divide por tags <b>, <strong>, <i>, <em> e combinações // Divide o texto em tokens de formatação (<b>, <i>, etc)
// Exemplo: "Texto <i>itálico <b>negrito-itálico</b></i> normal"
let cursor = x;
let tokens: { text: string, bold: boolean, italic: boolean }[] = [];
let regex = /(<\/?(b|strong|i|em)>)/gi; let regex = /(<\/?(b|strong|i|em)>)/gi;
let stack: { bold: boolean, italic: boolean }[] = []; let tokens: { text: string, bold: boolean, italic: boolean }[] = [];
let lastIndex = 0; let lastIndex = 0;
let match; let match;
let currentStyle = { bold: false, italic: false }; let currentStyle = { bold: false, italic: false };
@@ -361,62 +358,80 @@ export class PdfService {
italic: currentStyle.italic italic: currentStyle.italic
}); });
} }
// Renderiza cada token com a fonte correta
let line = ''; // Junta todos os tokens em uma lista de palavras com formatação
let lineTokens: { text: string, font: any }[] = []; let words: { text: string, font: any }[] = [];
for (const token of tokens) { for (const token of tokens) {
let usedFont = font; let usedFont = font;
if (token.bold && token.italic) usedFont = fontBoldItalic; if (token.bold && token.italic) usedFont = fontBoldItalic;
else if (token.bold) usedFont = fontBold; else if (token.bold) usedFont = fontBold;
else if (token.italic) usedFont = fontItalic; else if (token.italic) usedFont = fontItalic;
// Quebra em palavras para respeitar largura máxima // Divide token.text em palavras, mantendo espaços
const words = token.text.split(' '); const split = token.text.split(/(\s+)/);
for (let i = 0; i < words.length; i++) { for (const part of split) {
let word = words[i]; if (part.length > 0) {
let testLine = line ? line + ' ' + word : word; words.push({ text: part, font: usedFont });
let testWidth = 0;
let tempLineTokens = [...lineTokens, { text: (line ? ' ' : '') + word, font: usedFont }];
for (const t of tempLineTokens) {
testWidth += t.font.widthOfTextAtSize(t.text, fontSize);
}
if (testWidth > maxWidth && line) {
// Renderiza a linha atual
let drawX = x;
if (align === 'center') {
drawX = x + (maxWidth - testWidth + usedFont.widthOfTextAtSize(word, fontSize)) / 2;
}
for (const t of lineTokens) {
page.drawText(t.text, {
x: drawX,
y,
size: fontSize,
font: t.font,
color
});
drawX += t.font.widthOfTextAtSize(t.text, fontSize);
}
y -= fontSize * 1.25;
line = word;
lineTokens = [{ text: word, font: usedFont }];
} else {
if (line) {
line += ' ' + word;
lineTokens.push({ text: ' ' + word, font: usedFont });
} else {
line = word;
lineTokens.push({ text: word, font: usedFont });
}
} }
} }
} }
// Renderiza última linha
if (line) { // Monta linhas respeitando largura máxima
let lines: { text: string, tokens: { text: string, font: any }[] }[] = [];
let currentLine = '';
let currentTokens: { text: string, font: any }[] = [];
let currentWidth = 0;
for (const word of words) {
const wordWidth = word.font.widthOfTextAtSize(word.text, fontSize);
if (currentWidth + wordWidth > maxWidth && currentLine.trim() !== '') {
lines.push({ text: currentLine, tokens: currentTokens });
currentLine = word.text;
currentTokens = [word];
currentWidth = wordWidth;
} else {
currentLine += word.text;
currentTokens.push(word);
currentWidth += wordWidth;
}
}
if (currentLine.trim() !== '' || currentTokens.length > 0) {
lines.push({ text: currentLine, tokens: currentTokens });
}
// Renderiza cada linha
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
let drawX = x; let drawX = x;
let totalWidth = lineTokens.reduce((acc, t) => acc + t.font.widthOfTextAtSize(t.text, fontSize), 0); let totalWidth = line.tokens.reduce((acc, t) => acc + t.font.widthOfTextAtSize(t.text, fontSize), 0);
// Centralizado
if (align === 'center') { if (align === 'center') {
drawX = x + (maxWidth - totalWidth) / 2; drawX = x + (maxWidth - totalWidth) / 2;
} }
for (const t of lineTokens) { // Justificado (exceto última linha)
else if (align === 'justify' && i < lines.length - 1 && line.text.trim().length > 0) {
// Conta espaços
const spaceCount = line.tokens.filter(t => /^\s+$/.test(t.text)).length;
const extraSpace = spaceCount > 0 ? (maxWidth - totalWidth) / spaceCount : 0;
for (const t of line.tokens) {
page.drawText(t.text, {
x: drawX,
y,
size: fontSize,
font: t.font,
color
});
if (/^\s+$/.test(t.text)) {
drawX += t.font.widthOfTextAtSize(t.text, fontSize) + extraSpace;
} else {
drawX += t.font.widthOfTextAtSize(t.text, fontSize);
}
}
y -= fontSize * 1.25;
continue;
}
// Esquerda ou última linha justificada
for (const t of line.tokens) {
page.drawText(t.text, { page.drawText(t.text, {
x: drawX, x: drawX,
y, y,
@@ -426,6 +441,7 @@ export class PdfService {
}); });
drawX += t.font.widthOfTextAtSize(t.text, fontSize); drawX += t.font.widthOfTextAtSize(t.text, fontSize);
} }
y -= fontSize * 1.25;
} }
return y; return y;
} }
@@ -470,7 +486,6 @@ export class PdfService {
// Quebrar o texto em páginas // Quebrar o texto em páginas
let currentPar = 0; let currentPar = 0;
let currentLine = 0;
let pageIndex = 0; let pageIndex = 0;
while (currentPar < paragrafos.length) { while (currentPar < paragrafos.length) {
@@ -502,8 +517,8 @@ export class PdfService {
parWidth -= FONT_SIZE * 2; parWidth -= FONT_SIZE * 2;
} }
// Renderiza texto com formatação inline (negrito, itálico, ambos) // Renderiza texto com formatação inline (negrito, itálico, ambos) e controle de linhas
y = renderInlineFormattedText( let yAfter = renderInlineFormattedParagraph(
page, page,
text, text,
x, x,
@@ -517,7 +532,7 @@ export class PdfService {
align, align,
parWidth parWidth
); );
y -= FONT_SIZE * 0.5; y = yAfter - FONT_SIZE * 0.5;
currentPar++; currentPar++;
if (y < margens.bottom + FONT_SIZE * 1.25) break; if (y < margens.bottom + FONT_SIZE * 1.25) break;