title: give a bytes to reportlab.lib.utils.ImageReader
body: <p>I have read that you can use a bytes like object to <code>reportlab.lib.utils.ImageReader()</code>. 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.</p>
  
  <p>This is where I found the code to convert the image into a string
  <a href="https://www.programcreek.com/2013/09/convert-image-to-string-in-python/" rel="nofollow noreferrer">https://www.programcreek.com/2013/09/convert-image-to-string-in-python/</a></p>
  
  <p>This is an example of how to use BytesIO as input for <code>ImageReader()</code>
  <a href="https://stackoverflow.com/questions/40966401/how-to-draw-image-from-raw-bytes-using-reportlab">How to draw image from raw bytes using ReportLab?</a></p>
  
  <p>This class is used to make a plot and pass in a save it to memory with <code>BytesIO()</code>. string is the value I'm going to pass later</p>
  
  <pre><code>#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
  </code></pre>
  
  <pre><code>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
  </code></pre>
  
  <p>This is the minimum code to show how the information is moved to where the error occurs.</p>
  
  <pre><code>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()
  </code></pre>
  
  <p>This is where the error occurs, in the scaleImage function</p>
  
  <pre><code>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()
  </code></pre>
  
  <p>For Error1 I receive:</p>
  
  <blockquote>
    <p>raise IOError('Cannot open resource "%s"' % name)<br>
    img = utils.ImageReader(img_path)<br>
    "OSError: Cannot open resource "b'iVBORw0KGgoAAA' etc.,</p>
  </blockquote>
  
  <p>For Error2 I receive</p>
  
  <blockquote>
    <p>OSError: cannot identify image file &lt;_io.BytesIO object at 0x7f8e4057bc50><br>
    cannot identify image file &lt;_io.BytesIO object at 0x7f8e4057bc50><br>
    fileName=&lt;_io.BytesIO object at 0x7f8e4057bc50> identity=[ImageReader@0x7f8e43fd15c0]</p>
  </blockquote>