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 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
|
||||
let currentFont = normalFont;
|
||||
let boldActive = false;
|
||||
@@ -470,6 +476,17 @@ export class PdfService {
|
||||
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
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
const word = words[i];
|
||||
@@ -481,18 +498,23 @@ export class PdfService {
|
||||
currentLineWidth += word.width;
|
||||
} else {
|
||||
// Renderizar a linha atual
|
||||
if (y - lineHeight < marginBottom) {
|
||||
if (y - effectiveLineHeight < marginBottom) {
|
||||
return null; // Não há mais espaço na página
|
||||
}
|
||||
|
||||
// Ajustar X baseado no alinhamento
|
||||
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;
|
||||
|
||||
if (align === 'center') {
|
||||
if (effectiveAlign === 'center') {
|
||||
lineX = x + (maxWidth - currentLineWidth) / 2;
|
||||
} else if (align === 'right') {
|
||||
} else if (effectiveAlign === 'right') {
|
||||
lineX = x + maxWidth - currentLineWidth;
|
||||
}
|
||||
|
||||
@@ -500,11 +522,13 @@ export class PdfService {
|
||||
let posX = lineX;
|
||||
for (let j = 0; j < currentLine.length; j++) {
|
||||
const item = currentLine[j];
|
||||
const itemFontSize = isTitle ? effectiveFontSize : fontSize;
|
||||
|
||||
page.drawText(item.text, {
|
||||
x: posX,
|
||||
y: y,
|
||||
font: item.font,
|
||||
size: fontSize,
|
||||
size: itemFontSize,
|
||||
color
|
||||
});
|
||||
|
||||
@@ -512,18 +536,18 @@ export class PdfService {
|
||||
posX += item.width;
|
||||
|
||||
// Adicionar espaço extra se for justificado (exceto no final da linha)
|
||||
if (align === 'justify' && j < currentLine.length - 1) {
|
||||
posX += spacingFactor;
|
||||
if (shouldJustify && j < currentLine.length - 1) {
|
||||
posX += extraSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
// Avançar para a próxima linha
|
||||
y -= lineHeight;
|
||||
y -= effectiveLineHeight;
|
||||
currentLine = [word];
|
||||
currentLineWidth = word.width;
|
||||
|
||||
// Verificar se ainda temos espaço
|
||||
if (y - lineHeight < marginBottom) {
|
||||
if (y - effectiveLineHeight < marginBottom) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -531,41 +555,37 @@ export class PdfService {
|
||||
|
||||
// Renderizar a última linha, se houver
|
||||
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;
|
||||
if (align === 'center') {
|
||||
|
||||
// Se for título ou alinhado ao centro/direita, ajustar posição
|
||||
if (effectiveAlign === 'center') {
|
||||
lineX = x + (maxWidth - currentLineWidth) / 2;
|
||||
} else if (align === 'right') {
|
||||
} else if (effectiveAlign === 'right') {
|
||||
lineX = x + maxWidth - currentLineWidth;
|
||||
}
|
||||
|
||||
// Desenhar a linha
|
||||
let posX = lineX;
|
||||
for (const item of currentLine) {
|
||||
const itemFontSize = isTitle ? effectiveFontSize : fontSize;
|
||||
|
||||
page.drawText(item.text, {
|
||||
x: posX,
|
||||
y: y,
|
||||
font: item.font,
|
||||
size: fontSize,
|
||||
size: itemFontSize,
|
||||
color
|
||||
});
|
||||
posX += item.width;
|
||||
}
|
||||
|
||||
y -= lineHeight;
|
||||
y -= effectiveLineHeight;
|
||||
}
|
||||
|
||||
// Se estiver em modo debug, desenhar uma caixa ao redor do texto
|
||||
if (debug) {
|
||||
page.drawRectangle({
|
||||
x,
|
||||
y: y + lineHeight,
|
||||
width: maxWidth,
|
||||
height: startY - y,
|
||||
borderColor: rgb(0.8, 0.8, 0.8),
|
||||
borderWidth: 0.5,
|
||||
opacity: 0.1
|
||||
});
|
||||
// Se for título, adicionar um espaço extra depois
|
||||
if (isTitle) {
|
||||
y -= lineHeight * 0.5;
|
||||
}
|
||||
|
||||
return y;
|
||||
@@ -581,22 +601,49 @@ export class PdfService {
|
||||
const paragrafos = texto.split(/\n{2,}/).map(p => {
|
||||
let paragraph = p.trim();
|
||||
if (!paragraph) return '';
|
||||
|
||||
// Extrair informações de formatação
|
||||
let align = 'left'; // padrão é justificado
|
||||
const alignMatch = paragraph.match(/§§ALIGN=(center|right|justify)§§/);
|
||||
let align = 'justify'; // Padrão agora é justificado para texto normal
|
||||
|
||||
// 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) {
|
||||
align = alignMatch[1];
|
||||
paragraph = paragraph.replace(/§§ALIGN=(center|right|justify)§§/, '');
|
||||
paragraph = paragraph.replace(/§§ALIGN=(center|right|justify|left)§§/, '');
|
||||
}
|
||||
|
||||
let indent = 0;
|
||||
const indentMatch = paragraph.match(/§§INDENT=(\d+)(pt|px|em)§§/);
|
||||
const indentMatch = paragraph.match(/§§INDENT=(\d+)(pt|px|em)?§§/);
|
||||
if (indentMatch) {
|
||||
indent = parseInt(indentMatch[1]);
|
||||
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 pageIndex = 0;
|
||||
console.log(`Gerando PDF com ${paragrafos.length} parágrafos`);
|
||||
@@ -621,18 +668,35 @@ export class PdfService {
|
||||
while (currentPar < paragrafos.length) {
|
||||
const paraObj = paragrafos[currentPar];
|
||||
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 isTitle = paraObj.isTitle || false;
|
||||
|
||||
let x = margens.left + indent;
|
||||
let parWidth = MAX_WIDTH - indent;
|
||||
|
||||
// Se o texto for muito curto, avance para o próximo parágrafo
|
||||
if (text.length < 2) {
|
||||
currentPar++;
|
||||
processedAnyParagraph = true;
|
||||
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(
|
||||
page,
|
||||
text,
|
||||
@@ -642,7 +706,7 @@ export class PdfService {
|
||||
fontBold,
|
||||
fontItalic,
|
||||
fontBoldItalic,
|
||||
FONT_SIZE,
|
||||
fontSizeToUse,
|
||||
rgb(0, 0, 0),
|
||||
align,
|
||||
parWidth,
|
||||
|
||||
Reference in new issue
Block a user