tenta fix pdfservice.js

This commit is contained in:
rodrigo committed 2025-04-21 22:08:29 -03:00
1 parent 287ed34abf
commit eeeae75919
1 file changed
+70 -23
+70 -23
View File
@@ -329,38 +329,56 @@ export class PdfService {
.replace(/<!--[\s\S]*?-->/g, '');
}
// Função para renderizar texto com formatação inline (negrito, itálico, ambos) e controle de quebra de linha
function renderInlineFormattedParagraph(page, text: string, x: number, y: number, font, fontBold, fontItalic, fontBoldItalic, fontSize: number, color, align: string, maxWidth: number) {
// Divide o texto em tokens de formatação (<b>, <i>, etc)
let regex = /(<\/?(b|strong|i|em)>)/gi;
let tokens: { text: string, bold: boolean, italic: boolean }[] = [];
// Função para renderizar texto com formatação inline (negrito, itálico, sublinhado) e controle de quebra de linha e recuo
function renderInlineFormattedParagraph(
page,
text: string,
x: number,
y: number,
font,
fontBold,
fontItalic,
fontBoldItalic,
fontSize: number,
color,
align: string,
maxWidth: number,
indent: boolean
) {
// Divide o texto em tokens de formatação (<b>, <i>, <u>, etc)
let regex = /(<\/?(b|strong|i|em|u)>)/gi;
let tokens: { text: string, bold: boolean, italic: boolean, underline: boolean }[] = [];
let lastIndex = 0;
let match;
let currentStyle = { bold: false, italic: false };
let currentStyle = { bold: false, italic: false, underline: false };
while ((match = regex.exec(text)) !== null) {
if (match.index > lastIndex) {
tokens.push({
text: text.substring(lastIndex, match.index),
bold: currentStyle.bold,
italic: currentStyle.italic
italic: currentStyle.italic,
underline: currentStyle.underline
});
}
if (/^<(b|strong)>$/i.test(match[0])) currentStyle.bold = true;
if (/^<\/(b|strong)>$/i.test(match[0])) currentStyle.bold = false;
if (/^<(i|em)>$/i.test(match[0])) currentStyle.italic = true;
if (/^<\/(i|em)>$/i.test(match[0])) currentStyle.italic = false;
if (/^<u>$/i.test(match[0])) currentStyle.underline = true;
if (/^<\/u>$/i.test(match[0])) currentStyle.underline = false;
lastIndex = regex.lastIndex;
}
if (lastIndex < text.length) {
tokens.push({
text: text.substring(lastIndex),
bold: currentStyle.bold,
italic: currentStyle.italic
italic: currentStyle.italic,
underline: currentStyle.underline
});
}
// Junta todos os tokens em uma lista de palavras com formatação
let words: { text: string, font: any }[] = [];
let words: { text: string, font: any, underline: boolean }[] = [];
for (const token of tokens) {
let usedFont = font;
if (token.bold && token.italic) usedFont = fontBoldItalic;
@@ -370,19 +388,24 @@ export class PdfService {
const split = token.text.split(/(\s+)/);
for (const part of split) {
if (part.length > 0) {
words.push({ text: part, font: usedFont });
words.push({ text: part, font: usedFont, underline: token.underline });
}
}
}
// Monta linhas respeitando largura máxima
let lines: { text: string, tokens: { text: string, font: any }[] }[] = [];
let lines: { text: string, tokens: { text: string, font: any, underline: boolean }[] }[] = [];
let currentLine = '';
let currentTokens: { text: string, font: any }[] = [];
let currentTokens: { text: string, font: any, underline: boolean }[] = [];
let currentWidth = 0;
for (const word of words) {
for (const [i, word] of words.entries()) {
// Aplica recuo de parágrafo na primeira linha
let recuo = 0;
if (indent && lines.length === 0 && currentLine === '') {
recuo = fontSize * 2;
}
const wordWidth = word.font.widthOfTextAtSize(word.text, fontSize);
if (currentWidth + wordWidth > maxWidth && currentLine.trim() !== '') {
if (currentWidth + wordWidth + recuo > maxWidth && currentLine.trim() !== '') {
lines.push({ text: currentLine, tokens: currentTokens });
currentLine = word.text;
currentTokens = [word];
@@ -403,6 +426,13 @@ export class PdfService {
let drawX = x;
let totalWidth = line.tokens.reduce((acc, t) => acc + t.font.widthOfTextAtSize(t.text, fontSize), 0);
// Aplica recuo de parágrafo na primeira linha
let recuo = 0;
if (indent && i === 0) {
recuo = fontSize * 2;
drawX += recuo;
}
// Centralizado
if (align === 'center') {
drawX = x + (maxWidth - totalWidth) / 2;
@@ -420,13 +450,23 @@ export class PdfService {
font: t.font,
color
});
// Sublinhado
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)) {
drawX += t.font.widthOfTextAtSize(t.text, fontSize) + extraSpace;
} else {
drawX += t.font.widthOfTextAtSize(t.text, fontSize);
}
}
y -= fontSize * 1.25;
y -= fontSize * 1.5;
continue;
}
@@ -439,9 +479,19 @@ export class PdfService {
font: t.font,
color
});
// Sublinhado
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
});
}
drawX += t.font.widthOfTextAtSize(t.text, fontSize);
}
y -= fontSize * 1.25;
y -= fontSize * 1.5;
}
return y;
}
@@ -512,12 +562,8 @@ export class PdfService {
// Renderiza o parágrafo inteiro com recuo (não só a primeira linha)
let x = margens.left;
let parWidth = MAX_WIDTH;
if (indent) {
x += FONT_SIZE * 2;
parWidth -= FONT_SIZE * 2;
}
// Renderiza texto com formatação inline (negrito, itálico, ambos) e controle de linhas
// Renderiza texto com formatação inline (negrito, itálico, sublinhado, ambos) e controle de linhas
let yAfter = renderInlineFormattedParagraph(
page,
text,
@@ -530,12 +576,13 @@ export class PdfService {
FONT_SIZE,
rgb(0, 0, 0),
align,
parWidth
parWidth,
indent
);
y = yAfter - FONT_SIZE * 0.5;
currentPar++;
if (y < margens.bottom + FONT_SIZE * 1.25) break;
if (y < margens.bottom + FONT_SIZE * 1.5) break;
}
pageIndex++;
}