Using the C# code below, how would you write it in Visual Basic? 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
// levels, 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;
}
}
}
There is none. Period. Unless you are going to write your own state machine, there is no quick fix for this. See the blog post VB.NET's "yield return" .
For those who care about what is actually generated (yes, I love the C# precompiler and compiler :) ):
Try compiling this and take a look at the generated code with .NET Reflector or something:
class Program
{
static void Main(string[] args)
{
var foo = new Foo();
foreach(var result in foo.Bar())
{
Console.WriteLine(result);
}
Console.ReadLine();
}
}
class Foo
{
public IEnumerable<char> Bar()
{
const char start = 'a';
for(int x = 0;x < 26;x++)
{
yield return (char)(start + x);
}
}
}
I'm not going to copy the result, it's huge. But do take a look, you'll see that it isn't simple to solve.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With