Insertar imagen en Reportlab desde PIL image o StringIO

Estoy tratando de insertar una imagen de código de barras en Reportlab. Sé que hay muchas preguntas sobre esto, pero todas suponen que ya tiene el archivo de imagen en el directorio o en el sistema de archivos.

Debido al hecho de que Reportlab tiene problemas con los códigos de barras EAN13, decidí usar otro paquete llamado pyBarcode para generar la imagen para mí.

Inicialmente, guardé la imagen en una instancia de StringIO y la pasé directamente a reportlab.platypus.flowables.Image pero eso no pareció funcionar. Luego leo la documentación:

Los formatos compatibles con PIL / Java 1.4 (la biblioteca de imágenes de Python / Java) son compatibles.

¿Significa esto que si paso una imagen PIL, esto debería funcionar? Obtuve una excepción cuando probé lo siguiente:

 >>> import PIL >>> from reportlab.platypus.flowables import Image >>> fp = StringIO(the_barcode.getvalue()) >>> barcode_image = PIL.Image.open(fp) >>> doc = SimpleDocTemplate('barcode.pdf') >>> story = [Image(barcode_image)] >>> Traceback (most recent call last): File "create.py", line 57, in  main() File "create.py", line 24, in main save_pdf(fp, STYLE, ART, COLOR, SIZE) File "create.py", line 28, in save_pdf fp = StringIO(fp.getvalue()) File "/home/mark/.virtualenvs/barcode/local/lib/python2.7/site-packages/reportlab-2.6-py2.7-linux-i686.egg/reportlab/platypus/flowables.py", line 402, in __init__ if not fp and os.path.splitext(filename)[1] in ['.jpg', '.JPG', '.jpeg', '.JPEG']: File "/home/mark/.virtualenvs/barcode/lib/python2.7/posixpath.py", line 95, in splitext return genericpath._splitext(p, sep, altsep, extsep) File "/home/mark/.virtualenvs/barcode/lib/python2.7/genericpath.py", line 91, in _splitext sepIndex = p.rfind(sep) File "/home/mark/.virtualenvs/barcode/local/lib/python2.7/site-packages/PIL/Image.py", line 512, in __getattr__ raise AttributeError(name) AttributeError: rfind 

De alguna manera, la imagen de PIL tampoco parece funcionar. ¿Qué debo pasar como primer argumento a la función Imagen de Reportlab si no tengo el nombre de archivo de la imagen (porque mis imágenes se crean en la memoria)?

La statement repetitiva “Los formatos compatibles con PIL / Java 1.4 (la biblioteca de imágenes de Python / Java) son compatibles” simplemente significa que los formatos de datos compatibles con PIL son compatibles con reportlab (ya que utiliza PIL para leerlos).

Ahora, a partir del código reportlab.platypus.flowables.Image , es posible ver que acepta un nombre de archivo o un objeto de archivo como entrada. Lo primero no es lo que quieres, así que concentrémonos en lo que sigue. Dijiste que StringIO no parecía funcionar, pero funciona si te cuidas. Probablemente hiciste algo mal con esto, aquí hay dos formas correctas de usar StringIO :

 import sys import PIL from cStringIO import StringIO from reportlab.platypus.flowables import Image # Method 1 data = open(sys.argv[1]).read() img1 = StringIO(data) # Method 2 img2 = StringIO() PIL.Image.open(sys.argv[2]).save(img2, 'PNG') img2.seek(0) # Method 3 (fails) img3 = StringIO(PIL.Image.open(sys.argv[2]).tostring()) story = [Image(img1), Image(img2)] #Image(img3) 

El método 3 falla porque img3 ahora contiene los datos en bruto de la imagen, por lo que no tiene idea del formato real de estos datos. No hay ninguna razón para intentar usar este método para dicha tarea.

Si tiene datos sin procesar y conoce el modo de imagen de sus datos (‘L’, ‘RGB’, etc.) y también su ancho, altura, entonces puede usar un cuarto método (correcto) basado en PIL.Image.fromstring(...).save(mystrio, 'someformat') .

No tuve suerte con los métodos propuestos.

Verificando el código en pdfdoc.py muestra que AttributError resulta de tratar a StringIO como un nombre de archivo:

  if source is None: pass # use the canned one. elif hasattr(source,'jpeg_fh'): self.loadImageFromSRC(source) #it is already a PIL Image else: # it is a filename 

Además de verificar la fuente, muestra que jpeg_fh es un atributo de la clase ImageReader en reportlab.lib.utils. ImageReader acepta imágenes StringIO y PIL.

Así que envolver el StringIO en un ImageReader resolvió el problema por mí:

 import PIL from reportlab.lib.utils import ImageReader io_img = StringIO(data) pil_img = PIL.Image.open(StringIO(data)) reportlab_io_img = ImageReader(io_img) reportlab_pil_img = ImageReader(pil_img) canvas.drawImage(reportlab_io_img, ...) canvas.drawImage(reportlab_pil_img, ...) 

Creo que lo que los documentos de PIL quieren decir es que está utilizando PIL internamente para procesar los datos de la imagen.

Por lo que veo en el código fuente, puede pasar un objeto de archivo directamente, así que, algo con un método read() :

https://github.com/ejucovy/reportlab/blob/master/src/reportlab/platypus/flowables.py#L314

Supongo que de alguna manera puedes envolver los datos de imagen en bruto en un objeto similar a un archivo (StringIO o similar).

EDIT: Supongo que eso es lo que estabas haciendo antes, lo siento. De todos modos, parece ser la forma correcta. Tal vez si nos dices cuál es el problema en ese caso, podremos solucionarlo.