tenta fix pdfservice.js
This commit is contained in:
1 parent
bbff8eb317
commit
20b2f0e3c9
1 file changed
+253
@@ -355,6 +355,259 @@ export class PdfService {
|
||||
.replace(/>/g, '>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderiza um parágrafo com formatação inline (negrito, itálico)
|
||||
* @param page - Página do PDF
|
||||
* @param text - Texto a ser renderizado
|
||||
* @param x - Posição X inicial
|
||||
* @param y - Posição Y inicial
|
||||
* @param regularFont - Fonte normal
|
||||
* @param boldFont - Fonte negrito
|
||||
* @param italicFont - Fonte itálica
|
||||
* @param boldItalicFont - Fonte negrito+itálica
|
||||
* @param fontSize - Tamanho da fonte
|
||||
* @param color - Cor do texto
|
||||
* @param align - Alinhamento do texto
|
||||
* @param maxWidth - Largura máxima
|
||||
* @param debug - Modo debug
|
||||
* @param marginTop - Margem superior
|
||||
* @param marginBottom - Margem inferior
|
||||
* @param pageHeight - Altura da página
|
||||
* @returns Nova posição Y ou null se não couber na página
|
||||
*/
|
||||
function renderInlineFormattedParagraph(
|
||||
page: any,
|
||||
text: string,
|
||||
x: number,
|
||||
y: number,
|
||||
regularFont: any,
|
||||
boldFont: any,
|
||||
italicFont: any,
|
||||
boldItalicFont: any,
|
||||
fontSize: number,
|
||||
color: any,
|
||||
align: 'left' | 'center' | 'right' | 'justify' = 'left',
|
||||
maxWidth: number,
|
||||
debug: boolean = false,
|
||||
marginTop: number,
|
||||
marginBottom: number,
|
||||
pageHeight: number
|
||||
): number | null {
|
||||
if (y < marginBottom || y > pageHeight - marginTop) {
|
||||
return null; // Fora dos limites da página
|
||||
}
|
||||
|
||||
// Considera a linha inteira
|
||||
const lineHeight = fontSize * 1.2;
|
||||
|
||||
// Separa o texto em segmentos de formatação
|
||||
const segments: { text: string; isBold: boolean; isItalic: boolean }[] = [];
|
||||
let remaining = text;
|
||||
|
||||
// Padrões para encontrar tags de formatação inline
|
||||
const boldStartPattern = /<b>/i;
|
||||
const boldEndPattern = /<\/b>/i;
|
||||
const italicStartPattern = /<i>/i;
|
||||
const italicEndPattern = /<\/i>/i;
|
||||
|
||||
let boldActive = false;
|
||||
let italicActive = false;
|
||||
|
||||
// Extrai segmentos formatados do texto
|
||||
while (remaining.length > 0) {
|
||||
const boldStartMatch = remaining.search(boldStartPattern);
|
||||
const boldEndMatch = remaining.search(boldEndPattern);
|
||||
const italicStartMatch = remaining.search(italicStartPattern);
|
||||
const italicEndMatch = remaining.search(italicEndPattern);
|
||||
|
||||
// Encontra a próxima tag
|
||||
let nextTagPos = -1;
|
||||
let nextTagType = '';
|
||||
|
||||
if (boldStartMatch !== -1 && (nextTagPos === -1 || boldStartMatch < nextTagPos)) {
|
||||
nextTagPos = boldStartMatch;
|
||||
nextTagType = 'boldStart';
|
||||
}
|
||||
|
||||
if (boldEndMatch !== -1 && (nextTagPos === -1 || boldEndMatch < nextTagPos)) {
|
||||
nextTagPos = boldEndMatch;
|
||||
nextTagType = 'boldEnd';
|
||||
}
|
||||
|
||||
if (italicStartMatch !== -1 && (nextTagPos === -1 || italicStartMatch < nextTagPos)) {
|
||||
nextTagPos = italicStartMatch;
|
||||
nextTagType = 'italicStart';
|
||||
}
|
||||
|
||||
if (italicEndMatch !== -1 && (nextTagPos === -1 || italicEndMatch < nextTagPos)) {
|
||||
nextTagPos = italicEndMatch;
|
||||
nextTagType = 'italicEnd';
|
||||
}
|
||||
|
||||
if (nextTagPos === -1) {
|
||||
// Não há mais tags, adicione o texto restante como um único segmento
|
||||
segments.push({
|
||||
text: remaining,
|
||||
isBold: boldActive,
|
||||
isItalic: italicActive,
|
||||
});
|
||||
break;
|
||||
} else {
|
||||
// Adiciona texto antes da tag
|
||||
if (nextTagPos > 0) {
|
||||
segments.push({
|
||||
text: remaining.substring(0, nextTagPos),
|
||||
isBold: boldActive,
|
||||
isItalic: italicActive,
|
||||
});
|
||||
}
|
||||
|
||||
// Atualiza o estado de formatação com base na tag
|
||||
if (nextTagType === 'boldStart') {
|
||||
boldActive = true;
|
||||
remaining = remaining.substring(nextTagPos + 3); // <b> tem 3 caracteres
|
||||
} else if (nextTagType === 'boldEnd') {
|
||||
boldActive = false;
|
||||
remaining = remaining.substring(nextTagPos + 4); // </b> tem 4 caracteres
|
||||
} else if (nextTagType === 'italicStart') {
|
||||
italicActive = true;
|
||||
remaining = remaining.substring(nextTagPos + 3); // <i> tem 3 caracteres
|
||||
} else if (nextTagType === 'italicEnd') {
|
||||
italicActive = false;
|
||||
remaining = remaining.substring(nextTagPos + 4); // </i> tem 4 caracteres
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Função para quebrar um texto em palavras
|
||||
const getWords = (text: string): string[] => {
|
||||
return text.split(/(\s+)/).filter(word => word.length > 0);
|
||||
};
|
||||
|
||||
// Calcular largura de texto
|
||||
const getTextWidth = (text: string, font: any): number => {
|
||||
return font.widthOfTextAtSize(text, fontSize);
|
||||
};
|
||||
|
||||
// Organiza palavras em linhas, respeitando a formatação
|
||||
const lines: {
|
||||
segments: { text: string; isBold: boolean; isItalic: boolean }[];
|
||||
width: number;
|
||||
}[] = [];
|
||||
|
||||
let currentLine: {
|
||||
segments: { text: string; isBold: boolean; isItalic: boolean }[];
|
||||
width: number;
|
||||
} = { segments: [], width: 0 };
|
||||
|
||||
for (const segment of segments) {
|
||||
const words = getWords(segment.text);
|
||||
|
||||
for (const word of words) {
|
||||
// Para espaços, apenas adicione-os diretamente
|
||||
if (/^\s+$/.test(word)) {
|
||||
if (currentLine.segments.length > 0) {
|
||||
const lastSegment = currentLine.segments[currentLine.segments.length - 1];
|
||||
|
||||
// Apenas adicione espaço se não for o primeiro segmento da linha
|
||||
lastSegment.text += word;
|
||||
const font = getFont(lastSegment.isBold, lastSegment.isItalic);
|
||||
currentLine.width += getTextWidth(word, font);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const font = getFont(segment.isBold, segment.isItalic);
|
||||
const wordWidth = getTextWidth(word, font);
|
||||
|
||||
// Verifica se a palavra cabe na linha atual
|
||||
if (currentLine.segments.length === 0 || currentLine.width + wordWidth <= maxWidth) {
|
||||
// Tenta adicionar à última parte do mesmo tipo de formatação
|
||||
if (
|
||||
currentLine.segments.length > 0 &&
|
||||
currentLine.segments[currentLine.segments.length - 1].isBold === segment.isBold &&
|
||||
currentLine.segments[currentLine.segments.length - 1].isItalic === segment.isItalic
|
||||
) {
|
||||
currentLine.segments[currentLine.segments.length - 1].text += word;
|
||||
} else {
|
||||
// Adiciona novo segmento
|
||||
currentLine.segments.push({
|
||||
text: word,
|
||||
isBold: segment.isBold,
|
||||
isItalic: segment.isItalic,
|
||||
});
|
||||
}
|
||||
|
||||
currentLine.width += wordWidth;
|
||||
} else {
|
||||
// A palavra não cabe, iniciar nova linha
|
||||
lines.push(currentLine);
|
||||
currentLine = {
|
||||
segments: [
|
||||
{
|
||||
text: word,
|
||||
isBold: segment.isBold,
|
||||
isItalic: segment.isItalic,
|
||||
},
|
||||
],
|
||||
width: wordWidth,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adiciona a última linha se não estiver vazia
|
||||
if (currentLine.segments.length > 0) {
|
||||
lines.push(currentLine);
|
||||
}
|
||||
|
||||
// Função auxiliar para obter a fonte correta
|
||||
function getFont(isBold: boolean, isItalic: boolean): any {
|
||||
if (isBold && isItalic) return boldItalicFont;
|
||||
if (isBold) return boldFont;
|
||||
if (isItalic) return italicFont;
|
||||
return regularFont;
|
||||
}
|
||||
|
||||
// Renderiza as linhas
|
||||
let currentY = y;
|
||||
|
||||
for (const line of lines) {
|
||||
// Se não couber mais na página, retorna null
|
||||
if (currentY - lineHeight < marginBottom) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let lineX = x;
|
||||
|
||||
// Ajusta a posição X com base no alinhamento
|
||||
if (align === 'center') {
|
||||
lineX = x + (maxWidth - line.width) / 2;
|
||||
} else if (align === 'right') {
|
||||
lineX = x + maxWidth - line.width;
|
||||
}
|
||||
|
||||
// Renderiza cada segmento da linha
|
||||
for (const segment of line.segments) {
|
||||
const font = getFont(segment.isBold, segment.isItalic);
|
||||
page.drawText(segment.text, {
|
||||
x: lineX,
|
||||
y: currentY,
|
||||
font,
|
||||
size: fontSize,
|
||||
color,
|
||||
});
|
||||
|
||||
lineX += getTextWidth(segment.text, font);
|
||||
}
|
||||
|
||||
// Move para a próxima linha
|
||||
currentY -= lineHeight;
|
||||
}
|
||||
|
||||
return currentY;
|
||||
}
|
||||
|
||||
// Processe o texto com as novas funções melhoradas
|
||||
const textoLimpo = stripUnsupportedTags(
|
||||
this.processarTemplate(conteudo, escritorio)
|
||||
|
||||
Reference in new issue
Block a user