Tenho uma pasta contendo 600 arquivos PDF , e cada PDF tem 20 páginas . Preciso converter cada página em um PNG de alta qualidade o mais rápido possível.
Eu escrevi o seguinte script para esta tarefa:
import os
import multiprocessing
import fitz # PyMuPDF
from PIL import Image
def process_pdf(pdf_path, output_folder):
try:
pdf_name = os.path.splitext(os.path.basename(pdf_path))[0]
pdf_output_folder = os.path.join(output_folder, pdf_name)
os.makedirs(pdf_output_folder, exist_ok=True)
doc = fitz.open(pdf_path)
for i, page in enumerate(doc):
pix = page.get_pixmap(dpi=850) # Render page at high DPI
img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
img_path = os.path.join(pdf_output_folder, f"page_{i+1}.png")
img.save(img_path, "PNG")
print(f"Processed: {pdf_path}")
except Exception as e:
print(f"Error processing {pdf_path}: {e}")
def main():
input_folder = r"E:\Desktop\New folder (5)\New folder (4)"
output_folder = r"E:\Desktop\New folder (5)\New folder (5)"
pdf_files = [os.path.join(input_folder, f) for f in os.listdir(input_folder) if f.lower().endswith(".pdf")]
with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
pool.starmap(process_pdf, [(pdf, output_folder) for pdf in pdf_files])
print("All PDFs processed successfully!")
if __name__ == "__main__":
main()
Emitir:
Este script é muito lento , especialmente ao processar um grande número de PDFs. Tentei as seguintes otimizações, mas elas não melhoraram a velocidade significativamente :
- DPI reduzido ligeiramente – Reduzido de 1200 DPI para 850 DPI . (Eu também testei 600-800 DPI.)
- Habilitado
alpha=False
emget_pixmap()
– Uso de memória reduzido. - Usado
ThreadPoolExecutor
em vez demultiprocessing.Pool
– Nenhuma melhoria significativa. - Compressão PNG reduzida – Definida
optimize=False
ao salvar imagens. - Imagens convertidas em tons de cinza – Ajudou um pouco, mas preciso de imagens coloridas para minha tarefa.
Possíveis soluções que considerei:
- Processamento paralelo de páginas em vez de arquivos – Em vez de processar um arquivo por vez, processe cada página em paralelo para utilizar totalmente os núcleos da CPU.
- Use
ProcessPoolExecutor
em vez deThreadPoolExecutor
– Como a renderização exige muita CPU , o multiprocessamento deve ser melhor. - Use JPEG em vez de PNG – JPEG é muito mais rápido de salvar e ocupa menos espaço de armazenamento, mas preciso de imagens de alta qualidade .
- Reduzir DPI para 500-600 – Oferece um equilíbrio entre velocidade e qualidade .
- Grave arquivos em lote em vez de salvar um por um – Reduz a sobrecarga de E/S.
Com o que preciso de ajuda:
- Como posso acelerar significativamente essa conversão de PDF para PNG mantendo alta qualidade de imagem?
- Existem bibliotecas ou técnicas melhores que eu deva usar?
- Existe uma maneira de utilizar totalmente os núcleos da CPU de forma eficiente?
Qualquer sugestão será muito apreciada!
Este processo não só é altamente intensivo em CPU, como também requer RAM significativa. No MacOS (M2), rodar em apenas 4 CPUs (ou seja, metade do número disponível) melhora o desempenho significativamente. Mesmo assim, o tempo médio para processar uma página é de ~1,3s
Para este teste, tenho 80 PDFs. Um máximo de 20 páginas é processado por PDF.
Aqui está o teste:
Saída excluindo nomes de arquivos:
Average duration per page = 1.2667s
Resumo:
Renderizar a 850 dpi com fitz / PyMuPDF é lento. Reduzir a renderização para, por exemplo, 300 dpi diminuiu o tempo por página para ~0,17 s
Instalar a ferramenta Ghost Script
Você pode baixar o software de conversão de PDF para imagem do Ghost Script neste site-> https://ghostscript.com/releases/gsdnld.html
Instale o software no seu sistema.
Instalar Ghost Script Python Wrapper
Você então precisa de uma ferramenta python para chamar as funções de conversão de PDF para imagem no SDK que instalamos na etapa anterior, chamado ghostscript . Execute o comando pip install ghostscript
Use o seguinte código Python para converter
A conversão de PDF é naturalmente lenta, então use apenas arquivos de 9 x 20 páginas (pois a vida é muito curta). Alguns minutos devem ser suficientes para cronometrar 9 arquivos, pois têm apenas 180 páginas.
Esses são tempos CLI executáveis brutos sem nenhuma sobrecarga do Python. Os resultados sempre serão diferentes dependendo do único processador gráfico, então uma estação de trabalho dedicada com GPUs multithread terá um desempenho melhor que meus valores. Portanto, oferecido apenas para comparar os mesmos PDFs de 20 KB (diagramas com texto compactado aproximadamente para 1 KB por página) como um teste relativo "exe Vs exe".
Aqui estão alguns tempos baseados em impressões em PDF para dispositivos de imagem/papel, que são tradicionalmente considerados de alta velocidade, com 60 páginas por minuto.
Para comparação, eu uso Artifex GS e MuPDF. Vamos mostrar os tempos de leitura final do MuPDF, pois eles são mais fáceis de relatar e mais rápidos também.
As páginas 1 e 19 são, na verdade, conteúdos bem similares. No entanto, ler um PDF compactado leva tempos variáveis. Aqui, cerca de 1/2 segundo a 1 segundo inteiro, e isso se deve à necessidade de percorrer para frente e para trás entre (neste PDF de 20 páginas) quase 140 objetos compactados discretos. O PDF de página única deve ser mais rápido, sem significativamente menos "vai e vem". PDFs menores com conteúdo descompactado são sempre melhores do que imagens grandes compactadas.
Então, quais são as restrições de tempo e volumes retangulares envolvidos?
Portanto, o Mu PDF deve reduzir em uma hora o tempo gasto.
E quanto a outras ferramentas comuns usadas em aplicativos Python? Os arquivos são naturalmente mais lentos, pois geralmente são significativamente compactados muito mais (cerca de -40% do tamanho do MuPDF).
Muitas sugestões dizem para usar Multi-threading e acima dos tempos do MuPDF foram baseados em 4 Threads. E se mudarmos essa configuração?
Portanto, sem compartilhar o tempo entre 3 ou mais threads, os tempos de renderização sequencial podem ser melhorados usando 2 threads neste dispositivo de 2 núcleos.
Com um pouco mais de ajustes, podemos chegar a
180 pages = 64.54 seconds
Portanto, 600 arquivos com mais de 20 páginas = 4.302,66 segundos = tempo estimado de 1 hora e 12 minutos.
Em um
for
loop lento do Windows:Aqui está um script de exemplo que renderiza todas as páginas de um PDF para imagens usando multiprocessamento Python. Você pode esperar uma execução geral 2-4 vezes mais rápida do que a linear: