tenta fix pdfservice.js
This commit is contained in:
1 parent
49dba7c9be
commit
566ef2e123
1 file changed
+188
-187
+188
-187
@@ -386,336 +386,337 @@ export class PdfService {
|
|||||||
// 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 = text
|
text = text
|
||||||
.replace(/<u>|<\/u>/gi, '') // Remover tags de sublinhado
|
.replace(/<u>|<\/u>/gi, '') // Remover tags de sublinhados de alinhamento que não foram processados
|
||||||
.replace(/<span[^>]*>|<\/span>/gi, '') // Remover tags span
|
.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(/<(?!\/?(?:b|i|strong|em)(?!\w)[^>]*>)[^>]*>/gi, ''); // Manter apenas b, i, strong, em
|
||||||
// Primeiro, extrair partes do texto com suas formatações
|
// Primeiro, extrair partes do texto com suas formatações
|
||||||
let i = 0;
|
let i = 0;o, extrair partes do texto com suas formatações
|
||||||
while (i < text.length) {
|
while (i < text.length) {
|
||||||
// Limite de segurança para evitar loops infinitos
|
// Limite de segurança para evitar loops infinitos
|
||||||
if (textParts.length > 1000) {
|
if (textParts.length > 1000) {itar loops infinitos
|
||||||
console.error('Limite de processamento de texto excedido');
|
console.error('Limite de processamento de texto excedido');
|
||||||
break;
|
break;e.error('Limite de processamento de texto excedido');
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text.substring(i, i+3) === '<b>' || text.substring(i, i+7) === '<strong>') {
|
if (text.substring(i, i+3) === '<b>' || text.substring(i, i+7) === '<strong>') {
|
||||||
boldActive = true;
|
boldActive = true;, i+3) === '<b>' || text.substring(i, i+7) === '<strong>') {
|
||||||
currentFont = italicActive ? boldItalicFont : boldFont;
|
currentFont = italicActive ? boldItalicFont : boldFont;
|
||||||
i += text.substring(i, i+3) === '<b>' ? 3 : 7;
|
i += text.substring(i, i+3) === '<b>' ? 3 : 7;boldFont;
|
||||||
}
|
} i += text.substring(i, i+3) === '<b>' ? 3 : 7;
|
||||||
else if (text.substring(i, i+4) === '</b>' || text.substring(i, i+8) === '</strong>') {
|
else if (text.substring(i, i+4) === '</b>' || text.substring(i, i+8) === '</strong>') {
|
||||||
boldActive = false;
|
boldActive = false;ng(i, i+4) === '</b>' || text.substring(i, i+8) === '</strong>') {
|
||||||
currentFont = italicActive ? italicFont : normalFont;
|
currentFont = italicActive ? italicFont : normalFont;
|
||||||
i += text.substring(i, i+4) === '</b>' ? 4 : 8;
|
i += text.substring(i, i+4) === '</b>' ? 4 : 8;lFont;
|
||||||
}
|
} i += text.substring(i, i+4) === '</b>' ? 4 : 8;
|
||||||
else if (text.substring(i, i+3) === '<i>' || text.substring(i, i+4) === '<em>') {
|
else if (text.substring(i, i+3) === '<i>' || text.substring(i, i+4) === '<em>') {
|
||||||
italicActive = true;
|
italicActive = true;g(i, i+3) === '<i>' || text.substring(i, i+4) === '<em>') {
|
||||||
currentFont = boldActive ? boldItalicFont : italicFont;
|
currentFont = boldActive ? boldItalicFont : italicFont;
|
||||||
i += text.substring(i, i+3) === '<i>' ? 3 : 4;
|
i += text.substring(i, i+3) === '<i>' ? 3 : 4;alicFont;
|
||||||
}
|
} i += text.substring(i, i+3) === '<i>' ? 3 : 4;
|
||||||
else if (text.substring(i, i+4) === '</i>' || text.substring(i, i+5) === '</em>') {
|
else if (text.substring(i, i+4) === '</i>' || text.substring(i, i+5) === '</em>') {
|
||||||
italicActive = false;
|
italicActive = false;(i, i+4) === '</i>' || text.substring(i, i+5) === '</em>') {
|
||||||
currentFont = boldActive ? boldFont : normalFont;
|
currentFont = boldActive ? boldFont : normalFont;
|
||||||
i += text.substring(i, i+4) === '</i>' ? 4 : 5;
|
i += text.substring(i, i+4) === '</i>' ? 4 : 5;t;
|
||||||
}
|
} i += text.substring(i, i+4) === '</i>' ? 4 : 5;
|
||||||
else {
|
else {
|
||||||
// Encontrar o próximo início de tag
|
// Encontrar o próximo início de tag
|
||||||
let nextTagPos = text.indexOf('<', i);
|
let nextTagPos = text.indexOf('<', i);
|
||||||
|
let nextTagPos = text.indexOf('<', i);
|
||||||
if (nextTagPos === -1) {
|
if (nextTagPos === -1) {
|
||||||
// Não há mais tags, pegar o restante do texto
|
// Não há mais tags, pegar o restante do texto
|
||||||
textParts.push({
|
textParts.push({ags, pegar o restante do texto
|
||||||
text: text.substring(i),
|
text: text.substring(i),
|
||||||
font: currentFont
|
font: currentFonting(i),
|
||||||
});
|
});ont: currentFont
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
// Pegar texto até a próxima tag
|
// Pegar texto até a próxima tag
|
||||||
textParts.push({
|
textParts.push({té a próxima tag
|
||||||
text: text.substring(i, nextTagPos),
|
text: text.substring(i, nextTagPos),
|
||||||
font: currentFont
|
font: currentFonting(i, nextTagPos),
|
||||||
});
|
});ont: currentFont
|
||||||
i = nextTagPos;
|
i = nextTagPos;
|
||||||
|
} i = nextTagPos;
|
||||||
|
} }
|
||||||
|
} }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Processa partes de texto em palavras para quebra de linha
|
// Processa partes de texto em palavras para quebra de linha
|
||||||
for (const part of textParts) {
|
for (const part of textParts) {palavras para quebra de linha
|
||||||
|
const partWords = part.text.split(/\s+/);
|
||||||
const partWords = part.text.split(/\s+/);
|
const partWords = part.text.split(/\s+/);
|
||||||
|
|
||||||
for (let i = 0; i < partWords.length; i++) {
|
for (let i = 0; i < partWords.length; i++) {
|
||||||
|
if (partWords[i].length === 0) continue; {
|
||||||
if (partWords[i].length === 0) continue;
|
if (partWords[i].length === 0) continue;
|
||||||
|
|
||||||
const wordText = i < partWords.length - 1 ? partWords[i] + ' ' : partWords[i];
|
const wordText = i < partWords.length - 1 ? partWords[i] + ' ' : partWords[i];
|
||||||
|
const wordWidth = part.font.widthOfTextAtSize(wordText, fontSize);artWords[i];
|
||||||
const wordWidth = part.font.widthOfTextAtSize(wordText, fontSize);
|
const wordWidth = part.font.widthOfTextAtSize(wordText, fontSize);
|
||||||
|
|
||||||
words.push({
|
words.push({
|
||||||
text: wordText,
|
text: wordText,
|
||||||
font: part.font,
|
font: part.font,
|
||||||
width: wordWidth
|
width: wordWidth
|
||||||
});
|
});idth: wordWidth
|
||||||
|
} });
|
||||||
|
} }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Processa palavras em linhas
|
// Processa palavras em linhas
|
||||||
for (let i = 0; i < words.length; i++) {
|
for (let i = 0; i < words.length; i++) {
|
||||||
|
const word = words[i];s.length; i++) {
|
||||||
const word = words[i];
|
const word = words[i];
|
||||||
|
|
||||||
if (currentLineWidth + word.width <= maxWidth) {
|
if (currentLineWidth + word.width <= maxWidth) {
|
||||||
// A palavra cabe na linha atual
|
// A palavra cabe na linha atual<= maxWidth) {
|
||||||
currentLine.push(word);
|
currentLine.push(word);nha atual
|
||||||
currentLineWidth += word.width;
|
currentLineWidth += word.width;
|
||||||
} else {
|
} else {tLineWidth += word.width;
|
||||||
// A palavra não cabe, desenha a linha atual e começa nova linha
|
// A palavra não cabe, desenha a linha atual e começa nova linha
|
||||||
// Primeiro verifica se há espaço vertical suficiente
|
// Primeiro verifica se há espaço vertical suficiente nova linha
|
||||||
if (y - lineHeight < marginBottom) {
|
if (y - lineHeight < marginBottom) {rtical suficiente
|
||||||
return null; // Não há espaço suficiente na página
|
return null; // Não há espaço suficiente na página
|
||||||
|
} return null; // Não há espaço suficiente na página
|
||||||
}
|
}
|
||||||
|
|
||||||
// Desenha a linha com o alinhamento apropriado
|
// Desenha a linha com o alinhamento apropriado
|
||||||
y = drawFormattedLine(page, currentLine, x, y, maxWidth, align, fontSize, color);
|
y = drawFormattedLine(page, currentLine, x, y, maxWidth, align, fontSize, color);
|
||||||
|
y = drawFormattedLine(page, currentLine, x, y, maxWidth, align, fontSize, color);
|
||||||
// Começa uma nova linha com a palavra atual
|
// Começa uma nova linha com a palavra atual
|
||||||
currentLine = [word];
|
currentLine = [word];nha com a palavra atual
|
||||||
currentLineWidth = word.width;
|
currentLineWidth = word.width;
|
||||||
|
} currentLineWidth = word.width;
|
||||||
|
} }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Desenha a última linha se houver palavras restantes
|
// Desenha a última linha se houver palavras restantes
|
||||||
if (currentLine.length > 0) {
|
if (currentLine.length > 0) {houver palavras restantes
|
||||||
if (y - lineHeight < marginBottom) {
|
if (y - lineHeight < marginBottom) {
|
||||||
return null; // Não há espaço suficiente na página
|
return null; // Não há espaço suficiente na página
|
||||||
|
} return null; // Não há espaço suficiente na página
|
||||||
}
|
}
|
||||||
|
|
||||||
y = drawFormattedLine(page, currentLine, x, y, maxWidth, align, fontSize, color);
|
y = drawFormattedLine(page, currentLine, x, y, maxWidth, align, fontSize, color);
|
||||||
|
} y = drawFormattedLine(page, currentLine, x, y, maxWidth, align, fontSize, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
return y;
|
return y;
|
||||||
|
} return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Desenha uma linha formatada com alinhamento específico
|
* Desenha uma linha formatada com alinhamento específico
|
||||||
*/
|
*/Desenha uma linha formatada com alinhamento específico
|
||||||
function drawFormattedLine(
|
function drawFormattedLine(
|
||||||
page: any,
|
page: any, FormattedLine(
|
||||||
line: Array<{text: string, font: any, width: number}>,
|
line: Array<{text: string, font: any, width: number}>,
|
||||||
x: number,
|
x: number,y<{text: string, font: any, width: number}>,
|
||||||
y: number,
|
y: number,
|
||||||
maxWidth: number,
|
maxWidth: number,
|
||||||
align: 'left' | 'center' | 'right' | 'justify',
|
align: 'left' | 'center' | 'right' | 'justify',
|
||||||
fontSize: number,
|
fontSize: number,center' | 'right' | 'justify',
|
||||||
color: any
|
color: anynumber,
|
||||||
): number {
|
): number {y
|
||||||
const lineHeight = fontSize * 1.5;
|
const lineHeight = fontSize * 1.5;
|
||||||
let currentX = x;
|
let currentX = x;= fontSize * 1.5;
|
||||||
|
let totalWidth = line.reduce((sum, word) => sum + word.width, 0);
|
||||||
let totalWidth = line.reduce((sum, word) => sum + word.width, 0);
|
let totalWidth = line.reduce((sum, word) => sum + word.width, 0);
|
||||||
|
|
||||||
// Calcula o espaço adicional entre palavras para justificação
|
// Calcula o espaço adicional entre palavras para justificação
|
||||||
let extraSpacing = 0;
|
let extraSpacing = 0;dicional entre palavras para justificação
|
||||||
if (align === 'justify' && line.length > 1 && totalWidth < maxWidth * 0.8) {
|
if (align === 'justify' && line.length > 1 && totalWidth < maxWidth * 0.8) {
|
||||||
extraSpacing = (maxWidth - totalWidth) / (line.length - 1);
|
extraSpacing = (maxWidth - totalWidth) / (line.length - 1);xWidth * 0.8) {
|
||||||
|
} extraSpacing = (maxWidth - totalWidth) / (line.length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ajusta a posição x inicial baseada no alinhamento
|
// Ajusta a posição x inicial baseada no alinhamento
|
||||||
if (align === 'center') {
|
if (align === 'center') {cial baseada no alinhamento
|
||||||
currentX = x + (maxWidth - totalWidth) / 2;
|
currentX = x + (maxWidth - totalWidth) / 2;
|
||||||
} else if (align === 'right') {
|
} else if (align === 'right') {talWidth) / 2;
|
||||||
currentX = x + maxWidth - totalWidth;
|
currentX = x + maxWidth - totalWidth;
|
||||||
|
} currentX = x + maxWidth - totalWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Desenha cada palavra
|
// Desenha cada palavra
|
||||||
for (let i = 0; i < line.length; i++) {
|
for (let i = 0; i < line.length; i++) {
|
||||||
const word = line[i];
|
const word = line[i];e.length; i++) {
|
||||||
page.drawText(word.text, {
|
page.drawText(word.text, {
|
||||||
x: currentX,
|
x: currentX,word.text, {
|
||||||
y: y,
|
y: y,rrentX,
|
||||||
font: word.font,
|
font: word.font,
|
||||||
size: fontSize,
|
size: fontSize,,
|
||||||
color: color
|
color: colorze,
|
||||||
|
});olor: color
|
||||||
});
|
});
|
||||||
|
|
||||||
// Avança X para a próxima palavra
|
// Avança X para a próxima palavra
|
||||||
|
currentX += word.width;ima palavra
|
||||||
currentX += word.width;
|
currentX += word.width;
|
||||||
|
|
||||||
// Adiciona espaço extra para justificação, exceto na última palavra
|
// Adiciona espaço extra para justificação, exceto na última palavra
|
||||||
if (align === 'justify' && i < line.length - 1) {
|
if (align === 'justify' && i < line.length - 1) {o na última palavra
|
||||||
currentX += extraSpacing;
|
currentX += extraSpacing;i < line.length - 1) {
|
||||||
|
} currentX += extraSpacing;
|
||||||
|
} }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Retorna a nova posição Y após desenhar a linha
|
// Retorna a nova posição Y após desenhar a linha
|
||||||
return y - lineHeight;
|
return y - lineHeight;ção Y após desenhar a linha
|
||||||
|
} return y - lineHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Processe o texto com as novas funções melhoradas
|
// Processe o texto com as novas funções melhoradas
|
||||||
const textoLimpo = stripUnsupportedTags(
|
const textoLimpo = stripUnsupportedTags( melhoradas
|
||||||
this.processarTemplate(conteudo, escritorio)
|
this.processarTemplate(conteudo, escritorio)
|
||||||
);
|
);this.processarTemplate(conteudo, escritorio)
|
||||||
|
const texto = decodeHtmlEntities(textoLimpo);
|
||||||
const texto = decodeHtmlEntities(textoLimpo);
|
const texto = decodeHtmlEntities(textoLimpo);
|
||||||
|
|
||||||
console.log('Texto processado para renderização:', texto.substring(0, 100) + '...');
|
console.log('Texto processado para renderização:', texto.substring(0, 100) + '...');
|
||||||
|
console.log('Texto processado para renderização:', texto.substring(0, 100) + '...');
|
||||||
// Corrigir o processamento de parágrafos para lidar melhor com formatações
|
// Corrigir o processamento de parágrafos para lidar melhor com formatações
|
||||||
const paragrafos = texto.split(/\n{2,}/).map(p => {
|
const paragrafos = texto.split(/\n{2,}/).map(p => {r melhor com formatações
|
||||||
let paragraph = p.trim();
|
let paragraph = p.trim();lit(/\n{2,}/).map(p => {
|
||||||
if (!paragraph) return '';
|
if (!paragraph) return '';
|
||||||
|
if (!paragraph) return '';
|
||||||
// Extrair informações de formatação
|
// Extrair informações de formataçãoo a todos os parágrafos normais
|
||||||
let align = 'left'; // padrão
|
let align = 'left'; // padrãorão é justificadomatação
|
||||||
const alignMatch = paragraph.match(/§§ALIGN=(center|right|justify)§§/);
|
const alignMatch = paragraph.match(/§§ALIGN=(center|right|justify)§§/);
|
||||||
if (alignMatch) {
|
if (alignMatch) { parece um título (começa com # ou tem menos de 50 caracteres e termina com :)= paragraph.match(/§§ALIGN=(center|right|justify)§§/);
|
||||||
align = alignMatch[1];
|
align = alignMatch[1];('#') ||
|
||||||
paragraph = paragraph.replace(/§§ALIGN=(center|right|justify)§§/, '');
|
paragraph = paragraph.replace(/§§ALIGN=(center|right|justify)§§/, '');
|
||||||
}
|
} (paragraph.toUpperCase() === paragraph && paragraph.length < 100)) { paragraph = paragraph.replace(/§§ALIGN=(center|right|justify)§§/, '');
|
||||||
|
align = 'center'; // centraliza títulos}
|
||||||
let indent = 0;
|
let indent = 0;aragraph.replace(/^#+\s*/, ''); // Remove marcadores de título #
|
||||||
const indentMatch = paragraph.match(/§§INDENT=(\d+)(pt|px|em)§§/);
|
const indentMatch = paragraph.match(/§§INDENT=(\d+)(pt|px|em)§§/);
|
||||||
if (indentMatch) {
|
if (indentMatch) {/§§INDENT=(\d+)(pt|px|em)§§/);
|
||||||
indent = parseInt(indentMatch[1]);
|
indent = parseInt(indentMatch[1]);nhamento se estiverem presentes explicitamente
|
||||||
if (indentMatch[2] === 'em') indent *= 12; // Converter em para pontos aproximadamente
|
if (indentMatch[2] === 'em') indent *= 12; // Converter em para pontos aproximadamente
|
||||||
paragraph = paragraph.replace(/§§INDENT=\d+(pt|px|em)§§/, '');
|
paragraph = paragraph.replace(/§§INDENT=\d+(pt|px|em)§§/, '');
|
||||||
}
|
} align = alignMatch[1]; paragraph = paragraph.replace(/§§INDENT=\d+(pt|px|em)§§/, '');
|
||||||
|
paragraph = paragraph.replace(/§§ALIGN=(center|right|justify|left)§§/, '');}
|
||||||
return `§§ALIGN=${align}§§§§INDENT=${indent}§§${paragraph.trim()}`;
|
return { text: paragraph.trim(), align, indent };
|
||||||
}).filter(Boolean);
|
}).filter(Boolean);=${indent}§§${paragraph.trim()}`;
|
||||||
|
let indent = 0;}).filter(Boolean);
|
||||||
let currentPar = 0;
|
let currentPar = 0; = paragraph.match(/§§INDENT=(\d+)(pt|px|em)?§§/);
|
||||||
let pageIndex = 0;
|
let pageIndex = 0; {;
|
||||||
console.log(`Gerando PDF com ${paragrafos.length} parágrafos`);
|
console.log(`Gerando PDF com ${paragrafos.length} parágrafos`);
|
||||||
|
if (indentMatch[2] === 'em') indent *= 12; // Converter em para pontos aproximadamenteconsole.log(`Gerando PDF com ${paragrafos.length} parágrafos`);
|
||||||
// Define um contador máximo para evitar loops infinitos
|
// Define um contador máximo para evitar loops infinitos)?§§/, '');
|
||||||
const MAX_PAGES = 100;
|
const MAX_PAGES = 100;loops infinitos
|
||||||
while (currentPar < paragrafos.length && pageIndex < MAX_PAGES) {
|
while (currentPar < paragrafos.length && pageIndex < MAX_PAGES) {
|
||||||
console.log(`Criando página ${pageIndex + 1}, processando parágrafo ${currentPar + 1} de ${paragrafos.length}`);
|
console.log(`Criando página ${pageIndex + 1}, processando parágrafo ${currentPar + 1} de ${paragrafos.length}`);
|
||||||
let page = pdfDoc.addPage([PAGE_WIDTH, PAGE_HEIGHT]);
|
let page = pdfDoc.addPage([PAGE_WIDTH, PAGE_HEIGHT]);+ 1} de ${paragrafos.length}`);
|
||||||
|
align: align as 'left' | 'center' | 'right' | 'justify',let page = pdfDoc.addPage([PAGE_WIDTH, PAGE_HEIGHT]);
|
||||||
// Adicionar timbrado à página
|
// Adicionar timbrado à página
|
||||||
if (timbradoPages.length > 0) {
|
if (timbradoPages.length > 0) {
|
||||||
console.log(`Adicionando timbrado na página ${pageIndex + 1}`);
|
console.log(`Adicionando timbrado na página ${pageIndex + 1}`);
|
||||||
page.drawPage(timbradoPages[0], {
|
page.drawPage(timbradoPages[0], {
|
||||||
x: 0,
|
x: 0,Par = 0;awPage(timbradoPages[0], {
|
||||||
y: 0,
|
y: 0,ex = 0;
|
||||||
width: PAGE_WIDTH,
|
width: PAGE_WIDTH, com ${paragrafos.length} parágrafos`);
|
||||||
height: PAGE_HEIGHT
|
height: PAGE_HEIGHT
|
||||||
});
|
});ne um contador máximo para evitar loops infinitoseight: PAGE_HEIGHT
|
||||||
}
|
}st MAX_PAGES = 100; });
|
||||||
|
ile (currentPar < paragrafos.length && pageIndex < MAX_PAGES) {}
|
||||||
let y = PAGE_HEIGHT - margens.top;
|
let y = PAGE_HEIGHT - margens.top;Index + 1}, processando parágrafo ${currentPar + 1} de ${paragrafos.length}`);
|
||||||
|
let processedAnyParagraph = false; // Flag para verificar se processamos algum parágrafo
|
||||||
let processedAnyParagraph = false; // Flag para verificar se processamos algum parágrafo
|
let processedAnyParagraph = false; // Flag para verificar se processamos algum parágrafo
|
||||||
|
|
||||||
// Tenta processar parágrafos na página atual
|
// Tenta processar parágrafos na página atual
|
||||||
while (currentPar < paragrafos.length) {
|
while (currentPar < paragrafos.length) {
|
||||||
const paraText = paragrafos[currentPar];
|
const paraObj = paragrafos[currentPar];ina ${pageIndex + 1}`);
|
||||||
|
page.drawPage(timbradoPages[0], {const paraText = paragrafos[currentPar];
|
||||||
|
// Extrair propriedades do parágrafo
|
||||||
|
const text = paraObj.text;
|
||||||
|
const align = paraObj.align || 'justify'; // Por padrão, justifica o texto
|
||||||
|
const indent = paraObj.indent || 0;IGHT= paraText.match(/^§§ALIGN=(center|justify|right)§§/);
|
||||||
|
|
||||||
// Extract alignment
|
let x = margens.left + indent;lign = alignMatch[1] as 'center' | 'justify' | 'left';
|
||||||
let align: 'left' | 'center' | 'justify' = 'left';
|
|
||||||
const alignMatch = paraText.match(/^§§ALIGN=(center|justify|right)§§/);
|
|
||||||
if (alignMatch) {
|
|
||||||
align = alignMatch[1] as 'center' | 'justify' | 'left';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract indentation
|
|
||||||
let indent = 0;
|
|
||||||
const indentMatch = paraText.match(/§§INDENT=([0-9.]+)§§/);
|
|
||||||
if (indentMatch) {
|
|
||||||
indent = parseFloat(indentMatch[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean text
|
|
||||||
let text = paraText
|
|
||||||
.replace(/^§§ALIGN=(center|justify|right)§§/, '')
|
|
||||||
.replace(/§§INDENT=[0-9.]+§§/, '')
|
|
||||||
.trim();
|
|
||||||
let x = margens.left + indent;
|
|
||||||
let parWidth = MAX_WIDTH - indent;
|
let parWidth = MAX_WIDTH - indent;
|
||||||
|
rgens.top;
|
||||||
// Se o texto for muito curto, avance para o próximo parágrafo
|
// Se o texto for muito curto, avance para o próximo parágrafoaragraph = false; // Flag para verificar se processamos algum parágrafontation
|
||||||
if (text.length < 2) {
|
if (text.length < 2) {
|
||||||
currentPar++;
|
currentPar++;arágrafos na página atual= paraText.match(/§§INDENT=([0-9.]+)§§/);
|
||||||
processedAnyParagraph = true;
|
processedAnyParagraph = true;
|
||||||
continue;
|
continue;onst paraText = paragrafos[currentPar]; indent = parseFloat(indentMatch[1]);
|
||||||
}
|
}}
|
||||||
|
ignment
|
||||||
console.log(`Tentando renderizar parágrafo ${currentPar + 1} em y=${y}`);
|
console.log(`Tentando renderizar parágrafo ${currentPar + 1} em y=${y} com alinhamento ${align}`); 'center' | 'justify' = 'left';
|
||||||
let yAfter = renderInlineFormattedParagraph(
|
let yAfter = renderInlineFormattedParagraph(|justify|right)§§/);
|
||||||
page,
|
page,
|
||||||
text,
|
text,alignMatch[1] as 'center' | 'justify' | 'left';(/§§INDENT=[0-9.]+§§/, '')
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
font,
|
font,// Extract indentationlet parWidth = MAX_WIDTH - indent;
|
||||||
fontBold,
|
fontBold,
|
||||||
fontItalic,
|
fontItalic,raText.match(/§§INDENT=([0-9.]+)§§/);o curto, avance para o próximo parágrafo
|
||||||
fontBoldItalic,
|
fontBoldItalic,) { < 2) {
|
||||||
FONT_SIZE,
|
FONT_SIZE,ch[1]);
|
||||||
rgb(0, 0, 0),
|
rgb(0, 0, 0),ph = true;
|
||||||
align,
|
align,continue;
|
||||||
parWidth,
|
parWidth,// Clean text}
|
||||||
false,
|
false,
|
||||||
margens.top,
|
margens.top,§/, ''){currentPar + 1} em y=${y}`);
|
||||||
margens.bottom,
|
margens.bottom,ace(/§§INDENT=[0-9.]+§§/, '')ter = renderInlineFormattedParagraph(
|
||||||
PAGE_HEIGHT
|
PAGE_HEIGHT();
|
||||||
);
|
);x = margens.left + indent;xt,
|
||||||
|
parWidth = MAX_WIDTH - indent;
|
||||||
if (yAfter === null) {
|
if (yAfter === null) {
|
||||||
// Se não conseguimos renderizar este parágrafo, vamos para a próxima página
|
// Se não conseguimos renderizar este parágrafo, vamos para a próxima páginato for muito curto, avance para o próximo parágrafo
|
||||||
// Mas só se já tivermos processado algum parágrafo nesta página
|
// Mas só se já tivermos processado algum parágrafo nesta páginath < 2) {
|
||||||
if (processedAnyParagraph) {
|
if (processedAnyParagraph) {
|
||||||
console.log(`Página ${pageIndex + 1} está cheia, criando nova página`);
|
console.log(`Página ${pageIndex + 1} está cheia, criando nova página`);nyParagraph = true;alic,
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
// Se não conseguimos nem processar um parágrafo, algo está errado
|
// Se não conseguimos nem processar um parágrafo, algo está errado
|
||||||
// Vamos avançar para o próximo parágrafo para evitar um loop infinito
|
// Vamos avançar para o próximo parágrafo para evitar um loop infinitolog(`Tentando renderizar parágrafo ${currentPar + 1} em y=${y}`);th,
|
||||||
console.log(`Não foi possível processar o parágrafo ${currentPar + 1}, avançando`);
|
console.log(`Não foi possível processar o parágrafo ${currentPar + 1}, avançando`);enderInlineFormattedParagraph(
|
||||||
currentPar++;
|
currentPar++;
|
||||||
processedAnyParagraph = true;
|
processedAnyParagraph = true;
|
||||||
}
|
}x,PAGE_HEIGHT
|
||||||
} else {
|
} else { y,);
|
||||||
// Parágrafo foi renderizado com sucesso
|
// Parágrafo foi renderizado com sucesso
|
||||||
y = yAfter - FONT_SIZE * 0.5;
|
y = yAfter - FONT_SIZE * 0.5;
|
||||||
currentPar++;
|
currentPar++;
|
||||||
processedAnyParagraph = true;
|
processedAnyParagraph = true; parágrafo nesta página
|
||||||
console.log(`Parágrafo ${currentPar} processado com sucesso, nova posição y=${y}`);
|
console.log(`Parágrafo ${currentPar} processado com sucesso, nova posição y=${y}`);
|
||||||
|
, 0),e.log(`Página ${pageIndex + 1} está cheia, criando nova página`);
|
||||||
// Verifica se ainda temos espaço para pelo menos uma linha
|
// Verifica se ainda temos espaço para pelo menos uma linha
|
||||||
if (y < margens.bottom + FONT_SIZE * 2) {
|
if (y < margens.bottom + FONT_SIZE * 2) {
|
||||||
console.log(`Espaço insuficiente para próximo parágrafo, criando nova página`);
|
console.log(`Espaço insuficiente para próximo parágrafo, criando nova página`);
|
||||||
break;
|
break;
|
||||||
|
}Não foi possível processar o parágrafo ${currentPar + 1}, avançando`);
|
||||||
}
|
}
|
||||||
}
|
}processedAnyParagraph = true;
|
||||||
}
|
|
||||||
|
|
||||||
pageIndex++;
|
pageIndex++;
|
||||||
}
|
}zar este parágrafo, vamos para a próxima páginacom sucesso
|
||||||
|
já tivermos processado algum parágrafo nesta páginaFONT_SIZE * 0.5;
|
||||||
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.`);
|
||||||
}
|
} break;console.log(`Parágrafo ${currentPar} processado com sucesso, nova posição y=${y}`);
|
||||||
|
|
||||||
console.log(`PDF gerado com ${pageIndex} páginas`);
|
console.log(`PDF gerado com ${pageIndex} páginas`);parágrafo, algo está erradolo menos uma linha
|
||||||
const pdfBytes = await pdfDoc.save();
|
const pdfBytes = await pdfDoc.save();
|
||||||
return Buffer.from(pdfBytes);
|
return Buffer.from(pdfBytes);e.log(`Não foi possível processar o parágrafo ${currentPar + 1}, avançando`);e.log(`Espaço insuficiente para próximo parágrafo, criando nova página`);
|
||||||
} catch (error) {
|
} catch (error) { currentPar++; break;
|
||||||
console.error('Erro geral ao gerar PDF:', error);
|
console.error('Erro geral ao gerar PDF:', error); processedAnyParagraph = true; }
|
||||||
throw error;
|
throw error; } }
|
||||||
}
|
} } else {}
|
||||||
}
|
}rafo foi renderizado com sucesso
|
||||||
|
y = yAfter - FONT_SIZE * 0.5; pageIndex++;
|
||||||
private processarTemplate(template: string, dados: any): string {
|
private processarTemplate(template: string, dados: any): string { currentPar++;}
|
||||||
return template.replace(/\{\{([^}]+)\}\}/g, (match, key) => {
|
return template.replace(/\{\{([^}]+)\}\}/g, (match, key) => { true;
|
||||||
const keyParts = key.trim().split('.');
|
const keyParts = key.trim().split('.');
|
||||||
let value = dados;
|
let value = dados; console.warn(`AVISO: Número máximo de páginas (${MAX_PAGES}) atingido. Geração de PDF interrompida.`);
|
||||||
for (const part of keyParts) {
|
for (const part of keyParts) { // Verifica se ainda temos espaço para pelo menos uma linha }
|
||||||
if (value && typeof value === 'object' && part in value) {
|
if (value && typeof value === 'object' && part in value) {
|
||||||
value = value[part];
|
value = value[part];nte para próximo parágrafo, criando nova página`);ex} páginas`);
|
||||||
} else {
|
} else {
|
||||||
value = undefined;
|
value = undefined;ytes);
|
||||||
break;
|
break;
|
||||||
}
|
}eral ao gerar PDF:', error);
|
||||||
}
|
} throw error;
|
||||||
return value !== undefined ? value : match;
|
return value !== undefined ? value : match; pageIndex++; }
|
||||||
});
|
}); } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} } }); 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;
|
||||||
Reference in new issue
Block a user