public static async Task GenerateMosaicFromTilesAsync( Stream sourceImage, CloudBlobContainer tileContainer, string tileDirectory, Stream outputStream, int tilePixels, TraceWriter log) { using (var tileProvider = new QuadrantMatchingTileProvider()) { MosaicBuilder.TileHeight = int.Parse(Environment.GetEnvironmentVariable("MosaicTileWidth")); MosaicBuilder.TileWidth = int.Parse(Environment.GetEnvironmentVariable("MosaicTileHeight")); // override default tile width and height if specified if (tilePixels != 0) { MosaicBuilder.TileWidth = MosaicBuilder.TileHeight = tilePixels; } MosaicBuilder.DitheringRadius = -1; MosaicBuilder.ScaleMultiplier = 1; List <byte[]> tileImages = await GetTileImagesAsync(tileContainer, tileDirectory, log); tileProvider.SetSourceStream(sourceImage); tileProvider.ProcessInputImageColors(MosaicBuilder.TileWidth, MosaicBuilder.TileHeight); tileProvider.ProcessTileColors(tileImages); log.Info("Generating mosaic..."); var start = DateTime.Now; GenerateMosaic(tileProvider, sourceImage, tileImages, outputStream); log.Info($"Time to generate mosaic: {(DateTime.Now - start).TotalMilliseconds}"); } }
public static void GenerateMosaicFromTiles( Stream sourceImage, CloudBlobContainer tileContainer, string tileDirectory, Stream outputStream) { using (var tileProvider = new QuadrantMatchingTileProvider()) { MosaicBuilder.TileHeight = int.Parse(Environment.GetEnvironmentVariable("MosaicTileWidth")); MosaicBuilder.TileWidth = int.Parse(Environment.GetEnvironmentVariable("MosaicTileHeight")); MosaicBuilder.DitheringRadius = -1; MosaicBuilder.ScaleMultiplier = 1; var directory = tileContainer.GetDirectoryReference(tileDirectory); var blobs = directory.ListBlobs(true); var tileImages = new List <byte[]>(); foreach (var b in blobs) { if (b.GetType() == typeof(CloudBlockBlob)) { var blob = (CloudBlockBlob)b; blob.FetchAttributes(); var bytes = new byte[blob.Properties.Length]; blob.DownloadToByteArray(bytes, 0); tileImages.Add(bytes); } } tileProvider.SetSourceStream(sourceImage); tileProvider.ProcessInputImageColors(MosaicBuilder.TileWidth, MosaicBuilder.TileHeight); tileProvider.ProcessTileColors(tileImages); GenerateMosaic(tileProvider, sourceImage, tileImages, outputStream); } }
private static void GenerateMosaic(QuadrantMatchingTileProvider tileProvider, Stream inputStream, List <byte[]> tileImages, Stream outputStream) { SKBitmap[,] mosaicTileGrid; inputStream.Seek(0, SeekOrigin.Begin); using (var skStream = new SKManagedStream(inputStream)) using (var bitmap = SKBitmap.Decode(skStream)) { // use transparency for the source image overlay var srcImagePaint = new SKPaint() { Color = SKColors.White.WithAlpha(200) }; int xTileCount = bitmap.Width / MosaicBuilder.TileWidth; int yTileCount = bitmap.Height / MosaicBuilder.TileHeight; int tileCount = xTileCount * yTileCount; mosaicTileGrid = new SKBitmap[xTileCount, yTileCount]; int finalTileWidth = MosaicBuilder.TileWidth * MosaicBuilder.ScaleMultiplier; int finalTileHeight = MosaicBuilder.TileHeight * MosaicBuilder.ScaleMultiplier; int targetWidth = xTileCount * finalTileWidth; int targetHeight = yTileCount * finalTileHeight; var tileList = new List <(int, int)>(); // add coordinates for the left corner of each tile for (int x = 0; x < xTileCount; x++) { for (int y = 0; y < yTileCount; y++) { tileList.Add((x, y)); } } // create output surface var surface = SKSurface.Create(targetWidth, targetHeight, SKImageInfo.PlatformColorType, SKAlphaType.Premul); surface.Canvas.DrawColor(SKColors.White); // clear the canvas / fill with white surface.Canvas.DrawBitmap(bitmap, 0, 0, srcImagePaint); // using the Darken blend mode causes colors from the source image to come through var tilePaint = new SKPaint() { BlendMode = SKBlendMode.Darken }; surface.Canvas.SaveLayer(tilePaint); // save layer so blend mode is applied var random = new Random(); while (tileList.Count > 0) { // choose a new tile at random int nextIndex = random.Next(tileList.Count); var tileInfo = tileList[nextIndex]; tileList.RemoveAt(nextIndex); // get the tile image for this point //var exclusionList = GetExclusionList(mosaicTileGrid, tileInfo.Item1, tileInfo.Item2); var tileBitmap = tileProvider.GetImageForTile(tileInfo.Item1, tileInfo.Item2); mosaicTileGrid[tileInfo.Item1, tileInfo.Item2] = tileBitmap; // draw the tile on the surface at the coordinates SKRect tileRect = SKRect.Create(tileInfo.Item1 * TileWidth, tileInfo.Item2 * TileHeight, finalTileWidth, finalTileHeight); surface.Canvas.DrawBitmap(tileBitmap, tileRect); } surface.Canvas.Restore(); // merge layers surface.Canvas.Flush(); var imageBytes = surface.Snapshot().Encode(SKEncodedImageFormat.Jpeg, 80); imageBytes.SaveTo(outputStream); } }