DevX HomePage

The Progress and Promise of Deep Zoom

In its latest release alongside Silverlight 2 Beta 2, Deep Zoom Composer shifts to a more accessible XML format and offers better control of image quality. Those are just the latest improvements to a tool that's grown far more capable since its introduction back at MIX 08.

Microsoft made a big splash with Deep Zoom at the MIX 08 conference, introducing the technology to a thrilled audience (and many more who followed along with events online). Deep Zoom allows Silverlight developers to support smooth zoom and pan on huge, high-resolution images, even across limited-bandwidth connections.

There were really two big Deep Zoom news items from MIX. First, Vertigo had built a sensational Silverlight site for Hard Rock using Deep Zoom. Hard Rock Memorabilia, now a de facto Deep Zoom reference implementation, showcases Deep Zoom's incredibly smooth pan and zoom with features like mouse wheel support, filtering, position animation, and linked item information. The second MIX item was that Deep Zoom, along with an image composition/decomposition tool called Deep Zoom Composer, was available to Silverlight developers.

The gap between what the first iteration of Deep Zoom Composer produced (a tree of image tiles) and what Vertigo had done in Hard Rock Memorabilia (a feature-rich application) was sizeable, and there was neither code nor documentation to bridge that gap. The Expression Blend team quickly followed up with samples, and work by developers including Pete Blois, Scott Hanselman, Wilfred Pinto, and Jaime Rodriguez helped to establish a set of practices for working with Deep Zoom images and image collections in Silverlight.

Deep Zoom Composer's May preview pulled that work together into the composition tool. For the first time, Deep Zoom Composer built a starter Silverlight application to go along with the image tree. The starter application showed exactly how you could add essential features such as panning and mouse wheel zoom.

The current release of Deep Zoom Composer (download here) made its debut about a month later, alongside Silverlight 2 Beta 2. It drops the original binary file format in favor of XML, supports lossless PNG images as well as JPEG, and supports tagging images in a collection. This change to Deep Zoom Composer coincides with a Silverlight release because the new XML format must be supported by the MultiScaleImage display control as well as by the image composition tool.

Using Deep Zoom Composer
Deep Zoom provides users with the visceral experience of rapid and seamless zooming of large images served over the network. Although it appears as if you've got the breadth and depth of, say, the entire Hard Rock collection at your fingertips, you don't. Deep Zoom works by serving up tiles of the source image scaled at various resolutions, as few tiles as necessary to maintain the user experience without straining the bandwidth of the network.

Those tile sets must be prepared ahead of time. The XML file format and tile layout is documented, but at the moment there's no .NET framework support for building these tile sets programmatically. Instead, you use Deep Zoom Composer to lay out one or more source images and then publish that layout in the Deep Zoom format.

Figure 1. Deep Zoom Composer: In the Composition step, shown here, you take imported images and arrange them into a layout for later export in Deep Zoom format.

Using Deep Zoom Composer is pretty simple. There are three steps: Import, Compose, and Export. In the Import step, you pull in your source images. Deep Zoom Composer maintains images in lossless formats, so you have the opportunity to export a PNG or high-quality JPEG image at export time.

In the Compose step, shown in Figure 1, you arrange these images into the composition you want to present in your Silverlight program. There are tools for moving, aligning, and resizing each source image as you create the layout. Deep Zoom Composer can also automatically arrange collections of images into a grid. During composition, you can add tags to images in a collection. You can use these tags to support filtering in your Silverlight application.

When you're ready to export, you have a few choices to make (Figure 2). First, you can choose between exporting a single composition or exporting a collection. This is an important distinction. A composition is logically a single image for display, and it's static. The arrangement you created in Deep Zoom Composer will be preserved and presented as is. If you choose a collection, your Silverlight application will have access to each subimage that you've imported, and you'll be able to rearrange or hide these subimages using code. A composition is how you'd display a map or a large-format developer reference poster. A collection is the dynamic set of images you see in Hard Rock Memorabilia.

Figure 2. Export Options in Deep Zoom Composer : In the Silverlight 2 Beta 2 release, you can export as PNG or JPEG and set JPEG image quality.

You also need to decide the export image format. Deep Zoom Composer supports JPEG as a lossy format and PNG for lossless images. If you choose a JPEG export, you can also set the image quality.

Finally, Deep Zoom Composer gives you the option of creating a starter Silverlight application to host the generated image. If you go that route, Deep Zoom Composer creates a complete Silverlight project that you can pull into Visual Studio 2008.

When you click the export button, Deep Zoom Composer slices the image or image collection into its component tiles and places these into a set of folders in the export directory. It also creates a file that describes the generated image called dzc_output.xml. This is the file that you'll supply as the source to the MultiScaleImage control when you display the image in Silverlight.

That's the short version of the export process, but it doesn't do much to explain why some of the changes introduced with Silverlight 2 Beta 2 are so interesting. A longer description may make that clearer. At export, Deep Zoom Composer first creates a file called SparseImageSceneGraph.xml that lists the images you've added to your composition and describes the layout. This file is then fed to SparseImageTool, a command line tool that actually creates the Deep Zoom image or image collection.

SparseImageSceneGraph.xml specifies the Z-order for each image in a collection. The Z-order determines the order in which subimages will appear when the collection is loaded into a MultiScaleImage control. That means that Z-order can be used as an identifier when locating subimages in your application. To support tagging of subimages, Deep Zoom Composer generates a second file called Metadata.xml with a structure very similar to that of SparseImageSceneGraph (including Z-order) but with an additional Tag property for each image. In your Silverlight application, you can run queries against Metadata.xml to find the Z-order of images that match selected tags. This provides a basis for supporting filtering of images in a collection.

SparseImageTool both generates the tiles and creates the output XML file that's used as the MultiScaleImage source. Before the Silverlight 2 Beta 2 release the output file format was binary, so making changes to a collection required re-running SparseImageTool against the full set of source images. With the XML output format it is much easier to make incremental changes, using SparseImageTool to generate tiles only for new or modified images and editing the XML file by hand or with a script.





Learning from the Generated Application
Silverlight's MultiScaleImage control is the display engine for Deep Zoom images. To show the image that we created in Deep Zoom Composer, we add a MultiScaleImage control in XAML and set its source to the dzc_output.xml file generated by the composer:

<MultiScaleImage Source="GeneratedImages/dzc_output.xml" x:Name="msi"/> 

You can also set the source for the MultiScaleImage in code:

msi.Source = new DeepZoomImageTileSource(
new Uri("GeneratedImages/dzc_output.xml",
UriKind.Relative)); 

In fact, this is how the generated project sets the source in the latest release, noting a current problem in Expression Blend's handling of MultiScaleImage controls with source set from XAML.

With the XAML snippet you can display the Deep Zoom image, but nothing more. To actually zoom the image you use the MultiScaleImage ZoomAboutLogicalPoint method, specifying a zoom factor and a point on which to center the zoom:

msi.ZoomAboutLogicalPoint(zoom, logicalPoint.X, logicalPoint.Y); 

You'll generally call ZoomAboutLogicalPoint in response to a keyboard or mouse event.

The application generated by Deep Zoom Composer includes these essentials, plus mouse event handlers, mouse wheel support, and panning. It also stubs in handlers for the MultiScaleImage's Loaded and ImageOpenSucceeded events. Reviewing the source output by Deep Zoom Composer is a good place to start learning how to support Deep Zoom in your own applications.

In the generated sample, there are two ways to zoom the image. You can click and shift-click to zoom in and out, or you can use the mouse wheel, rolling forward to zoom in and back for out. Click-to-zoom is implemented with this left button up event handler:


            this.msi.MouseLeftButtonUp += delegate(object sender,
 				MouseButtonEventArgs e)
            {
                mouseButtonPressed = false;
                if (mouseIsDragging == false)
                {
                    bool shiftDown = (Keyboard.Modifiers &
 				ModifierKeys.Shift) == ModifierKeys.Shift;

                    ZoomFactor = 2.0;
                    if (shiftDown) ZoomFactor = 0.5;
                    Zoom(ZoomFactor, this.lastMousePos);
                }
                mouseIsDragging = false;
            }; 

mouseIsDragging is a variable used to support panning, which we'll discuss in a minute. ZoomFactor is a property that always tracks the current zoom level. It's not used in the generated Page class, but it could be used to display the zoom level in another control. The key part of this function is the call to Zoom, which translates the clicked point into logical coordinates and then calls ZoomAboutLogicalPoint (logical coordinates represent a point within the image as a double value between 0 and 1):


        public void Zoom(double zoom, Point pointToZoom)
        {
            Point logicalPoint =
 				this.msi.ElementToLogicalPoint(pointToZoom);
            this.msi.ZoomAboutLogicalPoint(zoom, 
logicalPoint.X, logicalPoint.Y);
        } 

The Zoom method is used whether zooming by click or by mouse wheel. The mouse wheel zoom code is fairly simple:


new MouseWheelHelper(this).Moved += delegate(object
 sender, MouseWheelEventArgs e)
      {
                e.Handled = true;
                if (e.Delta > 0)
                    ZoomFactor = 1.2;
                Else
                    ZoomFactor = .80;

                Zoom(ZoomFactor, this.lastMousePos);
      }; 

But that's because the magic is packed into the MouseWheelHelper class, created by Pete Blois and included with the generated application. MouseWheelHelper uses the Silverlight HtmlPage class to install C# handlers for mouse wheel DOM events, allowing us to get mouse wheel events in our Page class without having to write any JavaScript.

You can drag the mouse to pan the image. Panning is implemented by this code in a mouse move event handler:


      if (mouseIsDragging)
      {
        Point newOrigin = new Point();
        newOrigin.X = currentPosition.X –
 		(((e.GetPosition(msi).X - dragOffset.X) / msi.ActualWidth)
 			* msi.ViewportWidth);
        newOrigin.Y = currentPosition.Y –
 		(((e.GetPosition(msi).Y - dragOffset.Y) / msi.ActualHeight)
 			* msi.ViewportWidth);
        msi.ViewportOrigin = newOrigin;
      } 

To pan, we change the ViewportOrigin of the MultiScaleImage control to a new point that is offset by the amount that we just dragged the mouse along each axis. The currentPosition point is the MultiScaleImage ViewportOrigin at the start of the drag. The change in position is scaled so that it is relative to the size of the viewport; dragging across 1/3 of the control causes the image to move across 1/3 of the viewport.

As with zooming, Deep Zoom itself builds in easing to make panning smoother. Simply setting the ViewportOrigin property makes the image appear to slide gently to its new location. This behavior is controlled by the UseSprings property of the MultiScaleImage, which is true by default. If you set UseSprings to false, the image jumps to its new position when you set the ViewportOrigin.

Deep Zoom Composer's starter Silverlight application isn't all the way up to Hard Rock Memorabilia on its own. To match the latter's features you would need to also add filtering and the ability to link external data to subimages. As mentioned above, you can use the Metadata.xml file generated by Deep Zoom Composer as a source of tag information to support filtering. Wilfred Pinto's blog is an excellent source of information on implementing filters.

By taking your project all the way from source image to Silverlight, Deep Zoom Composer provides a solid foundation on which to build your own applications. The tool has been improving steadily since MIX, and those working with Deep Zoom have continued to come up with new applications for the technology and to build ever more impressive demos (Tim Heuer's blog shows some examples of these). We can't wait to see what the next release will have in store.

* This article was commissioned by and prepared for Microsoft Corporation. This document is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, IN THIS SUMMARY.


Steve Apiki is senior developer at Appropriate Solutions, Inc., a Peterborough, NH consulting firm that builds server-based software solutions for a wide variety of platforms using an equally wide variety of tools. Steve has been writing about software and technology for over 15 years.