First why it's specific. In a typical case a web app wants to save user submitted images to Google app engine data store. This can be simply done by presenting user with a form and adding an 'input' tag with type 'file'. The submitted image can be extracted in GAE using request.get() and packaged into db.Blob to eventually store into BlobProperty. I am not going to explain this typical case, because it's covered nicely in the GAE's documentation. However, the process is not as straightforward when the image you want to store is not an image file on user's computer, but a dump of HTML5 canvas element in the web app.
An HTML5 canvas element lets you export its content as jpeg or png image with the toDataURL API. This function returns a data URL that contains base64 encoded jpeg/png image. So how do we convert this image data into GAE's db.Blob object?
The solution is to send the base64 encoded data as POST param to GAE app, do some regex matching to extract the exact portion of the data URL that is the encoded image and pass it through the base64 decoder (which is part of standard python library).
Here is client side:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The client side code sends the canvas's content via | |
// a jQuery post method to server | |
params = { imgdata : canvas.toDataURL('image/jpeg') }; | |
$.post('/save', params, function (data) { /* ... */ }) | |
//... |
Here is server side code:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
import base64 | |
# ... | |
class SaveHandler(webapp.RequestHandler): | |
dataUrlPattern = re.compile('data:image/(png|jpeg);base64,(.*)$') | |
def post(self): | |
# ... | |
imgdata = self.request.get('imgdata') | |
imgb64 = self.dataUrlPattern.match(imgdata).group(2) | |
if imgb64 is not None and len(imgb64) > 0: | |
datamodel.image = db.Blob(base64.b64decode(imgb64)) |
Code is also accessible as gist here, in case you can't see the embedded version above.
This code works in 3DTin where a thumbnail of user's canvas is sent to GAE app for storage. It works without problem.
Ads:
No comments:
Post a Comment