tenta fix pdfservice.js
This commit is contained in:
1 parent
c485960759
commit
e21dea582c
1 file changed
+247
@@ -378,6 +378,253 @@ export class PdfService {
|
|||||||
return `§§ALIGN=${align}§§§§INDENT=${indent}§§${paragraph}`;
|
return `§§ALIGN=${align}§§§§INDENT=${indent}§§${paragraph}`;
|
||||||
}).filter(Boolean);
|
}).filter(Boolean);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renderiza um parágrafo com formatação inline (negrito, itálico, sublinhado)
|
||||||
|
*/
|
||||||
|
const renderInlineFormattedParagraph = (
|
||||||
|
page: any,
|
||||||
|
text: string,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
normalFont: any,
|
||||||
|
boldFont: any,
|
||||||
|
italicFont: any,
|
||||||
|
boldItalicFont: any,
|
||||||
|
fontSize: number,
|
||||||
|
color: any,
|
||||||
|
align: 'left' | 'center' | 'justify' = 'left',
|
||||||
|
maxWidth: number = MAX_WIDTH,
|
||||||
|
isContinuation: boolean = false,
|
||||||
|
marginTop: number = margens.top,
|
||||||
|
marginBottom: number = margens.bottom,
|
||||||
|
pageHeight: number = PAGE_HEIGHT
|
||||||
|
): number | null => {
|
||||||
|
// Se não houver espaço suficiente na página atual para pelo menos uma linha de texto
|
||||||
|
if (y < marginBottom + fontSize) {
|
||||||
|
return null; // Indica que precisa criar nova página
|
||||||
|
}
|
||||||
|
|
||||||
|
const words = text.split(/\s+/);
|
||||||
|
let currentLine = '';
|
||||||
|
let currentX = x;
|
||||||
|
let currentY = y;
|
||||||
|
const lineHeight = fontSize * 1.2;
|
||||||
|
|
||||||
|
// Processamento de formatação inline básica
|
||||||
|
let formattedChunks: { text: string, isItalic: boolean, isBold: boolean }[] = [];
|
||||||
|
|
||||||
|
// Pré-processamento do texto para detectar formatação
|
||||||
|
let remaining = text;
|
||||||
|
let inBold = false;
|
||||||
|
let inItalic = false;
|
||||||
|
let currentChunk = '';
|
||||||
|
|
||||||
|
while (remaining.length > 0) {
|
||||||
|
if (remaining.startsWith('<b>') || remaining.startsWith('<strong>')) {
|
||||||
|
// Adiciona o texto acumulado antes da tag
|
||||||
|
if (currentChunk) {
|
||||||
|
formattedChunks.push({ text: currentChunk, isItalic, isBold });
|
||||||
|
currentChunk = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
inBold = true;
|
||||||
|
remaining = remaining.replace(/^<(b|strong)>/, '');
|
||||||
|
}
|
||||||
|
else if (remaining.startsWith('</b>') || remaining.startsWith('</strong>')) {
|
||||||
|
// Adiciona o texto acumulado em negrito
|
||||||
|
if (currentChunk) {
|
||||||
|
formattedChunks.push({ text: currentChunk, isItalic, isBold: true });
|
||||||
|
currentChunk = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
inBold = false;
|
||||||
|
remaining = remaining.replace(/^<\/(b|strong)>/, '');
|
||||||
|
}
|
||||||
|
else if (remaining.startsWith('<i>') || remaining.startsWith('<em>')) {
|
||||||
|
// Adiciona o texto acumulado antes da tag
|
||||||
|
if (currentChunk) {
|
||||||
|
formattedChunks.push({ text: currentChunk, isItalic, isBold });
|
||||||
|
currentChunk = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
inItalic = true;
|
||||||
|
remaining = remaining.replace(/^<(i|em)>/, '');
|
||||||
|
}
|
||||||
|
else if (remaining.startsWith('</i>') || remaining.startsWith('</em>')) {
|
||||||
|
// Adiciona o texto acumulado em itálico
|
||||||
|
if (currentChunk) {
|
||||||
|
formattedChunks.push({ text: currentChunk, isItalic: true, isBold });
|
||||||
|
currentChunk = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
inItalic = false;
|
||||||
|
remaining = remaining.replace(/^<\/(i|em)>/, '');
|
||||||
|
}
|
||||||
|
else if (remaining.startsWith('<br>') || remaining.startsWith('<br/>') || remaining.startsWith('<br />')) {
|
||||||
|
// Adiciona o texto acumulado e então adiciona uma quebra de linha
|
||||||
|
if (currentChunk) {
|
||||||
|
formattedChunks.push({ text: currentChunk, isItalic, isBold });
|
||||||
|
currentChunk = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
formattedChunks.push({ text: '\n', isItalic: false, isBold: false });
|
||||||
|
remaining = remaining.replace(/^<br\s*\/?>/i, '');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Acumula caractere a caractere
|
||||||
|
currentChunk += remaining[0];
|
||||||
|
remaining = remaining.substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adiciona qualquer texto restante
|
||||||
|
if (currentChunk) {
|
||||||
|
formattedChunks.push({ text: currentChunk, isItalic, isBold });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agora temos o texto dividido em chunks com formatação
|
||||||
|
let lines: { chunks: { text: string, isItalic: boolean, isBold: boolean }[], width: number }[] = [{ chunks: [], width: 0 }];
|
||||||
|
let currentLineIndex = 0;
|
||||||
|
|
||||||
|
for (const chunk of formattedChunks) {
|
||||||
|
if (chunk.text === '\n') {
|
||||||
|
// Forçar quebra de linha
|
||||||
|
lines.push({ chunks: [], width: 0 });
|
||||||
|
currentLineIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const words = chunk.text.split(/\s+/);
|
||||||
|
|
||||||
|
for (let i = 0; i < words.length; i++) {
|
||||||
|
const word = words[i];
|
||||||
|
if (!word) continue;
|
||||||
|
|
||||||
|
const font = chunk.isBold && chunk.isItalic ? boldItalicFont :
|
||||||
|
chunk.isBold ? boldFont :
|
||||||
|
chunk.isItalic ? italicFont : normalFont;
|
||||||
|
|
||||||
|
const wordWidth = font.widthOfTextAtSize(word, fontSize);
|
||||||
|
const spaceWidth = font.widthOfTextAtSize(' ', fontSize);
|
||||||
|
|
||||||
|
// Verificar se precisamos adicionar espaço antes da palavra
|
||||||
|
let wordWithSpace = word;
|
||||||
|
let totalWidth = wordWidth;
|
||||||
|
|
||||||
|
// Adicionar espaço se não for a primeira palavra da linha e não estivermos após uma quebra forçada
|
||||||
|
if (lines[currentLineIndex].chunks.length > 0) {
|
||||||
|
wordWithSpace = ' ' + word;
|
||||||
|
totalWidth = wordWidth + spaceWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar se a palavra cabe na linha atual
|
||||||
|
if (lines[currentLineIndex].width + totalWidth <= maxWidth) {
|
||||||
|
// Adicionar à linha atual
|
||||||
|
lines[currentLineIndex].chunks.push({
|
||||||
|
text: wordWithSpace,
|
||||||
|
isItalic: chunk.isItalic,
|
||||||
|
isBold: chunk.isBold
|
||||||
|
});
|
||||||
|
lines[currentLineIndex].width += totalWidth;
|
||||||
|
} else {
|
||||||
|
// Criar nova linha
|
||||||
|
lines.push({
|
||||||
|
chunks: [{ text: word, isItalic: chunk.isItalic, isBold: chunk.isBold }],
|
||||||
|
width: wordWidth
|
||||||
|
});
|
||||||
|
currentLineIndex++;
|
||||||
|
|
||||||
|
// Verificar se temos espaço para mais uma linha
|
||||||
|
if (currentY - lineHeight < marginBottom) {
|
||||||
|
// Não há espaço suficiente para mais uma linha
|
||||||
|
return null; // Indica que precisa criar nova página
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desenhar as linhas com formatação
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
const line = lines[i];
|
||||||
|
currentY -= lineHeight;
|
||||||
|
|
||||||
|
// Verificar se temos espaço para esta linha
|
||||||
|
if (currentY < marginBottom) {
|
||||||
|
return null; // Indica que precisa criar nova página
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ajustar posição X baseada no alinhamento
|
||||||
|
let startX = x;
|
||||||
|
|
||||||
|
if (align === 'center') {
|
||||||
|
startX = x + (maxWidth - line.width) / 2;
|
||||||
|
} else if (align === 'justify' && i < lines.length - 1 && line.chunks.length > 1) {
|
||||||
|
// Justificar texto (exceto última linha do parágrafo)
|
||||||
|
let wordCount = 0;
|
||||||
|
let textWidth = 0;
|
||||||
|
|
||||||
|
// Contar palavras e determinar largura total do texto
|
||||||
|
for (const chunk of line.chunks) {
|
||||||
|
const text = chunk.text.trim();
|
||||||
|
if (text) {
|
||||||
|
wordCount += text.split(/\s+/).length;
|
||||||
|
const font = chunk.isBold && chunk.isItalic ? boldItalicFont :
|
||||||
|
chunk.isBold ? boldFont :
|
||||||
|
chunk.isItalic ? italicFont : normalFont;
|
||||||
|
textWidth += font.widthOfTextAtSize(text, fontSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calcular espaçamento extra entre palavras para justificar
|
||||||
|
const totalSpaces = wordCount - 1;
|
||||||
|
const spaceWidth = totalSpaces > 0 ? (maxWidth - textWidth) / totalSpaces : 0;
|
||||||
|
|
||||||
|
// Desenhar cada chunk com espaçamento justificado
|
||||||
|
let runningX = x;
|
||||||
|
for (const chunk of line.chunks) {
|
||||||
|
const font = chunk.isBold && chunk.isItalic ? boldItalicFont :
|
||||||
|
chunk.isBold ? boldFont :
|
||||||
|
chunk.isItalic ? italicFont : normalFont;
|
||||||
|
|
||||||
|
// Desenhar texto do chunk
|
||||||
|
page.drawText(chunk.text, {
|
||||||
|
x: runningX,
|
||||||
|
y: currentY,
|
||||||
|
size: fontSize,
|
||||||
|
font: font,
|
||||||
|
color: color
|
||||||
|
});
|
||||||
|
|
||||||
|
// Avançar posição X
|
||||||
|
runningX += font.widthOfTextAtSize(chunk.text, fontSize) + spaceWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pular para a próxima linha
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desenhar cada chunk
|
||||||
|
let runningX = startX;
|
||||||
|
for (const chunk of line.chunks) {
|
||||||
|
const font = chunk.isBold && chunk.isItalic ? boldItalicFont :
|
||||||
|
chunk.isBold ? boldFont :
|
||||||
|
chunk.isItalic ? italicFont : normalFont;
|
||||||
|
|
||||||
|
page.drawText(chunk.text, {
|
||||||
|
x: runningX,
|
||||||
|
y: currentY,
|
||||||
|
size: fontSize,
|
||||||
|
font: font,
|
||||||
|
color: color
|
||||||
|
});
|
||||||
|
|
||||||
|
runningX += font.widthOfTextAtSize(chunk.text, fontSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentY; // Retorna a posição Y final
|
||||||
|
};
|
||||||
|
|
||||||
let timbradoPdf: PDFDocument | null = null;
|
let timbradoPdf: PDFDocument | null = null;
|
||||||
let timbradoPageCount = 0;
|
let timbradoPageCount = 0;
|
||||||
let timbradoPages: any[] = [];
|
let timbradoPages: any[] = [];
|
||||||
|
|||||||
Reference in new issue
Block a user