Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Including base64-encoded image in ReportLab-generated PDF

I am trying to decode base64-encoded image and put it into PDF I generate using ReportLab. I currently do it like that (image_data is base64-encoded image, story is already a ReportLab's story):

# There is some "story" I append every element
img_height = 1.5 * inch  # max image height
img_file = tempfile.NamedTemporaryFile(mode='wb', suffix='.png')
img_file.seek(0)
img_file.write(image_data.decode('base64'))
img_file.seek(0)
img_size = ImageReader(img_file.name).getSize()
img_ratio = img_size[0] / float(img_size[1])
img = Image(img_file.name,
    width=img_ratio * img_height,
    height=img_height,
)
story.append(img)

and it works (although still looks ugly to me). I thought about getting rid of the temporary file (shouldn't file-like object do the trick?).

To get rid of the temporary file I tried to use StringIO module, to create file-like object and pass it instead of file name:

# There is some "story" I append every element
img_height = 1.5 * inch  # max image height
img_file = StringIO.StringIO()
img_file.seek(0)
img_file.write(image_data.decode('base64'))
img_file.seek(0)
img_size = ImageReader(img_file).getSize()
img_ratio = img_size[0] / float(img_size[1])
img = Image(img_file,
    width=img_ratio * img_height,
    height=img_height,
)
story.append(img)

But this gives me IOError with the following message: "cannot identify image file".

I know ReportLab uses PIL to read images different than jpg, but is there any way I can avoid creating named temporary files and do this only with file-like objects, without writing files to the disk?

like image 430
Tadeck Avatar asked Nov 05 '22 02:11

Tadeck


1 Answers

You should wrap StringIO() by PIL.Image.open, so simply img_size = ImageReader(PIL.Image.open(img_file)).getSize(). Its actually a thin wrapper around Image.size, as Tommaso's answer suggests. Also, there is actually no need to calculate the desc size on your own, bound mode of reportlab.Image could do it for you:

img_height = 1.5 * inch  # max image height
img_file = StringIO.StringIO(image_data.decode('base64'))
img_file.seek(0)
img = Image(PIL.Image.open(img_file),
            width=float('inf'),
            height=img_height,
            kind='bound')
)
story.append(img)
like image 156
okm Avatar answered Nov 14 '22 21:11

okm