Symmetri Developer Blog

April 29, 2009

Download Flex UI Component as JPG

Flash/Flex - By Shourov Bhattacharya

So I finally got this working. What I wanted to do was to add a "Save As Image" option to charts and grids which are part of a client’s reporting suite that is being developed as an online Flex application; the idea being that this would work just like it does with images in a browser’s HTML pages, allowing the user to save an image to the desktop or anywhere else on the local filesystem.

Getting the image data is easy - the new ImageSnapshot class in Flex 3 allows you to easily take a Bitmap "snapshot" of any DisplayObject and keep it as a ByteArray. However, getting the captured image back to the user is a little trickier. Flash Player 9 and below has a security sandbox model that disallows your Flex application from sending a file straight back through the browser, so what we have to do is "reflect" the image data off a server page - in other words, get our user’s browser to handle a new request that uploads the image data back to the server and then downloads that exact same data again, with the right headers, back in the browser client.

On the Flex side, I wrote up a little class which handles all the mechanics of taking the snapshot and launching the "reflected" page:

	
package com.symmetri.Tools
{
    import flash.display.IBitmapDrawable;
    import flash.events.*;
    import flash.net.*;
    import flash.net.navigateToURL;
    import flash.utils.ByteArray;
	
    import mx.controls.*;
    import mx.core.*;
    import mx.graphics.ImageSnapshot;
    import mx.graphics.codec.JPEGEncoder;
    import mx.utils.*;    
	
    public class ImageExporter
    {
        private var _reflectUrl:String;
	
        private var _snapshot:ImageSnapshot;
        private var _rawData:ByteArray;
	
        public function ImageExporter(reflectUrl:String)
        {
            _reflectUrl = reflectUrl;
        }
	
        // take a snapshot of a UI component as a JPG image
        // pass dpi of zero to take it at native screen resolution
        public function snapshotObjectAsJPGByteArray(source:IBitmapDrawable, dpi:Number = 0):ByteArray
        {
            // take the snapshot
            _snapshot = ImageSnapshot.captureImage(source, dpi, new JPEGEncoder());
            return (_snapshot.data as ByteArray);
	
        }
	
        // take a snapshot of a UI component as a JPG image
        // and send it to the browser as a download file
        // pass dpi of zero to take it at native screen resolution
        public function downloadObjectAsJPG(source:IBitmapDrawable, dpi:Number = 0):void
        {
            _rawData = this.snapshotObjectAsJPGByteArray(source, dpi);
	
            var _request:URLRequest = new URLRequest(_reflectUrl);
            _request.method = URLRequestMethod.POST;
            _request.contentType = application/octet-stream;
            _request.data = _rawData;
	
            navigateToURL(_request, _self);
        }
    }
}

On the server side, we have a blank ASPX page with the following code-behind (C#):

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.IO;
	
public partial class ReflectJPG : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // method “attachment” or “inline”
        string method = (Request.QueryString[method] == null ? attachment: Request.QueryString[method].ToString());
	
        // filename
        string filename = (Request.QueryString[filename] == null ? image.jpg : Request.QueryString[filename].ToString());
	
        byte[] data = readPostedFile();
	
        Response.ContentType = image/jpg;
        Response.AddHeader(Content-Length, data.Length.ToString());
        Response.AddHeader(Content-disposition, method + ; filename= + filename);
        Response.BinaryWrite(data);
        Response.End();
    }
	
    // read the posted file
    private byte[] readPostedFile()
    {
        if (Request.ContentLength > 0)
        {
            byte[] buffer = new byte[Request.ContentLength];
            using (BinaryReader br = new BinaryReader(Request.InputStream))
                br.Read(buffer, 0, buffer.Length);
            return buffer;
        }
        else
        {
            return null;
        }
    }
}

Finally, to use the ImageExporter class in Flex, I use the following pattern to download a JPG snapshot of the component viewReport:

var exporter:ImageExporter = new ImageExporter(”http://www.symmetri.com/ReflectJPG.aspx”);
    exporter.downloadObjectAsJPG(viewReport);

April 20, 2009

Export Flex UI as image?

Flash/Flex - By Shourov Bhattacharya

I have been doing some research into how it might be possible to implement a "Right Click –>Save As Image" type functionality within a Flex application. This may run up against some problems with the Flash Player security sandbox, which will generally stop your local Flex application from saving anything to the local file system unless it is first bounced off a server (Flash Player 9-).

It appears that a solution that works across all version of Flash player will definitely the help of a server page - essentially, we need to take a snapshot of a bitmap image, save to the server and then use the server as a download location for the client. There is also a "server-less" solution, but that will only work in Flash player 10.

 The table below summarizes the options:

Solution Flash Player Server? Effort? Notes
Create Bitmap data from Flex UI and bounce off a server page e.g. see this article All versions Yes High Probably best, most robust solution but will need server side development and will take time
Use FusionCharts and supported SAI functionality All versions Yes Medium/Low Good solution but needs server side development
Use new capabilities of Flex for Flash Player 10 to save image (FileReference for local file) Flash Player 10+ No Low Quickest but will not work on Flash Player 9 or less without upgrade ( about 40% of clients - see stats)
Use “hacked” solution that uses JavaScript to save on local filesystem - see example All versions but won’t work in IE! No Medium/Low Not suitable as won’t work in IE and may not work for larger images

 

April 2, 2009

browsershots.org

General - By Shourov Bhattacharya

Something a colleague of mine pointed me to that seems like a very cool implementation of a cool idea. browsershots.org is a site that uses a network of distributed computers to render your webpage in a variety of different browsers. Could be a wonderful tool for front-end web developers. Developed by Johann C. Rocholl.

Get free blog up and running in minutes with Blogsome
Theme designed by Janis Joseph