图像延迟渲染 - 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)
    }
  });
}

Reproducible sample

这已在 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