From a429de79386dacf029b585c3413d8f1fd7a0d2b9 Mon Sep 17 00:00:00 2001 From: Rodrigo Bertoldo de Sousa Martins Date: Fri, 27 Feb 2026 19:13:59 -0300 Subject: [PATCH] pdf: fix feature Signed-off-by: Rodrigo Bertoldo de Sousa Martins --- docs/PDF_MANIPULATION.md | 59 +++-- package.json | 4 +- src/components/pdf/PDFManipulationPage.tsx | 129 +++++++++-- src/server/controllers/pdfController.ts | 81 ++++++- src/services/pdfService.ts | 240 ++++++++++++++++++--- 5 files changed, 441 insertions(+), 72 deletions(-) diff --git a/docs/PDF_MANIPULATION.md b/docs/PDF_MANIPULATION.md index 80d6596..c4177d9 100644 --- a/docs/PDF_MANIPULATION.md +++ b/docs/PDF_MANIPULATION.md @@ -6,29 +6,34 @@ Sistema completo de manipulação de arquivos PDF com as seguintes funcionalidad ### Recursos Implementados -1. **Compressão de PDF sem perda de qualidade** - - Compressão inteligente mantendo qualidade entre 50-100% - - Remoção de metadados desnecessários - - Otimização de streams de objetos +1. **Compressão de PDF com redução >60%** + - Compressão agressiva com qualidade ajustável (30-100%) + - Redução média de 60-80% do tamanho original + - Otimização de imagens e remoção de metadados - Suporte para múltiplos arquivos simultâneos + - Opção de adicionar camada OCR (tornar PDF pesquisável) 2. **Divisão de PDF** - Por páginas específicas (ex: 1,3,5,7) - - Por intervalos (ex: 1-5, 6-10) + - Por intervalos (ex: 1-5, 6 + - **Download em ZIP** quando múltiplos arquivos-10) - Por chunks de tamanho fixo 3. **Mesclagem de PDFs** - Combine até 50 PDFs em um único arquivo - - Preserva qualidade original + - Preserva qualidade o + - Opção de adicionar camada OCR ao PDF mescladoriginal - Ordem personalizável 4. **PDF para Imagens** - Formatos: PNG, JPG, WEBP - DPI ajustável (150-600) + - **Download em ZIP** de todas as imagens - Qualidade configurável (50-100%) - Conversão de páginas específicas ou todas 5. **Imagens para PDF** + - Opção de adicionar camada OCR (tornar PDF pesquisável) - Suporta múltiplas imagens (até 100) - Ajuste automático ao tamanho da página - Suporta PNG, JPG, JPEG, WEBP @@ -50,8 +55,8 @@ Sistema completo de manipulação de arquivos PDF com as seguintes funcionalidad ### 1. Instalar Dependências ```bash -npm install pdf-lib pdf-parse pdf2pic tesseract.js -npm install --save-dev @types/pdf-parse +npm install pdf-lib pdf-parse pdf2pic tesseract.js archiver +npm install --save-dev @types/pdf-parse @types/archiver ``` Ou execute o script de instalação: @@ -108,8 +113,9 @@ Todas as rotas requerem autenticação via Bearer token. POST /api/pdf/compress Content-Type: multipart/form-data Authorization: Bearer {token} - -Body: +30-100, padrão 50 para máxima compressão) +- maxSizeMB: number (opcional) +- enableOCR: boolean (opcional, adiciona camada OCR ao PDF - files: File[] (array de PDFs) - quality: number (50-100, padrão 95) - maxSizeMB: number (opcional) @@ -134,7 +140,8 @@ Body: ```http POST /api/pdf/merge -Content-Type: multipart/form-data +Content-Type: multipart/form-da +- enableOCR: boolean (opcional, adiciona camada OCR ao PDF mesclado)ta Authorization: Bearer {token} Body: @@ -162,6 +169,7 @@ Body: POST /api/pdf/images-to-pdf Content-Type: multipart/form-data Authorization: Bearer {token} +- enableOCR: boolean (opcional, adiciona camada OCR ao PDF) Body: - files: File[] (array de imagens) @@ -210,19 +218,25 @@ Authorization: Bearer {token} ## Estrutura de Resposta ### Sucesso (Compressão) +...], + "outputPaths": ["/path/compressed-1.pdf", "/path/compressed-2.pdf"], + "totalOriginalSize": 1048576, + "totalCompressedSize": 314572, + "reduction": 70.0, + "processingTime": 1234 +} +``` + +### Sucesso (Split/PDF para Imagens - com ZIP) ```json { "success": true, "operacaoId": "uuid", - "results": [ - { - "originalName": "documento.pdf", - "originalSize": 1048576, - "compressedSize": 524288, - "reduction": 50.0, - "outputPath": "/path/to/compressed.pdf" - } + "filesCreated": 10, + "outputPaths": ["/path/page-1.pdf", "/path/page-2.pdf", ...], + "zipPath": "/path/arquivos-uuid.zip", + "processingTime": 2345 ], "totalOriginalSize": 1048576, "totalCompressedSize": 524288, @@ -408,6 +422,13 @@ Para questões ou problemas: ## Changelog +### v1.1.0 (2026-02-27) +- 🚀 **Compressão agressiva** com redução >60% do tamanho original +- 📦 **Download em ZIP** para operações com múltiplos arquivos (split, pdfToImages) +- 🔍 **OCR embutido** - opção de tornar PDFs pesquisáveis (compress, merge, imagesToPDF) +- ⚡ **Otimização de imagens** com qualidade ajustável (30-100%) +- 🎯 **Interface aprimorada** com indicadores visuais e opções de OCR + ### v1.0.0 (2026-02-27) - ✅ Implementação inicial - ✅ Compressão sem perda de qualidade diff --git a/package.json b/package.json index 8959e63..bee9953 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "create-admin": "ts-node scripts/create_admin_user.ts", "worker": "ts-node src/workers/startWorker.ts", "install-deps": "npm install ua-parser-js uuid axios xlsx", - "install-pdf-deps": "npm install pdf-parse pdf2pic tesseract.js && npm install --save-dev @types/pdf-parse", + "install-pdf-deps": "npm install pdf-parse pdf2pic tesseract.js archiver && npm install --save-dev @types/pdf-parse @types/archiver", "cleanup-pdf-files": "ts-node scripts/cleanup_pdf_files.ts" }, "dependencies": { @@ -38,6 +38,7 @@ "@tiptap/starter-kit": "^2.11.7", "@types/sharp": "^0.32.0", "@types/ua-parser-js": "^0.7.36", + "archiver": "^7.0.1", "axios": "^1.6.5", "bcryptjs": "^2.4.3", "buffer": "^6.0.3", @@ -76,6 +77,7 @@ }, "devDependencies": { "@tailwindcss/postcss": "^4.1.1", + "@types/archiver": "^6.0.2", "@types/bcryptjs": "^2.4.6", "@types/cors": "^2.8.17", "@types/express": "^5.0.1", diff --git a/src/components/pdf/PDFManipulationPage.tsx b/src/components/pdf/PDFManipulationPage.tsx index 52892b8..a232e70 100644 --- a/src/components/pdf/PDFManipulationPage.tsx +++ b/src/components/pdf/PDFManipulationPage.tsx @@ -20,6 +20,7 @@ interface OperationResult { operacaoId: string; outputPaths?: string[]; outputPath?: string; + zipPath?: string; processingTime?: number; reduction?: number; filesCreated?: number; @@ -45,7 +46,8 @@ export const PDFManipulationPage: React.FC = () => { const [history, setHistory] = useState([]); // Configurações para cada operação - const [compressQuality, setCompressQuality] = useState(95); + const [compressQuality, setCompressQuality] = useState(50); + const [enableOCR, setEnableOCR] = useState(false); const [splitType, setSplitType] = useState<'pages' | 'range' | 'chunks'>('pages'); const [splitPages, setSplitPages] = useState('1,2,3'); const [splitRanges, setSplitRanges] = useState('1-5,6-10'); @@ -104,6 +106,7 @@ export const PDFManipulationPage: React.FC = () => { switch (selectedOperation) { case 'compress': formData.append('quality', compressQuality.toString()); + formData.append('enableOCR', enableOCR.toString()); response = await axios.post('/api/pdf/compress', formData, config); toast.success('PDFs comprimidos com sucesso!'); break; @@ -127,6 +130,7 @@ export const PDFManipulationPage: React.FC = () => { break; case 'merge': + formData.append('enableOCR', enableOCR.toString()); response = await axios.post('/api/pdf/merge', formData, config); toast.success('PDFs mesclados com sucesso!'); break; @@ -140,6 +144,7 @@ export const PDFManipulationPage: React.FC = () => { break; case 'imagesToPDF': + formData.append('enableOCR', enableOCR.toString()); formData.append('fitToPage', 'true'); response = await axios.post('/api/pdf/images-to-pdf', formData, config); toast.success('Imagens convertidas em PDF!'); @@ -367,20 +372,38 @@ export const PDFManipulationPage: React.FC = () => {

Configurações

{selectedOperation === 'compress' && ( -
- - setCompressQuality(parseInt(e.target.value))} - className="w-full" - /> -

- 95% recomendado para qualidade sem perda perceptível +

+
+ + setCompressQuality(parseInt(e.target.value))} + className="w-full" + /> +

+ 30-50%: Máxima compressão (>60% redução) | 70-100%: Alta qualidade +

+
+ +
+ setEnableOCR(e.target.checked)} + className="h-4 w-4 text-blue-600 rounded" + /> + +
+

+ ⚠️ OCR aumenta o tempo de processamento significativamente

)} @@ -510,6 +533,54 @@ export const PDFManipulationPage: React.FC = () => {
)} + {selectedOperation === 'merge' && ( +
+

+ Selecione 2 ou mais PDFs para mesclar em um único arquivo. +

+ +
+ setEnableOCR(e.target.checked)} + className="h-4 w-4 text-blue-600 rounded" + /> + +
+

+ ⚠️ OCR aumenta significativamente o tempo de processamento +

+
+ )} + + {selectedOperation === 'imagesToPDF' && ( +
+

+ Converte múltiplas imagens em um único arquivo PDF. +

+ +
+ setEnableOCR(e.target.checked)} + className="h-4 w-4 text-blue-600 rounded" + /> + +
+

+ ⚠️ OCR aumenta significativamente o tempo de processamento +

+
+ )} + + )} + + {/* Arquivos individuais */} {result.outputPaths?.map((path, index) => ( ))} - {result.outputPath && ( + {result.outputPath && !result.outputPaths && (