tenta fix pdfservice.js
This commit is contained in:
1 parent
597236c525
commit
854531bce0
1 file changed
+262
-341
+262
-341
@@ -289,31 +289,34 @@ export class PdfService {
|
|||||||
const cleanHtml = html
|
const cleanHtml = html
|
||||||
// Preserva quebras de linha HTML como marcadores especiais
|
// Preserva quebras de linha HTML como marcadores especiais
|
||||||
.replace(/<br\s*\/?>|<\/p><p>|<\/div><div>/gi, '\n')
|
.replace(/<br\s*\/?>|<\/p><p>|<\/div><div>/gi, '\n')
|
||||||
// Substitui parágrafos, divs e blockquote por marcadores de bloco + quebra de linha
|
// Extrair alinhamentos de texto de parágrafos e divs
|
||||||
.replace(/<p[^>]*style="[^"]*text-align\s*:\s*(center|right|justify)[^"]*"[^>]*>/gi, >]*align="(center|right|justify)"[^>]*>/gi,
|
.replace(/<p[^>]*style="[^"]*text-align\s*:\s*(center|right|justify)[^"]*"[^>]*>|<p[^>]*align="(center|right|justify)"[^>]*>/gi,
|
||||||
(match, align) => `<p style="text-align:${align}">`)yle || alignAttr}§§`)
|
(match, alignStyle, alignAttr) => `§§ALIGN=${alignStyle || alignAttr}§§`)
|
||||||
.replace(/<div[^>]*style="[^"]*text-align\s*:\s*(center|right|justify)[^"]*"[^>]*>/gi, [^>]*align="(center|right|justify)"[^>]*>/gi,
|
.replace(/<div[^>]*style="[^"]*text-align\s*:\s*(center|right|justify)[^"]*"[^>]*>|<div[^>]*align="(center|right|justify)"[^>]*>/gi,
|
||||||
(match, align) => `<div style="text-align:${align}">`)e || alignAttr}§§`)
|
(match, alignStyle, alignAttr) => `§§ALIGN=${alignStyle || alignAttr}§§`)
|
||||||
.replace(/<p[^>]*>|<div[^>]*>|<blockquote[^>]*>/gi, '')res de bloco + quebra de linha
|
// Substituir parágrafos, divs e blockquote por marcadores de bloco + quebra de linha
|
||||||
.replace(/<\/p>|<\/div>|<\/blockquote>/gi, '\n\n'), '')
|
.replace(/<p[^>]*>|<div[^>]*>|<blockquote[^>]*>/gi, '')
|
||||||
// Marca formatação de textolockquote>/gi, '\n\n')
|
.replace(/<\/p>|<\/div>|<\/blockquote>/gi, '\n\n')
|
||||||
|
// Marca formatação de texto
|
||||||
.replace(/<b>|<strong>/gi, '<b>')
|
.replace(/<b>|<strong>/gi, '<b>')
|
||||||
.replace(/<\/b>|<\/strong>/gi, '</b>')
|
.replace(/<\/b>|<\/strong>/gi, '</b>')
|
||||||
.replace(/<i>|<em>/gi, '<i>'), '</b>')
|
.replace(/<i>|<em>/gi, '<i>')
|
||||||
.replace(/<\/i>|<\/em>/gi, '</i>')
|
.replace(/<\/i>|<\/em>/gi, '</i>')
|
||||||
|
// Detectar sublinhados também
|
||||||
|
.replace(/<u>/gi, '<b>') // Usamos negrito para representar sublinhado
|
||||||
|
.replace(/<\/u>/gi, '</b>')
|
||||||
// Normaliza espaços extras e quebras de linha
|
// Normaliza espaços extras e quebras de linha
|
||||||
.replace(/\n{3,}/g, '\n\n')bém
|
.replace(/\n{3,}/g, '\n\n')
|
||||||
.replace(/[ \t]+/g, ' '); // Usamos itálico para representar sublinhado
|
|
||||||
.replace(/<\/u>/gi, '</i>')
|
|
||||||
return cleanHtml;paços extras e quebras de linha
|
|
||||||
} .replace(/\n{3,}/g, '\n\n')
|
|
||||||
.replace(/[ \t]+/g, ' ');
|
.replace(/[ \t]+/g, ' ');
|
||||||
|
return cleanHtml;
|
||||||
|
}
|
||||||
|
|
||||||
// Função para decodificar entidades HTML comuns
|
// Função para decodificar entidades HTML comuns
|
||||||
function decodeHtmlEntities(str: string): string {
|
function decodeHtmlEntities(str: string): string {
|
||||||
if (!str) return '';
|
if (!str) return '';
|
||||||
|
|
||||||
return strra decodificar entidades HTML comuns
|
return str
|
||||||
.replace(/\r\n/g, '\n')(str: string): string {
|
.replace(/\r\n/g, '\n')
|
||||||
// Acentos e caracteres especiais
|
// Acentos e caracteres especiais
|
||||||
.replace(/Á/g, 'Á').replace(/á/g, 'á')
|
.replace(/Á/g, 'Á').replace(/á/g, 'á')
|
||||||
.replace(/É/g, 'É').replace(/é/g, 'é')
|
.replace(/É/g, 'É').replace(/é/g, 'é')
|
||||||
@@ -325,168 +328,168 @@ export class PdfService {
|
|||||||
.replace(/Ì/g, 'Ì').replace(/ì/g, 'ì')
|
.replace(/Ì/g, 'Ì').replace(/ì/g, 'ì')
|
||||||
.replace(/Ò/g, 'Ò').replace(/ò/g, 'ò')
|
.replace(/Ò/g, 'Ò').replace(/ò/g, 'ò')
|
||||||
.replace(/Ù/g, 'Ù').replace(/ù/g, 'ù')
|
.replace(/Ù/g, 'Ù').replace(/ù/g, 'ù')
|
||||||
.replace(/Â/g, 'Â').replace(/â/g, 'â')')
|
.replace(/Â/g, 'Â').replace(/â/g, 'â')
|
||||||
.replace(/Ê/g, 'Ê').replace(/ê/g, 'ê')')
|
.replace(/Ê/g, 'Ê').replace(/ê/g, 'ê')
|
||||||
.replace(/Î/g, 'Î').replace(/î/g, 'î')')
|
.replace(/Î/g, 'Î').replace(/î/g, 'î')
|
||||||
.replace(/Ô/g, 'Ô').replace(/ô/g, 'ô')')
|
.replace(/Ô/g, 'Ô').replace(/ô/g, 'ô')
|
||||||
.replace(/Û/g, 'Û').replace(/û/g, 'û')
|
.replace(/Û/g, 'Û').replace(/û/g, 'û')
|
||||||
.replace(/Ã/g, 'Ã').replace(/ã/g, 'ã')
|
.replace(/Ã/g, 'Ã').replace(/ã/g, 'ã')
|
||||||
.replace(/Õ/g, 'Õ').replace(/õ/g, 'õ')
|
.replace(/Õ/g, 'Õ').replace(/õ/g, 'õ')
|
||||||
.replace(/Ç/g, 'Ç').replace(/ç/g, 'ç')
|
.replace(/Ç/g, 'Ç').replace(/ç/g, 'ç')
|
||||||
.replace(/Ñ/g, 'Ñ').replace(/ñ/g, 'ñ')
|
.replace(/Ñ/g, 'Ñ').replace(/ñ/g, 'ñ')
|
||||||
.replace(/Ü/g, 'Ü').replace(/ü/g, 'ü')'ã')
|
.replace(/Ü/g, 'Ü').replace(/ü/g, 'ü')
|
||||||
// Símbolos e caracteres especiais(/õ/g, 'õ')
|
// Símbolos e caracteres especiais
|
||||||
.replace(/º/g, 'º')').replace(/ç/g, 'ç')
|
.replace(/º/g, 'º')
|
||||||
.replace(/ª/g, 'ª')').replace(/ñ/g, 'ñ')
|
.replace(/ª/g, 'ª')
|
||||||
.replace(/§/g, '§').replace(/ü/g, 'ü')
|
.replace(/§/g, '§')
|
||||||
.replace(/°/g, '°')s especiais
|
.replace(/°/g, '°')
|
||||||
.replace(/ /g, ' ')
|
.replace(/ /g, ' ')
|
||||||
.replace(/&/g, '&'))
|
.replace(/&/g, '&')
|
||||||
.replace(/"/g, '"')
|
.replace(/"/g, '"')
|
||||||
.replace(/'/g, "'")
|
.replace(/'/g, "'")
|
||||||
.replace(/</g, '<')')
|
.replace(/</g, '<')
|
||||||
.replace(/>/g, '>');
|
.replace(/>/g, '>');
|
||||||
} .replace(/"/g, '"')
|
}
|
||||||
.replace(/'/g, "'")
|
|
||||||
/** .replace(/</g, '<')
|
/**
|
||||||
* Renderiza um parágrafo com formatação inline (negrito, itálico)
|
* Renderiza um parágrafo com formatação inline (negrito, itálico)
|
||||||
* @returns A posição Y após renderizar ou null se não coube na página
|
* @returns A posição Y após renderizar ou null se não coube na página
|
||||||
*/
|
*/
|
||||||
function renderInlineFormattedParagraph(
|
function renderInlineFormattedParagraph(
|
||||||
page: any, um parágrafo com formatação inline (negrito, itálico)
|
page: any,
|
||||||
text: string,osição Y após renderizar ou null se não coube na página
|
text: string,
|
||||||
x: number,
|
x: number,
|
||||||
startY: number,lineFormattedParagraph(
|
startY: number,
|
||||||
normalFont: any,
|
normalFont: any,
|
||||||
boldFont: any,
|
boldFont: any,
|
||||||
italicFont: any,
|
italicFont: any,
|
||||||
boldItalicFont: any,
|
boldItalicFont: any,
|
||||||
fontSize: number,
|
fontSize: number,
|
||||||
color: any,ny,
|
color: any,
|
||||||
align: 'left' | 'center' | 'right' | 'justify',
|
align: 'left' | 'center' | 'right' | 'justify',
|
||||||
maxWidth: number,ny,
|
maxWidth: number,
|
||||||
debug: boolean = false,
|
debug: boolean = false,
|
||||||
marginTop: number,
|
marginTop: number,
|
||||||
marginBottom: number,er' | 'right' | 'justify',
|
marginBottom: number,
|
||||||
pageHeight: number
|
pageHeight: number
|
||||||
): number | null { false,
|
): number | null {
|
||||||
const lineHeight = fontSize * 1.5;
|
const lineHeight = fontSize * 1.5;
|
||||||
let y = startY;umber,
|
let y = startY;
|
||||||
let currentX = x;r
|
let currentX = x;
|
||||||
let words: Array<{text: string, font: any, width: number}> = [];
|
let words: Array<{text: string, font: any, width: number}> = [];
|
||||||
let currentLine: Array<{text: string, font: any, width: number}> = [];
|
let currentLine: Array<{text: string, font: any, width: number}> = [];
|
||||||
let currentLineWidth = 0;
|
let currentLineWidth = 0;
|
||||||
let currentX = x;
|
|
||||||
// Verifica se o texto parece ser um título (todo em maiúsculas ou curto)
|
// Verifica se o texto parece ser um título (todo em maiúsculas ou curto)
|
||||||
const isTitle = text.toUpperCase() === text || text.length < 50; = [];
|
|
||||||
let currentLineWidth = 0;
|
|
||||||
// Se for título, centralizar independente do alinhamento fornecido
|
|
||||||
const effectiveAlign = isTitle ? 'center' : align;em maiúsculas ou curto)
|
|
||||||
const isTitle = text.toUpperCase() === text || text.length < 50;
|
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
|
// Processa texto com formatação - remover tags HTML e aplicar estilos
|
||||||
let currentFont = normalFont; independente do alinhamento fornecido
|
let currentFont = normalFont;
|
||||||
let boldActive = false;isTitle ? 'center' : align;
|
let boldActive = false;
|
||||||
let italicActive = false;
|
let italicActive = false;
|
||||||
// Processa texto com formatação - remover tags HTML e aplicar estilos
|
|
||||||
// Simplificar texto antes de processar para evitar loops infinitos
|
// Simplificar texto antes de processar para evitar loops infinitos
|
||||||
// Remove tags não suportadas como <u>, <span>, etc.
|
// Remove tags não suportadas como <u>, <span>, etc.
|
||||||
text = textctive = false;
|
text = text
|
||||||
.replace(/<u>|<\/u>/gi, '') // Remover tags de sublinhados
|
.replace(/<u>|<\/u>/gi, '') // Remover tags de sublinhados
|
||||||
.replace(/<span[^>]*>|<\/span>/gi, '') // Remover tags spaninitos
|
.replace(/<span[^>]*>|<\/span>/gi, '') // Remover tags span
|
||||||
.replace(/<[^>]*style=[^>]*>/gi, '') // Remover atributos style
|
.replace(/<[^>]*style=[^>]*>/gi, '') // Remover atributos style
|
||||||
.replace(/<(?!\/?(?:b|i|strong|em)(?!\w)[^>]*>)[^>]*>/gi, ''); // Manter apenas b, i, strong, em
|
.replace(/<(?!\/?(?:b|i|strong|em)(?!\w)[^>]*>)[^>]*>/gi, ''); // Manter apenas b, i, strong, em
|
||||||
.replace(/<u>|<\/u>/gi, '') // Remover tags de sublinhados
|
|
||||||
// Primeiro, extrair partes do texto com suas formataçõesspan
|
|
||||||
let remainingText = text;^>]*>/gi, '') // Remover atributos style
|
|
||||||
let textParts: Array<{text: string, bold: boolean, italic: boolean}> = []; apenas b, i, strong, em
|
|
||||||
|
|
||||||
while (remainingText.length > 0) {to com suas formatações
|
// Primeiro, extrair partes do texto com suas formatações
|
||||||
|
let remainingText = text;
|
||||||
|
let textParts: Array<{text: string, bold: boolean, italic: boolean}> = [];
|
||||||
|
|
||||||
|
while (remainingText.length > 0) {
|
||||||
const boldStartMatch = remainingText.match(/<b>|<strong>/i);
|
const boldStartMatch = remainingText.match(/<b>|<strong>/i);
|
||||||
const italicStartMatch = remainingText.match(/<i>|<em>/i);oolean}> = [];
|
const italicStartMatch = remainingText.match(/<i>|<em>/i);
|
||||||
const boldEndMatch = remainingText.match(/<\/b>|<\/strong>/i);
|
const boldEndMatch = remainingText.match(/<\/b>|<\/strong>/i);
|
||||||
const italicEndMatch = remainingText.match(/<\/i>|<\/em>/i);
|
const italicEndMatch = remainingText.match(/<\/i>|<\/em>/i);
|
||||||
const boldStartMatch = remainingText.match(/<b>|<strong>/i);
|
|
||||||
// Encontrar a próxima tagemainingText.match(/<i>|<em>/i);
|
// Encontrar a próxima tag
|
||||||
const matches = [boldStartMatch, italicStartMatch, boldEndMatch, italicEndMatch]
|
const matches = [boldStartMatch, italicStartMatch, boldEndMatch, italicEndMatch]
|
||||||
.filter(m => m !== null);iningText.match(/<\/i>|<\/em>/i);
|
.filter(m => m !== null);
|
||||||
|
|
||||||
if (matches.length === 0) {
|
if (matches.length === 0) {
|
||||||
// Não há mais tags, adicionar o texto restante, boldEndMatch, italicEndMatch]
|
// Não há mais tags, adicionar o texto restante
|
||||||
if (remainingText.length > 0) {
|
if (remainingText.length > 0) {
|
||||||
textParts.push({
|
textParts.push({
|
||||||
text: remainingText,{
|
text: remainingText,
|
||||||
bold: boldActive,adicionar o texto restante
|
bold: boldActive,
|
||||||
italic: italicActive > 0) {
|
italic: italicActive
|
||||||
});tParts.push({
|
|
||||||
} text: remainingText,
|
|
||||||
break;ld: boldActive,
|
|
||||||
} italic: italicActive
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Ordenar matches por índice
|
// Ordenar matches por índice
|
||||||
matches.sort((a, b) => a!.index! - b!.index!);
|
matches.sort((a, b) => a!.index! - b!.index!);
|
||||||
const nextMatch = matches[0]!;
|
const nextMatch = matches[0]!;
|
||||||
const matchIndex = nextMatch.index!;
|
const matchIndex = nextMatch.index!;
|
||||||
// Ordenar matches por índice
|
|
||||||
// Texto antes da próxima tagex! - b!.index!);
|
// Texto antes da próxima tag
|
||||||
if (matchIndex > 0) {ches[0]!;
|
if (matchIndex > 0) {
|
||||||
textParts.push({ nextMatch.index!;
|
textParts.push({
|
||||||
text: remainingText.substring(0, matchIndex),
|
text: remainingText.substring(0, matchIndex),
|
||||||
bold: boldActive,xima tag
|
|
||||||
italic: italicActive
|
|
||||||
});tParts.push({
|
|
||||||
} text: remainingText.substring(0, matchIndex),
|
|
||||||
bold: boldActive,
|
bold: boldActive,
|
||||||
|
italic: italicActive
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Atualizar estado de formatação
|
// Atualizar estado de formatação
|
||||||
if (nextMatch[0].match(/<b>|<strong>/i)) boldActive = true;
|
if (nextMatch[0].match(/<b>|<strong>/i)) boldActive = true;
|
||||||
else if (nextMatch[0].match(/<\/b>|<\/strong>/i)) boldActive = false;
|
else if (nextMatch[0].match(/<\/b>|<\/strong>/i)) boldActive = false;
|
||||||
else if (nextMatch[0].match(/<i>|<em>/i)) italicActive = true;
|
else if (nextMatch[0].match(/<i>|<em>/i)) italicActive = true;
|
||||||
else if (nextMatch[0].match(/<\/i>|<\/em>/i)) italicActive = false;
|
else if (nextMatch[0].match(/<\/i>|<\/em>/i)) italicActive = false;
|
||||||
if (nextMatch[0].match(/<b>|<strong>/i)) boldActive = true;
|
|
||||||
// Remover o texto processado e a tag/strong>/i)) boldActive = false;
|
|
||||||
remainingText = remainingText.substring(matchIndex + nextMatch[0].length);
|
|
||||||
} else if (nextMatch[0].match(/<\/i>|<\/em>/i)) italicActive = false;
|
|
||||||
|
|
||||||
// Processar as partes extraídase a tag
|
// Remover o texto processado e a tag
|
||||||
for (const part of textParts) {.substring(matchIndex + nextMatch[0].length);
|
remainingText = remainingText.substring(matchIndex + nextMatch[0].length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Processar as partes extraídas
|
||||||
|
for (const part of textParts) {
|
||||||
// Determinar a fonte baseado na formatação
|
// Determinar a fonte baseado na formatação
|
||||||
let font = normalFont;
|
let font = normalFont;
|
||||||
if (part.bold && part.italic) font = boldItalicFont;
|
if (part.bold && part.italic) font = boldItalicFont;
|
||||||
else if (part.bold) font = boldFont;
|
else if (part.bold) font = boldFont;
|
||||||
else if (part.italic) font = italicFont;ção
|
|
||||||
let font = normalFont;
|
|
||||||
// Dividir em palavrasitalic) font = boldItalicFont;
|
|
||||||
const partWords = part.text.split(/\s+/);
|
|
||||||
else if (part.italic) font = italicFont;
|
else if (part.italic) font = italicFont;
|
||||||
|
|
||||||
|
// Dividir em palavras
|
||||||
|
const partWords = part.text.split(/\s+/);
|
||||||
|
|
||||||
for (const wordText of partWords) {
|
for (const wordText of partWords) {
|
||||||
if (!wordText) continue;
|
if (!wordText) continue;
|
||||||
nst partWords = part.text.split(/\s+/);
|
|
||||||
const width = font.widthOfTextAtSize(wordText, fontSize);
|
const width = font.widthOfTextAtSize(wordText, fontSize);
|
||||||
words.push({ text: wordText, font, width });
|
words.push({ text: wordText, font, width });
|
||||||
words.push({ text: ' ', font, width: font.widthOfTextAtSize(' ', fontSize) });
|
words.push({ text: ' ', font, width: font.widthOfTextAtSize(' ', fontSize) });
|
||||||
}
|
}
|
||||||
const width = font.widthOfTextAtSize(wordText, fontSize);
|
|
||||||
// Remove o último espaço adicionado width });
|
// Remove o último espaço adicionado
|
||||||
if (words.length > 0) {', font, width: font.widthOfTextAtSize(' ', fontSize) });
|
if (words.length > 0) {
|
||||||
words.pop();
|
words.pop();
|
||||||
}
|
}
|
||||||
} // Remove o último espaço adicionado
|
}
|
||||||
if (words.length > 0) {
|
|
||||||
// Verificar se há espaço suficiente na página para pelo menos uma linha
|
// Verificar se há espaço suficiente na página para pelo menos uma linha
|
||||||
if (y - lineHeight < marginBottom) {
|
if (y - lineHeight < marginBottom) {
|
||||||
return null; // Não há espaço suficiente para renderizar
|
return null; // Não há espaço suficiente para renderizar
|
||||||
}
|
}
|
||||||
// Verificar se há espaço suficiente na página para pelo menos uma linha
|
|
||||||
// Aumentar ligeiramente o espaçamento de linhas para títulos
|
// Aumentar ligeiramente o espaçamento de linhas para títulos
|
||||||
const effectiveLineHeight = isTitle ? lineHeight * 1.3 : lineHeight;
|
const effectiveLineHeight = isTitle ? lineHeight * 1.3 : lineHeight;
|
||||||
}
|
|
||||||
// Aumentar o tamanho da fonte para títulos
|
// Aumentar o tamanho da fonte para títulos
|
||||||
const effectiveFontSize = isTitle ? fontSize * 1.2 : fontSize;
|
const effectiveFontSize = isTitle ? fontSize * 1.2 : fontSize;
|
||||||
const effectiveLineHeight = isTitle ? lineHeight * 1.3 : lineHeight;
|
|
||||||
// Se for um título, adicionar um espaço extra antes
|
// Se for um título, adicionar um espaço extra antes
|
||||||
if (isTitle && y < startY) {te para títulos
|
if (isTitle && y < startY) {
|
||||||
y -= lineHeight * 0.5;= isTitle ? fontSize * 1.2 : fontSize;
|
y -= lineHeight * 0.5;
|
||||||
}
|
}
|
||||||
// Se for um título, adicionar um espaço extra antes
|
|
||||||
// Agora, renderizar as palavras em linhas
|
// Agora, renderizar as palavras em linhas
|
||||||
for (let i = 0; i < words.length; i++) {
|
for (let i = 0; i < words.length; i++) {
|
||||||
const word = words[i];
|
const word = words[i];
|
||||||
@@ -495,302 +498,220 @@ export class PdfService {
|
|||||||
if (currentLineWidth + word.width <= maxWidth || currentLine.length === 0) {
|
if (currentLineWidth + word.width <= maxWidth || currentLine.length === 0) {
|
||||||
// Adicionar palavra à linha atual
|
// Adicionar palavra à linha atual
|
||||||
currentLine.push(word);
|
currentLine.push(word);
|
||||||
currentLineWidth += word.width; linha atual
|
currentLineWidth += word.width;
|
||||||
} else {entLineWidth + word.width <= maxWidth || currentLine.length === 0) {
|
} else {
|
||||||
// Renderizar a linha atuala atual
|
// Renderizar a linha atual
|
||||||
if (y - effectiveLineHeight < marginBottom) {
|
if (y - effectiveLineHeight < marginBottom) {
|
||||||
return null; // Não há mais espaço na página
|
return null; // Não há mais espaço na página
|
||||||
}lse {
|
|
||||||
// Renderizar a linha atual
|
|
||||||
// Ajustar X baseado no alinhamentonBottom) {
|
|
||||||
let lineX = x; // Não há mais espaço na página
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ajustar X baseado no alinhamento
|
||||||
|
let lineX = x;
|
||||||
|
|
||||||
// Para justificado, calcular espaçamentos extras entre palavras
|
// Para justificado, calcular espaçamentos extras entre palavras
|
||||||
// Mas não justificar a última linha de um parágrafo ou títulos
|
// Mas não justificar a última linha de um parágrafo ou títulos
|
||||||
const isLastLine = i === words.length - 1;
|
const isLastLine = i === words.length - 1;
|
||||||
const shouldJustify = effectiveAlign === 'justify' && !isLastLine && !isTitle && currentLine.length > 1;
|
const shouldJustify = effectiveAlign === 'justify' && !isLastLine && !isTitle && currentLine.length > 1;
|
||||||
const extraSpacing = shouldJustify ? entos extras entre palavras
|
const extraSpacing = shouldJustify ?
|
||||||
(maxWidth - currentLineWidth) / (currentLine.length - 1) : 0;
|
(maxWidth - currentLineWidth) / (currentLine.length - 1) : 0;
|
||||||
const isLastLine = i === words.length - 1;
|
|
||||||
if (effectiveAlign === 'center') {gn === 'justify' && !isLastLine && !isTitle && currentLine.length > 1;lavras, mesmo para não justificado
|
// Garantir espaço mínimo entre palavras, mesmo para não justificado
|
||||||
lineX = x + (maxWidth - currentLineWidth) / 2;ntre palavras
|
const minSpacing = fontSize * 0.3; // Espaçamento mínimo entre palavras
|
||||||
} else if (effectiveAlign === 'right') {rentLine.length - 1) : 0;
|
|
||||||
|
if (effectiveAlign === 'center') {
|
||||||
|
lineX = x + (maxWidth - currentLineWidth) / 2;
|
||||||
|
} else if (effectiveAlign === 'right') {
|
||||||
lineX = x + maxWidth - currentLineWidth;
|
lineX = x + maxWidth - currentLineWidth;
|
||||||
}f (effectiveAlign === 'center') { lineX = x + (maxWidth - currentLineWidth) / 2;
|
}
|
||||||
lineX = x + (maxWidth - currentLineWidth) / 2;} else if (effectiveAlign === 'right') {
|
|
||||||
// Desenhar a linhaeAlign === 'right') {dth - currentLineWidth;
|
// Desenhar a linha
|
||||||
let posX = lineX;Width - currentLineWidth;
|
let posX = lineX;
|
||||||
for (let j = 0; j < currentLine.length; j++) {
|
for (let j = 0; j < currentLine.length; j++) {
|
||||||
const item = currentLine[j];
|
const item = currentLine[j];
|
||||||
const itemFontSize = isTitle ? effectiveFontSize : fontSize;
|
const itemFontSize = isTitle ? effectiveFontSize : fontSize;
|
||||||
t posX = lineX;r (let j = 0; j < currentLine.length; j++) {
|
|
||||||
page.drawText(item.text, {ine.length; j++) {];
|
page.drawText(item.text, {
|
||||||
x: posX, = currentLine[j];FontSize = isTitle ? effectiveFontSize : fontSize;
|
x: posX,
|
||||||
y: y,temFontSize = isTitle ? effectiveFontSize : fontSize;
|
y: y,
|
||||||
font: item.font,
|
font: item.font,
|
||||||
size: itemFontSize,xt, {
|
size: itemFontSize,
|
||||||
colorsX,
|
color
|
||||||
});: y,ont: item.font,
|
|
||||||
font: item.font, size: itemFontSize,
|
|
||||||
// Avançar posição X,
|
|
||||||
posX += item.width;
|
|
||||||
});
|
});
|
||||||
// Adicionar espaço extra se for justificado (exceto no final da linha)
|
|
||||||
if (shouldJustify && j < currentLine.length - 1) {
|
// Avançar posição X
|
||||||
posX += extraSpacing;
|
posX += item.width;
|
||||||
} Adicionar espaço extra entre palavras
|
|
||||||
} // Adicionar espaço extra se for justificado (exceto no final da linha) if (j < currentLine.length - 1) {
|
// Adicionar espaço extra entre palavras
|
||||||
if (shouldJustify && j < currentLine.length - 1) { // Usar espaçamento mínimo ou espaçamento justificado, o que for maior
|
if (j < currentLine.length - 1) {
|
||||||
// Avançar para a próxima linhay ? Math.max(extraSpacing, minSpacing) : minSpacing;
|
// Usar espaçamento mínimo ou espaçamento justificado, o que for maior
|
||||||
|
const spacingToUse = shouldJustify ? Math.max(extraSpacing, minSpacing) : minSpacing;
|
||||||
|
posX += spacingToUse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avançar para a próxima linha
|
||||||
y -= effectiveLineHeight;
|
y -= effectiveLineHeight;
|
||||||
currentLine = [word];
|
currentLine = [word];
|
||||||
currentLineWidth = word.width;
|
currentLineWidth = word.width;
|
||||||
// Avançar para a próxima linha
|
|
||||||
// Verificar se ainda temos espaço
|
// Verificar se ainda temos espaço
|
||||||
if (y - effectiveLineHeight < marginBottom) {
|
if (y - effectiveLineHeight < marginBottom) {
|
||||||
return null;th = word.width;[word];
|
return null;
|
||||||
}rrentLineWidth = word.width;
|
}
|
||||||
} // Verificar se ainda temos espaço
|
}
|
||||||
} if (y - effectiveLineHeight < marginBottom) { // Verificar se ainda temos espaço
|
}
|
||||||
return null; if (y - effectiveLineHeight < marginBottom) {
|
|
||||||
// Renderizar a última linha, se houver
|
// Renderizar a última linha, se houver
|
||||||
if (currentLine.length > 0) {
|
if (currentLine.length > 0) {
|
||||||
// Ajustar X baseado no alinhamento (última linha nunca é justificada, exceto se for curta)
|
// Ajustar X baseado no alinhamento (última linha nunca é justificada, exceto se for curta)
|
||||||
let lineX = x;
|
let lineX = x;
|
||||||
Renderizar a última linha, se houver
|
|
||||||
// Se for título ou alinhado ao centro/direita, ajustar posição
|
// Se for título ou alinhado ao centro/direita, ajustar posição
|
||||||
if (effectiveAlign === 'center') {o (última linha nunca é justificada, exceto se for curta)
|
if (effectiveAlign === 'center') {
|
||||||
lineX = x + (maxWidth - currentLineWidth) / 2;or curta)
|
lineX = x + (maxWidth - currentLineWidth) / 2;
|
||||||
} else if (effectiveAlign === 'right') {
|
} else if (effectiveAlign === 'right') {
|
||||||
lineX = x + maxWidth - currentLineWidth;eita, ajustar posição
|
lineX = x + maxWidth - currentLineWidth;
|
||||||
}f (effectiveAlign === 'center') {/ Se for título ou alinhado ao centro/direita, ajustar posição
|
}
|
||||||
lineX = x + (maxWidth - currentLineWidth) / 2;if (effectiveAlign === 'center') {
|
|
||||||
// Desenhar a linhaeAlign === 'right') {idth - currentLineWidth) / 2;
|
// Desenhar a linha
|
||||||
let posX = lineX;Width - currentLineWidth;iveAlign === 'right') {
|
let posX = lineX;
|
||||||
for (const item of currentLine) {
|
for (const item of currentLine) {
|
||||||
const itemFontSize = isTitle ? effectiveFontSize : fontSize;
|
const itemFontSize = isTitle ? effectiveFontSize : fontSize;
|
||||||
Desenhar a linha
|
|
||||||
page.drawText(item.text, {
|
page.drawText(item.text, {
|
||||||
x: posX,tem of currentLine) {ineX;
|
x: posX,
|
||||||
y: y,temFontSize = isTitle ? effectiveFontSize : fontSize;t item of currentLine) {
|
y: y,
|
||||||
font: item.font,tiveFontSize : fontSize;
|
font: item.font,
|
||||||
size: itemFontSize,xt, {
|
size: itemFontSize,
|
||||||
colorsX,awText(item.text, {
|
color
|
||||||
});: y,: posX,
|
});
|
||||||
posX += item.width;
|
posX += item.width;
|
||||||
} size: itemFontSize, font: item.font,
|
|
||||||
color size: itemFontSize,
|
// Adicionar espaço mínimo entre palavras
|
||||||
y -= effectiveLineHeight;
|
if (posX < lineX + maxWidth) {
|
||||||
} posX += item.width; });
|
posX += fontSize * 0.3;
|
||||||
} posX += item.width;
|
|
||||||
// Se for título, adicionar um espaço extra depois
|
|
||||||
if (isTitle) {veLineHeight;
|
|
||||||
y -= lineHeight * 0.5;
|
|
||||||
}
|
|
||||||
// Se for título, adicionar um espaço extra depois
|
|
||||||
return y;le) { título, adicionar um espaço extra depois
|
|
||||||
} y -= lineHeight * 0.5; if (isTitle) {
|
|
||||||
} y -= lineHeight * 0.5;
|
|
||||||
// Processe o texto com as novas funções melhoradas
|
|
||||||
const textoLimpo = stripUnsupportedTags(
|
|
||||||
this.processarTemplate(conteudo, escritorio)
|
|
||||||
);
|
|
||||||
const texto = decodeHtmlEntities(textoLimpo);oradas
|
|
||||||
console.log('Texto processado para renderização:', texto.substring(0, 100) + '...');
|
|
||||||
// Corrigir o processamento de parágrafos para lidar melhor com formatações
|
|
||||||
const paragrafos = texto.split(/\n{2,}/).map(p => {
|
|
||||||
let paragraph = p.trim();ities(textoLimpo);
|
|
||||||
if (!paragraph) return '';o para renderização:', texto.substring(0, 100) + '...');ties(textoLimpo);
|
|
||||||
Corrigir o processamento de parágrafos para lidar melhor com formataçõesnsole.log('Texto processado para renderização:', texto.substring(0, 100) + '...');
|
|
||||||
// Extrair informações de formatação/).map(p => {fos para lidar melhor com formatações
|
|
||||||
let align = 'left'; // Default align
|
|
||||||
if (!paragraph) return '';let paragraph = p.trim();
|
|
||||||
// Verificar se há marcadores de alinhamento definidos pelo HTML
|
|
||||||
const alignMatch = paragraph.match(/§§ALIGN=(center|right|justify|left)§§/);
|
|
||||||
if (alignMatch) {ficado para texto normal
|
|
||||||
align = alignMatch[1];
|
|
||||||
paragraph = paragraph.replace(/§§ALIGN=(center|right|justify|left)§§/, '');rios:
|
|
||||||
} '#' (estilo markdown) texto parece ser um título por diversos critérios:
|
|
||||||
ativamente curtoarkdown)
|
|
||||||
// Verifica se o texto tem formatação que indica um título
|
|
||||||
const hasStrongFormatting = paragraph.includes('<b>') && paragraph.includes('</b>');urto (como "Considerando:")e ponto (como "1. Título")
|
|
||||||
const hasUnderline = paragraph.includes('<u>') && paragraph.includes('</u>');
|
|
||||||
paragraph.startsWith('#') ||const isTitle =
|
|
||||||
// Verifica se o texto parece ser um título por diversos critérios:paragraph && paragraph.length < 100) ||
|
|
||||||
// 1. Começa com '#' (estilo markdown)+/.test(paragraph) ||oUpperCase() === paragraph && paragraph.length < 100) ||
|
|
||||||
// 2. Todo em maiúsculas e relativamente curtoth(':') && paragraph.length < 70);st(paragraph) ||
|
|
||||||
// 3. Começa com números seguidos de ponto (como "1. Título")
|
|
||||||
// 4. Termina com dois pontos e é curto (como "Considerando:")/ Se for um título, centraliza
|
|
||||||
// 5. Tem formatação especial como negrito ou sublinhado e é curtoif (isTitle) {// Se for um título, centraliza
|
|
||||||
const isTitle =
|
|
||||||
paragraph.startsWith('#') ||o estilo markdown
|
|
||||||
(paragraph.toUpperCase() === paragraph && paragraph.length < 100) ||^#+\s*/, ''); // Remove marcadores de título estilo markdown
|
|
||||||
/^\d+\.\s+\S+/.test(paragraph) ||
|
|
||||||
(paragraph.endsWith(':') && paragraph.length < 70) ||
|
|
||||||
((hasStrongFormatting || hasUnderline) && paragraph.length < 150);onst alignMatch = paragraph.match(/§§ALIGN=(center|right|justify|left)§§/);/ Processa alinhamentos explícitos (têm precedência)
|
|
||||||
if (alignMatch) {const alignMatch = paragraph.match(/§§ALIGN=(center|right|justify|left)§§/);
|
|
||||||
// Se for um título e não tiver alinhamento definido explicitamente, centralizaMatch[1]; {
|
|
||||||
if (isTitle && !alignMatch) {)§§/, '');
|
|
||||||
align = 'center';ALIGN=(center|right|justify|left)§§/, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Se for um texto normal sem alinhamento definido, justifica);
|
|
||||||
if (!isTitle && !alignMatch) {f (indentMatch) {onst indentMatch = paragraph.match(/§§INDENT=(\d+)(pt|px|em)?§§/);
|
|
||||||
align = 'justify'; indent = parseInt(indentMatch[1]);if (indentMatch) {
|
|
||||||
}entMatch[2] === 'em') indent *= 12; // Converter em para pontos aproximadamente= parseInt(indentMatch[1]);
|
|
||||||
place(/§§INDENT=\d+(pt|px|em)?§§/, '');em') indent *= 12; // Converter em para pontos aproximadamente
|
|
||||||
// Remove marcadores de título estilo markdown
|
|
||||||
paragraph = paragraph.replace(/^#+\s*/, '');
|
|
||||||
|
|
||||||
let indent = 0;text: paragraph.trim(), turn {
|
|
||||||
const indentMatch = paragraph.match(/§§INDENT=(\d+)(pt|px|em)?§§/);ft' | 'center' | 'right' | 'justify',m(),
|
|
||||||
if (indentMatch) {| 'center' | 'right' | 'justify',
|
|
||||||
indent = parseInt(indentMatch[1]);
|
|
||||||
if (indentMatch[2] === 'em') indent *= 12; // Converter em para pontos aproximadamente
|
|
||||||
paragraph = paragraph.replace(/§§INDENT=\d+(pt|px|em)?§§/, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
text: paragraph.trim(), srafos`);
|
|
||||||
align: align as 'left' | 'center' | 'right' | 'justify',oops infinitos
|
|
||||||
indent,ngth && pageIndex < MAX_PAGES) {
|
|
||||||
isTitlefo ${currentPar + 1} de ${paragrafos.length}`);
|
|
||||||
};TH, PAGE_HEIGHT]);ndex + 1}, processando parágrafo ${currentPar + 1} de ${paragrafos.length}`);
|
|
||||||
}).filter(p => p.text);nar timbrado à página= pdfDoc.addPage([PAGE_WIDTH, PAGE_HEIGHT]);
|
|
||||||
let currentPar = 0;adoPages.length > 0) {nar timbrado à página
|
|
||||||
let pageIndex = 0;ando timbrado na página ${pageIndex + 1}`);th > 0) {
|
|
||||||
console.log(`Gerando PDF com ${paragrafos.length} parágrafos`);oPages[0], {ndo timbrado na página ${pageIndex + 1}`);
|
|
||||||
// Define um contador máximo para evitar loops infinitos: 0,e.drawPage(timbradoPages[0], {
|
|
||||||
const MAX_PAGES = 100; y: 0, x: 0,
|
|
||||||
while (currentPar < paragrafos.length && pageIndex < MAX_PAGES) {
|
|
||||||
console.log(`Criando página ${pageIndex + 1}, processando parágrafo ${currentPar + 1} de ${paragrafos.length}`);
|
|
||||||
let page = pdfDoc.addPage([PAGE_WIDTH, PAGE_HEIGHT]);
|
|
||||||
// Adicionar timbrado à página
|
|
||||||
if (timbradoPages.length > 0) {
|
|
||||||
console.log(`Adicionando timbrado na página ${pageIndex + 1}`);false; // Flag para verificar se processamos algum parágrafos.top;
|
|
||||||
page.drawPage(timbradoPages[0], {na página atuallse; // Flag para verificar se processamos algum parágrafo
|
|
||||||
x: 0,) {na atual
|
|
||||||
y: 0,
|
|
||||||
width: PAGE_WIDTH,const text = paraObj.text;const paraObj = paragrafos[currentPar];
|
|
||||||
height: PAGE_HEIGHT
|
|
||||||
});;
|
|
||||||
}const isTitle = paraObj.isTitle || false;const indent = paraObj.indent || 0;
|
|
||||||
let y = PAGE_HEIGHT - margens.top;
|
|
||||||
let processedAnyParagraph = false; // Flag para verificar se processamos algum parágrafo indent;
|
|
||||||
// Tenta processar parágrafos na página atualMAX_WIDTH - indent;.left + indent;
|
|
||||||
while (currentPar < paragrafos.length) {
|
|
||||||
const paraObj = paragrafos[currentPar];to for muito curto, avance para o próximo parágrafo
|
|
||||||
const text = paraObj.text;f (text.length < 2) {/ Se o texto for muito curto, avance para o próximo parágrafo
|
|
||||||
const align = paraObj.align; currentPar++;if (text.length < 2) {
|
|
||||||
const indent = paraObj.indent || 0;
|
|
||||||
const isTitle = paraObj.isTitle || false;
|
|
||||||
} continue;
|
|
||||||
let x = margens.left + indent;
|
|
||||||
let parWidth = MAX_WIDTH - indent;os
|
|
||||||
sTitle ? FONT_SIZE * 1.2 : FONT_SIZE;fonte para títulos
|
|
||||||
// Se o texto for muito curto, avance para o próximo parágrafot fontSizeToUse = isTitle ? FONT_SIZE * 1.2 : FONT_SIZE;
|
|
||||||
if (text.length < 2) {ágrafo da página)
|
|
||||||
currentPar++; o primeiro parágrafo da página)
|
|
||||||
processedAnyParagraph = true;T_SIZE * 0.8;e && processedAnyParagraph) {
|
|
||||||
continue;-= 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) { // Se não caber na página depois do espaço, vá para a próxima página
|
|
||||||
// Ajuste o tamanho da fonte para títulos
|
|
||||||
const fontSizeToUse = isTitle ? FONT_SIZE * 1.2 : FONT_SIZE; } break;
|
|
||||||
|
|
||||||
// Adicionar espaço extra antes de títulos (exceto para o primeiro parágrafo da página)
|
|
||||||
if (isTitle && processedAnyParagraph) {.log(`Tentando renderizar parágrafo ${currentPar + 1} em y=${y} com alinhamento ${align}${isTitle ? ' (título)' : ''}`);
|
|
||||||
y -= FONT_SIZE * 0.8;log(`Tentando renderizar parágrafo ${currentPar + 1} em y=${y} com alinhamento ${align}${isTitle ? ' (título)' : ''}`);
|
|
||||||
yAfter = renderInlineFormattedParagraph(
|
|
||||||
// Se não caber na página depois do espaço, vá para a próxima páginater = renderInlineFormattedParagraph(
|
|
||||||
if (y < margens.bottom + fontSizeToUse * 2) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Tentando renderizar parágrafo ${currentPar + 1} em y=${y} com alinhamento ${align}${isTitle ? ' (título)' : ''}`);alic,ld,
|
y -= effectiveLineHeight;
|
||||||
talic,c,
|
}
|
||||||
let yAfter = renderInlineFormattedParagraph(zeToUse,ldItalic,
|
|
||||||
page,,e,
|
// Se for título, adicionar um espaço extra depois
|
||||||
|
if (isTitle) {
|
||||||
|
y -= lineHeight * 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
const textoLimpo = stripUnsupportedTags(conteudo);
|
||||||
|
const texto = decodeHtmlEntities(textoLimpo);
|
||||||
|
console.log('Texto processado para renderização:', texto.substring(0, 100) + '...');
|
||||||
|
|
||||||
|
const paragrafos = texto.split(/\n{2,}/).map(p => p.trim()).filter(p => p.length > 0);
|
||||||
|
console.log(`Gerando PDF com ${paragrafos.length} parágrafos`);
|
||||||
|
|
||||||
|
let currentPar = 0;
|
||||||
|
let pageIndex = 0;
|
||||||
|
const MAX_PAGES = 100;
|
||||||
|
while (currentPar < paragrafos.length && pageIndex < MAX_PAGES) {
|
||||||
|
console.log(`Criando página ${pageIndex + 1}, processando parágrafo ${currentPar + 1} de ${paragrafos.length}`);
|
||||||
|
let page = pdfDoc.addPage([PAGE_WIDTH, PAGE_HEIGHT]);
|
||||||
|
let y = PAGE_HEIGHT - margens.top;
|
||||||
|
let processedAnyParagraph = false;
|
||||||
|
|
||||||
|
while (currentPar < paragrafos.length) {
|
||||||
|
const text = paragrafos[currentPar];
|
||||||
|
const align = 'justify';
|
||||||
|
const indent = 0;
|
||||||
|
const isTitle = false;
|
||||||
|
let x = margens.left + indent;
|
||||||
|
let parWidth = MAX_WIDTH - indent;
|
||||||
|
const fontSizeToUse = isTitle ? FONT_SIZE * 1.2 : FONT_SIZE;
|
||||||
|
|
||||||
|
if (text.length < 2) {
|
||||||
|
currentPar++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTitle && processedAnyParagraph) {
|
||||||
|
y -= FONT_SIZE * 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
text,
|
||||||
x,
|
x,
|
||||||
y,false,parWidth,
|
y,
|
||||||
font,
|
font,
|
||||||
fontBold,
|
fontBold,
|
||||||
fontItalic,
|
fontItalic,
|
||||||
fontBoldItalic,
|
fontBoldItalic,
|
||||||
fontSizeToUse,
|
fontSizeToUse,
|
||||||
rgb(0, 0, 0),o conseguimos renderizar este parágrafo, vamos para a próxima página === null) {
|
rgb(0, 0, 0),
|
||||||
align,ó se já tivermos processado algum parágrafo nesta páginao conseguimos renderizar este parágrafo, vamos para a próxima página
|
align,
|
||||||
parWidth,
|
parWidth,
|
||||||
false,;
|
false,
|
||||||
margens.top,
|
margens.top,
|
||||||
margens.bottom,
|
margens.bottom,
|
||||||
PAGE_HEIGHTcessar um parágrafo, algo está errado
|
PAGE_HEIGHT
|
||||||
); // Vamos avançar para o próximo parágrafo para evitar um loop infinito // Se não conseguimos nem processar um parágrafo, algo está errado
|
);
|
||||||
if (yAfter === null) {ole.log(`Não foi possível processar o parágrafo ${currentPar + 1}, avançando`);amos avançar para o próximo parágrafo para evitar um loop infinito
|
|
||||||
// Se não conseguimos renderizar este parágrafo, vamos para a próxima páginar + 1}, avançando`);
|
if (yAfter === null) {
|
||||||
// Mas só se já tivermos processado algum parágrafo nesta páginae;
|
if (processedAnyParagraph) {
|
||||||
if (processedAnyParagraph) { true;
|
|
||||||
console.log(`Página ${pageIndex + 1} está cheia, criando nova página`);
|
console.log(`Página ${pageIndex + 1} está cheia, criando nova página`);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
// Se não conseguimos nem processar um parágrafo, algo está errado
|
console.log(`Não foi possível processar o parágrafo ${currentPar + 1}, avançando`);
|
||||||
// Vamos avançar para o próximo parágrafo para evitar um loop infinito
|
currentPar++;
|
||||||
console.log(`Não foi possível processar o parágrafo ${currentPar + 1}, avançando`);log(`Parágrafo ${currentPar} processado com sucesso, nova posição y=${y}`);dAnyParagraph = true;
|
continue;
|
||||||
currentPar++;/ Verifica se ainda temos espaço para pelo menos uma linhaonsole.log(`Parágrafo ${currentPar} processado com sucesso, nova posição y=${y}`);
|
}
|
||||||
processedAnyParagraph = true; if (y < margens.bottom + FONT_SIZE * 2) { // Verifica se ainda temos espaço para pelo menos uma linha
|
} else {
|
||||||
} console.log(`Espaço insuficiente para próximo parágrafo, criando nova página`); if (y < margens.bottom + FONT_SIZE * 2) {
|
y = yAfter - FONT_SIZE * 0.5;
|
||||||
} else { break; console.log(`Espaço insuficiente para próximo parágrafo, criando nova página`);
|
|
||||||
// Parágrafo foi renderizado com sucesso
|
|
||||||
y = yAfter - FONT_SIZE * 0.5; } }
|
|
||||||
currentPar++;
|
currentPar++;
|
||||||
processedAnyParagraph = true;
|
processedAnyParagraph = true;
|
||||||
console.log(`Parágrafo ${currentPar} processado com sucesso, nova posição y=${y}`); pageIndex++;
|
console.log(`Parágrafo ${currentPar} processado com sucesso, nova posição y=${y}`);
|
||||||
// Verifica se ainda temos espaço para pelo menos uma linha } pageIndex++;
|
}
|
||||||
if (y < margens.bottom + FONT_SIZE * 2) {
|
|
||||||
console.log(`Espaço insuficiente para próximo parágrafo, criando nova página`);de páginas (${MAX_PAGES}) atingido. Geração de PDF interrompida.`);
|
if (y < margens.bottom + FONT_SIZE * 2) {
|
||||||
break;GES}) atingido. Geração de PDF interrompida.`);
|
console.log(`Espaço insuficiente para próximo parágrafo, criando nova página`);
|
||||||
}
|
break;
|
||||||
});
|
}
|
||||||
}es = await pdfDoc.save();`PDF gerado com ${pageIndex} páginas`);
|
}
|
||||||
return Buffer.from(pdfBytes); const pdfBytes = await pdfDoc.save();
|
|
||||||
pageIndex++; } catch (error) { return Buffer.from(pdfBytes);
|
pageIndex++;
|
||||||
} console.error('Erro geral ao gerar PDF:', error); } catch (error) {
|
}
|
||||||
|
|
||||||
if (pageIndex >= MAX_PAGES) {
|
if (pageIndex >= MAX_PAGES) {
|
||||||
console.warn(`AVISO: Número máximo de páginas (${MAX_PAGES}) atingido. Geração de PDF interrompida.`);
|
console.warn(`AVISO: Número máximo de páginas (${MAX_PAGES}) atingido. Geração de PDF interrompida.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`PDF gerado com ${pageIndex} páginas`);: string, dados: any): string {
|
console.log(`PDF gerado com ${pageIndex} páginas`);
|
||||||
const pdfBytes = await pdfDoc.save();
|
const pdfBytes = await pdfDoc.save();
|
||||||
return Buffer.from(pdfBytes);m().split('.');{\{([^}]+)\}\}/g, (match, key) => {
|
return Buffer.from(pdfBytes);
|
||||||
} catch (error) {= dados;arts = key.trim().split('.');
|
} catch (error) {
|
||||||
console.error('Erro geral ao gerar PDF:', error);Parts) {
|
console.error('Erro geral ao gerar PDF:', error);
|
||||||
throw error;e && typeof value === 'object' && part in value) { part of keyParts) {
|
throw error;
|
||||||
} value = value[part];f (value && typeof value === 'object' && part in value) {
|
}
|
||||||
} } else { value = value[part];
|
}
|
||||||
|
|
||||||
private processarTemplate(template: string, dados: any): string { break; value = undefined;
|
private processarTemplate(template: string, dados: any): string {
|
||||||
return template.replace(/\{\{([^}]+)\}\}/g, (match, key) => { } break;
|
return template.replace(/\{\{([^}]+)\}\}/g, (match, key) => {
|
||||||
const keyParts = key.trim().split('.'); } }
|
const keyParts = key.trim().split('.');
|
||||||
|
let value = dados;
|
||||||
|
for (const part of keyParts) {
|
||||||
|
if (value && typeof value === 'object' && part in value) {
|
||||||
|
value = value[part];
|
||||||
|
} else {
|
||||||
|
value = undefined;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} } }); return value !== undefined ? value : match; } } break; value = undefined; } else { value = value[part]; if (value && typeof value === 'object' && part in value) { for (const part of keyParts) { let value = dados;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} } }); return value !== undefined ? value : match; }
|
|
||||||
return value !== undefined ? value : match;
|
return value !== undefined ? value : match;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user