using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Drawing.Imaging; // for ImageFormat class namespace TileGenerator { /// <summary> /// Take a large image and generate quadkey-indexed tiles to a defined zoom level /// </summary> class Program { const int TILE_SIZE = 256; const string SOURCE_IMAGE = @"C:\Images\venus-whole.jpg"; // 5 const string TARGET_IMAGE_PREFIX = "c"; const int MAX_ZOOM = 5; const string TARGET_PATH = @"C:\Inetpub\TileClient06\Tiles\"; static void Main(string[] args) { int rowCount, colCount; for (int zoom = 1; zoom <= MAX_ZOOM; zoom++) { rowCount = colCount = (int)Math.Pow(Convert.ToDouble(2), Convert.ToDouble(zoom)); Console.WriteLine("ZOOM: " + zoom + " " + rowCount + "," + colCount); Bitmap zoomBitmap = LoadImageForZoom (SOURCE_IMAGE, zoom); for (int col = 0; col < colCount; col++) { Console.Write(" Row: "); for (int row = 0; row < rowCount; row++) { string quadKey = TileXYToQuadKey(row, col, zoom); CropImage(zoomBitmap, row * TILE_SIZE, col * TILE_SIZE, quadKey); Console.Write(quadKey + " "); } Console.WriteLine(" "); } Console.WriteLine("---"); } Console.ReadKey(); } /// <summary> /// Converts tile XY coordinates into a QuadKey at a specified level of detail. /// </summary> /// <remarks> /// Code (c) Microsoft /// http://msdn2.microsoft.com/en-us/library/bb259689.aspx /// </remarks> /// <param name="tileX">Tile X coordinate.</param> /// <param name="tileY">Tile Y coordinate.</param> /// <param name="levelOfDetail">Level of detail, from 1 (lowest detail) /// to 23 (highest detail).</param> /// <returns>A string containing the QuadKey.</returns> public static string TileXYToQuadKey(int tileX, int tileY, int levelOfDetail) { StringBuilder quadKey = new StringBuilder(); for (int i = levelOfDetail; i > 0; i--) { char digit = '0'; int mask = 1 << (i - 1); if ((tileX & mask) != 0) { digit++; } if ((tileY & mask) != 0) { digit++; digit++; } quadKey.Append(digit); } return quadKey.ToString(); } /// <summary> /// Open the source image, resize it to the correct dimensions for the given zoom /// level (2^zoom) gives the number of rows/columns, then multiply by TileSize. /// NOTE: will stretch image if it is too small. /// </summary> /// <remarks> /// Original code (c) Bob Powell /// http://www.bobpowell.net/changing_resolution.htm /// </remarks> public static Bitmap LoadImageForZoom (string imagePath, int zoom) { int imageSize = (int)Math.Pow(2, zoom) * TILE_SIZE; if (imageSize > int.MaxValue) throw new ArgumentException("Cannot create an image with dimesion " + imageSize); Bitmap bm = (Bitmap)Image.FromFile(imagePath); Bitmap resized = new Bitmap(imageSize, imageSize); //16384 Graphics g = Graphics.FromImage(resized); g.DrawImage(bm, new Rectangle(0, 0, resized.Width, resized.Height), 0, 0, bm.Width, bm.Height, GraphicsUnit.Pixel); g.Dispose(); return resized; } /// <summary> /// Crop the supplied image and save it as a tile /// </summary> /// <remarks> /// Original code (c) Bob Powell /// http://www.bobpowell.net/changing_resolution.htm /// </remarks> public static void CropImage(Bitmap image, int imageX, int imageY, string quadKey) { Bitmap cropped = new Bitmap(TILE_SIZE, TILE_SIZE); Graphics g = Graphics.FromImage(cropped); g.DrawImage(image, new Rectangle(0, 0, cropped.Width, cropped.Height), imageX, imageY, cropped.Width, cropped.Height, GraphicsUnit.Pixel); g.Dispose(); cropped.Save(TARGET_PATH + TARGET_IMAGE_PREFIX + quadKey + ".jpg", ImageFormat.Jpeg); } } }