private Bitmap createTileAsync(uint level, uint tileX, uint tileY)
        {
            //Console.WriteLine("Creating tile. x: {0}, y: {1}, level: {2}", tileX, tileY, level);

            // check if we're at the base of the pyramid
            if (level == 0)
            {
                //Console.WriteLine("Writing tile to file - level: {0}, tileX: {1}, tileY: {2}", level, tileX, tileY);

                Bitmap tile = tileReader.read(tileX, tileY);

                // write tile to file
                tile.Save(File.Create(outputDir + @"\" + string.Format("{0}_{1}_{2}.jpg", level, tileX, tileY)), ImageFormat.Jpeg);

                // read a tile at the given coordinates and return the image
                return(tile);
            }

            // create tasks for the four child tiles in the level below this one
            Bitmap scaledImage = null;

            uint[] xs = { 2 * tileX, 2 * tileX + 1 };
            uint[] ys = { 2 * tileY, 2 * tileY + 1 };
            using (var topLeft = Task <Bitmap> .Factory.StartNew(() => { return(createTileAsync(level - 1, xs[0], ys[0])); }))
                using (var topRight = Task <Bitmap> .Factory.StartNew(() => { return(createTileAsync(level - 1, xs[1], ys[0])); }))
                    using (var bottomLeft = Task <Bitmap> .Factory.StartNew(() => { return(createTileAsync(level - 1, xs[0], ys[1])); }))
                        using (var bottomRight = Task <Bitmap> .Factory.StartNew(() => { return(createTileAsync(level - 1, xs[1], ys[1])); }))
                        {
                            // wait for the tasks to finish
                            Task.WaitAll(topLeft, topRight, bottomLeft, bottomRight);

                            // stitch the four subtiles into one
                            using (Bitmap image = ImageUtils.combine(topLeft.Result, topRight.Result, bottomLeft.Result, bottomRight.Result))
                            {
                                // scale to half the size
                                scaledImage = new Bitmap(image, image.Width / 2, image.Height / 2);
                            }
                        }

            //Console.WriteLine("Writing tile to file - level: {0}, tileX: {1}, tileY: {2}", level, tileX, tileY);

            // write tile to file
            scaledImage.Save(File.Create(outputDir + @"\" + string.Format("{0}_{1}_{2}.jpg", level, tileX, tileY)), ImageFormat.Jpeg);

            return(scaledImage);
        }
        private Bitmap createTile(uint level, uint tileX, uint tileY)
        {
            // check if we're at the base of the pyramid
            if (level == 0)
            {
                //Console.WriteLine("Writing tile to file - level: {0}, tileX: {1}, tileY: {2}", level, tileX, tileY);

                Bitmap tile = tileReader.read(tileX, tileY);

                // write tile to file
                tile.Save(File.Create(outputDir + @"\" + string.Format("{0}_{1}_{2}.jpg", level, tileX, tileY)), ImageFormat.Jpeg);

                // read a tile at the given coordinates and return the image
                return(tile);
            }

            // create tasks for the four child tiles in the level below this one
            uint[] xs          = { 2 * tileX, 2 * tileX + 1 };
            uint[] ys          = { 2 * tileY, 2 * tileY + 1 };
            Bitmap scaledImage = null;

            using (var topLeft = createTile(level - 1, xs[0], ys[0]))
                using (var topRight = createTile(level - 1, xs[1], ys[0]))
                    using (var bottomLeft = createTile(level - 1, xs[0], ys[1]))
                        using (var bottomRight = createTile(level - 1, xs[1], ys[1]))
                            using (var image = ImageUtils.combine(topLeft, topRight, bottomLeft, bottomRight))
                            {
                                // scale to half the size
                                scaledImage = new Bitmap(image, image.Width / 2, image.Height / 2);
                            }

            //Console.WriteLine("Writing tile to file - level: {0}, tileX: {1}, tileY: {2}", level, tileX, tileY);

            // write tile to file
            scaledImage.Save(File.Create(outputDir + @"\" + string.Format("{0}_{1}_{2}.jpg", level, tileX, tileY)), ImageFormat.Jpeg);

            return(scaledImage);
        }