Thursday, July 14, 2011

Silverlight 4 - Save UIElement as image in IsolatedStorage

One of the common feature expectation in Silverlight Application is the option to save the entire page or part of the page as image. There are pretty good articles over the web to save an UIElement as an image. One such article is posted by Victor Gaudioso here.

Our example is going to deal with saving an UIElement in Silverlight as png image in isolated storage. WriteableBitmap accepts UIElement which in turn need to be encoded for which I use Joe Stegman’s PngEncoder. Following code Snippet 1,
  • Generates the png stream with the help of PngEncoder
  • Creates the byte[] from the png stream
  • Checks for the available free space in the isolated storage and increase quota if needed
  • Save the image in png format in the isolated storage.
Snippet 1
private void SaveInIsolatedStorage()
{
    string fileName = "FileCheck1.png";
    Byte[] printBuffer;
    System.Windows.Media.Imaging.WriteableBitmap wBitmap;
    
    wBitmap = new WriteableBitmap(ElGrid, null);

    wBitmap.Invalidate();

    System.IO.Stream pngStream = Encode(wBitmap); 

    printBuffer = new Byte[pngStream.Length];
    pngStream.Read(printBuffer, 0, printBuffer.Length);
    
    if (!FileExists(fileName))
    {
        using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
        {
            if (isoStore.AvailableFreeSpace < pngStream.Length)
            {                        
                if (isoStore.IncreaseQuotaTo(isoStore.Quota + (pngStream.Length - isoStore.AvailableFreeSpace) + 1024))
                {
                    using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.CreateNew, isoStore))
                    {
                        stream.Write(printBuffer, 0, printBuffer.Length);
                    }
                }
            }
            else
            {
                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.CreateNew, isoStore))
                {
                    stream.Write(printBuffer, 0, printBuffer.Length);
                }
            }
            
        }

    }
    
}

Snippet 2
(Encode: got from an article. Download PngEncode.cs from the above specified blogs in order to execute the line "return PngEncoder.Encode(buffer, w, h);")
public static Stream Encode(WriteableBitmap wb)
{
    int w = wb.PixelWidth;
    int h = wb.PixelHeight;
    int adr;

    int rowLength = w * 4 + 1;

    byte[] buffer = new byte[rowLength * h];

    for (int y = 0; y < h; y++)
    {
        buffer[y * rowLength] = 0; // filter byte

        for (int x = 0; x < w; x++)
        {
            adr = y * rowLength + x * 4 + 3;

            int pixel = wb.Pixels[x + y * w];

            buffer[adr--] = (byte)(pixel & 0xff); pixel >>= 8;
            buffer[adr--] = (byte)(pixel & 0xff); pixel >>= 8;
            buffer[adr--] = (byte)(pixel & 0xff); pixel >>= 8;
            buffer[adr] = (byte)(pixel & 0xff);
        }
    }

    return PngEncoder.Encode(buffer, w, h);
}

In order to verify the storage manually, follow the path "C:\Users\[USER NAME]\AppData\LocalLow\Microsoft\Silverlight\is" in windows 7.

To save the image in the database, modify the Snippet 1 by removing the isolated storage related code (probably lines after 15) and make use of the printBuffer byte[] for storage.

This is just to introduce a basic idea of saving an UIElement in image format. Different encoders need to be used with respect to the format to be saved. Libraries like http://imagetools.codeplex.com/ can help you to achieve this.

References
http://blogs.msdn.com/b/jstegman/archive/2008/04/21/dynamic-image-generation-in-silverlight.aspx
http://www.windowspresentationfoundation.com/?p=406
http://imagetools.codeplex.com/

2 comments:

  1. This will only work on out of the browser mode right??
    In the browser it will throw a Security Exception at runtime, isn't it?

    ReplyDelete
  2. @Albino: This will work in regular (browser) mode without any issue. Browser won't throw any Security Exception.
    Only thing is, the IncreaseQuotaTo()(Snippet 1 , Line 22) will prompt you with a dialog "Do you want to increase available storage?" If you click "Yes" in that dialog, the quota will be increased and respective proceedings will take place which you can infer from Snippet1.

    ReplyDelete

Creative Commons License
This work by Tito is licensed under a Creative Commons Attribution 3.0 Unported License.