Wednesday, 7 July 2010

Part 2 of 3 - Creating a Pivot Collection


This series of articles cover the process from concept to release of how integrated visual search using Pivot Viewer for Silverlight:

This is part 1 of a 3 part series:

Part 1 – What is Pivot

Part 2 – Creating a Pivot Collection (this article)

Part 3 – Creating a custom Silverlight Pivot View application

Creating a Pivot View Collection

For a deep dive on general collection design check out the article on, in this post we look at the steps required to create a pivot collection.

  1. Create composite images for input to deep zoom
  2. Create deep zoom data
  3. Create Pivot meta data

Step 1 - Create composite images

To keep things simple, pivot view only displays static images, so any text overlays, borders etc need to be burnt into an image.

Key things to consider are aspect ratio, size, borders, and image quality along with the information you want to overlay. For we decide on the following info:

  • Hotel Name, Town, County (State), Star rating, Star accreditor
  • Hotel Photo
  • Room Price from
  • Location

A sample composite image taken from the site is shown below containing the text overlays and location information on a map.


So knowing what we want, how do we go about creating these 7000 images? Options include:

  1. Manual via Paint
  2. 3rd party tool such as Photoshop which allows for a data merge functionality
  3. Create a custom app

Option 1 is clearly a non-starter, but depending on your in house skills options 2 and 3 are the way to go.

For us a custom app seemed the most flexible, as it could pull data direct from the database and integrate future changes via our content management system. So the only question now is what sort of app, options considered were:

  1. Create images via .NET bitmap APIs
  2. Create images via embedded IE web control
  3. Create images via XAML using WPF app

For simple image templates option 1 would be the simplest solution, but we wanted to have the image driven via a content template which pushed us into the direction of either being HTML based or XAML based. In the end we went for XAML as we could then create the templates in Expression Blend and incorporate smart controls such as our hotel map.

So we ended up with a WPF app that pulled the data from the database and then created a custom Bitmap for each hotel based on a XAML template and inject the hotel data. Once we had our custom XAML this was then loaded into a canvas object using the code below:

   1: Canvas oCanvas = (Canvas) XamlReader.Parse(
   2:                 InjectData(xamlTemplate,hotel));
   3: int  iWidth  =  (int)oCanvas.Width;
   4: int  iHeight  =  (int)oCanvas.Height;
   6: oCanvas.Arrange(new  Rect(0,  0,  iWidth,  iHeight));
   8: RenderTargetBitmap  oRenderTargetBitmap  =  new  RenderTargetBitmap(iWidth,  iHeight,  96,  96, PixelFormats.Default);
  10: oRenderTargetBitmap.Render(oCanvas);
  12: // Save image using JpegBitmapEncoder 

Xaml to Bitmap code

So the end result is a direct with 7,000 custom images which can now be used to create the deep zoom collections.

Step 2 - Create deep zoom data

Creating the deep zoom data is the easiest part of this project thanks to the DeepZoom.dll library. A deep zoom collection consists of image tiles and collection meta data.

Using the .NET4 parallel extension the following code will kick off 4 threads to create the deep zoom imagery via the DeepZoom API ImageCreator

   1: Parallel.ForEach(titles, new ParallelOptions { MaxDegreeOfParallelism = 4 }, (title) =>
   2:      {
   3:       new ImageCreator{ MaxLevel = 9 }.Create( imagePath, 
   4:     string.Format(@"{0}\{1}.xml", outputDirectory, title.Id));  
   5:      });
   7: Once the images have been produced we then create the meta data, via the CollectionCreator API:
   9:   new CollectionCreator().Create(titles.Select(t => string.Format(@"{0}\{1}.xml", outputDirectory, t.Id)).ToList(), string.Format(@"{0}\collection.dzc", outputDirectory));

Thanks to for this code, used as part of his NetFlix browsing article.

And that’s pretty much it, though using the DeepZoom.dll I couldn’t figure out how to set a minimium zoom level as the tool wanted to create 9 zoom levels, of which levels 0 to 4 are very small and <1k in size, ( need a MinLevel = 3 option)?

Note: Word of warning my 7,000 files (400MB) now went up to 100,000 files (575MB size / 842MB size on disk) and 78,000 folders.

Step 3 of 3 - Create Pivot metadata

In the previous steps we created the deep zoom data, now we need to create Pivot metadata to inform the viewer:

  • How we allow the user to filter or search the information via the filter panel e.g. Number of rooms, Location, price.
  • How we group the results via the sort drop down, e.g. by city, user ratings.
  • What information is displayed in the information panel for a given image e.g. hotel description, contact details etc.
  • Collection Name provides the ability to give the collection a name and (in Silverlight) a custom logo.


For a deep dive on the Pivot meta data see the Collection XML Schema article on

Filter panel For us this is still a work in progress, we’ve got the basics such as price, ratings, location, but are still iterating with attention to group of data e.g. hotel features / room features.

Sort Dropdown Care should be taken to not overload the user with irrelevant sort groups, e.g. is group by hotel name really useful? At present we’ve got most of the filter panel appearing in the sort dropdown, but may remove some after testing / user feedback.

Item panel I need to investigate this further, but currently my item panel will only display a button to link to an external URL via the Pivot app, but for the Silverlight control we have to option to multiple buttons and custom event handlers, e.g. to display a Silverlight dialog box. Note: For this release of the Silverlight control you cannot change the size / color of the buttons.

Info Panel Displays data related to the hotel, including extended information pulled from a secondary.cxml data file that holds the hotel descriptions which can be quite large.

The key part of the design here is to decide what information is important to your users. You may want to group things to help the user find the correct info, for example our database has a list of hotel features, but for this panel we broke down the features into groups for hotel and room features to keep the options brief as the panels are quite narrow so text needs to be concise.


  • To reduce the size of downloads I split the collection into 7 collections of ~1000 hotels each. This has the negative effect of searches in the filter panel being restricted to items in the current collection, e.g. if the user is viewing hotels in the South East of England they won’t see any search results for the South West unless they switch collections.
  • Do you want your collection to be consumed by both your Silverlight control, other Silverlight apps, WFP Pivot App? If so then you may want to ensure core functionality does not rely on logic built into your custom Silverlight Pivot Viewer app.
  • The secondary file can be quite large, would be good if that was split into multiple files, not sure if this is possible or not?
  • In the future I may also support dynamic collections e.g. based on search / availability.



This is part 2 of a 3 part series:

Part 1 – What is Pivot

Part 2 – Creating a Pivot Collection (this article)

Part 3 – Creating a custom Silverlight Pivot View application


Larsson, swe said...

Hello Martin,
I have been googling the net for information on how to create customized deepzoom images and then using them when creating the pivot collection. Do you think there is any possibility for me to take part of your source code. I believe it would help me a lot when creating the images and my collection.

Mixmasterxp said...

@Larsson lol dude, aren't u already gonna take his code anyways, like wat i'm doing now.

Martin Duffy said...

Feel free to use the code in the blog post.

I haven't posted the app as it's a very ugly WPF hack based on code from for his NetFlix browsing app demo.