I’m always looking for ways to take advantage of Silverlight to accomplish tasks that traditional web technologies can’t. Here’s one that will save you money, increase scalability, and improve your user’s experience…
Allowing users to upload images is becoming common place for many websites and applications today. Equally common is the fact that most cameras and phones today produce very large and high quality images. On the other hand, very rarely do you actually want a high resolution / low compression image sitting on your server; nor does the average user know or care enough to manually reduce the size of their image before uploading it to your site.
Therefore, unless you’re lazy or in “get it done” mode, you are probably going to want to shrink the image and even increase the compression on that image before storing it on your server. Doing so will result in faster downloads of that image which means lower bandwidth costs and a better user experience.
The typical (and only option for standard Javascript+HTML based sites) is to do the work on the server. But wouldn’t it be great if you could do this work on the client BEFORE sending it up to your server!? Doing so would 1) decrease the time it takes to upload the image in the first place, 2) decrease the amount of work required by your server; thereby increasing scalability of your site, and 3) decrease the bandwidth used by both you and your user; thereby saving you money.
Silverlight has your answer! Here’s how:
Step 1) Use the OpenFileDialog to acquire the stream that contains the bytes of the image.
OpenFileDialog openDialog = new OpenFileDialog();
openDialog.Filter = “JPEG Files (*.jpg;*.jpeg)|*.jpg;*.jpeg”;
if (openDialog.ShowDialog().GetValueOrDefault(false))
{
using (FileStream stream = openDialog.File.OpenRead())
{
// now you have the filestream
}
}
Step 2) Create a WriteableBitmap from those bytes using a ScaleTransform to shrink the image.
public static WriteableBitmap GetImageSource(Stream stream, double maxWidth, double maxHeight)
{
BitmapImage bmp = new BitmapImage();
bmp.SetSource(stream);
Image img = new Image();
img.Effect = new DropShadowEffect() { ShadowDepth = 0, BlurRadius = 0 };
img.Source = bmp;
double scaleX = 1;
double scaleY = 1;
if (bmp.PixelHeight > maxHeight)
scaleY = maxHeight / bmp.PixelHeight;
if (bmp.PixelWidth > maxWidth)
scaleX = maxWidth / bmp.PixelWidth;
// maintain aspect ratio by picking the most severe scale
double scale = Math.Min(scaleY, scaleX);
return new WriteableBitmap(img, new ScaleTransform() { ScaleX = scale, ScaleY = scale });
}
Note: I’m still investigating the need for setting the Effect property on your image control. While this code does not actually affect the user’s image, it is necessary to get this to work. Maybe a bug in Silverlight 3?
Step 3) Encode the WriteableBitmap object back to a Jpeg using FJCore and set your compression quality.
Stream Source = Encode(wb, 20);
public static Stream Encode(WriteableBitmap bitmap, int quality)
{
//Convert the Image to pass into FJCore
int width = bitmap.PixelWidth;
int height = bitmap.PixelHeight;
int bands = 3;
byte[][,] raster = new byte[bands][,];
for (int i = 0; i < bands; i++)
{
raster[i] = new byte[width, height];
}
for (int row = 0; row < height; row++)
{
for (int column = 0; column < width; column++)
{
int pixel = bitmap.Pixels[width * row + column];
raster[0][column, row] = (byte)(pixel >> 16);
raster[1][column, row] = (byte)(pixel >> 8);
raster[2][column, row] = (byte)pixel;
}
}
ColorModel model = new ColorModel { colorspace = ColorSpace.RGB };
FluxJpeg.Core.Image img = new FluxJpeg.Core.Image(model, raster);
//Encode the Image as a JPEG
MemoryStream stream = new MemoryStream();
JpegEncoder encoder = new JpegEncoder(img, quality, stream);
encoder.Encode();
//Move back to the start of the stream
stream.Flush();
stream.Seek(0, SeekOrigin.Begin);
return stream;
}
Step 4) Send the stream for the new, potentially MUCH smaller Jpeg up to your server!
byte[] buffer;
using (Stream Source = JpgEncoder.Encode(wb, 50))
{
int bufferSize = Convert.ToInt32(Source.Length);
buffer = new byte[bufferSize];
Source.Read(buffer, 0, bufferSize);
Source.Close();
}
Service1Client service = new Service1Client();
service.SaveImageAsync(buffer);
That’s it! Plug this code into your Silverlight app everywhere you upload images and improve your website!
Download the source code here.
Credits
Kudos to the folks that made FJCore for sharing all their hard work with those of us that would never consider trying to build it ourselves!
Kudos to nokola for finding a way to build a WriteableBitmap object from an image control without touching the VisualTree.








Google Web Toolkit 2.0 brings web apps one step closer to… Silverlight
December 10, 2009 by Tim Greenfield
What is GWT?
In case you haven’t had a chance to explore, Google Web Toolkit (GWT) is a great new tool for building web applications. At its core, GWT allows developers to code in Java and essentially “compile” to Javascript. But it offers much more: GWT also provides a set of common controls (or widgets) to build UIs and even provides a plugin for Eclipse that allows developers to debug both client and server-side code in the same environment that they write their code. Cross browser compatibility is taken care of for you and if you stay within the confines of GWT, for all practical purposes you’ll think you were building a native Java client/server application.
What’s new in GWT 2.0?
Yesterday Google released Google Web Toolkit 2.0. GWT 2.0 provides a number of improvements but the most important one is the ability to define your UI using markup instead of code. You could always create good old fashion html with GWT, but if you wanted to use the native UI widgets, you’d have to do all the creational work in code. With 2.0 you are now able to use a feature called uiBinder to build your own native GWT widgets (the equivalent of UserControls) all in markup. The cool part is, you can mix html with your GWT markup if you want to.
The Good:
GWT helps developers build complex client/server applications with first class tools in a first class language and target any browser without the need for a plugin. The developer doesn’t have to know anything about Javascript, Html, or cross browser quirks and can use accepted design patterns for building complex web applications.
The Bad:
Before my time, assembly programmers must have argued with C programmers that they could never write code in C that would be as efficient as assembly. They must have argued that there would be certain advanced tasks that couldn’t be done easily in C, and that the compiled C would be bloated by comparison and nearly impossible to read if something went wrong and you needed to inspect your code. This is the same argument GWT faces today from the Javascript camp. Ultimately, a javascript app is still being created under the hood and because of it, GWT developers will never have the same level of control and flexibility as if it had built in Javascript from the beginning. All choices have tradeoffs and this is one of GWT’s.
The Ugly:
The product that GWT allows a developer to create will always only be as good as the browser running it and will be held back by the older browsers that it needs to support. In the near term, in order for the GWT feature set to progress, 2 things have to happen: 1) browsers have to natively start supporting new features (can anyone say HTML5?), and 2) certain features in your GWT app won’t support older browsers. While this is a reasonable way to compete with ASP.NET Webforms, jQuery, and Ruby on Rails, this is not a sustainable path to compete with Flash, Silverlight, or Java FX. Hence…
My opinion on GWT’s long term strategy:
Either GWT will ultimately be positioned as a technology suited for catering to lowest common denominator scenarios or…
Google will have to adopt something similar to the plugin approach. GWT developers will still build their app using GWT the way they do today but if they want access to all those extra goodies that Flash, Silverlight and Java FX have (the ones that are not supported in the current version of HTML or Javascript), GWT will need to build those features into Chrome and allow developers to build apps that require some variation of Chrome (Chrome browser, the Chrome OS, or the Chrome Frame plugin). Google may try to bake these feautres into whatever the next version of HTML is at the time but my guess is that they won’t always be willing to wait around for W3C to agree and will start adding them to Chrome as they need them. In the end, GWT apps that need the latest features will essentially be native Chrome apps built on (for all practical purposes) a Java powered plugin framework.
Personally, I say unless you need a plugin independent app, why wait? Silverlight, Flash, and Java FX give you today everything that GWT will provide tomorrow.
Posted in Commentary | Tagged Flash, GWT, GWT 2.0, HTML 5, Java FX, silverlight | 2 Comments »