Reputation: 81
I have read that you can use a bytes like object to reportlab.lib.utils.ImageReader()
. If I read in a file path it works fine, but I want to use a byte like object instead that way I can save the plot I want in memory, and not have to constantly be saving updated plots on the drive.
This is where I found the code to convert the image into a string https://www.programcreek.com/2013/09/convert-image-to-string-in-python/
This is an example of how to use BytesIO as input for ImageReader()
How to draw image from raw bytes using ReportLab?
This class is used to make a plot and pass in a save it to memory with BytesIO()
. string is the value I'm going to pass later
#imports
import PyPDF2
from io import BytesIO
from reportlab.lib import utils
from reportlab.lib.pagesizes import landscape, letter
from reportlab.platypus import (Image, SimpleDocTemplate,
Paragraph, Spacer)
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch, mm
import datetime
import os
import csv
import io
import base64
import urllib
from django.contrib import admin
from django.forms import model_to_dict
from django.http import HttpResponse
from django.urls import path
from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator
from reporting import models, functions, functions2
import matplotlib
matplotlib.use('agg')
from matplotlib import pyplot as plt
import numpy as np
def make_plot(data):
items = [tuple(item) for item in data.items()]
keys = [item[0] for item in items]
vals = [item[1] for item in items]
fig, ax = plt.subplots()
ind = np.arange(len(keys)) # the x locations for the groups
width = 0.35 # the width of the bars
rects1 = ax.bar(ind - width/2, vals, width)
ax.set_ylabel('Count')
ax.set_xticks(ind)
ax.set_xticklabels(keys)
buf = io.BytesIO()
fig.savefig(buf, format='png')
buf.seek(0)
string = base64.b64encode(buf.read())
return 'data:image/png;base64,' + urllib.parse.quote(string), string
This is the minimum code to show how the information is moved to where the error occurs.
class ProgressReportAdmin(ReadOnlyAdmin):
current_extra_context = None
@csrf_protect_m
def changelist_view(self, request, extra_context=None):
plot = make_plot(data)
self.current_extra_context = plot[1]
def export(self, request):
image = self.current_extra_context
pdf = functions.LandscapeMaker(image, fname, rotate=True)
pdf.save()
This is where the error occurs, in the scaleImage function
class LandscapeMaker(object):
def __init__(self, image_path, filename, rotate=False):
self.pdf_file = os.path.join('.', 'media', filename)
self.logo_path = image_path
self.story = [Spacer(0, 1*inch)]
def save(self):
fileObj = BytesIO()
self.doc = SimpleDocTemplate(fileObj, pagesize=letter,
leftMargin=1*inch)
self.doc.build(self.story,
onFirstPage=self.create_pdf)
def create_pdf(self, canvas, doc):
logo = self.scaleImage(self.logo_path)
def scaleImage(self, img_path, maxSize=None):
#Error1 occurs on
img = utils.ImageReader(img_path)
img.fp.close()
#Error2
#image = BytesIO(img_path)
#img = utils.ImageReader(image)
#img.fp.close()
For Error1 I receive:
raise IOError('Cannot open resource "%s"' % name)
img = utils.ImageReader(img_path)
"OSError: Cannot open resource "b'iVBORw0KGgoAAA' etc.,
For Error2 I receive
OSError: cannot identify image file <_io.BytesIO object at 0x7f8e4057bc50>
cannot identify image file <_io.BytesIO object at 0x7f8e4057bc50>
fileName=<_io.BytesIO object at 0x7f8e4057bc50> identity=[ImageReader@0x7f8e43fd15c0]
Upvotes: 3
Views: 5096
Reputation: 307
I think you have to pass buff
to ImageReader
somehow.
I'm using this function to save and draw the figures I generate with matplotlib
and it works perfectly for me.
seek(offset, whence=SEEK_SET)
Change the stream position to the given offset. Behaviour depends on the whence parameter. The default value for whence is SEEK_SET.
getvalue()
doesn't work except the seek(0)
def save_and_draw(fig, x_img, y_img, width_img=width_img, height_img=height_img):
imgdata = BytesIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0)
imgdata = ImageReader(imgdata)
self.c.drawImage(imgdata, x_img, y_img, width_img, height_img)
plt.close(fig)
Upvotes: 6