UPDATE – I’ve created a new version of Flex Paint which doesn’t require the server roundtrip.
Flex allows you to easily create beautiful UIs. But what if you want to take a piece of the UI and save it as an image? Well, using Tinic’s AS3 PNG Encoder, Remote Object, and Flash’s BitmapData and ByteArray API it’s very easy. To show how this is done, I created a simple application called Flex Paint.
Flex Paint (requires Flash 9)
How it Works
We use the Flash drawing API to draw on a canvas. Then when the “Save Image” button is clicked we do a few simple things. First we create a new BitmapData object:
var bd:BitmapData = new BitmapData(canvas.width,canvas.height);
Then we copy canvas’ pixels onto the BitmapData object:
bd.draw(canvas);
Now we convert the BitmapData object to a ByteArray encoded as a PNG:
var ba:ByteArray = PNGEnc.encode(bd);
And then upload the PNG via Remote Object:
ro.doUpload(ba);
Then Remote Object just saves the file to the file system. If you would like to download the code for Flex Paint, you can find it on Source Forge. Let me know what you think. Thanks!


99 Comments
Hi, James
Thanks for your valuable response.
Hi, James
Is there any posibility to convert DisplayObject to ByteArray
(and again ByteArray to DisplayObject )?
Thank You.
Hi Shetty,
Unfortunately not currently. DisplayObjects can not be serialized or introspected.
Please file a feature request:
http://bugs.adobe.com
-James
Is there a way to only capture what was writen to the page? Not a screenshot of the image, only what was written to the page while I had the mousedown event envoked.
Hi Chuck,
In Flash you can capture anything (there is an exception to this but it probably won’t affect you). Is the page you are referring to being rendered by Flash or by HTML in the browser?
-James
Hello to you, James,
I want to test it on a website and, unfortunately, I have an error opening on a Flash Player 9 window when I want to save.
The error is :
“[RPC Fault faultString="[MessagingError message='Unknown destination 'UploadImage-ro'.']” faultCode=”InvokeFailed” faultDetail=”Couldn’t establish a connection to ‘UploadImage-ro’”]
at mx.rpc::AbstractInvoker/http://www.adobe.com/2006/flex/mx/internal::invoke()
at mx.rpc.remoting.mxml::Operation/http://www.adobe.com/2006/flex/mx/internal::invoke()
at mx.rpc.remoting::Operation/send()
at Function/http://adobe.com/AS3/2006/builtin::apply()
at mx.rpc.remoting.mxml::Operation/send()
at Function/http://adobe.com/AS3/2006/builtin::apply()
at mx.rpc::AbstractService/http://www.adobe.com/2006/actionscript/flash/proxy::callProperty()
at flexpaint/::doSave()
at flexpaint/___Button2_click()”
Is there a way to place file in flex?
Thank you so much
Jo
Hi Jo,
Did you get this on my website or did you try to set this up yourself?
-James
Hi james..!!
Instead of drawing on a canvas i want to draw on the background image of the canvas but its not supporting do..!!!
Is there any modification to perform the above..!!!
How can i,
draw on the canvas backgroundimage and then the modified image should be saved…!!!
can any one suggest me at rajveerg@gmail.com
-Rajveer
hello,
I want to know how, in the same way, we can draw on any image and save the final image as bitmap… plz do help me with a solution.
@Pradeep
For bitmaps I believe you can just grab the pixels and not run them through the PNG encoder. But I’m not 100% sure whether there needs to be some header information in the bitmaps file. Let me know what you find.
Hi,
Here are the steps I use to draw on an image and save the whole thing as a bitmap.
1. Create a Canvas with an alpha of 1.0 – give this canvas an ID.
2. Place an image container inside the canvas containing the image I want to draw on.
3. Place a second canvas inside the first canvas with the height and width bound to the image height and width an an alpha of 0.0. It’s like placing tracing paper on top of the image.
4. Add the add the mouseDown, Up, Move and Out handlers to the second canvas – like Jims code.
5. Create a button that calls a function to take a snapshot of the FIRST canvas.
You’ll need these lines of code to get a byte array of the entire drawing:
import mx.graphics.ImageSnapshot;
private function takeSnapshot():void {
var imageSnap : ImageSnapshot = ImageSnapshot.captureImage( firstCanvasID );
var imageByteArray:ByteArray = imageSnap.data as ByteArray;
}
The imageByteArray is now a binary object that is the composite of canvas 1, the image and canvas 2(which you drew on)
Post the imageByteArray to the server and save it as a file (I use the coldfusion cffile function for this task)
hope this helps
Thnx james… will try out & let u know…
Pradeep
Thnx David… that was in detail… thnx a lot
Pradeep
I’ve used a thicker linestyle when drawing the lines on the graphics/canvas, and I find the thicker line allowed part of the drawn line be made OUTSIDE of the canvas width/height.
You can slightly see this happen on the example here if you move your mouse slowly and close to the edge.
Any fix for this?
I’ve tried masking, it works great until I scaling stuff, then the mask object didn’t scale with the canvas.
Secondly, an added note, I believe the newer Flex library also includes a PNGEncoder, so no need for the hand coded one.
Thanks!
@Jason
I’m not sure how to deal with the drawing outside the boundary issue. Sorry.
Yes. Flex now includes a built-in PNGEncoder.
-James
Hi James,
Im trying to implement an UNDO function in a Flex application where it should undo the previous drawings on the canvas. Can u help me out with it.
Pradeep
You can either reply to this forum or send me a mail
pradeep.theprince@gmail.com
@Pradeep
You can certainly do UNDO but I haven’t done that. You should ask your question on the FlexCoders Yahoo Group.
Hi James,
Is it possible to get snapshot of swf at Java server side which out rendering the object at clined side
Thanks,
Sushant
@sushant
You could potentially create an AIR app that runs server side that does this. But scalability is not going to be great.
@James Ward
Hi James
Thanks for your suggestion
Basically i want to export the screen shot of the swf objects which are not render in browser.
Is there any other alternative rather then air approach.
Is it possible to do the same using lcds or any java supported flex libaries.
Thanks,
Sushant B. Pawar
@sushant
The only runtimes for SWF are Flash Player and AIR. And there isn’t a good way to run those in a server process.
-James
@David Bridges
David, thanks for this neat trick. For some reason, mine is not working. I can’t seem to be able to draw over the image area (only outside of it, if I stretch the embedded canvas outside the image borders). It seems as if my image is never “behind” the second canvas, and I’ve tried all the permutations I can think of. Is it correct to embed as follows: (Panel (Canvas,w/ID,1.0 (Canvas,w/draw parms,0.0) (Image) ))
@Fred Rodriguez
@Fred
I’ve handled this kind of case. For drawing over an image with the mouse, try the following:
Jst interchange the positions of 2nd canvas & the image & change the ALPHA of the 2nd canvas to 1.0, i.e., Embed as
(Panel (Canvas,w/ID,1.0 (Image) (Canvas,w/draw parms,1.0) ))
post ur problems, if any, after trying the above solution. It has to work as I did it in the same way & it worked.
Hello James ,
Nice work , But I have some Problems
1 :- Can I use Image Component at the Place of Canvas?
2 :- Thus PNGEnc.as Class creates the Png format Image and that we can Save that Image to the Data Base ?
Thanks
Vivek Manchanda
Hi Vivek,
PNGEnc can read any pixels (a bitmap) and convert them to a PNG. Once you have the PNG you can do whatever you want with it… Save it to a database. Allow the user to download it. Whatever.
-James
Hello James,
Thanks for your reply, I have some more issue ,
1:- I tried to Use Image Component at the Place of Canvas but I was not Able to make it work. May be I am doing some thing wrong but can’t find what I am doing wrong.
2:- In second case If I put an Image component under canvas component in your codes then I How I can combined both the Component and make it one Image.
Thanks
Vivek Manchanda
This is too cool! Everything in our project is working. Two tweaks I wondered about: 1) Is it possible to change the drawing pointer and/or the drawing line width? 2) Is it possible to have the image in the canvas “fit to width” of the canvas container or provide zoom capability? Thanks for this great technology!
Hi Fred,
1) Yes. You can change the pointer using the CursorManager. The line width is controlled by the changing the parameters on the graphics.lineStyle() method call.
2) You could zoom or move the image by changing scaleX and scaleY or x and y properties.
-James
@James
Hi,
I’ve implemented a Flex application similar to yours. But one thing different is, I draw on an image and save it. Now I am to save the markings in xml… can you suggest me the way to do it!! plzzzz
I am able to create an xml object with marking co-ordinates in it. But not able to write that into a file… So plz suggest me the way!!
Hi Pradeep,
To write to a file you need to use Adobe AIR. Otherwise you will have to do some sort of file download within the browser.
-James
@James
Can you be a bit specific in what you said!! Im completely new to this software, so if you could xplain me in detail, I will be happy.
Hi Pradeep,
I’d encourage you to visit the Adobe Developer Center and the Adobe Forums to learn more about Flex and AIR and have your questions answered. Those are much better resources for those new to Flex than my blog.
-James
@Anyone
Can anyone guide me the way to connect Flex with MySQL so that I can insert & delete values from the database!!!
EX: I need to insert (Image_Name, Status) into the database in the respective format…
Pradeep,
You need to go through a server like PHP, Java, etc. If you search for your question on Google you will find a lot of examples.
-James
Thank you James…
Hi! i need to know some, im some new on flex, i trying to brush over an image, to reduce red eye effect, i though that i can use your example, drawing with conditions like, when im over a red pixel then brush with other color like brown. I want to understand how u make the brush bigger or smaller.
I was tried to used GetPixel and setPixel, but this last method its very small, coz it only paint a pixel, and its very hard to brush a picture with 2000×1500 pixeles.
Hope you can understand what i trying to do
Thanks in advance
Sun
Hi Sun,
I’m not sure of the best approach for that. You might want to ask on http://stackoverflow.com
-James
@anyone
Hi all… Im facing a prob in my project. There will be two application files in my src folder. After runnin the 1st application & clicking a button in it, it shud disappear & the 2nd application shud become visible… Can anyone help me out!!
Regards
Pradeep
I’m trying to figure out how I can modify this so that when the mouse leave the canvas area and then re-enters, it starts the line again where the mouse enters. Can anybody help me with this? Using this code the point where the mouse leave and the point where the mouse enters is connected.
Hi Greg,
You can catch a mouseOut event to handle that.
-James
Hey James, thanks for the reply. I changed some of the code and figured I’d post my methods back here since so many people read this blog.
1) in the mousedown event handler I added a stage event handler for mouse up. In the stage mouse up handler I simply remove the handler and set drawing=false. This fixed the problem where if you release the mouse outside of the canvas it keeps drawing inside the canvas.
2) As per your advice, in the mouse out handler I de-register the mouse move handler and in the mouse over handler I re-register the mouse move handler and reset the x & y coordinates. This makes the line pick up from the point it reenters the canvas.
3) I added a brush size slider and subsequently had to add a mask to the canvas so when the bigger brush sizes are close to the edge they didn’t bleed outside.
4) In the mouse down handler I draw a filled circle at the point of the mouse click so you can add points by just clicking on the canvas (no need to drag the mouse).
Thanks again for the great post, it has been a wonderful help.
Wow Greg! Great work! Thanks for posting the details here.
hi
james nice work and clear example
but my application have multiple bitmaps, need to save into server
while encoding the bitmaps am playing spinner(then the entire appliction strucking spinner(loading inditcator)is not playing)
my requriement is need to play sppinner while saving the mutiple bitmaps…
can you help me out….
thank you
yugandhar.
Hi yugandhar,
You need to move the processing of the bitmaps across frames. The spinner never gets a chance to spin if you do everything in a single frame. You can process one, then do a callLater that processes the next one and so on. Let me know if that helps.
-James
I am working on a project that has a similar feature but with one difference. I have a “paint” like feature but it also has the ability to import images and then they can draw and add text similar to your example above, but then the entire contents of the “paint palette” are saved as a new image. The issue is that the images that I am dealing with are very large ( like over 200 megs ) and the only thing that seems to make sense is to convert the image to a smaller size while in the paint pallette. We use a similar technique to save the image, but the issue is that when the new saved image is blown up it looks pixelated ( I am guessing this is because the imported 200 meg file lost some resolution when being converted to a smaller size, but this is the only way to make it look good in the pallette ). Any suggestions AT ALL would be so greatly appreciated. The end “saved” image needs to be able to be blown up LARGE ( like the size of a billboard large). PLEASE PLEASE PLEASE HELP!!!!!
@Gene I haven’t tried this with large images. Without some code to play with it’s hard to say what the best approach is.
5 Trackbacks
[...] I just got done adding another sample app to the Flex RoR SDK that I have been working on with Mike Potter. Basically, all I did was take the FlexPaint app created by James Ward and replace the Java back end with Ruby on Rails back end. I also added a simple interface for adding an image to the canvas (see below), so that you can draw on it. This sample app uses both WEBOrb and regular ole’ HTTP calls to integrate Flex with Rails. [...]
[...] My friend John and I were pounding some beers at our local pub when the topic of Digital Ink arose. He thought it would be cool to capture a signature via the web using JavaScript. Of course I then decided to implement the thing in Flex 2. I got the digital ink working in less than an hour (which is a testament to how bad ass Adobe Flex 2 is). But I soon realized that I was only half way to capturing signatures via the web. A screen with a vector graphic signature is cool, but damn near useless. To complete this task I needed to send the signature somewhere to be archived. I started searching Google for code to convert a canvas to a bitmap and came across James Ward’s blog. Rats!! He had already done what I was trying to do. I downloaded his source and noticed that my implementation of the digital ink is slightly different. So I decided to publish my implementation after all. I totally ripped off his “doSave” method which leverages Tinic Uro’s AS3 PNG Encoder. That being said I highly recommend visiting his blog. He goes in to detail on how to use remoting to send the image to the server. Thanks to the both of them for their help! [...]
[...] of the piece come from two places. James Ward has described this technique in his Flex Paint sample. And Tinic Uro has written the PNG Encoder library. Let’s see the code [...]
[...] component as an image that the user can then save, either by bouncing the information off a server (James Ward – RIA Cowboy and Flex Cookbook) or interacting with JavaScript (Doug McCune). However, additions made to the [...]
[...] simple, short, and to be honest kinda boring that end up being read by tons of people. My original Flex Paint blog is one of those simple, short but highly viewed blogs. I would never have thought that out of all [...]