Files
advx/docs/PDF_MANIPULATION.md
T
rodrigo db7b832044 pdf: fix feature
Signed-off-by: Rodrigo Bertoldo de Sousa Martins <rodrigo.sousa.577@gmail.com>
2026-02-27 20:15:07 -03:00

16 KiB

Funcionalidade de Manipulação de PDFs

Visão Geral

Sistema completo de manipulação de arquivos PDF com as seguintes funcionalidades:

Recursos Implementados

  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
    • 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 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
  6. OCR (Reconhecimento Ótico de Caracteres)

    • Extração de texto de PDFs escaneados
    • Suporte para Português, Inglês e Espanhol
    • Retorna confiança da extração
    • Processamento por página
  7. Informações do PDF

    • Número de páginas
    • Tamanho do arquivo
    • Metadados (título, autor, criador, etc.)
    • Datas de criação e modificação

Instalação

1. Instalar Dependências

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:

npm run install-pdf-deps

2. Instalar GraphicsMagick (Requerido para PDF → Imagens)

Docker: O GraphicsMagick já está incluído no Dockerfile. Rebuild a imagem se necessário:

docker-compose down
docker-compose build --no-cache
docker-compose up -d

Local (desenvolvimento):

Ubuntu/Debian:

sudo apt-get update
sudo apt-get install graphicsmagick

MacOS:

brew install graphicsmagick

Windows:

Verifique a instalação:

gm version

3. Executar Migration do Banco de Dados

npm run prisma:migrate

Ou manualmente:

npx prisma migrate dev --name add_operacoes_pdf

4. Gerar Cliente Prisma

npm run prisma:generate

5. Criar Diretórios Necessários

Os diretórios serão criados automaticamente na primeira execução, mas você pode criá-los manualmente:

mkdir -p storage/temp/pdf-ops
mkdir -p storage/pdf-output
mkdir -p storage/temp/uploads

Uso

Frontend

Acesse a página de manipulação de PDFs através da rota:

/pdf

API Endpoints

Todas as rotas requerem autenticação via Bearer token.

1. Comprimir PDF

POST /api/pdf/compress
Content-Type: multipart/form-data
Authorization: Bearer {token}
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)

2. Dividir PDF

POST /api/pdf/split
Content-Type: multipart/form-data
Authorization: Bearer {token}

Body:
- files: File (único PDF)
- splitType: 'pages' | 'range' | 'chunks'
- pages: string (ex: "1,2,3") - para splitType='pages'
- ranges: string (ex: "1-5,6-10") - para splitType='range'
- chunkSize: number - para splitType='chunks'

3. Mesclar PDFs

POST /api/pdf/merge
Content-Type: multipart/form-da
- enableOCR: boolean (opcional, adiciona camada OCR ao PDF mesclado)ta
Authorization: Bearer {token}

Body:
- files: File[] (mínimo 2 PDFs)

4. PDF para Imagens

POST /api/pdf/pdf-to-images
Content-Type: multipart/form-data
Authorization: Bearer {token}

Body:
- files: File (único PDF)
- format: 'png' | 'jpg' | 'webp' (padrão: png)
- quality: number (50-100, padrão: 95)
- density: number (DPI, 150-600, padrão: 300)
- pages: string (opcional, ex: "[1,2,3]" ou "all")

5. Imagens para PDF

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)
- fitToPage: boolean (padrão: true)
- pageSize: string (opcional, JSON: {"width":595,"height":842})

6. OCR

POST /api/pdf/ocr
Content-Type: multipart/form-data
Authorization: Bearer {token}

Body:
- files: File (único PDF)
- language: string ('por' | 'eng' | 'spa', padrão: 'por')
- pages: string (opcional, ex: "[1,2]" ou "all")

7. Informações do PDF

POST /api/pdf/info
Content-Type: multipart/form-data
Authorization: Bearer {token}

Body:
- files: File (único PDF)

8. Histórico de Operações

GET /api/pdf/history?page=1&limit=20
Authorization: Bearer {token}

9. Download de Arquivo Processado

GET /api/pdf/download/:operacaoId/:fileIndex
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",
  "filesCreated": 10,
  "outputPaths": ["/path/page-1.pdf", "/path/page-2.pdf", ...],
  "zipPath": "/path/arquivos-uuid.zip",
  "processingTime": 2345
  ],
  "totalOriginalSize": 1048576,
  "totalCompressedSize": 524288,
  "totalReduction": 50.0,
  "processingTime": 1234
}

Sucesso (OCR)

{
  "success": true,
  "operacaoId": "uuid",
  "result": {
    "text": "Texto extraído completo...",
    "confidence": 95.5,
    "pages": [
      {
        "pageNumber": 1,
        "text": "Texto da página 1...",
        "confidence": 96.2
      }
    ]
  },
  "processingTime": 5678
}

Erro

{
  "error": "Falha ao processar arquivo",
  "message": "Detalhes específicos do erro"
}

Modelo de Dados

OperacaoPDF

interface OperacaoPDF {
  id: string;
  tipoOperacao: 'COMPRIMIR' | 'DIVIDIR' | 'MESCLAR' | 'PDF_PARA_IMAGEM' | 'IMAGEM_PARA_PDF' | 'OCR';
  status: 'PROCESSANDO' | 'CONCLUIDO' | 'ERRO';
  usuarioId: string;
  arquivosOriginais: string[];
  arquivosResultado: string[];
  tamanhoOriginal: bigint;
  tamanhoResultado: bigint | null;
  parametros: any;
  mensagemErro: string | null;
  detalhesOCR: any | null;
  tempoProcessamento: number | null;
  criadoEm: Date;
  atualizadoEm: Date;
}

Segurança

  • ✅ Autenticação obrigatória em todas as rotas
  • ✅ Validação de tipos de arquivo (apenas PDF e imagens)
  • ✅ Limite de tamanho de arquivo (100MB por arquivo)
  • ✅ Limite de quantidade de arquivos por operação
  • ✅ Sanitização de nomes de arquivo
  • ✅ Isolamento de arquivos por operação
  • ✅ Limpeza automática de arquivos temporários

Performance

  • ✅ Processamento assíncrono
  • ✅ Otimização de memória com streams
  • ✅ Compressão sem perda de qualidade perceptível
  • ✅ Cache de workers de OCR
  • ✅ Índices no banco de dados para consultas rápidas
  • ✅ Limpeza automática de arquivos antigos

Tratamento de Erros

Todos os erros são:

  • Logados no console do servidor
  • Registrados no banco de dados (tabela operacoes_pdf)
  • Retornados ao cliente com mensagens descritivas
  • Capturados por try-catch em todas as operações

Limitações

  • Tamanho máximo por arquivo: 100MB
  • Máximo de arquivos para compressão: 10
  • Máximo de arquivos para mesclagem: 50
  • Máximo de imagens para conversão em PDF: 100
  • Arquivos processados são mantidos por 24 horas
  • Timeout de operações: 10 minutos (600 segundos)
    • Operações longas (OCR, compressão de PDFs grandes) podem levar alguns minutos
    • O sistema está configurado para suportar até 10 minutos de processamento

Manutenção

Limpeza de Arquivos Antigos

Execute periodicamente (recomendado: diariamente via cron):

import { PDFService } from './src/services/pdfService';

// Remove arquivos com mais de 24 horas
await PDFService.cleanupOldFiles(24);

Monitoramento

Consulte a tabela operacoes_pdf para:

  • Estatísticas de uso
  • Taxa de erro
  • Tempo médio de processamento
  • Operações mais utilizadas
-- Operações por tipo
SELECT "tipoOperacao", COUNT(*) as total
FROM operacoes_pdf
GROUP BY "tipoOperacao"
ORDER BY total DESC;

-- Taxa de sucesso
SELECT 
  status,
  COUNT(*) as total,
  ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 2) as percentual
FROM operacoes_pdf
GROUP BY status;

-- Tempo médio por operação
SELECT 
  "tipoOperacao",
  AVG("tempoProcessamento") as tempo_medio_ms,
  MIN("tempoProcessamento") as tempo_min_ms,
  MAX("tempoProcessamento") as tempo_max_ms
FROM operacoes_pdf
WHERE status = 'CONCLUIDO'
GROUP BY "tipoOperacao";

Troubleshooting

Erro: "Could not execute GraphicsMagick/ImageMagick"

Sintoma: Erro ao converter PDF para imagens:

Error: Could not execute GraphicsMagick/ImageMagick: gm "convert" ... 
this most likely means the gm/convert binaries can't be found

Causa: GraphicsMagick não está instalado no sistema/container.

Solução:

Docker:

# Rebuild a imagem Docker com GraphicsMagick incluído
docker-compose down
docker-compose build --no-cache
docker-compose up -d

Local:

# Ubuntu/Debian
sudo apt-get install graphicsmagick

# MacOS
brew install graphicsmagick

# Verifique a instalação
gm version

Erro 504: Gateway Timeout (Timeout ao processar PDF)

Sintoma: Operação de compressão ou OCR retorna erro 504 após ~60 segundos:

Failed to load resource: the server responded with a status of 504

Causa: Operações de PDF (especialmente compressão e OCR) podem levar vários minutos para arquivos grandes. O timeout padrão de 60 segundos é insuficiente.

Solução: As configurações de timeout foram aumentadas para 10 minutos em:

  • ✅ Express server (src/server/index.ts)
  • ✅ Vite proxy (vite.config.ts)
  • ✅ Axios frontend (PDFManipulationPage.tsx)

Se ainda ocorrer timeout:

  1. Verifique se rebuild foi feito após as alterações
  2. Reduza o tamanho do arquivo ou qualidade
  3. Processe menos arquivos por vez
  4. Para PDFs muito grandes (>50MB), considere fazer upload em partes

Dicas de performance:

  • Compressão: Use qualidade 50-70 para PDFs grandes
  • OCR: Processe apenas páginas necessárias, não o PDF inteiro
  • Split: Use chunks menores para PDFs com muitas páginas

Erro: ENOENT ao deletar arquivos do histórico

Sintoma: Erro ao limpar histórico:

Error: ENOENT: no such file or directory, unlink '/path/to/file.pdf'

Causa: Tentativa de deletar arquivos que não existem mais (já foram removidos manualmente ou por outro processo).

Solução: ✅ Corrigido automaticamente - O sistema agora verifica se o arquivo existe antes de tentar deletar e ignora erros ENOENT silenciosamente.

Erro: Imagens baixadas com extensão .pdf (ou sem extensão correta)

Sintoma: Ao baixar imagens geradas pela conversão PDF→Imagens, os arquivos vêm com extensão .pdf ou precisam ser renomeados para .png/.jpg para serem visualizados.

Causa: O servidor não estava enviando o Content-Type correto no header HTTP, OU o frontend estava ignorando os headers do servidor e forçando o nome como .pdf.

Solução: ✅ Corrigido automaticamente - O sistema agora:

Backend:

  • Detecta automaticamente o tipo MIME correto baseado na extensão (.png, .jpg, .webp, .zip, .pdf)
  • Define headers HTTP apropriados (Content-Type e Content-Disposition)
  • Garante que o nome do arquivo no download mantém a extensão original
  • Adiciona logs de debug para facilitar troubleshooting

Frontend:

  • Extrai o nome do arquivo do header Content-Disposition enviado pelo servidor
  • Usa o Content-Type correto do servidor ao criar o Blob para download
  • Não força mais extensão .pdf em todos os downloads
  • Adiciona log no console do browser: Download frontend: arquivo.png (image/png)
  • Libera memória do blob URL após download

Se ainda ocorrer o problema:

  1. Abra o Console do DevTools (F12) e verifique os logs de download
  2. Verifique se os headers estão sendo recebidos corretamente na aba Network
  3. Limpe o cache do browser (Ctrl+Shift+Del)
  4. Teste em uma aba anônima/privada
  5. Use a opção de Download ZIP que sempre funciona corretamente

Erro: "Tesseract worker failed"

Solução: Certifique-se de que o Tesseract está instalado corretamente:

npm install tesseract.js --force

Erro: "Cannot find module 'sharp'"

Solução: Reinstale o Sharp com rebuild:

npm uninstall sharp
npm install sharp
npm rebuild sharp

Erro: "ENOSPC: no space left on device"

Solução: Aumente o espaço em disco ou execute a limpeza:

npm run cleanup-pdf-files

Performance lenta no OCR

Solução: Reduza o DPI ou processe menos páginas por vez.

Suporte

Para questões ou problemas:

  1. Verifique os logs do servidor
  2. Consulte a tabela operacoes_pdf para detalhes do erro
  3. Verifique se os diretórios de storage têm permissões corretas
  4. Certifique-se de que todas as dependências estão instaladas

Changelog

v1.1.2 (2026-02-27)

  • 🔧 Correção DEFINITIVA de downloads - Arquivos agora baixam com nome e extensão corretos
    • Backend: Detecta tipo MIME e define headers HTTP apropriados (Content-Type, Content-Disposition)
    • Frontend: Extrai nome do arquivo e tipo MIME dos headers da resposta
    • Frontend: Não força mais .pdf em todos os downloads - usa nome real do servidor
    • Frontend: Cria Blob com Content-Type correto preservando o formato original
    • Adiciona logs de debug no backend e frontend para troubleshooting
    • Suporta formato 'jpeg' além de 'jpg'
    • Fallback para PNG em formatos não suportados
    • Libera memória de blob URLs após download
  • 🐛 Melhorias no pdfToImages - Adicionado suporte para 'jpeg' e fallback para formatos inválidos

v1.1.1 (2026-02-27)

  • 🔧 Correção de timeout 504 - Aumentado timeout para 10 minutos em todas as camadas
    • Express server: 600 segundos
    • Vite proxy: 600 segundos
    • Axios frontend: 600 segundos
  • 🗑️ Correção ENOENT - Sistema agora ignora arquivos já deletados ao limpar histórico
  • 📋 Gerenciamento de histórico - Botões para limpar histórico completo ou arquivos antigos
  • 🐛 Melhorias de estabilidade - Verificação de existência de arquivos antes de deletar
  • 📚 Documentação expandida - Adicionado troubleshooting completo

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
  • ✅ Divisão de PDFs
  • ✅ Mesclagem de PDFs
  • ✅ Conversão PDF para imagens
  • ✅ Conversão de imagens para PDF
  • ✅ OCR com Tesseract
  • ✅ Histórico de operações
  • ✅ Interface React completa
  • ✅ Validação e segurança