using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using StitcherApi.Services.Utilities; namespace StitcherApi.Services.Fast; public class FastProcessor { private readonly string _assetPath; private readonly ILogger _logger; private const int TILE_SIZE = 720; public FastProcessor(string assetPath, ILogger logger) { _assetPath = assetPath; _logger = logger; } public async Task ProcessAsync(StitchRequest stitchRequest) { using Image finalImage = new(stitchRequest.CropW, stitchRequest.CropH); for (int r = stitchRequest.StartTileRow; r <= stitchRequest.EndTileRow; r++) { for (int c = stitchRequest.StartTileCol; c <= stitchRequest.EndTileCol; c++) { string tileFileName = TileHelper.GetTileFileName(r, c); string tileFilePath = Path.Combine(_assetPath, tileFileName); if (!File.Exists(tileFilePath)) { throw new FileNotFoundException($"Asset not found: {tileFileName}"); } using Image tileImage = await Image.LoadAsync(tileFilePath); int tileOriginX = (c - stitchRequest.MinCol) * TILE_SIZE; int tileOriginY = (r - stitchRequest.MinRow) * TILE_SIZE; int srcX = Math.Max(0, stitchRequest.CropX - tileOriginX); int srcY = Math.Max(0, stitchRequest.CropY - tileOriginY); int destX = Math.Max(0, tileOriginX - stitchRequest.CropX); int destY = Math.Max(0, tileOriginY - stitchRequest.CropY); int overlapW = Math.Max( 0, Math.Min(stitchRequest.CropX + stitchRequest.CropW, tileOriginX + TILE_SIZE) - Math.Max(stitchRequest.CropX, tileOriginX) ); int overlapH = Math.Max( 0, Math.Min(stitchRequest.CropY + stitchRequest.CropH, tileOriginY + TILE_SIZE) - Math.Max(stitchRequest.CropY, tileOriginY) ); if (overlapW > 0 && overlapH > 0) { Rectangle sourceRect = new Rectangle(srcX, srcY, overlapW, overlapH); finalImage.Mutate(ctx => ctx.DrawImage( tileImage, new Point(destX, destY), sourceRect, new GraphicsOptions() ) ); } } } if (stitchRequest.OutputScale > 0 && stitchRequest.OutputScale < 1.0) { int newWidth = (int)(stitchRequest.CropW * stitchRequest.OutputScale); int newHeight = (int)(stitchRequest.CropH * stitchRequest.OutputScale); finalImage.Mutate(x => x.Resize(newWidth, newHeight, KnownResamplers.Bicubic)); } using MemoryStream memoryStream = new MemoryStream(); await finalImage.SaveAsPngAsync(memoryStream); return memoryStream.ToArray(); } }