Tuesday 11 August 2009

Determining the size of a Silverlight multi-scale image deep zoom source

Had a bit of a problem today trying to set a multi-scale image with a deep zoom source to fit the height. Fitting the width is easy:

   1: //Reset origin
   2: multiSourceImage.ViewportOrigin = new Point(0, 0);
   3: multiSourceImage.ViewportWidth = 1;

That is right you are just setting the viewport width to 1 which makes sense!! But unfortunately there is no such thing as a viewport height. So another way is required:

   1: //locals
   2: double lastRow = -1;
   3: double lastBottom = 0.0;
   4: double height = 0.0;
   5: bool firstRow = true;
   6:  
   7: //Loop over images
   8: foreach (MultiScaleSubImage subImage in multiSourceImage.SubImages)
   9: {
  10:     //Have we reached a new row ? (NB this only works with images layed out in a grid)
  11:     if (subImage.ViewportOrigin.Y != lastRow)
  12:     {
  13:         //Have new row
  14:         //Take aspect ratio of image here
  15:         lastRow = subImage.ViewportOrigin.Y;
  16:  
  17:         //Work out bottom of image - to get to gap
  18:         double width = multiSourceImage.ActualWidth / (multiSourceImage.ViewportWidth * subImage.ViewportWidth);
  19:         double height2 = multiSourceImage.ActualWidth / (multiSourceImage.ViewportWidth * subImage.ViewportWidth * subImage.AspectRatio);
  20:  
  21:         Point pos = multiSourceImage.LogicalToElementPoint(new Point(
  22:             -subImage.ViewportOrigin.X / subImage.ViewportWidth,
  23:             -subImage.ViewportOrigin.Y / subImage.ViewportWidth)
  24:         );
  25:         Rect rect = new Rect(pos.X, pos.Y, width, height2);
  26:  
  27:         //Work out gap
  28:         double gapHeight = rect.Top - lastBottom;
  29:         lastBottom = rect.Bottom;
  30:  
  31:         //height += height2;
  32:         height += (multiSourceImage.ActualWidth / subImage.ViewportWidth) * 1 / (subImage.AspectRatio);
  33:         if (!firstRow)
  34:             height += gapHeight;
  35:         firstRow = false;
  36:     }
  37: }
  38:  
  39: //Set to actual height here
  40: multiSourceImage.ViewportWidth = height / multiSourceImage.ActualHeight;            
  41: multiSourceImage.ViewportOrigin = new Point(0, 0);

As noted in the notes, this only works if the images are in a nice gridded layout. I guess you can modify it to work with the left hand most image of each row.

It basically works by looping over each sub image. Seeing if that image is on a new line, if it is record its origin y co-ordinate.

For any subsequent rows, work out the gap between the bottom of the image in the row above, and add those dimensions to a running total.

You can work out the height of a sub image simply by



   1: subImageHeight = multiSourceImage.ActualWidth / (subImage.ViewPortWidth * subImage.AspectRatio)

Finally this running total for the height over the size of the multi source image element should give you the viewport width you require.

Setting the viewport origin to 0,0 will also make it line up in the element box nicely.

No comments: