Skip to content
Advertisement

Cherrypy base64 image encoding not working as expected

The Problem:

I have been playing around with CherryPy for the past couple of days but I’m still having some trouble with getting images to work how I could expect them to. I can save an uploaded image as a jpg without issue but I can’t convert it to a base64 image properly. Here’s the simple server I wrote:

server.py

#server.py
import os 
import cherrypy #Import framework


frameNumber = 1
lastFrame = ''
lastFrameBase64 = ''

class Root (object):

    def upload(self, myFile, username, password):
        global frameNumber
        global lastFrameBase64
        global lastFrame
        size = 0
        lastFrameBase64 = ''
        lastFrame = ''
        while True:
            data = myFile.file.read(8192)
            if not data:
                break
            size += len(data)
            lastFrame += data
            lastFrameBase64 += data.encode('base64').replace('n','')
        

        f = open('/Users/brian/Files/git-repos/learning-cherrypy/tmp_image/lastframe.jpg','w')
        f.write(lastFrame)
        f.close()
        f = open('/Users/brian/Files/git-repos/learning-cherrypy/tmp_image/lastframe.txt','w')
        f.write(lastFrameBase64)
        f.close()

        cherrypy.response.headers['Content-Type'] = 'application/json'
        print "Image received!"
        frameNumber = frameNumber + 1
        out = "{"status":"%s"}"
        return out % ( "ok" )
    upload.exposed = True

cherrypy.config.update({'server.socket_host': '192.168.1.14',
                        'server.socket_port': 8080,
                       })
if __name__ == '__main__':
    # CherryPy always starts with app.root when trying to map request URIs
    # to objects, so we need to mount a request handler root. A request
    # to '/' will be mapped to HelloWorld().index().
    cherrypy.quickstart(Root())

When I view the lastframe.jpg file, the image renders perfectly. However, when I take the text string found in lastframe.txt and prepend the proper data-uri identifier data:image/jpeg;base64, to the base64 string, I get a broken image icon in the webpage I’m trying to show the image in.

<!DOCTYPE>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <img src="data:image/jpeg;base64,/9....." >
    </body>
</html>

I have tried using another script to convert my already-saved jpg image into a data-uri and it works. I’m not sure what I’m doing wrong in the server example b/c this code gives me a string that works as a data-uri:

Working Conversion

jpgtxt = open('tmp_image/lastframe.jpg','rb').read().encode('base64').replace('n','')

f = open("jpg1_b64.txt", "w")
f.write(jpgtxt)
f.close()

So basically it comes down to how is the data variable taken from myFile.file.read(8192) is different from the data variable taken from open('tmp_image/lastframe.jpg','rb') I read that the rb mode in the open method tells python to read the file as a binary file rather than a string. Here’s where I got that.

Summary

In summary, I don’t know enough about python or the cherrypy framework to see how the actual data is stored when reading from the myFile variable and how the data is store when reading from the output of the open() method. Thanks for taking the time to look at this problem.

Advertisement

Answer

Base64 works by taking every 3 bytes of input and producing 4 characters. But what happens when the input isn’t a multiple of 3 bytes? There’s special processing for that, appending = signs to the end. But that’s only supposed to happen at the end of the file, not in the middle. Since you’re reading 8192 bytes at a time and encoding them, and 8192 is not a multiple of 3, you’re generating corrupt output.

Try reading 8190 bytes instead, or read and encode the entire file at once.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement