[reportlab-users] Patch: PIL images with ReportLab

Sam Hunter shunter at dbsupply.com
Mon May 2 13:46:47 EDT 2005


Well, I dug a bit deeper, and found this comment in the pdfutils.py
-----------------------------
#########################################################################
#
#  JPEG processing code - contributed by Eric Johnson
#
#########################################################################

# Read data from the JPEG file. We should probably be using PIL to
# get this information for us -- but this way is more fun!
# Returns (width, height, color components) as a triple
# This is based on Thomas Merz's code from GhostScript (viewjpeg.ps)
def readJPEGInfo(image):
    "Read width, height and number of components from open JPEG file."
------------------------------

So, I took the plunge, and re-wrote a bunch of stuff.  These changes 
make it so that ReportLab handles PIL images whether they have been 
modified or not.  The readJPEGInfo(image) function is no longer used for 
PILs.  PILs are always put into the PDF document as a JPG so they are 
small, and drawImage() will catch PILs without the need for the user to 
save them to the harddisk or wrap them in StringIO. 

I think these changes shouldn't alter the functionality of anything else.

If anyone is interested I can post more detailed information, but major 
changes are below.

Sam

In pdfdoc.PDFImageXObject I added a new member function:
           
#-------------------------------------------------------------------------------
    def loadImageFromImageReader(self, im):
       
        "Extracts width, height, image mode, etc from ImageReader image"
        self.width, self.height = im.getSize()
        self.colorSpace = im.getcolorSpace()     
       
        #bitsPerComponent might be bad since black and white images have 
only 1
        #I'm not sure if it is really used anywhere however.. and seem 
to default to 8
        #in loadImageFromSRC(self, im)
        self.bitsPerComponent = 8 
        zlib = import_zlib()
        if not zlib: return
       
        #default to jpeg type images from PIL
        #raw = im.getRGBData()
        #assert(len(raw) == self.width*self.height, "Wrong amount of 
data for image")
        self.streamContent = 
pdfutils._AsciiBase85Encode(im.getJPEG())      
        self._filters = 'ASCII85Decode','DCTDecode' #'A85','DCT'
        self.mask = None
       
        print "Exiting loadImageFromImageReader"
#-------------------------------------------------------------------------------

Changed the first part of Canvas.drawImage() quite a bit..
#-------------------------------------------------
       if(hasattr(image, "__class__")):
          imtype = str(image.__class__).split(".")[0]
        else:
          imtype = None
               
        if type(image) == type(''):
            #filename, use it
            name = _digester('%s%s' % (image, mask))
        elif(imtype == 'PIL'):
            #convert to ImageReader type
            image = ImageReader(image)
            rawdata = image.getRGBData()
            name = _digester(rawdata+str(mask))

        else: 
            rawdata = image.getRGBData()
            name = _digester(rawdata+str(mask))
#--------------------------------------------------


And added two new functions to the ImageReader class to extend it's PIL 
handling capabilities.
#-------------------------------------------------------------------------------
    def getcolorSpace(self):
        "Return one of the following color codes:"
        "'DeviceGray', 'DeviceRGB', 'DeviceCMYK', None"
 
        if sys.platform[0:4] == 'java':
          #I'm not sure how to get color information from javax.imageio
          #a quick search on google doesn't suggest anything quick and 
painless.
          return None
        else:
          #this is a PIL image, values should be "1", "L", "RGB", or "CMYK."
          #"1" = black and white, "L" = gray scale
          mode = self._image.mode

          if mode in ('1','L'):
            self._mode = 'DeviceGray'
            return self._mode
          if mode == 'RGB':
            self._mode = 'DeviceRGB'
            return self._mode
          if mode == 'CMYK':
            self._mode = 'DeviceCMYK'
            return self._mode
         
          #if it isn't one of these
          return None

    def getJPEG(self):
        "Return a string with jpeg data in it"
        from cStringIO import StringIO
        f = StringIO()
        self._image.save(f, format="JPEG")
        return f.getvalue()
     
#-------------------------------------------------------------------------------



Robin Becker wrote:

>>
>>
> ..... so far as I remember we originally intended that the ImageReader 
> class should be
> a reader only. We used PIL internally to do conversions. It was never 
> intended that we knew
> anything about the images. That's why I feel reluctant to bring PIL 
> "inside". Because
> of earlier assumptions the internal code feels able to reject PIL if 
> the pil format option
> reveals the original image to be JPEG. I'm not an expert on PIL, but 
> if PIL is a valid option
> then we need to know what conversions etc etc are valid. At present 
> (in the SVN code) we're
> alllowing conversions based on the PIL mode and possibly wrongly have 
> allowed the format to
> leak into the internals. Before we used PIL internally. Now you 
> propose making PIL a valid
> image format. Suppose you read a JPEG using PIL and pass it into 
> ImageReader. Do I believe the
> given PIL or can I revert to the original semantics and use the file 
> as a standard JPEG.



More information about the reportlab-users mailing list