Acknowledgement

This code has grown out of two other projects/articles: the DecosDeepZoom by Berend Engelbrecht, and an article from Mike Ormond about the MultiTileSource. I used code from Berend Engelbrecht to generate the tiles.

Introduction

This article shows how to store a Deep Zoom image in a database, and how to retrieve the data for display in a Silverlight app. For simplicity, I use a Microsoft Access database, but the code can easily be adapted for Microsoft SQL Server or Oracle. As simple as this might sound, it takes quite a lot to make it work. The article covers the following ground:

How to create a Deep Zoom image from a single (large) image. (Or more exactly, how to create the tiles that make up a Deep Zoom image.)

How to store the created tiles in a database.

The database model that is required.

How to read the tiles from the database and pass it to the MultiScaleImage control.

Along the journey, you will see some other useful stuff, for example, how to store a bitmap in an Access database, or how you can use LINQ to convert a DataSet into a list of objects that can be the data source for a Silverlight control.

Background

I have always been fascinated by how you can zoom in endlessly in Google Earth. When Silverlight came with the Deep Zoom feature, I was quite excited. However, I found it awkward that you would have to use a separate tool (Deep Zoom Composer) to create such an image. I also found the files that it generates on the file system impractical. It certainly works if you have to deploy one or two Deep Zoom images onto a website. But what do you do, if you have to create thousands of them?

I work for a company called Scope Solutions, located in Basle, Switzerland. We do software for "historical" archives, which means that we mainly manage meta data about the archival holding, which includes images, maps, and building plans. Of course, the archives scan their interesting items to make them available to the public. And, if an archivist is going to scan an old map, he will do that in the highest possible quality so he has a "backup" that matches the original as close as possible. Just in case the original is damaged/lost. This can lead to very large files and bitmaps. For example, a bitmap with 13722 x 9737 pixels is not uncommon. Such a bitmap uses, depending on the format, up to 400 MB on the disk. And having said this, it should be no surprise to hear that some archives have map collections with ten thousands of maps or over a quarter million images.

Wouldn't it be cool if hobby archivists from all over the world could view "deep zoomable" images of these historical maps? Using the Deep Zoom Composer and a file based system is surely not the way to go. That is why I investigated and wanted to find out how to store the images in the database.

Using the Code

The demo presented here consists of two applications:

A Windows Forms application that generates the tiles for a Deep Zoom image and stores them in a Microsoft Access database.

A Silverlight web application that displays the images from the database.

Both applications are contained in the same solution. To compile and run the solutions, you will need VS 2008 SP 1 (required for Silverlight development) with .NET 3.5. (for simplicity, I decided to wrap both applications in one solution). For that reason, you will have to change the startup project, depending on which app you want to run.

Important: Before you can run the solution on your machine, you have to change the connection string in the configuration to match your path location. The connection string for the Windows Forms application can be changed in the settings file. The connection string for the ASP.NET application can be changed in the web.config file. The (empty) sample database is located in the App_Data directory of the ASP.NET application.

The four projects found within the solution are:

DatabaseDeepZoom: A simple Windows Forms application that provides the UI for creating the tiles of a Deep Zoom image.

DbDzComposer: This library is used by both projects, and does most of the work. It contains a class for generating the tiles, and a class for storing and retrieving the data from the database.

DeepZoomSilverlightProject: The Silverlight app that displays the images. This is mainly the default project that you get when you use Deep Zoom Composer. It has been extended by a list for displaying the thumbnails to the right of the Deep Zoom image.

DeepZoomSilverlightWeb: The ASP.NET app that hosts the Silverlight app. It is an extended version of the default project that Deep Zoom Composer creates. Two HttpHandlers have been added that return the tiles and the thumbnails that the Silverlight app requires, and a WCF Web Service for returning the data about the images.

In this article, I have omitted most of the code comments. The code you can download is better documented.

DatabaseDeepZoom Project

This simple app generated the tiles for a Deep Zoom image. The user provides a filename and a name for the image. The code calls the function GenerateFromFile from the DeepZoomComposer class that is part of the DbDzComposer library. The DeepZoomGenerator class is instantiated with the default constructor which instructs the class to create 256 x 256 pixel tiles and save them as 24bit color JPEG tiles with a quality of 90. You can change that behavior using the second constructor or by setting properties.

The most important fact is that we also instantiate the database access class. This class inherits the interface from an abstract base class that defines the basic interface. Using that interface, it is easy to write an additional provider that would store the data in an Oracle or SQL Server database instead of the Access class we use here.

The rest of the code just deals with opening the image file, and some other UI related stuff like progress bars.

DbDzComposer Project

This library is used by the Windows Forms application and the ASP.NET application. It contains classes for creating the Deep Zoom image as well as a class for storing the generated tiles in a Microsoft Access database. The DzDbAccess class inherits from an abstract interface that defines the methods for storing and retrieving the images from the database. I have chosen to create this interface so I could easily add another database storage provider for a different database system. As you can see from the code, the interface is quite simple. It provides a method to save the information about an image and a method to save the individual tiles. Then, it has methods to return a list with the information about the images stored in the database, and methods to return a thumbnail preview and the individual tiles back to the caller. And, of course, it needs a property with the information about the database connection.

The concrete database persister class is used by the DeepZoomGenerator class for storing the images. This DeepZoomGenerator class is based on the work by Berend Engelbrecht, and is a stripped down version, as my goal was to create tiles for single images only. This class takes a large image, and creates the tiles required for creating the Deep Zoom image. It does, however, not support the more advanced stuff like image collections that the Deep Zoom technology provides and that Berend in his original class provided.

DeepZoomSilverlight Project

This Silverlight project consists of a single page that displays the Deep Zoom image and displays the available images from the database in a listbox. The question is, of course, how does the MultiScaleImage control display the tiles that are stored in the database? Usually, one would assign the Source property of that control the URI to an XML file, e.g., something like msi.Source="../GeneratedImages/dzc_output.xml". But, this property actually is of type MultiScaleTileSource.

So, what we have to do is create a class that inherits from MultiScaleTileSource and implement its interface. The main method of that class is called GetTileLayers, and is called from the MultiScaleImage control for every tile that is needed. Inside that method, you add each tile to a list, but not in the form of a bitmap, but in the form of an URI. The URI itself must then stream back the image, and that is why we use a HttpHandler in the web project.

The HttpHandler is not part of the Silverlight project, but of the ASP.NET application that hosts the Silverlight app. This kind of architecture is required because Silverlight itself is not capable of accessing the database as it runs in a secure sandbox environment.

DeepZoomSilverlight Web Project

This is the ASP.NET application that hosts the Silverlight control. This application also provides the Silverlight control with the data. There are two HttpHandlers in this application, one that returns the bitmap tiles, and one that returns a thumbnail for a specific image. Besides that, there is a WCF service defined that the Silverlight app uses to retrieve the information about the images.

Points of Interest

After having given an overview about the different projects involved in this solution and cleared the most important points, I would like to go deeper and give you additional insight on the code.

Deep Zoom File Format

Of course, this article would not be complete without some words about the Deep Zoom file format. But, I am not going to repeat what Microsoft has described in detail in MSDN.

Database Design

One of the questions I had to answer was the database structure that is needed to store the image tiles. It turned out that this is easier than I first thought after looking at all the files the Deep Zoom Composer generates. The database design consists of two tables. One table is needed to store information about the image, most importantly about the width and height, the tile size, and the overlap, as this information is required to correctly initialize the MultiScaleTileSource. The other table stores the generated tiles, and on which level and on which coordinates they are used.

Storing the Bitmaps in the Microsoft Access Database

Even though I do quite a lot of database programming, I'm not storing bitmaps in a BLOB field every day. To achieve the goal, you have to use a parameterized command object. The parameter for the bitmap must be of type OleDbType.LongVarBinary, and you pass this parameter a byte array. To convert the bitmap into a byte array, you will serialize the bitmap into a memory stream using the BinaryFormatter.

Returning the Information About Images from the Database to the Silverlight Listbox

The web front-end shows a listbox to the right of the Deep Zoom image. This listbox displays data from the database. As Silverlight cannot deal with DataTables or DataSets, we cannot pass one of those objects as we would normally do. Therefore, the database access class returns a list of ImageInfo objects. Here, LINQ does a great job in simplifying the developer's work, once you have understood the syntax that it requires. You can use this example every time you have to return a list of objects from a DataSet. One thing that is special about this method is the passed parameter fromUri that is required to return the ThumbnailUrl. As the Silverlight app can be deployed anywhere on the net, and thus the path to the HttpHandler that returns the thumbnail image changes, I pass in the URI from the calling page. Like that, I am sure that the address for the ThumbnailUrl is always correct.

In the Silverlight app that consumes the returned list, we call the GetImageList method from within the constructor of the page. As this is an async call, we bind it in the completed event handler of that method.

License

Share

About the Author

I have my own software company called Evelix (www.evelix.ch). The company is located in Liestal, Switzerland. I develop software for the web and the desktop. Every now and then I give computer classes in a learning institution.

I was born in 1966, am married and have one kid. Hobbies are Fasnacht (www.bmg.bs), skiing and of course computers.

Actually I studied mechanical engineering and have a bachelors degree in it, but computers interested me since I had a Commodore C128. In the meantime my mobile has a thousand times more memory than my computers back then. First I started programming in Basic. After that I did use Pascal for a while, but the real (commercial) programming started with VB3. Now I do programming in C# and sometimes still in VB6 when I have to support an older application.

Hi Joerg
really amazing article ... it's wonderful
i wanna use your article and load all my images in msi ( not with click on the thumbnail on load page) im reading alot every where but i did not find a suitable article all of them using xml and i wanna use database (actually your project ) can you help me about this problem??
thanx alot
Best Regards

hi thank you for your replying
what i mean is i dont wanna show thumbnails and then click on it to load the image in msi
i wanna load all picture together in msi
if you can see this demo you can get all i mean here[^]
but it use xml
if you can help me i will be so thankful

Hi
I think you're heading down the wrong road.
Yes, my solutions uses the thumbnails to select between different images.
However the test page you showed me just shows ONE picture - albeit a big one.
As you can see from the previous article from the post you mentioned (http://www.silverlightshow.net/items/Using-the-DeepZoom-Composer-.aspx[^]) the author of this article creates one image with the brick background and then puts additional images over it.
After the deep-Zoom composer is finished processing this image, you get ONE multiscale image.

If you would use my project you would have to create the big image using photoshop or similar, and then feed the resulting large jpg to the small component that saves the tiles in the database.
After that the image will show up as thumbnail. However this is not a requirement to use the thumbnails.

It would be easy to change the main page to just load one specific image and not displaying several images.

HI thank you for your replying
So you mean i can not Load all my images in msi without merging them ????
if it is just a way so can i do that programatically ??
because i wanna it be dynamic and user add any picture to database the he can see them all in msi and zoom in to which one it ones... I know i have to load all images together but i can not set source for msi ( like collection if it get )

No, I don't think so.
If you want to have all pictures next to each other and want to be able to zoom in without selecting one first, you will have to create a composite image first and then do the tiles.
Doing this programatically would be possible as you would need to create this huge image with .NET instead Photoshop.
But it would not be dynamic.
If you want to have it dynamic, this means that everytime a user adds an image you would have to recalculate all the tiles for all levels, which is a big thing to do.

Hi thank you very much it's very useful article but i just wanna know how can i create deepzoom images with DbDzComposer from a Uploaded image and create the tile of deepzoom images ???
actually i wanna merge the windows application with silverlight application and use it as a silverlight application

Well there is a function called GenerateFromFile in the DeepZoomGenerator class. So first you will need to upload your image to the webserver and then call the method mentioned. After that the image is in the database and can be used by the application.

thank you for your help
now i can insert images to db using Generate from file
but one other question:
i wanna use sqlserver but with ADO entity model
should i write the whole inserting and getting data again??
is there any way to use your classes with ADO entity model???

You should be able to use the EntityFramework without any problems. The database access code is all contained in the class DzDbAccess that inherits from the abstract class IDzDbPersistance.

So what you would have to do is to create a new class (for example DzDbSqlServer) that inherits the same abstract class. You then simply have to implement all the required members, but instead of using OleDb and OleDBCommands you can use the Entity Framework and Linq to store and read the data.

Does anyone happen to know why the image quality generally isn't quite as good (especially when zoomed out) as it is with images generated via the DeepZoomTools.dll? If so, is there tweak to improve the quality? Note, I'm viewing mechanical drawings where the difference is image quality is actually quite apparent.

First of all a big thanks for sharing this concept with us....
Based on your explanation & processflow i managed to get the Silverlight
Deepzoom control working with a Progress OpenEdge backend, that handles business logic, data management + storage.

However in both my project as well as yours i discovered a glitch when working with certain images.... it seems the image dimensions or tiles are getting miscalculated / distorted, when zooming in on the image....

So far i havent been able to trace the problem to a specific part of the code... perhaps you can help out here.....

I linked a random image in which you can the distortion occuring....Testimage 1

Unfortunately I was not able to reproduce the "error" but I might know what you are talking about.
The testimage you provided worked fine as you can see under http://deepzoom.evelix.ch

If you look at the code, you might notice a parameter that is passed in when creating the tiles and when reading the tiles. The parameter is called "useOverlap". If set to true, image tiles are created that overlap each other by a pixel.
The problem is now, when you read an image that was created with overlap, but when displaying you tell the ImageSource not to use an overlap (or vice versa), then the image might show some distortion.
I guess, that is what happened here.

Thanks for the fast reply...
I'm going to check out the mentioned parameter straight away tonight and will get back to you with the new testresults..

Unfortunately my implementation isnt reacheable from internet,, but I've added links to three pictures, showing the distortion occuring in my environment.. its only occuring for specific images, not all of them, giving me the impression this isnt bound to tile calculation / generation in my environment...

some questions though, I changed the grid of the imageList from vertical right to horizontal bottom.

but the scroolbar as in the imagelist is still on the right hand side of the imageList.

How can i make the scroolbar to be on the bottom too instead of the right side of it.

And urs is uploading the pictures into a database...hence i cant really retrieve oe open image as in the image itself. do u have any idea how can i upload it onto a folder instead so that i can manually do anything with the image?