2025-07-31 19:39:06 +07:00
|
|
|
using StitcherApi.Models;
|
2025-08-01 20:18:01 +07:00
|
|
|
using StitcherApi.Services.Fast;
|
|
|
|
|
using StitcherApi.Services.Streaming;
|
2025-07-31 19:39:06 +07:00
|
|
|
using StitcherApi.Services.Utilities;
|
|
|
|
|
|
|
|
|
|
namespace StitcherApi.Services;
|
|
|
|
|
|
|
|
|
|
public class ImageService : IImageService
|
|
|
|
|
{
|
2025-08-01 20:18:01 +07:00
|
|
|
private readonly ILogger<ImageService> _logger;
|
|
|
|
|
private readonly FastProcessor _fastProcessor;
|
|
|
|
|
private readonly StreamingProcessor _streamingProcessor;
|
2025-07-31 19:39:06 +07:00
|
|
|
|
2025-08-01 20:18:01 +07:00
|
|
|
private const double ASPECT_RATIO_THRESHOLD_TALL = 0.25;
|
|
|
|
|
private const double ASPECT_RATIO_THRESHOLD_WIDE = 8.0;
|
|
|
|
|
private const int TILE_COUNT_THRESHOLD = 30;
|
|
|
|
|
|
|
|
|
|
public ImageService(IConfiguration config, ILoggerFactory loggerFactory)
|
2025-07-31 19:39:06 +07:00
|
|
|
{
|
2025-08-01 20:18:01 +07:00
|
|
|
_logger = loggerFactory.CreateLogger<ImageService>();
|
2025-07-31 19:39:06 +07:00
|
|
|
string assetPath =
|
2025-08-01 20:18:01 +07:00
|
|
|
config["AssetPath"] ?? throw new InvalidOperationException("AssetPath not configured.");
|
|
|
|
|
|
|
|
|
|
_fastProcessor = new FastProcessor(assetPath, loggerFactory.CreateLogger<FastProcessor>());
|
|
|
|
|
_streamingProcessor = new StreamingProcessor(
|
|
|
|
|
assetPath,
|
|
|
|
|
loggerFactory.CreateLogger<StreamingProcessor>()
|
|
|
|
|
);
|
2025-07-31 19:39:06 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<byte[]> GenerateImageAsync(GenerateImageRequest request)
|
|
|
|
|
{
|
2025-07-31 20:41:48 +07:00
|
|
|
(int minRow, int minCol, int maxRow, int maxCol) = CoordinateParser.ParseCanvasRect(
|
|
|
|
|
request.CanvasRect
|
|
|
|
|
);
|
2025-07-31 19:39:06 +07:00
|
|
|
|
2025-08-01 20:18:01 +07:00
|
|
|
int tileGridWidth = maxCol - minCol + 1;
|
|
|
|
|
int tileGridHeight = maxRow - minRow + 1;
|
|
|
|
|
int totalTiles = tileGridWidth * tileGridHeight;
|
|
|
|
|
|
|
|
|
|
StitchRequest stitchRequest = CreateStitchRequest(request, minRow, minCol, maxRow, maxCol);
|
|
|
|
|
|
|
|
|
|
double aspectRatio = (tileGridHeight > 0) ? (double)tileGridWidth / tileGridHeight : 0;
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
totalTiles > TILE_COUNT_THRESHOLD
|
|
|
|
|
|| aspectRatio > ASPECT_RATIO_THRESHOLD_WIDE
|
|
|
|
|
|| (aspectRatio > 0 && aspectRatio < ASPECT_RATIO_THRESHOLD_TALL)
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogInformation("Large, Tall, or Wide canvas detected. Using fast processor.");
|
|
|
|
|
return await _fastProcessor.ProcessAsync(stitchRequest);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_logger.LogInformation(
|
|
|
|
|
"Small, block-shaped canvas detected. Using robust streaming processor."
|
|
|
|
|
);
|
|
|
|
|
return await _streamingProcessor.ProcessAsync(stitchRequest);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private StitchRequest CreateStitchRequest(
|
|
|
|
|
GenerateImageRequest request,
|
|
|
|
|
int minRow,
|
|
|
|
|
int minCol,
|
|
|
|
|
int maxRow,
|
|
|
|
|
int maxCol
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
const int TILE_SIZE = 720;
|
2025-07-31 20:41:48 +07:00
|
|
|
int stitchedCanvasWidth = (maxCol - minCol + 1) * TILE_SIZE;
|
|
|
|
|
int stitchedCanvasHeight = (maxRow - minRow + 1) * TILE_SIZE;
|
2025-07-31 19:39:06 +07:00
|
|
|
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);
|
2025-08-01 20:18:01 +07:00
|
|
|
int startTileCol = minCol + cropX / TILE_SIZE;
|
|
|
|
|
int endTileCol = minCol + (cropX + cropW - 1) / TILE_SIZE;
|
|
|
|
|
int startTileRow = minRow + cropY / TILE_SIZE;
|
|
|
|
|
int endTileRow = minRow + (cropY + cropH - 1) / TILE_SIZE;
|
2025-07-31 19:39:06 +07:00
|
|
|
|
2025-08-01 20:18:01 +07:00
|
|
|
return new StitchRequest(
|
2025-07-31 19:39:06 +07:00
|
|
|
minRow,
|
|
|
|
|
minCol,
|
|
|
|
|
startTileRow,
|
|
|
|
|
startTileCol,
|
|
|
|
|
endTileRow,
|
|
|
|
|
endTileCol,
|
|
|
|
|
cropX,
|
|
|
|
|
cropY,
|
|
|
|
|
cropW,
|
|
|
|
|
cropH,
|
|
|
|
|
request.OutputScale
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|