using StitcherApi.Models; using StitcherApi.Services.Utilities; namespace StitcherApi.Services; public class ImageService : IImageService { private readonly ImageProcessor _processor; private const int TILE_SIZE = 720; public ImageService(IConfiguration configuration) { string assetPath = configuration["AssetPath"] ?? throw new InvalidOperationException("AssetPath is not configured."); _processor = new ImageProcessor(assetPath); } public async Task GenerateImageAsync(GenerateImageRequest request) { // 1. Delegate parsing to the CoordinateParser var (minRow, minCol, maxRow, maxCol) = CoordinateParser.ParseCanvasRect(request.CanvasRect); // 2. Perform high-level calculations var stitchedCanvasWidth = (maxCol - minCol + 1) * TILE_SIZE; var stitchedCanvasHeight = (maxRow - minRow + 1) * TILE_SIZE; int cropX = (int)(request.CropOffset[0] * stitchedCanvasWidth); int cropY = (int)(request.CropOffset[1] * stitchedCanvasHeight); int cropW = (int)(request.CropSize[0] * stitchedCanvasWidth); int cropH = (int)(request.CropSize[1] * stitchedCanvasHeight); if (cropW <= 0 || cropH <= 0) { throw new ArgumentException("Calculated crop dimensions are invalid."); } var startTileCol = minCol + (cropX / TILE_SIZE); var endTileCol = minCol + ((cropX + cropW - 1) / TILE_SIZE); var startTileRow = minRow + (cropY / TILE_SIZE); var endTileRow = minRow + ((cropY + cropH - 1) / TILE_SIZE); // 3. Create a parameter object for the processor var stitchRequest = new StitchRequest( minRow, minCol, startTileRow, startTileCol, endTileRow, endTileCol, cropX, cropY, cropW, cropH, request.OutputScale ); // 4. Delegate image processing work return await _processor.StitchAndCropAsync(stitchRequest); } }