Flex Paint – Flex Display Object to PNG

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!

This entry was posted in Flex, Java, Open Source, RIA. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

99 Comments

  1. Nishanth Shetty
    Posted October 1, 2008 at 3:26 am | Permalink

    Hi, James

    Thanks for your valuable response.

  2. Nishanth Shetty
    Posted October 1, 2008 at 4:46 am | Permalink

    Hi, James

    Is there any posibility to convert DisplayObject to ByteArray
    (and again ByteArray to DisplayObject )?

    Thank You.

  3. Posted October 1, 2008 at 6:18 am | Permalink

    Hi Shetty,

    Unfortunately not currently. DisplayObjects can not be serialized or introspected.

    Please file a feature request:
    http://bugs.adobe.com

    -James

  4. chuck
    Posted October 1, 2008 at 7:16 am | Permalink

    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.

  5. Posted October 2, 2008 at 2:31 am | Permalink

    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

  6. jo
    Posted November 12, 2008 at 12:59 pm | Permalink

    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

  7. Posted November 13, 2008 at 2:53 am | Permalink

    Hi Jo,

    Did you get this on my website or did you try to set this up yourself?

    -James

  8. Rajv
    Posted December 17, 2008 at 6:39 am | Permalink

    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

  9. Pradeep
    Posted February 10, 2009 at 3:57 am | Permalink

    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.

  10. Posted February 10, 2009 at 6:44 am | Permalink

    @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.

  11. David Bridges
    Posted February 10, 2009 at 9:32 am | Permalink

    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

  12. Pradeep
    Posted February 11, 2009 at 2:04 am | Permalink

    Thnx james… will try out & let u know…
    Pradeep

  13. Pradeep
    Posted February 11, 2009 at 2:28 am | Permalink

    Thnx David… that was in detail… thnx a lot
    Pradeep

  14. Jason
    Posted February 12, 2009 at 1:54 pm | Permalink

    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!

  15. Posted February 12, 2009 at 4:28 pm | Permalink

    @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

  16. Pradeep
    Posted February 17, 2009 at 2:56 am | Permalink

    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

  17. Pradeep
    Posted February 17, 2009 at 4:29 am | Permalink

    You can either reply to this forum or send me a mail
    pradeep.theprince@gmail.com

  18. Posted February 17, 2009 at 8:15 am | Permalink

    @Pradeep

    You can certainly do UNDO but I haven’t done that. You should ask your question on the FlexCoders Yahoo Group.

  19. sushant
    Posted February 23, 2009 at 10:41 am | Permalink

    Hi James,

    Is it possible to get snapshot of swf at Java server side which out rendering the object at clined side

    Thanks,

    Sushant

  20. Posted February 23, 2009 at 10:51 am | Permalink

    @sushant

    You could potentially create an AIR app that runs server side that does this. But scalability is not going to be great.

  21. sushant
    Posted February 24, 2009 at 10:19 am | Permalink

    @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

  22. Posted February 26, 2009 at 10:11 pm | Permalink

    @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

  23. Posted February 26, 2009 at 11:48 pm | Permalink

    @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) ))

  24. Pradeep
    Posted February 27, 2009 at 11:06 am | Permalink

    @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) ))

  25. Pradeep
    Posted February 27, 2009 at 11:09 am | Permalink

    post ur problems, if any, after trying the above solution. It has to work as I did it in the same way & it worked.

  26. Vivek Manchanda
    Posted March 16, 2009 at 6:19 am | Permalink

    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

  27. Posted March 16, 2009 at 12:56 pm | Permalink

    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

  28. Vivek Manchanda
    Posted March 16, 2009 at 11:12 pm | Permalink

    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

  29. Fred Rodriguez
    Posted March 27, 2009 at 11:15 am | Permalink

    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!

  30. Posted March 29, 2009 at 6:59 am | Permalink

    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

  31. Pradeep
    Posted April 14, 2009 at 12:25 am | Permalink

    @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

  32. Pradeep
    Posted April 14, 2009 at 12:28 am | Permalink

    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!!

  33. Posted April 14, 2009 at 9:27 pm | Permalink

    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

  34. Pradeep
    Posted April 15, 2009 at 12:19 am | Permalink

    @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.

  35. Posted April 15, 2009 at 11:17 am | Permalink

    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

  36. Pradeep
    Posted May 10, 2009 at 6:28 am | Permalink

    @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…

  37. Posted May 10, 2009 at 2:57 pm | Permalink

    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

  38. Pradeep
    Posted May 11, 2009 at 12:14 am | Permalink

    Thank you James…

  39. Sundance
    Posted May 12, 2009 at 11:26 am | Permalink

    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

  40. Posted May 13, 2009 at 12:20 pm | Permalink

    Hi Sun,

    I’m not sure of the best approach for that. You might want to ask on http://stackoverflow.com

    -James

  41. Pradeep
    Posted May 19, 2009 at 1:01 am | Permalink

    @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

  42. Greg Baker
    Posted June 13, 2009 at 5:20 pm | Permalink

    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.

  43. Posted June 15, 2009 at 4:32 pm | Permalink

    Hi Greg,

    You can catch a mouseOut event to handle that.

    -James

  44. Greg Baker
    Posted June 16, 2009 at 2:47 pm | Permalink

    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.

  45. Posted June 16, 2009 at 5:17 pm | Permalink

    Wow Greg! Great work! Thanks for posting the details here.

  46. Posted August 28, 2009 at 11:49 pm | Permalink

    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.

  47. Posted August 31, 2009 at 3:13 pm | Permalink

    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

  48. Gene
    Posted January 7, 2010 at 10:41 am | Permalink

    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!!!!!

  49. Posted January 7, 2010 at 10:54 am | Permalink

    @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

  1. [...] 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. [...]

  2. [...] 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!  [...]

  3. [...] 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 [...]

  4. By Save Flex chart as image « Odds On Flex on March 5, 2009 at 9:10 am

    [...] 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 [...]

  5. By Flex Paint 2.0 with Source Code on April 16, 2009 at 11:54 am

    [...] 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 [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

Subscribe without commenting

  • About James Ward



    View James Ward's profile on LinkedIn

  • First Steps in Flex by James Ward and Bruce Eckel




  • Twitter Updates


  • Tour de Flex