Insérez l'image dans Reportlab soit à partir de PIL image ou StringIO

j'essaie d'insérer une image de code à barres dans Reportlab. Je sais qu'il y a beaucoup de questions posées sur ce sujet, mais tous assumer que vous avez déjà le fichier image dans le répertoire ou sur le système de fichiers.

en raison du fait que Reportlab a des problèmes avec les codes-barres EAN13, j'ai décidé d'utiliser un autre paquet appelé pyBarcode pour générer l'image pour moi.

J'ai d'abord sauvegardé l'image dans une instance StringIO et je l'ai passée directement à reportlab.platypus.flowables.Image mais cela ne semble pas fonctionner. Puis j'ai lu la documentation:

les Formats supportés par Pil/Java 1.4 (la bibliothèque D'imagerie Python / Java) sont supportés.

est-ce que cela signifie que si je passe une image PIL, cela devrait fonctionner? J'ai eu une exception quand j'ai essayé le code suivant:

>>> 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 <module>
    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

D'une façon ou d'une autre, Pil Image ne semble pas fonctionner non plus. Que dois-je passer comme premier argument pour la fonction Image de Reportlab si je n'ai pas le nom de fichier de l'image (parce que mes images sont créées en mémoire)?

17
demandé sur Mark 2012-12-19 17:40:09

3 réponses

la déclaration répétitive "les Formats supportés par Pil / Java 1.4 (la bibliothèque D'imagerie Python / Java) sont supportés" signifie simplement que les formats de données supportés par PIL sont supportés par reportlab (car il utilise PIL pour les lire).

Maintenant, de jeter un oeil à reportlab.platypus.flowables.Image code, il est possible de voir qu'il accepte un nom de fichier ou un objet de fichier en entrée. L'ancien n'est pas ce que vous voulez, alors concentrons-nous sur le tard. Vous avez dit StringIO ne semblait pas fonctionner, mais il le fait si vous prenez un peu de soin. Vous n'avez probablement quelque chose de mal avec elle, voici deux façons correctes d'utiliser 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)

La méthode 3 échoue parce que img3 détient désormais les données brutes de l'image, de sorte qu'il n'a aucune idée sur le format de ces données. Il n'y a aucune raison de tenter d'utiliser cette méthode pour effectuer cette tâche.

si vous avez des données brutes et que vous connaissez le mode image de vos données ('L', 'RGB', etc) et aussi sa largeur, sa hauteur, alors vous pouvez utiliser une quatrième méthode (correcte) basée PIL.Image.fromstring(...).save(mystrio, 'someformat').

9
répondu mmgp 2012-12-20 03:26:58

j'ai pas eu de chance avec les méthodes proposées.

vérification du code pdfdoc.py montre que L'attribut ROR résulte du fait de traiter le StringIO comme un nom de fichier:

    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

une vérification plus poussée de la source montre que jpeg_fh est un attribut de classe ImageReader dans reportlab.lib.utils. ImageReader accepte à la fois les images StringIO et PIL.

donc envelopper le StringIO dans un ImageReader a résolu le problème pour moi:

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, ...)
8
répondu wolfmanx 2014-11-26 22:43:04

je crois que ce que veut dire PIL docs c'est qu'il utilise PIL en interne pour traiter les données d'image.

à partir de ce que je vois dans le code source, vous pouvez passer un objet file directement, donc, quelque chose avec un read() méthode:

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

je suppose que vous pouvez d'une façon ou d'une autre envelopper les données d'image brutes dans un objet de type fichier (StringIO ou tel.)

EDIT: je suppose que c'est ce que vous faisiez avant, désolé. De toute façon, il semble être de la bonne façon. Peut-être que si vous nous dites quel est le problème dans ce cas, nous serons en mesure de le régler.

0
répondu ubik 2012-12-19 14:23:54