Silverlight can help you build rich, interactive user experiences
using skills you already have. Daniel Crenna shows us how to create an
in-browser image editing component that provides a seamless experience
within a web application.
One of the reasons we pick up a new technology is the power it gives us to bring
better experiences to our customers, clients, and users. If you’re excited about
a new way to get the job done, there’s value in that, but when you can connect that
excitement with the people who rely on your work to get their jobs done, then you
really have something worth talking about.
Silverlight 2 is approaching its final release. As Microsoft’s latest technology
for enabling rich interactive experiences on the web, it provides developers a way
to use our existing .NET development skills to deliver more to our users than they
expect, in the form of enhanced media, graphics, animation, and design capabilities.
As a web developer you’re already building great experiences today using ASP.NET,
so the focus of this article is to solve one of your daily challenges working in
ASP.NET in an effective way with Silverlight 2 that gives a better experience for
your users.
The challenge
If you build ASP.NET web applications today that allow users to upload photos, you
know that it’s a process of posting back file content, manipulating it on the server,
and, if necessary, sending the image back to the user after each request. If you
want to give your users the ability to interact with that image in the browser,
then you’ll face another challenge in leveraging a client-side scripting language
to provide the wizardry that makes your images come to life.
Often your server pays the price, since photos must be uploaded in their entirety
to the server before you can take steps to resize or compress the image sufficiently
to ease the size of your database storage (and these days, nearly everyone I know
owns at least a ten megapixel camera). Of course, you can impose restrictions on
file sizes or provide instructions for your users to crop their images, but you
can do better. Silverlight 2 can make the image manipulation story one you can get
excited about.
Imagine an application...
Let’s think about an application that provides an end-to-end that makes good use
of images: a bug tracking application. With this application, a user can spot an
issue with a web site, take a screen capture of the problem, and upload it for further
analysis. With Silverlight 2 we can provide the user with an interactive experience
in which they upload their photo to a Silverlight control, crop the interesting
region, and then send the cropped image to the server. You win because only the
relevant information is sent to the server, saving bandwidth, and the users win
because they don’t need any special software or knowledge outside of your bug tracker
to get the job done.
Here’s what our bug tracking image component might look like:
Our application has an area to display the working image, and a preview of the
cropped selection. The user can click and drag over the working image to define
the cropping region.
In with the new but let’s keep the old, too
If you want to use Silverlight without throwing away your existing ASP.NET web applications,
the good news is that Silverlight can live snugly within an ASP.NET form. This means
we can wrap our existing applications around one or several XAML controls that we
build in Silverlight. For example, we might decide to use our image component within
an ASP.NET page:
You are free to incorporate one or many Silverlight controls in your existing
ASP.NET markup. In this example the image cropping component fits neatly within
a traditional page layout.
Working with Silverlight 2
To build our application, we’ll use XAML, which is a markup language similar to
HTML that lets us define our interface. As an example, here is the XAML markup for
the main canvas which displays the working image above.
XAML gives us an expressive way to define how our application
will appear.
As you can see, the thick black border around the
working area is defined as a Border element,
and the CornerRadius property is responsible
for the rounded corners. Inside the ‘canvas’ element we add an Image
control which we can use to display our working image. A similar XAML snippet will
define the “picture in picture” preview you see in the application.
Working with Buttons and Events in Silverlight 2 is similar to ASP.NET. You can
declare your event handlers, either in XAML or in code-behind, to configure application
behavior. In this case we’ve declared an upload button that will use Silverlight’s
OpenFileDialog class to select a supported image on the client’s
computer, open it, and obtain a stream for the selected image. We’ll use this stream
to display our image in the main form and in the “picture-in-picture” preview area.
Silverlight allows immediate use of a user’s files
using streams, creating opportunities for working with client-side
files not previously possible in ASP.NET.
Imagine an interface...
Another nice aspect of Silverlight application development is that we can program
against a stateful, persistent UI that simple ‘behaves’, rather than a UI whose
client-side updates require asynchronous feedback to the server (as is the case
with ASP.NET AJAX applications) and partial page refreshes to achieve a smooth,
snappy experience. This means that to design the interactive cropping region that
a user can click and drag around the image, all we need to do is define its appearance
in XAML or in code-behind, and change its properties (such as width, height, and
location) in order to see those changes come alive in our application. This also
means you can perform powerful data-binding scenarios in which you bind your UI
elements to values that change in real-time.
Here we’re creating a new Rectangle
visual element in code-behind and adding event
handlers to mouse actions that occur within the main image control.
Changing the properties of the ‘_cropBox’ element in response to mouse events is
all that’s required to achieve an interactive region selection feature that would
be difficult to duplicate in ASP.NET.
Images in Silverlight
Silverlight 2 is designed with a focus on user
experience. One aspect of that experience is the size
of the Silverlight 2 runtime itself. In order to provide a fast and
lean installation for users, many of the classes you’re accustomed to using in .NET
and Windows Presentation Foundation (WPF) aren’t present in Silverlight. Included
in this list are the encoder and decoder classes for image formats like JPEG, PNG,
GIF, and BMP.
This means that while Silverlight can effortlessly display PNG and JPEG images that
the user selects via the OpenFileDialog control, it cannot decode
the images into the usable data you need to manipulate them. Fortunately Silverlight
is built on a foundation of .NET, which means that whatever functionality we might
need for our applications, we can provide our own code to bridge the gap and get
the job done. In our case, we’re going to draw from a wide variety of community
contributions to put together an imaging library that will allow us to easily work
with JPEG, PNG, GIF, and BMP files directly in the client application.
Imaging 101
A photo stored in an image format like JPEG is really nothing more than a bunch
of bytes that describe the color information, or the color of each pixel in the
image. To save space on disk, image formats are compressed, similar to how ASP.NET
can compress static resources like CSS and JavaScript files using the .NET 2.0
GZipStream or DeflateStream classes.
Every pixel color is made up of a combination of values representing the amount
of red, green, blue, and alpha, or opacity values. Commonly referred to as RGB,
every pixel in an image has all four of these values. As a simple example, an array
of bytes that we’ve obtained from a file stream to a JPEG image, and have successfully
decoded, might look like this:
[125, 17, 8, 255, 14, 12, 19, 255, 20, 55, 77, 255 …]
But what it really means behind the scenes is this:
[R, G, B, A, R, G, B, A, R, G, B, A …]
This decoded array is very useful because it contains the color information for
each pixel in our image. With this information we can reconstruct the image, crop
a smaller section of it, apply a filter, or do anything else we desire. Our goal
for this application, then, is to take a regular, encoded JPEG, PNG, GIF, or BMP
file from a stream we open in Silverlight 2, and translate it into bytes we can
manipulate in code.
A community of help
Fortunately, there is an active and vibrant open source community in .NET that we
can call upon to solve our challenges. Imaging is a specialized field, which means
there are many people who dedicate their careers to producing useful work in imaging
for others [1]. While we can certainly learn how image
formats work in depth, our real goal is to produce great web applications.
To make use of client-side imaging in Silverlight we’re going to draw from several
sources to make it happen. One of those sources is Joe Stegman, Group Program Manager
of the Silverlight presentation and graphics team. Joe has posted several examples
for dynamic image generation in Silverlight[2], several
of which we use in our application to provide BMP and GIF decoding support, as well
as the ClientImage class that we can interact with to work with decoded images.
We'll still need to provide JPEG and PNG support if we want to round out our image
offering and not restrict the user in what kinds of images our application can handle.
JPEG support is available from the talented team at
Occiptal.com,
whose “fluxify” image application allows users to resize JPEG photos on the
fly in their browser using Silverlight [3].
They’ve released the source code for their JPEG decoder, which just leaves PNG support
to make our application really shine. Thanks to another open source library, this
capability is also part of our cropping application.
Conclusion
If you build web applications, Silverlight can help you build rich, interactive
user experiences using skills you already have. You can build Silverlight components
that work within your existing ASP.NET applications or build an entire application
from the ground up. In this example, we saw how Silverlight makes it possible to
implement an image editing feature that is a win for both you and your users: you
save server bandwidth by cropping images directly on the client, and users gain
a seamless experience working with images within your application. There is a growing
developer community around Silverlight and plenty of resources available for you
to go even further and discover new ways to impress. Go find out what’s possible!
Source code
You can download the full source code for this article
here, which goes further to demonstrate the following concepts
which you can put to use in your Silverlight applications that use images:
-
How to upload images from Silverlight to your
ASP.NET server using a WCF service
-
How to store the decoded working image in Isolated Storage, a persistent user
state capability familiar to .NET Windows client developers
Note: To use the solution, you’ll need to install Visual Studio 2008
Standard edition or higher, as well as Silverlight Tools Beta 2
for Visual Studio 2008. You can learn more about these pre-requisites
here. Choose ‘PhotoCropper.aspx’ as your startup page in the ‘PhotoCropperWeb’
web application project within the solution.
Have fun!
References
[1] If you’re interested in writing your own image format
encoders, like fluxcapacity.net did for JPEG images,
you can find a wealth of information
online on how each image format is constructed. For example, the JPEG format is
described in detail
here.
[2] Joe Stegman’s blog has several useful posts with full
source code, including an EditableImage class that represents decoded or created
images you can manipulate directly, as well as example BMP and GIF decoders.
[3] fluxify is a great example of client-side
image editing in Silverlight 2. Similar to this example, it allows a user to upload
a JPEG image and select a pre-defined size, performing all the work on the client
side. It is also a good example of the kind of rich interfaces we can build in Silverlight.
Check it out here
Licenses and Attributions PNG Decoder:
Based on the sharppng pr2.code project
Under the Lesser General Public License
Under the MIT License
PNG Encoder:
Based on the examples written by Joe Stegman
GIF Decoder:
Based on the examples written by Joe Stegman
Derived from the 'GifUtility' project here
Copyright (c) 2008, jillzhang
All rights reserved.
Under the New BSD License
BMP Decoder:
Based on the examples written by Joe Stegman, provided
here.
JPG Decoder:
Copyright (c) 2008 Jeffrey Powers for
Fluxcapacity Open Source. Under the MIT License.