Save images from Flash to your server using ASP.NET webservices
Problem:
You want to save an image from Flash to a server using Actionscript 3.0 and ASP.NET.
Solution:
Read this article!
Note: This blog is hosted on a Linux based server that uses PHP, therefore I can’t show you a working example directly on this blog (unless anyone with a Windows based hosting account would like to host one for me?). However, I can assure you this does work and you can download the files here and try it for yourself.
Download “FlashBitmapSave.zip”
Get this thing running
…or just take a look at the code/explanation…Open the downloaded website in Visual Studio 2008 or Visual Web Developer Express 2008. 2005 versions should be fine as well.
Run it.
The default page should come up in your browser. You’ll see my example Flash app. Draw a picture and click “save to server” to - of course - save a JPEG version of your drawing from Flash.
Note: Saved JPEGs will be assigned a random GUID as a filename and saved directly to the root of your C: drive. You can modify the path in App_Code/Service.vb. If you need to know more about that aspect of it, I would continue reading the rest of this post.
If the flash app comes up but gives you the message “webservice failed to initialize…” then:
Click on the root of the project in your solution explorer.
In the properties panel below, take a look at your Virtual Path.
It should only have a “/” in it.
Try it again.
The process
- Take a BitmapData object in Flash, and convert it to a ByteArray object using the JPGEncoder class (or, in my example, the Asynchronous JPEG Encoder class).
- Take that ByteArray and Base64 encode it. We do this so that Actionscript and the .NET back-end will be speaking the same language. If we were using Flex and remoting software like WebORB, this type of conversion would likely happen automatically when sending or receiving a ByteArray object to/from Actionscript or .NET. But for this one-off scenario, doing it ourselves isn’t a big deal.
- Use a third party AS3 webservice class to send the encoded ByteArray to our .NET webservice.
- Our .NET webservice unencodes the ByteArray into its own form of ByteArray, creates a random file name using a GUID, and then saves the raw binary information to a .jpg file.
Some extra stuff you will need
-
Base64 encoder/decoder class
This class from Dynamic Flash will be used to encode our ByteArray to Base64. -
WebService component
Adobe left the WebService classes out of Flash CS3. wellconsidered made their own. This is how we’ll be communicating with the server. This download is available as a .swc and needs to be dropped into your .fla to work. -
Asynchronous JPEG Encoder
In my example I use the Asynchronous JPEG Encoder. You could also use Adobe’s regular JPEG encode available in the AS3 CoreLib.
The Code
Now I’m just going to post the code. I did my best to comment the code thoroughly, but I’m not going to go through it line by line in this post. I’ll assume that if you’re in need of saving bitmap information from flash to a server using .NET, that most of what’s going on you already understand and maybe just needed an example to help you along. So here ya go!
The actionscript 3.0 code:
package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.text.TextField; import flash.net.*; import flash.events.*; import flash.display.MovieClip; import flash.utils.ByteArray; // We'll be sending a ByteArray encoded as Base64, and then decoding it on the .NET side. // http://dynamicflash.com/goodies/base64/ import com.dynamicflash.util.Base64; // be.wellconsidered classes give us an easy means to communicate with webservices. // The extension needs to be installed and the component then dropped into your .FLA. // You'll see a component called "Service" in the library of the example .FLA. // http://www.wellconsidered.be/blog/as3-webservice-component/ import be.wellconsidered.services.WebService; import be.wellconsidered.services.Operation; import be.wellconsidered.services.events.OperationEvent; import be.wellconsidered.services.events.WebServiceEvent; // com.pfp includes classes for the Asynchronous JPEG encoder. There is also a JPEG encoder // in Adobe's CoreLib (http://code.google.com/p/as3corelib/), but because this one is asynchronous it allows to // monitor the rendering of the jpeg and therefore create a progress bar. It is also essential when rendering larger // bitmaps, otherwise Flash could time out during the processing. import com.pfp.events.*; import com.pfp.utils.*; public class FlashBitmapSave extends MovieClip { // we create our WebService object. Remember to include "?wsdl" in the URL. private var wsMainService:WebService = new WebService("/Service.asmx?wsdl"); public function FlashBitmapSave() { mcDrawingBoard.addEventListener(MouseEvent.MOUSE_DOWN, mcDrawingBoard_MouseDown); btnSaveToServer.addEventListener(MouseEvent.CLICK, btnSaveToServer_Click); // the listener on our webservice will let us know if there's a problem with the webservice, // if the url is wrong, if the service is down, etc. wsMainService.addEventListener(WebServiceEvent.INITFAILED, wsMainService_InitFailed); } // **** functions for the drawing pad **** // private function mcDrawingBoard_MouseDown(e:MouseEvent):void { mcDrawingBoard.addEventListener(MouseEvent.MOUSE_MOVE, mcDrawingBoard_MouseMove); stage.addEventListener(MouseEvent.MOUSE_UP, stage_MouseUp); mcDrawingBoard.graphics.moveTo(mcDrawingBoard.mouseX, mcDrawingBoard.mouseY); } private function mcDrawingBoard_MouseMove(e:MouseEvent):void { mcDrawingBoard.graphics.lineStyle(1, 0x000000); mcDrawingBoard.graphics.lineTo(mcDrawingBoard.mouseX, mcDrawingBoard.mouseY); } private function stage_MouseUp(e:MouseEvent):void { mcDrawingBoard.removeEventListener(MouseEvent.MOUSE_MOVE, mcDrawingBoard_MouseMove); } // ************************************** // private function btnSaveToServer_Click(e:MouseEvent):void { var bmdSnapshot:BitmapData = new BitmapData(mcDrawingBoard.width, mcDrawingBoard.height); // take a snapshot of what was drawn in "mcDrawingBoard" bmdSnapshot.draw(mcDrawingBoard); saveImage(bmdSnapshot); } private function wsMainService_InitFailed(e:WebServiceEvent):void { log("Webservice failed to initialize."); } private function saveImage(bmdSend:BitmapData):void { // create a new JPEGAsyncEncoder. 80 is the JPEG quality. var jpgEncoder:JPEGAsyncEncoder = new JPEGAsyncEncoder(80); // encodes 400 pixels before sending out a ProgressEvent. That means every 400 pixels the CPU has a chance to "breath" // and process some other code. jpgEncoder.PixelsPerIteration = 400; jpgEncoder.addEventListener(JPEGAsyncCompleteEvent.JPEGASYNC_COMPLETE, jpgEncoder_Complete); jpgEncoder.addEventListener(ProgressEvent.PROGRESS, jpgEncoder_Progress); jpgEncoder.encode(bmdSend); } private function jpgEncoder_Complete(e:JPEGAsyncCompleteEvent):void { var jpgByteArray:ByteArray = new ByteArray(); // put the raw image data we got back from the encoder into our ByteArray jpgByteArray = e.ImageData; sendToServer(jpgByteArray); } private function jpgEncoder_Progress(e:ProgressEvent):void { log("encoding... " + Math.round(e.bytesLoaded / e.bytesTotal * 100).toString()); } private function sendToServer(byteArray:ByteArray):void { var opJPEGSaver:Operation = new Operation(wsMainService); // unfortunately, I don't think the WebService class we're using has a working ProgressEvent. // if I'm wrong, please let me know! opJPEGSaver.addEventListener(OperationEvent.COMPLETE, opJPEGSaver_Complete); opJPEGSaver.addEventListener(OperationEvent.FAILED, opJPEGSaver_Failed); var strEncodedString:String = new String(); // the Base64 class is static, so we can just call it using Base64.<whatever> strEncodedString = Base64.encodeByteArray(byteArray); // send the encoded bytes to our webservice function we called "SaveJPEG". opJPEGSaver.SaveJPEG(strEncodedString); } private function opJPEGSaver_Complete(e:OperationEvent):void { log("ByteArray successfully sent to server."); } private function opJPEGSaver_Failed(e:OperationEvent):void { log("Error sending ByteArray to server."); } private function log(strLog:String):void { // my own way of tracing to the textfield txtTrace -- as you can see. // not an important part of anything going on here. txtTrace.appendText(strLog + "\n"); traceScrollBar.scrollTarget = txtTrace; txtTrace.scrollV = txtTrace.numLines; } } }
The VB.NET code:
Imports System.Web Imports System.Web.Services Imports System.Web.Services.Protocols Imports System.IO ' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. ' <System.Web.Script.Services.ScriptService()> _ <WebService(Namespace:="http://tempuri.org/")> _ <WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _ <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _ Public Class Service Inherits System.Web.Services.WebService <WebMethod()> _ Public Function SaveJPEG(ByVal strJPEG As String) As String 'saves an uploaded photo and returns a unique name reference Dim BinaryContent As Byte() = Convert.FromBase64String(strJPEG) Try 'generate a unique name (GUID) for the filename Dim strFileName As String = System.Guid.NewGuid.ToString("n") 'MAKE SURE to change the save path! Dim fStream As New FileStream("C:\" + strFileName + ".jpg", FileMode.CreateNew) Dim bw As New BinaryWriter(fStream) bw.Write(BinaryContent) bw.Close() fStream.Close() 'return the filename for use in Flash Return strFileName Catch ex As Exception Return ex.Message End Try End Function End Class
Comments
9 Responses to “Save images from Flash to your server using ASP.NET webservices”
Leave a Reply




it is not working at all
Hey Ashish,
Where are things going wrong? When you try and run the project from Visual Studio? Also, keep in mind that I have the flash movie set to send the image to server (your localhost in this case), but not re-download it. That is a very simple thing to add, and maybe I should have/will. Without any modifications you should be seeing your saved drawing as a JPEG directly on your C drive. Let me know, because I’d hate if everybody was having the same problem.
Hey … It is perfect now..
encoding… 101
encoding… 102
encoding… 100
ByteArray successfully sent to server.
I got saved image on C:\815df32f6d8740c9aebc1dcc33bb4fd9.jpg
Thanks buddy..
There was some mistake in configuring local host…
Here one more thing i would like to ask..
1. How Can i trace save image file name ???
Ashish,
e.data will contain any string send back from the web server. So, in the case of my example you could trace e.data from the opJPEGSaver_Complete(e:OperationEvent) function. Now, keep in mind, this works because the C# code returns the filename (Return strFileName). e.data will contain whatever it returns.
hey there, great piece of code,
had to comment out the Line number 12
//[Microsoft.VisualBasic.CompilerServices.DesignerGenerated()]
line when i transformed it to c#
and add
using System;
thank a lot!
No problem Alexandros. Glad you managed to convert it to C#.
For the lazy plp :-p here is the c# code of the Services class.
Don’t forget to update the Services.asmx to target the new c# class, and exclude your Services.vb or else the compiler will complain.
using System;
using System.IO;
using System.Web.Services;
[WebService(Namespace = "http://microsoft.com/webservices/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : WebService
{
///
/// Saves an uploaded photo and returns a unique name reference
///
[WebMethod]
public string SaveJPEG(string data)
{
byte[] image = Convert.FromBase64String(data);
try
{
// Generate a unique name (GUID) for the filename
string filename = Guid.NewGuid().ToString(”n”);
// MAKE SURE to change the save path!
FileStream s = new FileStream(”C:\\” + filename + “.jpg”, FileMode.CreateNew);
BinaryWriter b = new BinaryWriter(s);
b.Write(image);
b.Close();
s.Close();
// Return the filename for use in Flash
return filename;
}
catch (Exception e)
{
return e.ToString();
}
}
}
indyone,
Thanks a lot for posting that. It will likely help someone out there!
hi,
i unzipped and opened a solution as u said..working fine…i added this app to the server another app which is running live(havethe virtual directory)..when i run this it throws error as web service falied…how to over come this…i got the same error when i run in local..but i solved what u suggested..how to solve in the server..
Thanks in advance
arun