public static Stream GenerateMosaicFromTiles( Stream sourceImage, string tileBucket, string tileDirectory, int tilePixels, ILogger logger) { using (var tileProvider = new QuadrantMatchingTileProvider()) { // 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 = GetTileImages(tileBucket, tileDirectory, logger); tileProvider.SetSourceStream(sourceImage); tileProvider.ProcessInputImageColors(MosaicBuilder.TileWidth, MosaicBuilder.TileHeight); tileProvider.ProcessTileColors(tileImages); logger.LogInformation("Generating mosaic..."); var start = DateTime.Now; return(GenerateMosaic(tileProvider, sourceImage, tileImages)); } }
private static Stream GenerateMosaic( QuadrantMatchingTileProvider tileProvider, Stream inputStream, List <byte[]> tileImages) { 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 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); return(new MemoryStream(imageBytes.ToArray())); } }