Summary: Saving Bitmaps to Isolated Storage in Silverlight 3
There may be times when you wish to save a bitmap image to the user’s local storage. Perhaps it was a generated image that is used in the application, or maybe it is an externally referenced image that you are loading locally for caching purposes. I found many examples online of generating a “save dialog” box, but none for saving it.
This is a very bare bones application that demonstrates how to save the image. This is in no industry-standard format-it literally writes out the size of the image in pixels (height, width), then streams out the bytes for alpha, red, green, and blue. It is meant as a foundation to better understand how to get the image data and manipulate it. Once you “know” the pixels, then you can easily start to apply more advanced algorithms like BMP, PNG , JPG, or even GIF to save and retrieve the data.
Here is the XAML-you can create a new Silverlight Application and literally p lop in the XAML and code-behind to get started:
view sourceprint?
01.
<
UserControl
x:Class
=
"BitmapSaver.MainPage"
02.
????< /code>
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
?
< code>03.????
xmlns:x
=
"http://schemas.microsoft.com /winfx/2006/xaml"
04.
????
xmlns:d
= code>
"http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc
=
"http: //schemas.openxmlformats.org/markup-compatibility/2006"
?
05.
????
mc:Ignorable code>
=
"d"
d:DesignWidth
=
"640"
d:DesignHeight
=
"480"
>
06.< /code>
??
<
Grid
x:Name
=
" LayoutRoot"
>
07.
????????
<
< code>Grid.RowDefinitions>
08.
????????????
<
RowDefinition
Height
=
"30"
>
RowDefinition
>
09.
????????????
<
RowDefinition
Height
=
"30"
>
RowDefinition
>
10.
????????????
<
RowDefinition
>
RowDefinition
>
11.
????????
Grid.RowDefinitions
>
12.
????????
<
Canvas
Ho rizontalAlignment
=
"Left"
x:Name
=
"CanvasSource"
Height
=
"20"
Width
=
"100"< /code>
Grid.Row
=
"0"
>
13.
????????????????
<
TextBlock
FontSize
=
"14"
VerticalAlignment
=
"Center"
HorizontalAlignment
=
"Center"
Width
=
"Auto"
Height
code>=
"Auto"
Foreground
=
"Red"
FontWeight
=
"Bold"
Text
=
"BitMapExample"
/>????????????????????????????
14.
????????
Canvas
>
15.
????????
<
Image
HorizontalAlignment
=
"Left"
x:Name
=
"BitmapImageRef"
Stretch
=
"None"
Grid.Row
=
"1"
/> code>
16.
????????
<
TextBlock
x: Name
=
"Status"
Text
=
"Processing..." code>
Grid.Row
=
"2"
/>????????
17.
??
Grid
>
18.
UserControl
>
In the XAML, there is a grid with three rows. The first is a canvas with red text inside it. This is what we'll turn into a bitmap image and save. The second row is an image "placeholder" for the image that we process. The final row is a simple text block to update the status.
Here is the code-behind:
view sourceprint?
001.
< code>public partial
class
MainPage
002.
{
003.
????
private
const
string
SAVEDIMG =
"SavedBitmapImage.xyz"
;
004.
???????? ?
?
005.
????
///
006.
????
///???? Default constructor code>
007.
????
///
008.
????
public
MainPage()
009.
????
{
010.
????????< /code>
InitializeComponent();
011.
????????
CanvasSource.Loaded += _MainPageLoaded;
012.
????
}
013.
?
?
014.
?? ??
///
015.
????
< code>///???? Canvas loaded 016.
????
///
summary>
017.
????
///
018.
????
///
019.< /code>????
void
_MainPageLoaded(
object
sender, RoutedEventArgs e)
020.
????
{
021.
??? ?????
Status.Text =
"Checking disk..."
;
022.
????????
byte
[] buffer = _LoadIfExists(SAVEDIMG);?
023.
?
? 024.
????????
if code> (buffer.Length> 0)
025.
????????
{
026.
????????????
Status.Text =
"Loading.. ."
;
027.
????????????
BitmapImageRef. Source = _GetImage(buffer);
028.
????????????
Status.Text = < /code>"Loaded."
;
029.
????????
< code>}
030.
????????
else
031.
????????
{
032.
???????? ????
Status.Text =
"Rendering..."
;
033. code>????????????
WriteableBitmap bitmap =
new
WriteableBitmap(CanvasSource,
new
TransformGroup());
034.
????????????
BitmapImageRef.Source = bitmap;
< code>035.
????????????
Status.Text =
"Saving..."
;
036.
????????????
_SaveToDisk(_GetSaveBuffer(bitmap), SAVEDIMG);
037.
????????????
Status.Text =
< code>"Saved."
;
038.
????????
}? ??????????????????????
039.
????
< code>}
040.
?
? 041.
????
///
042.
????
/// ???? Load file, if it exists
043.
????
///
044.
????
/// The filename
045.
????
/// < returns> The byte array for the file
046.
????
private
static
byte
[] _LoadIfExists(
string
fileName)
047.< /code>????
{
048.
????????
< code>byte
[] retVal;
049.
?
? 050.
????????
using
(IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication())
051.< /code>????????
{
052.
????????? ???
if
(iso.FileExists(fileName))
053.
????? ???????
{
054.
????????????????
using
(IsolatedStorageFileStream stream = iso.OpenFile(fileName, FileMode.Open))
055.
? ???????????????
{
056.
????????????????????
retVal =
new
byte
[stream.Length];
057.
????????????????????
stream.Read(retVal, 0, retVal.Length);
058.
????????????????
}
059.< /code>????????????
}
060.
????? ???????
else
061.
????????????
{
062.
????????????????
retVal = code>new
byte
[0];
063.
?????? ??????
}
064.
????????
} < /code>
065.
????????
return
retVal;
066.
????
}
067.
?
? < br> 068.
????
///
069.
????
///?? ?? Saves to isolated storage
070.
????
///
071.
????
/// The buffer
072.
????
///
073.
????
private
static
void
_SaveToDisk(
byte code>[] buffer,
string
fileName)
074.
????< /code>{
075.
????????
using
( IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication())
076.
????????
{
077.
????????????
using
(
078.
????????????????
IsolatedSto rageFileStream stream =
new
IsolatedStorageFileStream(fileName, FileMode.CreateNew,
079.
????? ??????????????????????????????????????????????? ???????????????????????
iso))
080.
iso))
080.
iso)) code>????????????
{
081.
?????? ??????????
stream.Write(buffer, 0, buffer.Length);
082.
? ???????????
}
083.
????????
}
084.
????
}
085.
?
?
086.
????
///
< /code>
087.
????
///???? Gets an image from storage
088.
????
///
089.
????
///
090.
????< /c ode>/// The bitmap
091.
????
private code> static
WriteableBitmap _GetImage(
byte
[] buffer)
092.
????
{
093.
????????
int
width = buffer[0]*256 + buffer[1];
094.
????????< /code>int
height = buffer[2]*256 + buffer[3];
095.
? code>?
096.
????????
long
matrixSize = width*height;
097.
?
?
098.
????????
< code>WriteableBitmap retVal =
new
WriteableBitmap(width, height);
099.
?
?
100.
????????
int
bufferPos = 4;?
< br> 101.
?
?
102.
????????
for
(
int
matrixPos = 0; matrixPos
103.
????????
{
104.
????????????
int
pixel = buffer[bufferPos++]; < /code>
105.
????????????
pixel = pixel << 8 | buffer[bufferPos++]; < /code>
106.
????????????
pixel = pixel << 8 | buffer[bufferPos++]; < /code>
107.
????????????
pixel = pixel << 8 | buffer[bufferPos++]; < /code>
108.
????????????
retVal.Pixels[matrixPos] = pixel;
109.
????????
}
110.
?
?
111.
????????
return
retVal;?
112.
????
}
113.
? code>? < br> 114.
????
///
115.
????
///???? Gets the buffer to save to disk from the writeable bitmap
116. code>????
///
117.
? ???
/// The bitmap image
118.
????
/// The buffer of bytes
119.
????
private< /code> static
byte
[] _GetSaveBuffer(WriteableBitmap bitmap)
120.
?? ??
{
121.
????????
long
< code>matrixSize = bitmap.PixelWidth*bitmap.PixelHeight;
122.
?????????
?
123.
????????
long
byteSize = matrixSize*4 + 4;?
< code>124.
?
?
125.
????????
byte
[] retVal =
new
byte
[byteSize];
126.
?
?
127.
????????
long
bufferPos = 0;
128.
?
?
129.
????????
retVal [bufferPos++] = (
byte
) ((bitmap.PixelWidth / 256) & 0xff);
130.
< code>????????
retVal[bufferPos++] = (
byte
) ((bitmap.PixelWidth% 256) & 0xff) ;
131.
????????
retVal[bufferPos++] = (
byte< /code>) ((bitmap.PixelHeight / 256) & 0xff);
132.
????????
retVal[bufferPos++] = (
byte
) ((bitmap.PixelHeight% 256) & 0xff);
133.< /code>?
?
134.
????????
for
(
int
matrixPos = 0; matrixPos
135.< /code>????????
{
136.
????????? ???
retVal[bufferPos++] = (
byte
)((bitmap.Pixels[matrixPos] >> 24) & 0xff);
code>
137.
????????????
retVal[bufferPos++] = (
byte
)((bitmap.Pixels[matrixPos] >> 16) & 0xff);
138.
??????? ?????
retVal[bufferPos++] = (
byte
)((bitmap.Pixels[matrixPos] >> 8) & 0xff);
139.
????????????
retVal[bufferPos++] = (
byte
)((bitmap.Pixels[matrixPos]) & 0xff);????
140.
???? ????
}
141.
?
?
142.
< code>????????
return
retVal;
143.< /code>????
}
144.
}
The main process simply waits for the canvas to be loaded.
We check if the image is saved in isolated storage. If it exists, we render it and attach it to the image. If not , we render it based on the cavas in the first row and then save it.
_LoadIfExists
is a basic routine that checks for a file's existence and if it is there, loads it into a byte buffer and returns it. If the file is not there, it returns an empty byte array.
_SaveToDisk
takes a byte array and persists it to isolated storage. Possible enhancements to this routine include checking to see if the available storage exists and prompting the user to extend it if needed, as well as organizing files into subdirectories and checking for/creating those as well.
_GetSaveBuffer
takes the bitmap and returns a buffer of bytes. The first two bytes are the width, the s econd two the height, and finally the remaining bytes contain the alpha, red, green, and blue channels for each pixel in the bitmap. Obviously this is where you can conform to any one of the graphics standards available and supply your own compression.< /p>
_GetImage
takes the buffer for an image saved in the previous format, and renders it to the bitmap so it can be displayed.
The idea behind this example is to run in debug and step through to see. The first time you run it, it will simply copy the image (the text in this case) and display it as well as save it to isolated storage. Any subsequent run will load it from storage and show it unless you clear storage or change the file name.
Again, this is just a basic introduction to manipulating and saving bitmaps in isolated storage.
Original: Large column Saving Bitmaps to Isolated Storage in Silverlight 3