Sending Images From Flex to a Server
Today's challenge has been to allow a Flex app to create images, and have the new images uploaded back to the server as a bitmap. The application is for a simple buddy-icon editing application: users can upload their photos, drag in bits of clip art, resize and so on, then use their generated buddy icon on the site. The same could be useful for doing basic image editing, uploading for print.
There are two issues. First is getting uploaded images into Flex. That's a topic for a future post (but basically you have to upload them to the server, then download them again).
The second is uploading a final image generated by Flex. And it turns out this is surprisingly easy.
Flash has the ability to render any display component to a bitmap, using the BitmapData class. So in my graphic-design-canvas component I did:
private var bitmapData:BitmapData;
private function saveToBitmap():void
{
bitmapData = new BitmapData(48, 48, true, 0x00ffffff);
bitmapData.draw(this);
The next stage was to convert the raw bitmap data into an image format (to reduce bandwidth requirements). In Flex 2.01 I used Adobe's PNGEncoder from their corelib package. Once you've set up a classpath, or copied the .swc file into /frameworks/lib, you can do this:
var imageData:ByteArray = PNGEncoder.encode(bitmapData);
Easy as pie.
Finally to send it to the server I use a POST HTTP request. This requires that the bitmap data is encoded in Base 64:
var encoder : Base64Encoder = new Base64Encoder();
encoder.encodeBytes(imageData);
var params:Object = { image_data: encoder.flush() };
imageSend.send(params);
}
where imageSend is the name of a HTTPService I created:
<mx:HTTPService id="imageSend" showBusyCursor="true" useProxy="false" url="http://www.example.com/upload_image/" method="POST" result="imageSentConfirmation()"/>
Which is all very neat and simple: 8 lines of code.
On the Django end you simply need to extract the data from request.POST and decode the base-64 coded string:
def upload_image(request):
data = base64.b64decode(request.POST['image_data'])
You can feed this data into a file directly:
open("filename.png", "wb").write(data)
or send it to the Python Imaging Library for size-checks, conversion, or other jiggery pokery:
img = Image.open(StringIO(data))
img = img.resize((48,48), Image.ANTIALIAS)
img.save(os.path.join(MEDIA_ROOT, "filename.png"))
Then return something that your Flex component understands:
return http.HttpResponse("<ok/>", mimetype="text/xml")
Of course, you'll probably want to do some more error handling on the server: trapping garbage content, file issues and the like. But the basic functionality is yours for just two lines of Django code!