Using the c# code below, how would you write it in vb? What is it trying to say?
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Microsoft.LiveLabs.Pivot
{
/// <summary>
/// Tile Builder class
/// </summary>
public static class TileBuilder
{
/// <summary>
/// Specifies which images are required in the images array used in CreateTile according to the morton fractal pattern used by Seadragon.
/// </summary>
/// <remarks>
/// Usage of this and CreateTile are kind of tricky. Here's an example:
/// Say you have a results set that is a collection of items like so: { item1, item2, ..., item100 }
/// Since Seadragon expects the tiles to be laid out in a Morton pattern, level 6 will look like the following:
/// --------------------------
/// |0 1 4 5 | 16 17...
/// |2 3 6 7 | 18 19
/// |8 9 12 13 | 24 25
/// |10 11 14 15 | 26 27
/// |-----------------------
/// |32 33 36 37 | 48 49
/// |34 35 38 39 | 50 51...
/// |. .
/// |. .
/// . .
/// Each tile at level 6 is 4x4, so the dashes represent tile boundaries. Now, say you want to build 0,0.
/// You need the images on that tile. The ids 0, 1, 4, 5... represent the ids in your result set, { item1, item2, ..., item100 }.
/// Calling this method tells you the ids to use for a given tile. You then must retrieve the necessary images out the result set,
/// and supply them in the order this method gave you to CreateTile. This will result in a correctly built tile that Seadragon can use.
/// </remarks>
/// <param name="imageCount">Number of images in the full set.</param>
/// <param name="level">The level to which each image will be downsampled.</param>
/// <param name="row">The row number which specifies what images to render.</param>
/// <param name="column">The row number which specifies what images to render.</param>
/// <param name="tileSize">The size of the tile to return.</param>
public static IEnumerable<int> GetTileIds(
int imageCount,
int level,
int row,
int column,
int tileSize)
{
// calculate upper-left hand corner of tile in image space (1 unit = 1 image)
int levelSize = (int)Math.Pow(2, level);
int imagePerSide = tileSize / levelSize;
int xOffset = row * imagePerSide;
int yOffset = column * imagePerSide;
if (imagePerSide <= 0)
{
throw new ArgumentOutOfRangeException("Level is greater than the maximum depth allowed by the tile size, or the tile size is 0.");
}
// loop through x and y in image space, starting at the upper-left hand corner of the tile
// find all ids on the given tile
for (int x = 0; x < imagePerSide; x++)
{
for (int y = 0; y < imagePerSide; y++)
{
int n = XYToMorton(x + xOffset, y + yOffset);
if (n < imageCount)
{
yield return n;
}
}
}
}
/// <summary>
/// Create a tile for a collection according to the morton fractal pattern used by Seadragon.
/// </summary>
/// <remarks>
/// See GetTileIds for more information.
/// </remarks>
/// <param name="imageCount">The total number of images in the collection.</param>
/// <param name="images">Jpeg images to render on this tile.
/// If this is null, a blank tile will be returned.
/// See GetTileIds remarks for more information.</param>
/// <param name="level">The level to which each image will be downsampled.</param>
/// <param name="row">The row number which specifies what images to render.</param>
/// <param name="column">The row number which specifies what images to render.</param>
/// <param name="tileSize">The size of the tile to return.</param>
/// <param name="output">The stream to use to output the result.</param>
public static void CreateTile(
int imageCount,
IEnumerable<ImageBag> images,
int level,
int row,
int column,
int tileSize,
string fileType,
Stream output)
{
// calculate upper-left hand corner of tile in image space (1 unit = 1 image)
int levelSize = (int)Math.Pow(2, level);
int imagePerSide = tileSize / levelSize;
int xOffset = row * imagePerSide;
int yOffset = column * imagePerSide;
if (imagePerSide <= 0)
{
throw new ArgumentOutOfRangeException("Level is greater than the maximum depth allowed by the tile size, or the tile size is 0.");
}
if (output == null)
{
throw new ArgumentNullException("The given output stream is null.");
}
// create the tile
WriteableBitmap outputBitmap = new WriteableBitmap(
tileSize,
tileSize,
96,
96,
PixelFormats.Bgr24,
null);
// if images is null, return a blank tile
if (images != null)
{
// loop through the tile in relative x and y image-space
IEnumerator<ImageBag> imageEnumerator = images.GetEnumerator();
for (int x = 0; x < imagePerSide; x++)
{
for (int y = 0; y < imagePerSide; y++)
{
// convert to morton id-space from the absolute image-space (to get absolute, add offsets)
int n = XYToMorton(x + xOffset, y + yOffset);
if (n < imageCount)
{
if (imageEnumerator.MoveNext())
{
if (imageEnumerator.Current == null)
{
continue;
}
// compute the pixel location
int locX = levelSize * x;
int locY = levelSize * y;
int width = 0;
int height = 0;
imageEnumerator.Current.ImageSize(out width, out height);
MemoryStream imageStream = new MemoryStream(imageEnumerator.Current.ImageData);
// determine the largest tile size to the nearest power of two for this image: 2^ceil(lg max(width, height))
double maxTileSize = Math.Pow(2, Math.Ceiling(Math.Log(Math.Max(width, height), 2)));
// downsample to the correct size and decompress the image
// the correct size is total dimenion of the image * level size / max tile size required for total width
// think of this as dividing the dimensions by two foreach level, starting at the max tile size,
// and going up to the current tile size
TransformedBitmap downsampledImage = JpegDecoder.DownsampleJpeg(
imageStream,
Math.Ceiling(width * levelSize / maxTileSize),
Math.Ceiling(height * levelSize / maxTileSize));
// copy the pixels to a buffer and then write them to the appropriate region on the output image
int stride = (downsampledImage.PixelWidth * downsampledImage.Format.BitsPerPixel + 7) / 8;
byte[] buffer = new byte[stride * downsampledImage.PixelHeight];
downsampledImage.CopyPixels(buffer, stride, 0);
Int32Rect outputRect = new Int32Rect(locX, locY, downsampledImage.PixelWidth, downsampledImage.PixelHeight);
outputBitmap.WritePixels(outputRect, buffer, stride, 0);
}
else
{
// we should render the image, but we're done with our list
// so, exit both loops
x = imagePerSide;
y = imagePerSide;
}
}
else
{
// since n is monotonic wrt y, we know y has gone too far down, so we can reset it
y = imagePerSide;
}
}
}
}
// write the output
BitmapFrame outputFrame = BitmapFrame.Create(outputBitmap);
BitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(outputFrame);
encoder.Save(output);
}
/// <summary>
/// Converts an x and y to a Morton number
/// </summary>
/// <param name="x">x location to convert.</param>
/// <param name="y">y location to convert.</param>
/// <returns>Returns the morton number which corresponds to the given x and y coordinates.</returns>
private static int XYToMorton(int x, int y)
{
const uint BITS_PER_BYTE = 8;
const uint BIT_PAIRS = sizeof(int) * BITS_PER_BYTE / 2;
int morton = 0;
for (int i = 0; i < BIT_PAIRS; i++)
{
morton |= (x & 1) << (i * 2);
morton |= (y & 1) << ((i * 2) + 1);
x >>= 1;
y >>= 1;
}
return morton;
}
}
}