tenta fix pdfservice.js
This commit is contained in:
1 parent
fefc6ce434
commit
92239d0a99
1 file changed
+248
@@ -348,6 +348,254 @@ export class PdfService {
|
||||
.replace(/&#(\d+);/g, (m, code) => String.fromCharCode(code));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderiza um parágrafo com formatação inline (negrito, itálico, etc)
|
||||
* Retorna a nova posição Y após renderizar o parágrafo, ou null se precisar de nova página
|
||||
*/
|
||||
function renderInlineFormattedParagraph(
|
||||
page: any,
|
||||
text: string,
|
||||
x: number,
|
||||
y: number,
|
||||
font: any,
|
||||
fontBold: any,
|
||||
fontItalic: any,
|
||||
fontBoldItalic: any,
|
||||
fontSize: number,
|
||||
color: any,
|
||||
align: 'left' | 'center' | 'justify' = 'left',
|
||||
maxWidth: number,
|
||||
forceNewPage: boolean = false,
|
||||
marginTop: number,
|
||||
marginBottom: number,
|
||||
pageHeight: number
|
||||
): number | null {
|
||||
if (forceNewPage || y < marginBottom + fontSize * 2) {
|
||||
return null; // Indica necessidade de nova página
|
||||
}
|
||||
|
||||
// Dividir o texto em palavras preservando as tags
|
||||
const segments: { text: string; isBold: boolean; isItalic: boolean }[] = [];
|
||||
let currentSegment = { text: '', isBold: false, isItalic: false };
|
||||
|
||||
// Regex para encontrar tags <b>, </b>, <i>, </i>, <strong>, </strong>, <em>, </em>
|
||||
const regex = /<\/?(?:b|strong|i|em)>/gi;
|
||||
let lastIndex = 0;
|
||||
let match;
|
||||
|
||||
// Clone do texto para manipulação
|
||||
let textToProcess = text;
|
||||
|
||||
// Processar tags de indentação e alinhamento
|
||||
let indentPt = 0;
|
||||
let textAlign = align;
|
||||
|
||||
const indentMatch = textToProcess.match(/^§§INDENT=([0-9.]+(?:pt|px|em))§§/);
|
||||
if (indentMatch) {
|
||||
const indentValue = indentMatch[1];
|
||||
indentPt = parseInt(indentValue);
|
||||
if (isNaN(indentPt)) indentPt = 20; // Padrão: 20pt
|
||||
textToProcess = textToProcess.substring(indentMatch[0].length);
|
||||
x += indentPt;
|
||||
maxWidth -= indentPt;
|
||||
}
|
||||
|
||||
const alignMatch = textToProcess.match(/^§§ALIGN=(center|justify|right)§§/);
|
||||
if (alignMatch) {
|
||||
textAlign = alignMatch[1] as 'center' | 'justify' | 'left';
|
||||
textToProcess = textToProcess.substring(alignMatch[0].length);
|
||||
}
|
||||
|
||||
while ((match = regex.exec(textToProcess)) !== null) {
|
||||
// Adiciona texto entre as tags
|
||||
if (match.index > lastIndex) {
|
||||
currentSegment.text += textToProcess.substring(lastIndex, match.index);
|
||||
}
|
||||
|
||||
// Processa a tag
|
||||
const tag = match[0].toLowerCase();
|
||||
if (tag === '<b>' || tag === '<strong>') {
|
||||
// Finaliza o segmento atual se não vazio
|
||||
if (currentSegment.text) {
|
||||
segments.push({ ...currentSegment });
|
||||
currentSegment.text = '';
|
||||
}
|
||||
currentSegment.isBold = true;
|
||||
} else if (tag === '</b>' || tag === '</strong>') {
|
||||
// Finaliza o segmento atual se não vazio
|
||||
if (currentSegment.text) {
|
||||
segments.push({ ...currentSegment });
|
||||
currentSegment.text = '';
|
||||
}
|
||||
currentSegment.isBold = false;
|
||||
} else if (tag === '<i>' || tag === '<em>') {
|
||||
// Finaliza o segmento atual se não vazio
|
||||
if (currentSegment.text) {
|
||||
segments.push({ ...currentSegment });
|
||||
currentSegment.text = '';
|
||||
}
|
||||
currentSegment.isItalic = true;
|
||||
} else if (tag === '</i>' || tag === '</em>') {
|
||||
// Finaliza o segmento atual se não vazio
|
||||
if (currentSegment.text) {
|
||||
segments.push({ ...currentSegment });
|
||||
currentSegment.text = '';
|
||||
}
|
||||
currentSegment.isItalic = false;
|
||||
}
|
||||
|
||||
lastIndex = match.index + match[0].length;
|
||||
}
|
||||
|
||||
// Adiciona o texto restante
|
||||
if (lastIndex < textToProcess.length) {
|
||||
currentSegment.text += textToProcess.substring(lastIndex);
|
||||
}
|
||||
|
||||
// Adiciona o último segmento se não estiver vazio
|
||||
if (currentSegment.text) {
|
||||
segments.push(currentSegment);
|
||||
}
|
||||
|
||||
// Processa cada segmento e divide em linhas
|
||||
const lines: { segments: { text: string; isBold: boolean; isItalic: boolean; width: number; font: any }[]; totalWidth: number }[] = [];
|
||||
let currentLine: { segments: { text: string; isBold: boolean; isItalic: boolean; width: number; font: any }[]; totalWidth: number } = {
|
||||
segments: [],
|
||||
totalWidth: 0
|
||||
};
|
||||
|
||||
for (const segment of segments) {
|
||||
const words = segment.text.split(/\s+/);
|
||||
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
const word = words[i];
|
||||
if (!word) continue;
|
||||
|
||||
// Adiciona espaço antes se não for a primeira palavra da linha
|
||||
const wordWithSpace = currentLine.segments.length > 0 ? ' ' + word : word;
|
||||
// Seleciona a fonte correta com base na formatação
|
||||
let segmentFont;
|
||||
if (segment.isBold && segment.isItalic) {
|
||||
segmentFont = fontBoldItalic;
|
||||
} else if (segment.isBold) {
|
||||
segmentFont = fontBold;
|
||||
} else if (segment.isItalic) {
|
||||
segmentFont = fontItalic;
|
||||
} else {
|
||||
segmentFont = font;
|
||||
}
|
||||
|
||||
const wordWidth = segmentFont.widthOfTextAtSize(wordWithSpace, fontSize);
|
||||
|
||||
// Se a palavra cabe na linha atual
|
||||
if (currentLine.totalWidth + wordWidth <= maxWidth) {
|
||||
currentLine.segments.push({
|
||||
text: wordWithSpace,
|
||||
isBold: segment.isBold,
|
||||
isItalic: segment.isItalic,
|
||||
width: wordWidth,
|
||||
font: segmentFont
|
||||
});
|
||||
currentLine.totalWidth += wordWidth;
|
||||
} else {
|
||||
// Se a linha atual não está vazia, finalize-a
|
||||
if (currentLine.segments.length > 0) {
|
||||
lines.push(currentLine);
|
||||
currentLine = { segments: [], totalWidth: 0 };
|
||||
}
|
||||
|
||||
// Se a palavra for maior que a largura máxima, divida-a
|
||||
if (segmentFont.widthOfTextAtSize(word, fontSize) > maxWidth) {
|
||||
// Implementação simplificada: apenas adiciona a palavra muito longa
|
||||
// em uma nova linha, mesmo que ultrapasse a largura máxima
|
||||
currentLine.segments.push({
|
||||
text: word,
|
||||
isBold: segment.isBold,
|
||||
isItalic: segment.isItalic,
|
||||
width: segmentFont.widthOfTextAtSize(word, fontSize),
|
||||
font: segmentFont
|
||||
});
|
||||
currentLine.totalWidth = segmentFont.widthOfTextAtSize(word, fontSize);
|
||||
lines.push(currentLine);
|
||||
currentLine = { segments: [], totalWidth: 0 };
|
||||
} else {
|
||||
// Caso contrário, adicione a palavra na nova linha
|
||||
currentLine.segments.push({
|
||||
text: word,
|
||||
isBold: segment.isBold,
|
||||
isItalic: segment.isItalic,
|
||||
width: segmentFont.widthOfTextAtSize(word, fontSize),
|
||||
font: segmentFont
|
||||
});
|
||||
currentLine.totalWidth = segmentFont.widthOfTextAtSize(word, fontSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adiciona a última linha se não estiver vazia
|
||||
if (currentLine.segments.length > 0) {
|
||||
lines.push(currentLine);
|
||||
}
|
||||
|
||||
// Se não houver linhas após o processamento, retorne a posição Y atual
|
||||
if (lines.length === 0) {
|
||||
return y;
|
||||
}
|
||||
|
||||
// Verifica se todas as linhas cabem na página atual
|
||||
const totalHeight = lines.length * (fontSize * 1.2);
|
||||
if (y - totalHeight < marginBottom) {
|
||||
return null; // Precisa de uma nova página
|
||||
}
|
||||
|
||||
// Renderiza as linhas
|
||||
let currentY = y;
|
||||
const lineHeight = fontSize * 1.2;
|
||||
|
||||
for (const line of lines) {
|
||||
let currentX = x;
|
||||
|
||||
// Ajusta o X inicial com base no alinhamento
|
||||
if (textAlign === 'center') {
|
||||
currentX = x + (maxWidth - line.totalWidth) / 2;
|
||||
} else if (textAlign === 'justify' && line !== lines[lines.length - 1] && line.segments.length > 1) {
|
||||
// Para justificado, ajusta apenas linhas que não sejam a última e tenham mais de um segmento
|
||||
const extraSpace = maxWidth - line.totalWidth;
|
||||
const spaceBetweenSegments = extraSpace / (line.segments.length - 1);
|
||||
|
||||
for (const segment of line.segments) {
|
||||
const font = segment.font;
|
||||
page.drawText(segment.text, {
|
||||
x: currentX,
|
||||
y: currentY,
|
||||
size: fontSize,
|
||||
font: font,
|
||||
color: color
|
||||
});
|
||||
currentX += segment.width + spaceBetweenSegments;
|
||||
}
|
||||
} else {
|
||||
// Para alinhamento à esquerda ou a última linha de justificado
|
||||
for (const segment of line.segments) {
|
||||
const font = segment.font;
|
||||
page.drawText(segment.text, {
|
||||
x: currentX,
|
||||
y: currentY,
|
||||
size: fontSize,
|
||||
font: font,
|
||||
color: color
|
||||
});
|
||||
currentX += segment.width;
|
||||
}
|
||||
}
|
||||
|
||||
currentY -= lineHeight;
|
||||
}
|
||||
|
||||
return currentY;
|
||||
}
|
||||
|
||||
const texto = decodeHtmlEntities(
|
||||
stripUnsupportedTags(
|
||||
this.processarTemplate(conteudo, escritorio)
|
||||
|
||||
Reference in new issue
Block a user