Insert image into Reportlab either from PIL image or StringIO Insert image into Reportlab either from PIL image or StringIO python python

Insert image into Reportlab either from PIL image or StringIO


I had no luck with the proposed methods.

Checking the code in pdfdoc.py shows, that the AttributError results from treating the StringIO as a filename:

    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

Further checking the source, shows that jpeg_fh is an attribute of class ImageReader in reportlab.lib.utils. ImageReader accepts both StringIO and PIL images.

So wrapping the StringIO in an ImageReader solved the problem for me:

import PILfrom reportlab.lib.utils import ImageReaderio_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, ...)


The repetitive declaration "Formats supported by PIL/Java 1.4 (the Python/Java Imaging Library) are supported" simply means that data formats supported by PIL are supported by reportlab (since it uses PIL to read them).

Now, from peeking in reportlab.platypus.flowables.Image code it is possible to see that it accepts either a filename or a file object as input. The former is not what you want, so let us focus on the later. You said StringIO didn't seem to work, but it does if you take some care. You probably did something wrong with it, here are two correct ways to use StringIO:

import sysimport PILfrom cStringIO import StringIOfrom reportlab.platypus.flowables import Image# Method 1data = open(sys.argv[1]).read()img1 = StringIO(data)# Method 2img2 = 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)

The method 3 fails because img3 now holds the raw data of the image, so it has no idea about the actual format of this data. There is no reason to attempt to use this method for such task.

If you have raw data and you know the image mode of your data ('L', 'RGB', etc) and also its width, height, then you can use a fourth (correct) method based on PIL.Image.fromstring(...).save(mystrio, 'someformat').


I believe that what the PIL docs mean to say is that it is using PIL internally to process the image data.

From what I see in the source code, you can pass a file object directly, so, something with a read() method:

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

I guess you can somehow wrap the raw image data in a file-like object (StringIO or such).

EDIT: I guess that's what you were doing before, sorry. Anyway, it seems to be the correct way. Maybe if you tell us what is the problem in that case, we'll be able to sort it out.