图像延迟渲染 - Skia ASP
Delayed rendering of the image - Skia ASP
我正在尝试使用 SkiaSharp 绘制一组图像,将它们转换为字节数组,然后发送到 HttpContext
流。出于某种原因,每个 图像仅在渲染下一个图像 并发送到 HTTP 流时才会显示在浏览器中。
- 渲染第一个图像后,浏览器显示空白区域,没有图像
- 渲染第二张图片后,浏览器显示第一张图片
- 渲染第三张图片后,浏览器显示第二张图片,依此类推
这是 Web API 控制器。取消注释第二个 drawShapes
调用将使它工作,但我想了解为什么图像渲染会延迟。也许我只是没有调用一些重要的方法,比如 Flush
或类似的方法?
此外,这不是 ASP 问题,因为我尝试使用 System.Drawing.Common 渲染图像并且图像是实时渲染的,没有延迟。
有人知道这个方法缺少什么吗?
[Route("/source")]
public async Task Get()
{
// Initialize Skia
var res = new byte[1000];
var boundary = Guid.NewGuid().ToString();
var generator = new Random();
var map = new SKBitmap(250, 250);
var canvas = new SKCanvas(map);
var inPaint = new SKPaint
{
Color = SKColors.Black,
Style = SKPaintStyle.Fill,
FilterQuality = SKFilterQuality.High
};
var exPaint = new SKPaint
{
Color = SKColors.White,
Style = SKPaintStyle.Fill,
FilterQuality = SKFilterQuality.Low
};
// Create HTTP stream
Response.ContentType = "multipart/x-mixed-replace;boundary=" + boundary;
var outputStream = Response.Body;
var cancellationToken = Request.HttpContext.RequestAborted;
// Create method posting images to HTTP stream
async Task drawShapes()
{
using (var image = SKImage.FromBitmap(map))
{
var pos = generator.Next(50, 150);
canvas.DrawRect(0, 0, 250, 250, exPaint);
canvas.DrawCircle(pos, pos, 20, inPaint);
res = image.Encode(SKEncodedImageFormat.Webp, 100).ToArray();
}
var header = $"--{ boundary }\r\nContent-Type: image/webp\r\nContent-Length: { res.Length }\r\n\r\n";
var headerData = Encoding.ASCII.GetBytes(header);
await outputStream.WriteAsync(headerData);
await outputStream.WriteAsync(res);
await outputStream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
}
// Start HTTP stream
await Task.Run(async () =>
{
//while (true)
{
await drawShapes();
//await drawShapes(); // After uncommenting this shows the image (the previous one)
}
});
}
这已在 SkiaSharp 讨论中得到解答。
https://github.com/mono/SkiaSharp/discussions/1975
可能的解决方案是确保 Encode
图像仅在所有绘图完成后或在位图而不是图像上调用 Encode
。
最简单的就是替换这一行。
//res = image.Encode(SKEncodedImageFormat.Webp, 100).ToArray(); // wrong
res = map.Encode(SKEncodedImageFormat.Webp, 100).ToArray(); // correct
我正在尝试使用 SkiaSharp 绘制一组图像,将它们转换为字节数组,然后发送到 HttpContext
流。出于某种原因,每个 图像仅在渲染下一个图像 并发送到 HTTP 流时才会显示在浏览器中。
- 渲染第一个图像后,浏览器显示空白区域,没有图像
- 渲染第二张图片后,浏览器显示第一张图片
- 渲染第三张图片后,浏览器显示第二张图片,依此类推
这是 Web API 控制器。取消注释第二个 drawShapes
调用将使它工作,但我想了解为什么图像渲染会延迟。也许我只是没有调用一些重要的方法,比如 Flush
或类似的方法?
此外,这不是 ASP 问题,因为我尝试使用 System.Drawing.Common 渲染图像并且图像是实时渲染的,没有延迟。
有人知道这个方法缺少什么吗?
[Route("/source")]
public async Task Get()
{
// Initialize Skia
var res = new byte[1000];
var boundary = Guid.NewGuid().ToString();
var generator = new Random();
var map = new SKBitmap(250, 250);
var canvas = new SKCanvas(map);
var inPaint = new SKPaint
{
Color = SKColors.Black,
Style = SKPaintStyle.Fill,
FilterQuality = SKFilterQuality.High
};
var exPaint = new SKPaint
{
Color = SKColors.White,
Style = SKPaintStyle.Fill,
FilterQuality = SKFilterQuality.Low
};
// Create HTTP stream
Response.ContentType = "multipart/x-mixed-replace;boundary=" + boundary;
var outputStream = Response.Body;
var cancellationToken = Request.HttpContext.RequestAborted;
// Create method posting images to HTTP stream
async Task drawShapes()
{
using (var image = SKImage.FromBitmap(map))
{
var pos = generator.Next(50, 150);
canvas.DrawRect(0, 0, 250, 250, exPaint);
canvas.DrawCircle(pos, pos, 20, inPaint);
res = image.Encode(SKEncodedImageFormat.Webp, 100).ToArray();
}
var header = $"--{ boundary }\r\nContent-Type: image/webp\r\nContent-Length: { res.Length }\r\n\r\n";
var headerData = Encoding.ASCII.GetBytes(header);
await outputStream.WriteAsync(headerData);
await outputStream.WriteAsync(res);
await outputStream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
}
// Start HTTP stream
await Task.Run(async () =>
{
//while (true)
{
await drawShapes();
//await drawShapes(); // After uncommenting this shows the image (the previous one)
}
});
}
这已在 SkiaSharp 讨论中得到解答。 https://github.com/mono/SkiaSharp/discussions/1975
可能的解决方案是确保 Encode
图像仅在所有绘图完成后或在位图而不是图像上调用 Encode
。
最简单的就是替换这一行。
//res = image.Encode(SKEncodedImageFormat.Webp, 100).ToArray(); // wrong
res = map.Encode(SKEncodedImageFormat.Webp, 100).ToArray(); // correct