miércoles, 10 de septiembre de 2025

Textos. Python.

Biblioteca PyPDF2. Imágenes.


Hasta este momento hemos visto como usar PyPDF2 para acceder al contenido de documentos pdf; también conocemos algunas de sus limitaciones, pero aun nos queda mucho por aprender respecto al acceso y el manejo de los datos recuperados. Es más, posiblemente lo realmente importante, lo que nos puede aportar soluciones de interés para nuestro trabajo, está aun por tratar. La idea es que empecemos a hacerlo en esta entrada.


Hasta ahora hemos traslado la referencia y acceso al texto obtenido mediante PyPDF2 a una variable y nos hemos limitado a mostrar ese contenido en pantalla, pero es difícil de sostener que ese esa un modo razonable de trabajar; es más, posiblemente esa sea una forma contraproducente y limitante de trabajar, responsable además de algunas de las limitaciones que hemos observado en la [entrada anterior]. Nos interesa ahora plantearnos formas más razonables de manejar y tratar el volumen de información al que nos permite acceder PyPDF2, aunque para ello debamos establecer, además, qué objetivos y con qué restricciones nos planteamos el uso de esta biblioteca.

Digo esto porque, dependiendo del objetivo, una teórica limitación puede serlo o no (o no tanto); y dependiendo de las restricciones (por ejemplo, qué tipo de documento pdf usamos como fuente de datos) nos deberemos plantear un procedimiento de trabajo u otro. Si lo que queremos es acceder a varios documentos y unificar todos los datos que contienen en uno único, no es lo mismo que si lo que nos interesa es acceder a un contenido o tipo de contenido en concreto. Si trabajamos con textos más o menos extensos basados en párrafos no es lo mismo que si trabajamos con textos muy estructurados en forma de tablas. 

Podría seguir planteando opciones y condiciones, pero lo que me interesa es transmitir que nuestro enfoque de trabajo puede ser diferentes según condiciones y objetivos, y que esa diferencia incide en qué consideremos ventaja o limitación, y, en consecuencia, también en cómo abordamos la solución de la segunda.

Dicho esto, por entrar en materia, consideremos una de las limitaciones que vimos en su momento, y uno de los aspectos en los que lo es: el acceso a las imágenes contenidas en un pdf, consideradas éstas como tales (1).

Dentro del interés por "apropiarnos" del contenido de un pdf puede estar hacerlo de las imágenes que contiene, sean estas gráficos de esquemas, fotografías o dibujos o gráficos estadísticos. Sabemos hasta ahora que PyPDF2 no permite acceder a esas imágenes; y sabemos también que, si son pocas, podemos capturarlas directamente mediante la funcionalidad Capturar pantalla, pero si son muchas o son muchos los documentos, automatizar la captura con Python sin duda es una buena solución (2).

Empecemos por la limitación y por cómo solucionarla: hasta ahora sabemos que PyPDF2 no permite extraer imágenes y hemos comprobado esta limitación en la práctica [ver entrada]; pero en realidad esta biblioteca cuenta con recursos para extraer las imágenes de un pdf. Veremos cómo hacerlo sobre un documento que versa sobre el arte Románico (3).

Suponemos la existencia de un directorio que contiene nuestro script, dentro del cual hemos creado un subdirectorio que contiene los archivos pdf (pdf), incluyendo en este caso el que nos interesa (ArteRomanico.pdf). Dentro de este subdirectorio creamos otro para guardar las imágenes (imgs).

El script podría ser el siguiente:

import PyPDF2

archivo = input("Nombre del archivo (sin la extensión): ")
lector = PyPDF2.PdfReader(f'pdf/{archivo}.pdf')

paginas = len(lector.pages)

for n_pag in range(paginas):
    pag = lector.pages[n_pag]
    for image_file_object in pag.images:
        with open(f'pdf/imgs/{str(n_pag)}__{image_file_object.name}', 'wb') as img:    
            img.write(image_file_object.data)

print ("Imágenes guardadas")

Después de cargar la biblioteca (import PyPDF2) (4) se desarrolla la primera fase del script, que consiste en los siguiente: 
  • Creamos un procedimiento interactivo basado en la función input() para  que el usuario aporte el nombre del archivo (que, como sabes, debe estar ubicado en el directorio pfd/) (archivo = input("Nombre del archivo (sin la extensión): ")). 
  • Sobre la variable lector construimos la instrucción basada en la función PdfReader(), la cual nos permite acceder al documento que contiene las imágenes (en nuestro caso ver 3) (lector = PyPDF2.PdfReader(f'pdf/{archivo}.pdf')).
  • Finalizamos asignando a la variable paginas el número de páginas del documento mediante la función len() (paginas = len(lector.pages)) (5)
La segunda fase del script se concreta como una estructura compleja de bucle que anida otro bucle, que a su vez contiene una instrucción with
  • El primer bucle (for n_pag in range(paginas):) recorre las páginas del documento y captura cada una de ellas en la variable pag (pag = lector.pages[n_pag])
  • El segundo bucle (anidado en el anterior) (for image_file_object in pag.images:) recorre la colección de imágenes que contiene cada una de las páginas del documento y desarrolla la instrucción with (6).
  • Ese instrucción desarrolla la acción de acceder al directorio y a las imágenes y las copia, y la finaliza, evitando que quede pendiente de ser finalizada (ver nota 6).
  • Finalmente añadimos una instrucción print() para informar del éxito del procedimiento (print ("Imágenes guardadas")) (7)
De esta forma tan sencilla hemos creado un "capturador" de imágenes que permite solucionar una de las limitaciones de PyPDF2. No siempre funciona bien (8), pero cuando lo hace resulta muy útil.


NOTAS

(1) Esto es, al margen de aquellas que contienen texto "fotografiado". Este segundo tipo requiere un tratamiento específico que no es posible dar con PyPDF2, como tendremos ocasión de comprobar.
(2) Observa que aquí abordamos una limitación y cómo superarla en el contexto del logro de un objetivo concreto (obtener imágenes de un documento pdf), planteándonos un manejo realista de la documentación resultante y con una doble posible condición: un pdf con muchas imágenes o una colección de pdf de los que nos interesa extraer las imágenes.
(3) Contexto: ArteRománico.pdf contiene una colección amplia de imágenes sobre el arte románico que, con los debidos permisos de uso, nos serán de utilidad para proporcionar material gráfico a un grupo de alumnos interesados por el tema. Para ello vamos a crear un script basado en PyPDF. Para lograr este objetivo me basaré en la información que aporta Programación para el mundo en You Tube.
(4) Recuerda que también puedes usar la fórmula from PyPDF2 import PdfReader, lo que te permite simplificar la estructura de la instrucción asociada a lector (lector = PyPDF2.PdfReader(f'pdf/{archivo}.pdf'))
(5) La función len() actúa sobre el atributo .pages del objeto (documento) asignado a la variable lector (en(lector.pages)), dado que ese atributo devuelve la colección formada por las páginas del documento.
(6) Según [los entendidos] esta permite ejecutar una acción que tiene un inicio (en nuestro caso el  fragmento de código que contiene la instrucción de acceso al subdirectorio imgs/ y a cada una de las imágenes de la página (open(f'pdf/imgs/{str(n_pag)}__{image_file_object.name}', 'wb') as img) y un final (en nuestro caso la "escritura de la imagen obtenida ( img.write(image_file_object.data))
(7) Aquí correspondería manejar la excepción mediante el procedimiento pertinente, pero dada la simplicidad del proyecto considero suficiente la información que aporta el IDE.
(8) De momento no tengo respuesta ni alternativa a esta limitación, la cual se da con más frecuencia de la deseada: no es infrecuente que PyPDF2 falle en el acceso a imágenes, bien por no detectarlas, por fracasar en el acceso a las mismas o por devolverlas como su negativo. 

No hay comentarios:

Publicar un comentario

Comenta esta entrada