Feed Icon  

Contact

  • Bryant Likes
  • Send mail to the author(s) E-mail
  • twitter
  • View Bryant Likes's profile on LinkedIn
  • del.icio.us
Get Microsoft Silverlight
by clicking "Install Microsoft Silverlight" you accept the
Silverlight license agreement

Hosting By

Hot Topics

Tags

Open Source Projects

Archives

Ads

Deep Zoom Image Generation with DeepZoomTools.DLL

Posted in Silverlight | Deep Zoom at Wednesday, November 26, 2008 10:49 PM Pacific Standard Time

Yesterday I saw that the Expression Blend and Design team had blogged about the new DeepZoomTool.dll:

In our most recent release of Deep Zoom Composer, one of the major changes we made was to change how we generated the image tiles both for designing as well as exporting your Deep Zoom Content. In the past, ever since our first release at MIX, our image encoding was done using a combination of SparseImageTool.exe and ImageTool.exe command line tools. Starting with this release, we have retired those tools and have shifted to a preview version of a .NET based DLL that provides image generation capabilities.

Building Deep Zoom Images via code is something that I’ve wanted to do for some time. I’ve tried to figure out how to do this many different ways, but I’ve never gotten it to work. So I was pretty excited to try out this new API for Deep Zoom. I still don’t fully understand it all, but I was able to create a very simple program to generate a deep zoom image based on a bunch of photos.

First, I read all the image files into a List of strings. I created my code so that it will go into subfolders as well:

private static List<string> GetImagesInDirectory(string path)

{

    return GetImagesInDirectory(new DirectoryInfo(path));

}

 

private static List<string> GetImagesInDirectory(DirectoryInfo di)

{

    List<string> images = new List<string>();

 

    // get all the images in this directory first

    foreach (var fi in di.GetFiles("*.jpg"))

    {

        images.Add(fi.FullName);

    }

 

    // get all the directories with their images

    foreach (var sub in di.GetDirectories())

    {

        images.AddRange(GetImagesInDirectory(sub));

    }

 

    return images;

}

 

Next, once you have the list of Images, you need to generate all the Deep Zoom images which are folders containing tiles of the image at different zoom levels. We generate these images using the ImageCreator. For a great overview on Deep Zoom and Tiles, check out Jaime Rodriguez: A deepzoom primer.

List<string> images = GetImagesInDirectory(source);

List<string> data = new List<string>();

 

foreach (var image in images)

{

    ImageCreator ic = new ImageCreator();

 

    ic.TileSize = 256;

    ic.TileFormat = ImageFormat.Jpg;

    ic.ImageQuality = 0.95;

    ic.TileOverlap = 0;

 

    string target = dest + "\\output_images\\" + Path.GetFileNameWithoutExtension(image);

 

    ic.Create(image, target);

    data.Add(Path.ChangeExtension(target, ".xml"));

}

Now we should have a bunch of folders and xml files in our “output_images” folder in our destination. Now that we’ve created all the images and their tiles we need to create the collection using the CollectionCreator. The collection creator takes in the list of xml files that we generated and creates another xml file plus some more image tiles.

CollectionCreator cc = new CollectionCreator();

 

cc.TileSize = 256;

cc.TileFormat = ImageFormat.Jpg;

cc.MaxLevel = 8;

cc.ImageQuality = 0.95;

 

cc.Create(data, dest + "\\output");

 

Now we can actually start to use our Deep Zoom image. However, we will need a Silverlight Deep Zoom project in order to display the images. To do this just create a Deep Zoom project, add an image or two, and then export it to a Silverlight Project. In that project delete the contents of the GeneratedImages folder inside of the client bin and then set the dest variable in the above code to the path of the GeneratedImages folder you just cleaned out. Point the source variable to a folder containing the folder you want to load the images from and run it. You should get an output.xml file in the GeneratedImages folder.

You will need to make a couple of changes to the Silverlight project once you’ve done all that. First, we need to position our images since right now they are just a collection. We do this by setting the ViewportWidth and ViewportOrigin. I’m still trying to fully understand these, but the best explanation I’ve seen so far is also on Jaime Rodriguez’s blog: Working with Collections in Deep Zoom.

void msi_ImageOpenSucceeded(object sender, RoutedEventArgs e)

{

    //If collection, this gets you a list of all of the MultiScaleSubImages

    //

    var x = 0.0;

    var y = 0.0;

    foreach (MultiScaleSubImage subImage in msi.SubImages)

    {

        subImage.ViewportWidth = 5.333;

        subImage.ViewportOrigin = new Point(-x, -y);

        x += 1;

 

        if (x >= 5)

        {

            y += 1.333;

            x = 0.0;

        }

    }

 

    msi.ViewportWidth = 1;

}

Now we’ve arranged out images on the viewport, but we also need to point the MultiScaleImage to our output.xml instead of what it was before (do that in the page.xaml file). Once we’ve done that we should be able to run and see our generated deep zoom!

deepzoom

There is still a lot of work to do on this, like figuring out the proper ViewPortWidth based on the number of images and image size, but this is a good starting point. I’m hoping to get some more time to play with this this weekend and I’ll post more as I figure it out.

Happy Thanksgiving!

Update: Just uploaded my project which should make it a lot easier to try out. Just set the source and dest variables, run the console app, and then build and run the website. Have fun!

Silverlight IValueConverter vs. TypeConverter

Posted in Silverlight at Sunday, November 23, 2008 10:40 PM Pacific Standard Time

This is something that wasn’t clear to me so I decided to blog about so that I could fully understand it. Both IValueConverters and TypeConverters are used to do conversions (imagine that!), but they are used differently.

TypeConverters are used by the Xaml parser during parse time to convert values in the Xaml into values in CLR objects. So when you set Height=”100”, height isn’t a string so it has to be converted to a double. This is done using a type converter. Type converters are also one-way since once the value has been converted from Xaml to CLR it doesn’t have to go back. Custom type converters must be placed on the class they will be used on in order for them to work since otherwise the Xaml parser doesn’t know how to convert the value. There is a good MSDN article on TypeConverters which offers much more information.

IValueConverters are used during data binding via a property path. Typically these get created as a static resource in your Xaml file and then are referenced in the binding. Unlike type converters, value converters can go both ways since bindings can be two way bindings. Since value converters are specified in the binding they are much more dynamic and don’t require any references such as the type converters do. Value converters are also more flexible in that they can be passed a parameter via the ConverterParameter. You can read this great blog post on how this works if you’re interested.

A good example of how value converters make Silverlight more extensible is this question in the Silverlight forums. Odegaard was binding to a Dictionary object and was trying to get one of the keys to show up in his TextBlock.Text property. However, even though WPF supports this property bag type of binding, there is no way to do this directly in Silverlight. To get this type of binding to work you can use an IValueConverter. In this case the value converter would get the key in the dictionary and return the proper value. You can see the code for this in the original post (although the questioner didn’t like my implementation because it was too complicated, I thought it was rather simple).

I tried to come up with a more generic approach instead of requiring the dictionary to be of type Dictionary<string,string>, however the best I was able to do was have the value type be assignable but the key still had to be a string.

public class DictionaryItemConverter : IValueConverter

{

    public string ValueType { get; set; }

 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

    {

        Type generic = typeof(Dictionary<,>);

        Type[] typeArgs = new Type[] { typeof(string), Type.GetType(ValueType) };

        Type dictType = generic.MakeGenericType(typeArgs);

 

        if (dictType.IsInstanceOfType(value))

        {

            return dictType.GetMethod("get_Item").Invoke(value, new object[] { parameter });

        }

        throw new InvalidCastException(string.Format("Dictionary is not of type Dictionary<stirng,{0}>.", ValueType));

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

    {

        throw new NotImplementedException();

    }

}

So hopefully this post has been helpful for you in understanding IValueConverters vs. TypeConverters and when to use them. It has cleared it up for me. :)

Technorati Tags:

Developing User Experiences

Posted in Avanade | Silverlight | UX at Saturday, November 22, 2008 6:42 AM Pacific Standard Time

About six months ago I decided to take a break from blogging without feeling bad about it. It was a nice break, but really my lack of blogging was mostly due to the type of work I was doing. I was working on an interesting project for a large media and entertainment company that combined Microsoft Excel and Project Server 2007 with lots of .NET 3.5 goodness like WCF and WF. While it was an interesting project, I wasn’t really working with the technology that really interests me: Silverlight.

But I’m excited to announce that Avanade has gotten serious about UX and has created a UX practice in the west region (where I work). I’m very fortunate to get to be a part of the leadership team for this practice and I’m excited to see where things are headed. So I’m now a User Experience Developer and I get to work with the technologies that I’m passionate about like Silverlight and WPF.

So what does it mean to be a User Experience Developer? Well, I feel like that is something that I still have to figure out. I know that putting User Experience in front of Developer doesn’t suddenly make you better at UX. However, I think it is much like when you first start out as a developer, you don’t really know what it means yet, but you’re setting out to become a developer. So hopefully by focusing on becoming better at UX I will in the process become a true UX developer and I’ll be bringing this blog along for the ride.

I’ve actually been working on a Silverlight project for the last couple of months and have some blog posts in the works already. So keep an eye out from some Silverlight related posts coming soon.