Improve and fix ProvaService.ts

Signed-off-by: Rodrigo Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
rodrigo committed 2025-04-11 13:50:32 -03:00
1 parent b764c93106
commit c459997cd9
3 files changed
+106 -12

No files matched your search

+16 -1
View File
@@ -1,4 +1,5 @@
import { createHash } from 'crypto';
import sharp from 'sharp';
export class FileValidator {
async validateFile(buffer: Buffer, mimeType: string) {
@@ -18,7 +19,7 @@ export class FileValidator {
const allowedTypes = [
'application/pdf',
'image/jpeg',
'image/png', // Corrigido o tipo MIME para PNG
'image/png',
'image/gif',
'image.webp'
];
@@ -27,6 +28,20 @@ export class FileValidator {
return { valid: false, error: 'Tipo de arquivo não suportado. Use PDF, JPEG, PNG ou GIF.' };
}
// Verificação adicional para JPEG
if (mimeType === 'image/jpeg') {
try {
// Verificar se é um JPEG válido tentando processá-lo
await sharp(buffer).metadata();
} catch (jpegError) {
console.error('Erro ao validar JPEG:', jpegError);
return {
valid: false,
error: 'O arquivo JPEG parece estar corrompido. Tente salvar a imagem em um formato diferente e enviar novamente.'
};
}
}
return { valid: true };
} catch (error) {
console.error('Erro na validação de arquivo:', error);
+25 -1
View File
@@ -294,6 +294,18 @@ export class ProvaService {
private async processFileByType(file: Express.Multer.File) {
if (file.mimetype.startsWith('image/')) {
try {
// Para JPEGs, converter sempre para PNG para evitar problemas
if (file.mimetype === 'image/jpeg') {
return await sharp(file.buffer)
.png() // Converter para PNG é mais seguro
.resize(1200, 900, {
fit: 'inside',
withoutEnlargement: true
})
.toBuffer();
}
// Para outras imagens, manter o formato original
return await sharp(file.buffer)
.resize(1200, 900, {
fit: 'inside',
@@ -302,7 +314,19 @@ export class ProvaService {
.toBuffer();
} catch (error) {
console.error('Erro ao processar imagem com sharp:', error);
return file.buffer; // Fallback para o buffer original
// Se sharp falhar, tentar abordagem mais simples
try {
console.log('Tentando método alternativo de processamento de imagem...');
// Converter diretamente para PNG sem redimensionamento
return await sharp(file.buffer)
.png()
.toBuffer();
} catch (fallbackError) {
console.error('Falha total no processamento da imagem:', fallbackError);
// Em último caso, retornar o buffer original
return file.buffer;
}
}
}
return file.buffer;
+65 -10
View File
@@ -5,6 +5,7 @@ import ptBR from 'date-fns/locale/pt-BR';
import { prisma } from '../prismaClient';
import * as fs from 'fs/promises';
import * as path from 'path';
import sharp from 'sharp';
export class ReportGenerator {
async generateReport(data: {
@@ -175,7 +176,7 @@ export class ReportGenerator {
private async drawImagePage(page: any, data: any, helvetica: any, helveticaBold: any, pdfDoc: PDFDocument) {
const height = page.getHeight();
// Título
// Título e informações básicas (mantidos como estão)
page.drawText('Documento Original', {
x: 50,
y: height - 50,
@@ -184,7 +185,6 @@ export class ReportGenerator {
color: rgb(0, 0, 0.7)
});
// Informações básicas do arquivo
page.drawText(`Arquivo: ${data.file.originalname}`, {
x: 50,
y: height - 80,
@@ -192,7 +192,6 @@ export class ReportGenerator {
font: helvetica
});
// Formatação segura de data de registro
let timestampStr = 'Data não disponível';
try {
if (data.timestamp?.timestamp) {
@@ -212,7 +211,6 @@ export class ReportGenerator {
font: helvetica
});
// Data de modificação original
if (data.metadata?.fileInfo?.modifiedDate || data.metadata?.file_specific?.modified) {
const modifiedDate = new Date(data.metadata?.fileInfo?.modifiedDate || data.metadata?.file_specific?.modified);
if (!isNaN(modifiedDate.getTime())) {
@@ -225,15 +223,55 @@ export class ReportGenerator {
}
}
// Incorporar a imagem
// Incorporar a imagem com tratamento de erro mais robusto
try {
let image;
let imageBuffer = data.file.buffer;
// Se for JPEG, tentar pré-processar com sharp para garantir um formato válido
if (data.file.mimetype === 'image/jpeg') {
image = await pdfDoc.embedJpg(data.file.buffer);
} else if (data.file.mimetype === 'image/png') {
try {
// Converter para PNG primeiro - isso resolve muitos problemas de JPEGs corrompidos
const processedBuffer = await sharp(data.file.buffer)
.png() // Converter para PNG que é mais robusto
.toBuffer();
// Usar PNG em vez de JPEG para evitar o erro SOI
image = await pdfDoc.embedPng(processedBuffer);
console.log('JPEG convertido para PNG para evitar problemas de formatação');
} catch (sharpError) {
console.error('Erro ao processar JPEG com sharp:', sharpError);
// Se falhar, tentar abordagem alternativa
try {
// Tentar usar a versão processada se disponível
if (data.processedFile && data.processedFile.length > 0) {
image = await pdfDoc.embedPng(data.processedFile);
console.log('Usando versão processada da imagem');
} else {
throw new Error('Imagem processada não disponível');
}
} catch (fallbackError) {
console.error('Erro no fallback para imagem processada:', fallbackError);
throw new Error('Não foi possível processar a imagem JPEG');
}
}
}
// Para PNG ou outros formatos
else if (data.file.mimetype === 'image/png') {
image = await pdfDoc.embedPng(data.file.buffer);
} else {
image = await pdfDoc.embedPng(data.processedFile);
}
// Para todos os outros tipos, tentar converter para PNG
else {
try {
const pngBuffer = await sharp(data.file.buffer)
.png()
.toBuffer();
image = await pdfDoc.embedPng(pngBuffer);
} catch (conversionError) {
console.error('Erro ao converter imagem para PNG:', conversionError);
throw new Error('Formato de imagem não suportado');
}
}
// Calcular dimensões mantendo proporção
@@ -286,13 +324,30 @@ export class ReportGenerator {
});
} catch (imageError) {
console.error('Erro ao processar imagem:', imageError);
// Mensagem de erro mais informativa na página
page.drawText('Não foi possível exibir a imagem original.', {
x: 50,
y: height / 2,
y: height / 2 + 20,
size: 14,
font: helveticaBold,
color: rgb(0.8, 0, 0)
});
page.drawText(`Erro: ${imageError.message}`, {
x: 50,
y: height / 2 - 10,
size: 12,
font: helvetica,
color: rgb(0.7, 0, 0)
});
page.drawText('O documento foi validado, mas a visualização não está disponível.', {
x: 50,
y: height / 2 - 30,
size: 12,
font: helvetica
});
}
}