tenta fix pdfservice.js
This commit is contained in:
1 parent
045124be2f
commit
6fdfc99e7d
1 file changed
+99
-35
@@ -377,6 +377,12 @@ export class PdfService {
|
|||||||
let currentLine: Array<{text: string, font: any, width: number}> = [];
|
let currentLine: Array<{text: string, font: any, width: number}> = [];
|
||||||
let currentLineWidth = 0;
|
let currentLineWidth = 0;
|
||||||
|
|
||||||
|
// Verifica se o texto parece ser um título (todo em maiúsculas ou curto)
|
||||||
|
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;
|
let currentFont = normalFont;
|
||||||
let boldActive = false;
|
let boldActive = false;
|
||||||
@@ -470,6 +476,17 @@ export class PdfService {
|
|||||||
return null; // Não há espaço suficiente para renderizar
|
return null; // Não há espaço suficiente para renderizar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Aumentar ligeiramente o espaçamento de linhas para títulos
|
||||||
|
const effectiveLineHeight = isTitle ? lineHeight * 1.3 : lineHeight;
|
||||||
|
|
||||||
|
// Aumentar o tamanho da fonte para títulos
|
||||||
|
const effectiveFontSize = isTitle ? fontSize * 1.2 : fontSize;
|
||||||
|
|
||||||
|
// Se for um título, adicionar um espaço extra antes
|
||||||
|
if (isTitle && y < startY) {
|
||||||
|
y -= lineHeight * 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
// 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];
|
||||||
@@ -481,18 +498,23 @@ export class PdfService {
|
|||||||
currentLineWidth += word.width;
|
currentLineWidth += word.width;
|
||||||
} else {
|
} else {
|
||||||
// Renderizar a linha atual
|
// Renderizar a linha atual
|
||||||
if (y - lineHeight < 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ajustar X baseado no alinhamento
|
// Ajustar X baseado no alinhamento
|
||||||
let lineX = x;
|
let lineX = x;
|
||||||
const spacingFactor = align === 'justify' && currentLine.length > 1 ?
|
|
||||||
|
// Para justificado, calcular espaçamentos extras entre palavras
|
||||||
|
// Mas não justificar a última linha de um parágrafo ou títulos
|
||||||
|
const isLastLine = i === words.length - 1;
|
||||||
|
const shouldJustify = effectiveAlign === 'justify' && !isLastLine && !isTitle && currentLine.length > 1;
|
||||||
|
const extraSpacing = shouldJustify ?
|
||||||
(maxWidth - currentLineWidth) / (currentLine.length - 1) : 0;
|
(maxWidth - currentLineWidth) / (currentLine.length - 1) : 0;
|
||||||
|
|
||||||
if (align === 'center') {
|
if (effectiveAlign === 'center') {
|
||||||
lineX = x + (maxWidth - currentLineWidth) / 2;
|
lineX = x + (maxWidth - currentLineWidth) / 2;
|
||||||
} else if (align === 'right') {
|
} else if (effectiveAlign === 'right') {
|
||||||
lineX = x + maxWidth - currentLineWidth;
|
lineX = x + maxWidth - currentLineWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,11 +522,13 @@ export class PdfService {
|
|||||||
let posX = lineX;
|
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;
|
||||||
|
|
||||||
page.drawText(item.text, {
|
page.drawText(item.text, {
|
||||||
x: posX,
|
x: posX,
|
||||||
y: y,
|
y: y,
|
||||||
font: item.font,
|
font: item.font,
|
||||||
size: fontSize,
|
size: itemFontSize,
|
||||||
color
|
color
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -512,18 +536,18 @@ export class PdfService {
|
|||||||
posX += item.width;
|
posX += item.width;
|
||||||
|
|
||||||
// Adicionar espaço extra se for justificado (exceto no final da linha)
|
// Adicionar espaço extra se for justificado (exceto no final da linha)
|
||||||
if (align === 'justify' && j < currentLine.length - 1) {
|
if (shouldJustify && j < currentLine.length - 1) {
|
||||||
posX += spacingFactor;
|
posX += extraSpacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avançar para a próxima linha
|
// Avançar para a próxima linha
|
||||||
y -= lineHeight;
|
y -= effectiveLineHeight;
|
||||||
currentLine = [word];
|
currentLine = [word];
|
||||||
currentLineWidth = word.width;
|
currentLineWidth = word.width;
|
||||||
|
|
||||||
// Verificar se ainda temos espaço
|
// Verificar se ainda temos espaço
|
||||||
if (y - lineHeight < marginBottom) {
|
if (y - effectiveLineHeight < marginBottom) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -531,41 +555,37 @@ export class PdfService {
|
|||||||
|
|
||||||
// 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)
|
// Ajustar X baseado no alinhamento (última linha nunca é justificada, exceto se for curta)
|
||||||
let lineX = x;
|
let lineX = x;
|
||||||
if (align === 'center') {
|
|
||||||
|
// Se for título ou alinhado ao centro/direita, ajustar posição
|
||||||
|
if (effectiveAlign === 'center') {
|
||||||
lineX = x + (maxWidth - currentLineWidth) / 2;
|
lineX = x + (maxWidth - currentLineWidth) / 2;
|
||||||
} else if (align === 'right') {
|
} else if (effectiveAlign === 'right') {
|
||||||
lineX = x + maxWidth - currentLineWidth;
|
lineX = x + maxWidth - currentLineWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Desenhar a linha
|
// Desenhar a linha
|
||||||
let posX = lineX;
|
let posX = lineX;
|
||||||
for (const item of currentLine) {
|
for (const item of currentLine) {
|
||||||
|
const itemFontSize = isTitle ? effectiveFontSize : fontSize;
|
||||||
|
|
||||||
page.drawText(item.text, {
|
page.drawText(item.text, {
|
||||||
x: posX,
|
x: posX,
|
||||||
y: y,
|
y: y,
|
||||||
font: item.font,
|
font: item.font,
|
||||||
size: fontSize,
|
size: itemFontSize,
|
||||||
color
|
color
|
||||||
});
|
});
|
||||||
posX += item.width;
|
posX += item.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
y -= lineHeight;
|
y -= effectiveLineHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Se estiver em modo debug, desenhar uma caixa ao redor do texto
|
// Se for título, adicionar um espaço extra depois
|
||||||
if (debug) {
|
if (isTitle) {
|
||||||
page.drawRectangle({
|
y -= lineHeight * 0.5;
|
||||||
x,
|
|
||||||
y: y + lineHeight,
|
|
||||||
width: maxWidth,
|
|
||||||
height: startY - y,
|
|
||||||
borderColor: rgb(0.8, 0.8, 0.8),
|
|
||||||
borderWidth: 0.5,
|
|
||||||
opacity: 0.1
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return y;
|
return y;
|
||||||
@@ -581,22 +601,49 @@ export class PdfService {
|
|||||||
const paragrafos = texto.split(/\n{2,}/).map(p => {
|
const paragrafos = texto.split(/\n{2,}/).map(p => {
|
||||||
let paragraph = p.trim();
|
let paragraph = p.trim();
|
||||||
if (!paragraph) return '';
|
if (!paragraph) return '';
|
||||||
|
|
||||||
// Extrair informações de formatação
|
// Extrair informações de formatação
|
||||||
let align = 'left'; // padrão é justificado
|
let align = 'justify'; // Padrão agora é justificado para texto normal
|
||||||
const alignMatch = paragraph.match(/§§ALIGN=(center|right|justify)§§/);
|
|
||||||
|
// Verifica se o texto parece ser um título por diversos critérios:
|
||||||
|
// 1. Começa com '#' (estilo markdown)
|
||||||
|
// 2. Todo em maiúsculas e relativamente curto
|
||||||
|
// 3. Começa com números seguidos de ponto (como "1. Título")
|
||||||
|
// 4. Termina com dois pontos e é curto (como "Considerando:")
|
||||||
|
const isTitle =
|
||||||
|
paragraph.startsWith('#') ||
|
||||||
|
(paragraph.toUpperCase() === paragraph && paragraph.length < 100) ||
|
||||||
|
/^\d+\.\s+\S+/.test(paragraph) ||
|
||||||
|
(paragraph.endsWith(':') && paragraph.length < 70);
|
||||||
|
|
||||||
|
// Se for um título, centraliza
|
||||||
|
if (isTitle) {
|
||||||
|
align = 'center';
|
||||||
|
paragraph = paragraph.replace(/^#+\s*/, ''); // Remove marcadores de título estilo markdown
|
||||||
|
}
|
||||||
|
|
||||||
|
// Processa alinhamentos explícitos (têm precedência)
|
||||||
|
const alignMatch = paragraph.match(/§§ALIGN=(center|right|justify|left)§§/);
|
||||||
if (alignMatch) {
|
if (alignMatch) {
|
||||||
align = alignMatch[1];
|
align = alignMatch[1];
|
||||||
paragraph = paragraph.replace(/§§ALIGN=(center|right|justify)§§/, '');
|
paragraph = paragraph.replace(/§§ALIGN=(center|right|justify|left)§§/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
let indent = 0;
|
let indent = 0;
|
||||||
const indentMatch = paragraph.match(/§§INDENT=(\d+)(pt|px|em)§§/);
|
const indentMatch = paragraph.match(/§§INDENT=(\d+)(pt|px|em)?§§/);
|
||||||
if (indentMatch) {
|
if (indentMatch) {
|
||||||
indent = parseInt(indentMatch[1]);
|
indent = parseInt(indentMatch[1]);
|
||||||
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)?§§/, '');
|
||||||
}
|
}
|
||||||
return { text: paragraph.trim(), align, indent };
|
|
||||||
}).filter(Boolean);
|
return {
|
||||||
|
text: paragraph.trim(),
|
||||||
|
align: align as 'left' | 'center' | 'right' | 'justify',
|
||||||
|
indent,
|
||||||
|
isTitle
|
||||||
|
};
|
||||||
|
}).filter(p => p.text);
|
||||||
let currentPar = 0;
|
let currentPar = 0;
|
||||||
let pageIndex = 0;
|
let pageIndex = 0;
|
||||||
console.log(`Gerando PDF com ${paragrafos.length} parágrafos`);
|
console.log(`Gerando PDF com ${paragrafos.length} parágrafos`);
|
||||||
@@ -621,18 +668,35 @@ export class PdfService {
|
|||||||
while (currentPar < paragrafos.length) {
|
while (currentPar < paragrafos.length) {
|
||||||
const paraObj = paragrafos[currentPar];
|
const paraObj = paragrafos[currentPar];
|
||||||
const text = paraObj.text;
|
const text = paraObj.text;
|
||||||
const align = paraObj.align || 'justify'; // Por padrão, justifica o texto
|
const align = paraObj.align;
|
||||||
const indent = paraObj.indent || 0;
|
const indent = paraObj.indent || 0;
|
||||||
|
const isTitle = paraObj.isTitle || false;
|
||||||
|
|
||||||
let x = margens.left + indent;
|
let x = margens.left + indent;
|
||||||
let parWidth = MAX_WIDTH - indent;
|
let parWidth = MAX_WIDTH - indent;
|
||||||
|
|
||||||
// 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ágrafo
|
||||||
if (text.length < 2) {
|
if (text.length < 2) {
|
||||||
currentPar++;
|
currentPar++;
|
||||||
processedAnyParagraph = true;
|
processedAnyParagraph = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
console.log(`Tentando renderizar parágrafo ${currentPar + 1} em y=${y} com alinhamento ${align}`);
|
|
||||||
|
// Ajuste o tamanho da fonte para títulos
|
||||||
|
const fontSizeToUse = isTitle ? FONT_SIZE * 1.2 : FONT_SIZE;
|
||||||
|
|
||||||
|
// Adicionar espaço extra antes de títulos (exceto para o primeiro parágrafo da página)
|
||||||
|
if (isTitle && processedAnyParagraph) {
|
||||||
|
y -= 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) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Tentando renderizar parágrafo ${currentPar + 1} em y=${y} com alinhamento ${align}${isTitle ? ' (título)' : ''}`);
|
||||||
|
|
||||||
let yAfter = renderInlineFormattedParagraph(
|
let yAfter = renderInlineFormattedParagraph(
|
||||||
page,
|
page,
|
||||||
text,
|
text,
|
||||||
@@ -642,7 +706,7 @@ export class PdfService {
|
|||||||
fontBold,
|
fontBold,
|
||||||
fontItalic,
|
fontItalic,
|
||||||
fontBoldItalic,
|
fontBoldItalic,
|
||||||
FONT_SIZE,
|
fontSizeToUse,
|
||||||
rgb(0, 0, 0),
|
rgb(0, 0, 0),
|
||||||
align,
|
align,
|
||||||
parWidth,
|
parWidth,
|
||||||
|
|||||||
Reference in new issue
Block a user