(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

The MultiscaleImage control and the SubImages collection

(2 votes)
Martin Mihaylov
>
Martin Mihaylov
Joined Oct 29, 2007
Articles:   50
Comments:   70
More Articles
11 comments   /   posted on Jul 21, 2008
Categories:   Media , Controls

This article is compatible with the latest version of Silverlight.

Introduction

The MultiscaleImage is a really great control that allows us to do amazing things in Silverlight. That is why I decided to write a series of articles about the nice things that can be done using it. This is the first one and it is focused on the SubImages collection. It explains how to select an image from the collection and then fit it to the size of the control. If you're new to this control read my previous article about it - Using the MultiscaleImage control. Before going ahead you should also be familiar with the DeepZoom Composer and its latest changes. Note that in this article I've replaced the "Double-Click" zoom with “One-Click” zoom.

Live demo | Source code

The SubImage collection

The MultiscaleImage control has a property that contains a collection of the Images that are used in the composition. In order to use it you should export your DeepZoom Composer project as a collection. Now let's see how we can get an image from the collection when it's clicked with the mouse for example:

 private int GetSelectedImage( Point p )
 {
     for( int i = 0; i < MyMultiscaleImage.SubImages.Count; i++ )
     {
         MultiScaleSubImage subImage = MyMultiscaleImage.SubImages[ i ];
  
         double scaleBy = 1 / subImage.ViewportWidth;
         Rect rect = new Rect( -subImage.ViewportOrigin.X * scaleBy, 
                                       -subImage.ViewportOrigin.Y * scaleBy, 
                                        1 * scaleBy, 
                                      ( 1 / subImage.AspectRatio ) * scaleBy );
   
          if( rect.Contains( p ) )
              return i;
      }
   
      return -1;
  }

We have clicked on one of the images in the collection. In order to find the clicked image we have to iterate throughout the whole collection, of images calculate scale factor, which is reciprocal to the ViewportWidth of the SubImage. Than we create a rectangle that has the same coordinates as the SubImage in the MultiscaleImage control. The Rectangle class has a method Contains that takes a Point as an argument (in this case it's a logical point) and checks if that point is contained within the bounds of the rectangle. If the rectangle contains the point, then the SubImage also contains it. We return the found index, but if no image is clicked we return -1 as default value.

Fitting the image to the control

Since we can get the selected image out of the collection, let's now try to fit it to the MultiscaleImage control. Here is the method:

 private void FitImageToScreen( int index )
 {
     if( index != -1 )
     {
         MultiScaleSubImage subImage = MyMultiscaleImage.SubImages[ index ];
  
         this.parentViewportWidth = 1 / subImage.ViewportWidth;
         MyMultiscaleImage.ViewportWidth = this.parentViewportWidth;
         double scaleBy = 1 / subImage.ViewportWidth;
          MyMultiscaleImage.ViewportOrigin = new Point( -subImage.ViewportOrigin.X * scaleBy,
                                                        -subImage.ViewportOrigin.Y * scaleBy );
      }
  }

If the index is different then -1, than we have something that can be fitted. We get the image out of the SubImages using the index. The ViewportWidth property of the SubImage returns the ViewportWidth of the image when the VieweportWidth of the control is 1. So it's easy to calculate how much the ViewportWidth of the control must be so the SubImage has a ViewportWidth of 1. Than we calculate the new ViewportOrigin in dependence of the ViewportOrigin of the SubImage and the scale factor. Finally we save the new ViewportWidth of the control, in order to use it later.

Putting these methods in use

I do the zooming and the fitting in the handler for the MouseLeftButtonUp event of the MultiscaleImage control:

 private void MyMultiscaleImage_MouseLeftButtonUp( object sender, MouseButtonEventArgs e )
 {
     if( !dragInProgress )
     {
         Point p = e.GetPosition( MyMultiscaleImage );
         Point zoomPosition = MyMultiscaleImage.ElementToLogicalPoint( new Point( p.X, p.Y ) );
  
         if( ( Keyboard.Modifiers & ModifierKeys.Alt ) == ModifierKeys.Alt )
         {
              this.Zoom( 0.9, zoomPosition );
          }
          else
          {
              this.Zoom( 1.1, zoomPosition );
   
              int index = this.GetSelectedImage( MyMultiscaleImage.ElementToLogicalPoint(
                                                      e.GetPosition( MyMultiscaleImage ) ) );
              if( index == selectedImageIndex )
              {
                 if( ( float )this.parentViewportWidth < ( float )MyMultiscaleImage.ViewportWidth 
                       || MyMultiscaleImage.ViewportWIdth == 1)
                  {
                      this.FitImageToScreen( index );
                  }
   
              }
              else
              {
                  this.FitImageToScreen( index );
              }
   
              selectedImageIndex = index;
          }
      }
   
      dragInProgress = false;
      mouseLeftButtonClicked = false;
  }

The logic here is the following - if the image is not fitted and is smaller we fit it, if it's not fitted, but is bigger we don't fit it, so we can zoom it further. If another image is clicked it's fitted to the screen.

Summary

That is all for now and as you can see it isn’t complicated at all. Hope you weren’t scared by the spiders. Here is a link to the live demo and a link to the source code of this example. Stay tuned for the next article, because the things are going to become more and more impressive step by step.


Subscribe

Comments

  • -_-

    RE: The MultiscaleImage control and the SubImages collection


    posted by blackmonday on Sep 05, 2008 04:45

    When trying to follow along and recreate this I found many holes and items  left out but I've managed to fill them all in apart from the 'DeepZoomOutput' namespace. I can't find this anywhere and a search online and in various blogs turns up absolutely nothing. Can you please advise how to fix this?

  • Enrai

    RE: The MultiscaleImage control and the SubImages collection


    posted by Enrai on Sep 05, 2008 05:12

    Hi, blackmonday,

    Concretely for this sample the DeepZoomOutput namespace can be found in the MousWheelHelper.cs file. It's confusing, so I'll be sure to change it. I'll also be glad if you share the other holes with me, so I can improve the code and take myself a note. You know, any feedback is welcome :)

  • -_-

    RE: The MultiscaleImage control and the SubImages collection


    posted by cammer on 16:56

    How would I bring an image into focus based on a value I pass to it vs what the user clicks on?   I have multiple images that will take the whole space of the msi - I only want to show one at a time based on the value I pass it (with some conditional logic).

  • Enrai

    RE: The MultiscaleImage control and the SubImages collection


    posted by Enrai on Jan 27, 2009 08:19

    Hi, cammer!

    Based on the value you have passed you must calculate the index of the needed Image, so you would be able to access it later in the SubImages collection. You have to build your logic around that index and bind the value, you passed, to it somehow.

    If you can be more concrete and describe your case, I could give you some more hints and ideas! ;)

  • -_-

    RE: The MultiscaleImage control and the SubImages collection


    posted by codegolem on Jul 24, 2009 17:12

    Hello there! Thank you for this useful info!

    I was wondering how to fit a SubImage in the MultiScaleImage if the SubImage's AspectRatio is different from the MultiScaleImage's one... (for example... a vertical SubImage to be fit in an horizontal MultiScaleImage)...

    Any ideas? Thank you!

  • -_-

    RE: The MultiscaleImage control and the SubImages collection


    posted by Daniel on Aug 31, 2009 17:43

    Excelent article ..

    I've managed to make al work perfectly ..  Thanks Enrai :)

  • -_-

    RE: The MultiscaleImage control and the SubImages collection


    posted by Nate on Feb 10, 2010 00:45
    Thank you.  This article was perfect
  • lnikolov

    RE: The MultiscaleImage control and the SubImages collection


    posted by lnikolov on Jan 06, 2011 15:21
    The article has been updated to the latest version of Silverlight and Visual Studio.
  • bounce20

    Re: The MultiscaleImage control and the SubImages collection


    posted by bounce20 on Oct 04, 2011 01:34

    Mr. Martin, I hope you can help me with this..

    Here's a brief background of the project that i'm working:

    My goal is to attach/overlay an "PushPin image/icon on each subimages of my deep zoom image. 

    Basically, I want to achieve the same function that the "Deep Zoom Navigation -Default" export template where the subimages can be hovered as link (with border changing color and mouse icon changes to magnifying glass), then once clicked, it zooms and fit the image to the MSI control.

    This approach is very similar to yours. I tried to use some of your codes but it doesn't work when i click on the subimages.


  • bounce20

    Re: The MultiscaleImage control and the SubImages collection


    posted by bounce20 on Oct 04, 2011 01:36

    Mr. Martin, I hope you can help me with this..

    Here's a brief background of the project that i'm working:

    My goal is to attach/overlay an "PushPin image/icon on each subimages of my deep zoom image. 

    Basically, I want to achieve the same function that the "Deep Zoom Navigation -Default" export template where the subimages can be hovered as link (with border changing color and mouse icon changes to magnifying glass), then once clicked, it zooms and fit the image to the MSI control.

    This approach is very similar to yours. I tried to use some of your codes but it doesn't work when i click on the subimages.


  • bounce20

    Re: The MultiscaleImage control and the SubImages collection


    posted by bounce20 on Oct 06, 2011 00:04

    At last, after several trials and errors and headbanging on the wall, I finally got it to work. I would like to thank Martin for sharing this code. It helps me alot accessing the subimages of my Deep Zoom image and adding some functions to it. Thanks so much! 

Add Comment

Login to comment:
  *      *