Export a movie clip from Flash to an image file using C#/ASP.NET and ActionScript’s BitmapData

Update #2 : I fixed another bug where non-square images would not be rendered properly because the height and width were being processed backwards. I fixed the source code in the article, as well as in the ZIP file.

Update #1 : I realized that the ActionScript GetPixel() function doesn’t always return a 6 characters long string, which will cause the pixel data sent to the ASPX page to be corrupted.

Introduction

In this article, I’m going to demonstrate how to export the content of a movie clip from Flash to a JPEG file.

Flash is a great tool that I used for years now. I recently worked on a project involving Flash, and got asked if it was possible to save the content displayed inside Flash to a file. Yes, it’s possible, and actually not very difficult to achieve.

The key element here is to convert the vector graphics to a bitmap, then to get color information for every pixel of that bitmap, and send them to the server where a small program will re-compose the image.

The source code for this article is available for download.

Let’s get started.

Step 1: Create a Flash movie

I created an empty Flash movie (ExportBitmapData.fla), and added some code to its first and unique frame. The code does 3 things:

  • Generate a movieclip and draw some shape in it.
  • Create a BitmapData object and copy the content of the movieclip into it.
  • Send the pixel values to the server by clicking on a button

Please note that you need to manually add a Button component to the library, or it won’t be instanciated.

The first part of the code is about creating variables and calling the functions when the Flash loads:

import flash.display.BitmapData;

var container:MovieClip = null;
var fx:MovieClip = null;
var bmp:BitmapData = null;
var btnExport:mx.controls.Button = null;

function movie_load():Void
{
    // Create a container movieclip
    container = this.createEmptyMovieClip("container", this.getNextHighestDepth());
    // Create a BitmapData object that will hold the copy of the container movieclip
    bmp = new BitmapData(200, 200);
    fx = this.createEmptyMovieClip("fx", this.getNextHighestDepth());

    DrawMovieClip();
    DrawButton();
}

Then there is the method that draws some image as a regular vector graphic, and then creates a copy in the BitmapData object.

function DrawMovieClip():Void
{
    // Draw two overlapping square to the "container" movieclip
    container.clear();
    container.beginFill(0x000000, 50);
    container.moveTo(0,0);
    container.lineTo(200,0);
    container.lineTo(200,200);
    container.lineTo(0,200);
    container.endFill();

    container.beginFill(0x800000, 50);
    container.moveTo(50,50);
    container.lineTo(150,50);
    container.lineTo(150,150);
    container.lineTo(50,150);
    container.endFill();

    fx.clear();

    // copy the movieclip into the BitmapData
    bmp.draw(container);

    fx.attachBitmap(bmp, fx.getNextHighestDepth());
    fx._x = 250;
}

Add a button that will trigger exporting

function DrawButton():Void
{
    btnExport = this.createClassObject(mx.controls.Button, "btnExport", this.getNextHighestDepth(), {label:"Export"});
    btnExport.move(10, 210);
    btnExport.addEventListener("click", ExportBitmap);
}

Create the exporting function, the one that is called when the button is clicked. It works by iterating through each pixel of the BitmapData object, and building a string that contains all the colors value. In this case, the string looks like “8080808080808080808…”. That string is transmitted to the server, and will be processed by C#.

function ExportBitmap(evt:Object):Void
{
    var output:String = "";
    var col = "";
    for(var i:Number=0;i<bmp.height;i++)
    {
        for(var j:Number=0;j<bmp.width;j++)
        {

            col = bmp.getPixel(j,i).toString(16);		

            // In some cases, the color will be truncated (e.g. "00FF00" becomes "FF00")
            // so we are adding the missing zeros.
            while(col.length<6)
            {
                col = "0" + col;
            }
            output+=col;
        }
    }

    // Use a LoadVars to transmit the data to the ASPX page using POST
    var lv:LoadVars = new LoadVars();
    lv.pixels = output;
    lv.height = 200;
    lv.width = 200;

    lv.send("GetPixelData.aspx", "_blank", "POST");
}&#91;/sourcecode&#93;
Then just add a call to the main function
&#91;sourcecode language='jscript'&#93;
movie_load();
stop();&#91;/sourcecode&#93;
If I run the flash movie, here is what I get:<img src="https://saezndaree.files.wordpress.com/2007/10/bitmapdatatransform.gif" alt="Vector movieclip and bitmap copy side by side" />The vector movieclip is on the left, and its bitmap copy is on the right.We now have a way for flash to transmit the image to the server.  Let's look at how these pixel information should be processed on the server-side.
<h2>Part 2: Save the image with ASP.NET</h2>
I created a new Web Project in Visual Studio 2005, and copied the flash files to the project's directory.  The project will contain two web pages, the first one (default.aspx) will contain the flash, while the second (GetPixelData.aspx), will receive the pixel data and gather them to form the image.

The default.aspx page is very simple.  It only contains the code necessary to display the flash object:


<body>
    <form id="form1" runat="server">
    <div>
        <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" width="550" height="400" id="ExportBitmapData" align="middle">
        <param name="allowScriptAccess" value="sameDomain" />
        <param name="movie" value="ExportBitmapData.swf" /><param name="quality" value="high" /><param name="bgcolor" value="#ffffff" /><embed src="ExportBitmapData.swf" quality="high" bgcolor="#ffffff" width="550" height="400" name="ExportBitmapData" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
        </object>
    </div>
    </form>
</body>

The HTML code for GetPixelData.aspx is even simpler:

<body>
    <form id="form1" runat="server">
    <div>
    <asp:Label ID="lblPixelData" runat="server" />
    </div>
    </form>
</body>

The really intersting part is in its code-behind file, GetPixelData.aspx.cs:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using System.Drawing;

public partial class GetPixelData : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Retrieve the pixel data from Flash
string pixelData = Request[“pixels”];

// If there is no data, simply display a message
if (pixelData == null)
{
lblPixelData.Text = “No data available”;
return;
}

//The width and height of the image have been transmitted as well
int width = int.Parse(Request[“width”]);
int height = int.Parse(Request[“height”]);

Bitmap bmp = null;

string curPixelColor = String.Empty;

int x = 0;
int y = 0;

if (pixelData != String.Empty)
{
// Here we create a Bitmap object that has the same size as the one in Flash
bmp = new Bitmap(width, height);

// Iterate through each group of six characters and convert them to a Color
// then assign that color to the pixel of the Bitmap object
for (int i = 0; i < pixelData.Length / 6; i++) { curPixelColor = pixelData.Substring(i * 6, 6); bmp.SetPixel(x,y, ColorTranslator.FromHtml("0x" + curPixelColor)); if(x==width-1) { x = 0; y++; } else { x++; } } } // Set the content type as jpeg Response.ContentType="image/jpeg"; // Save the Bitmap object to the ouput stream, and flush the stream bmp.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg); bmp.Dispose(); Response.End(); } }[/sourcecode] Here is a little summary of what is going on:

  • When the user clicks the “export” button, the pixels from the BitmapData are sent to the GetPixelData.aspx page (which opens in a new window) as a long string. Each color value is a sequence of six characters, representing an hexdecimal value.
  • GetPixelData.aspx reads the string from POST.
  • The program loops through the content of the string, extracting the characters by groups of six.
  • At every iteration, the horizontal pixel position is incremented by one, so we’re moving from left to right, then every time we reach the end of a line, the vertical position is incremented as well.
  • The 6 characters group is converted to a color using the ColorTranslator.FromHtml() method, and its value is assigned to the pixel.
  • We set the content of the page as being a JPEG image and flush the content to send it back to the client.

The result looks like this, the new image has been created and is displayed in the browser:
Bitmap object that is sent back from the server

Conclusion

This is a very primitive example of what can be done to send an image from Flash to the server. We could as well save the content to the disk. The major drawback of saving images in such way is that the server load is pretty big. That technique is therefore not suitable for big images.

The end.

Advertisements

Tags: , , , , , , , , ,

36 Responses to “Export a movie clip from Flash to an image file using C#/ASP.NET and ActionScript’s BitmapData”

  1. JC Says:

    this is really interesting!

    i converted your c# into vb.net and started to play to try and improve the final compression. i tried using the .net encoder to save the image to the server at 100%, but still the image is saved server side with noise.

    any thoughts on how to save an image as an exact copy, with no noise, from flash using dot net?

  2. JC Says:

    ignore my previous comment – .net encoding works perfectly, IE cached images gave misleading results.

  3. Undolog.com » Blog Archive » Come salvare immagini in Flash CS3 Says:

    […] Export a movie clip from Flash to an image file using C#/ASP.NET and ActionScript’s BitmapData ActionScript 3.0, Bitmap, BitmapData, Flash CS3, GD, GD Library, Internet, PHP, Save Flash Image, Sviluppo, Tutorials Queste icone linkano i siti di social bookmarking sui quali i lettori possono condividere e trovare nuove pagine web. […]

  4. Bugs Shah Says:

    I hv a very big image about 1600 x 800 and I want to send it to the server for storage. I tried this code it is working fine for small and medium sized images but not for what I required.

    It gives error – “A script in this movie is causing Adobe flash player 9 to run slowly. Do you want to abort the script Yes / No?”

    Please let me know what will be solution so that I can send big image data to the server on any machine.

  5. saezndaree Says:

    Well, it’s no surprise. A 1600×800 image contains 1,280,000 pixels. The ActionScript is struggling processing that amount of information. The algorithm presented in my article is clearly not suitable for that kind of task, and I doubt Flash in general is even a good solution to deal with that kind of images.

    The only solution I can propose is to omit some of the image’s pixels, to reduce the CPU load.

  6. Sayeam Khan Says:

    This is very nice article.
    Is it possible to export an image file by using PHP and ActionScript’s BitmapData?

  7. saezndaree Says:

    Thanks!

    Yes, it is completely possible to do so with PHP. The ActionScript should remain the same, only the server-side module will change. PHP has several libraries to process the pixel data on the server side.

    You can look at http://www.sephiroth.it/tutorials/flashPHP/print_screen/ for example.

  8. Jeff Says:

    Would it be possible to send large image files if the output array was first converted into binary?

    Excellent article.

  9. saezndaree Says:

    It’s actually more a matter of converting the image to a *compressed* format. I’ve never tried doing that in ActionScript 2, but I know AS3 has language features to make that easier.

    Doing so, the new problem is that Flash is slow, and compressing very large images might take a lot of time and freeze Flash Player.

  10. zseven Says:

    Hi, great code, but in preview on page GetPixelData.aspx the image is very low quality…
    How can i have a better quality?

    Tx a lot for your work!

  11. saezndaree Says:

    If the low quality is related to JPEG compression, you can specify your own encoding settings when saving the image with Image.Save(Stream, ImageCodecInfo, EncoderParameters).

    See http://msdn.microsoft.com/en-us/library/ms142148.aspx. There is a code sample at http://msdn.microsoft.com/en-us/library/system.drawing.imaging.encoderparameter.aspx.

  12. Steve Says:

    Great article! I was wondering though, what if you wanted to create a .PNG, with transparency? would that be possible using a similar method?

  13. saezndaree Says:

    I did not try it formally, but I believe it would be as simple as passing 8 hex characters intead of 6 (ARGB), the additional pair being the alpha value for the selected pixel. The alpha value for a pixel can be retrieved in ActionScript using BitmapData.getPixel32().

    Then, on the server, you should be able to produce a PNG with transparent pixels, by assigning the alpha values in addition to the RGB values.

  14. Gavyn Says:

    I like this article, however is there a way of doing this in AS3?

  15. magnum blog » Blog Archive » links for 2008-07-04 Says:

    […] Export a movie clip from Flash to an image file using C#/ASP.NET and ActionScript’s BitmapData « … (tags: flash actionscript .net c# asp.net image export development dev code aspx important) […]

  16. ryan Says:

    Hi saezndaree,

    I am trying to get a webcam to show instead of that picture/movie clip, but you assign it to “container” and set it inside your AS it seems ( not very good with actionscript), i have tried editing it to show a webcam and direct it to take a picture of it but to no success(doesnt show when i run it).

    This short bit of AS shows a webcam in AS2

    //you need to have a video object on the pane named “video_vobj”
    var cam:Camera = Camera.get();
    cam.setMode(900,650,20);
    video_vobj.attachVideo(cam);

    Can any1 help me try accomplish showing the webcam and exporting( take a snapshot) through to your code?

  17. Selva Says:

    how to display a flash image which is stored as points(x,y) in a xml file using actionscript

  18. Andrew Says:

    As many have said here, thank you very much for this great tutorial. I have been searching for this type of information for 2 days and this is the best so far.

    Everything is great about this however, is it possible to provide direction regarding saving of the image to the users HD (prompt to save message) as you have mentioned?

    The new browser window that opens is somewhat elementary to use especially if the window size cannot be controlled.

    I would greatly appreciate it if you could provide guidance for saving to disk Thank you!

  19. James Says:

    Hello – this is working great.

    What would I need to do to save this to a file server location instead of displaying it?

  20. saezndaree Says:

    @Andrew: Thanks for your comment. Forcing download of an image on the client is tricky, as most browsers will display the pictures instead of prompting you for saving it. I don’t have an answer to that question. I would look for browser instructions (META tags) or MIME types instructing the browser to download the page instead of opening it.

    @James: Change the target stream to a FileStream when saving the image

    FileStream stream = new FileStream(“C:\\image.jpg”, FileMode.Create);
    bmp.Save(stream, ImageFormat.Jpeg);

  21. James Says:

    Thanks Saezndaree! Works like a charm!

    Now – hopefully you can see this before I head out of town for a week, but how would I go about saving a ‘snapshot’ of the stage upon the click of the button instead of saving an image/bitmap that was created at run time?

    I would like to take a snapshot of a rectangular area of the stage, save it to the bmp and then let it take over. I’m going to fool around with it, but if you have an idea, please let me know! Thanks! Great work!

  22. arun Says:

    hi,

    very nice article…my requirement is to save that images on the disk(c:,d:)
    or somewhere….

    Thanks in advance

  23. Dude Man Says:

    To save on the disk you simply push the image to the user through http request and a download popup shows up.

  24. Gurumoorthy Says:

    Hi,
    i am using the same concept , i am getting the exported image right side as shown in ablove example, i have tested it is working in local

    I have deployed the same files in IIS server, then i tried to like http://localhost:8080/export.html , on button press bitmap created with specified with and height

    // copy the movieclip into the BitmapData
    bmp.draw(container);

    fx.attachbitmap

    i am not seeing my movieclip inside that bitmap image (), anything i want to set in IIS , or i need to change any publish settings

  25. DMennenoh Says:

    Nice – couple things – you can avoid the error when getting the pixels of a large image by doing it with an interval instead of a for loop. Like grab one row every 5ms…
    Also – I have a super fast, and easy to use array compressor for just this. See http://www.blurredistinction.com/wordpress/?p=9
    It can dramatically reduce the load when sending the data.

  26. Yaary Says:

    could you please post example saving file to server instead of creating image in browser.

    I have tried implementing:

    FileStream stream = new FileStream(”C:\\image.jpg”, FileMode.Create);
    bmp.Save(stream, ImageFormat.Jpeg);

    but got an error, maybe I have not placed in the correct place

    my mail is tmpfool@gmail.com

    thank you

  27. Shefeek Jinnah Says:

    Hii dude…the work u did is really awesome.I have been searching for this code for the last 3 days….My intention was to bring webcam preview on my webpage in c#.net and to take photo . I can implement it using ur code snippets.I will upload the tutorials if which i have done with in a week in my website

  28. Flash Monkey - Stephen Burgess Says:

    […] biggest challenge was saving the scrapbook out as a JPEG but after a bit of a google search I found this really useful post which worked […]

  29. metalG Says:

    Hey… love this! Was wondering if there was a way of physically altering/ interacting with the movie clip i.e. dragging elements around and then importing the altered movie clip into the bitmapData object?

    Thanks

  30. saezndaree Says:

    Hi,

    Essentially, every change you make to the MovieClip instance that’s being passed to the bmp.draw(movieClip) function (where bmp is a BitmapData instance) *before* you actually call this function will be taken into account. It’s like taking a picture of the MovieClip.

    Obviously, it requires some additional coding, to enable drag & drop etc., but you can still use the same code to gather the pixel data. Just keep in mind that all the dynamic elements that you want to include in the BitmapData object need to be contained in the same MovieClip.

  31. metalG Says:

    thanks for the prompt reply. If the movie clip is being imported from the library at runtime, how can I alter the contents of that movie clip if I’m not able to update the library items at runtime?

    Basically I need to have the movie clip already on the stage, so that its contents can be interacted with, and then have some sort of button that submits that to the bitmapData object… etc…

    Is this possible? do I just need to remove the code that creates an empty movie clip?

  32. Parvaiz Patel Says:

    Wonderful!

    You rock man!!!

    I have been searching for this since last couple of weeks & got it by you.

    tnx,

  33. olivier fr Says:

    Great.

    is it possible to launch the flash on the asp.net server (after a request) and just return the exported image (the browser only see an image) ?

  34. dug Says:

    Hey Can you do it by using ASP.NET code, not by actionscript, just input a flash.swf file and capture a screenshot of it.
    Thanks !

  35. çocuk oyun Says:

    çocuk oyun…

    […]Export a movie clip from Flash to an image file using C#/ASP.NET and ActionScript’s BitmapData « Le Bash Blog[…]…

  36. Minimal Monkey - Stephen Burgess Says:

    […] biggest challenge was saving the scrapbook out as a JPEG but after a bit of a google search I found this really useful post which worked […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s


%d bloggers like this: