Enhance the speed at which animated images are displayed on web browsers

Currently, I am in the process of testing various methods for displaying images in a web browser. My goal is to develop a custom HTML element that can showcase a collection of images or frames as a continuous animation. The concept involves generating the images on the server side and streaming them to the client's browser. At the moment, the most straightforward approach appears to be utilizing the img tag which consistently updates its src attribute. To achieve this, I have subscribed to the onload event, where upon loading an image, I update the image URL with a random timestamp. This action triggers a new request, creating an infinite loop that mimics an animated effect. While this solution is effective, it does impact CPU performance and lacks GPU acceleration.

Utilizing a Controller as the Image Source

[ApiController]
public class StreamController : ControllerBase
{
  [Route("/source")]
  public ActionResult Get()
  {
    var o = new Random();
    var pos = o.Next(50, 150);
    var map = new SKBitmap(250, 250);
    var canvas = new SKCanvas(map);
    var paint = new SKPaint
    {
      Color = SKColors.Black,
      Style = SKPaintStyle.Fill,
      FilterQuality = SKFilterQuality.High
    };

    canvas.DrawCircle(pos, pos, 20, paint);

    var image = SKImage.FromBitmap(map);
    var ms = new MemoryStream();

    image.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms);
    ms.Position = 0;

    return new FileStreamResult(ms, "image/png");
  }
}

HTML Implementation

@page "/"

<!-- Solution #1 : SRC attribute -->

<img 
  width="250" 
  height="250" 
  @onload="OnLoad" 
  src="@Source" />

<!-- Solution #2 : background style URL -->

<div 
  style="width: 250px; height: 250px; background: url(@Source)">
</div>

<!-- Solution #3 : SRC of the picture element - does not work -->

<picture style="width: 250px; height: 250px">
  <source srcset="@Source" type="image/png" media="(min-width:250px)">
</picture>

@code 
{
  private Random _generator = new();
  public string Source { get; set; } = "/source";

  public void OnLoad()
  {
    // Creating an infinite loop of HTTP calls to animate by updating image source after loading the previous one

    var uid = Guid.NewGuid().ToString("N");
    var num = _generator.Next();
    var stamp = DateTime.Now.Ticks;
    
    Source = $"/source?{ uid }-{ num }-{ stamp }";
  }
}

The Result

The red border signifies HTML animation, while the blue border represents CSS background. Note that the Picture tag did not render as expected.

https://youtu.be/gk8Z-LrKxLE

Inquiries

  1. Why isn't solution #3, utilizing the picture element, functioning correctly?
  2. What causes solution #2, using CSS background, to perform slower than solution #1 with the image tag? Why does it skip some frames and lack GPU acceleration?
  3. Is there a method to reduce CPU load by modifying something within the HTML or controller, such as transitioning to async streams in the controller or converting images into a video stream?

Update

A major issue has surfaced with refreshing the img URL. It seems that the FileStreamResult returned from the ASP controller becomes locked by an image, resulting in each image update request (e.g., /source?1, /source/2, /source?3) being cached by the browser. As a consequence, .NET struggles to release this resource, leading to a significant increase in memory usage.

https://i.sstatic.net/S5Nva.png

Answer №1

Successfully resolved the issue by utilizing Motion JPEG as the source for either the img or iframe tag. It is also possible to use the video tag. It seems that most, if not all, browsers support a stream of images sent via HTTP as multipart/mixed content, where each image in the stream consists of bytes separated by a specific separator.

Motion JPEG Format

Sending the following via HTTP would prompt the browser to wait for continuous data from the stream.

HTTP/1.1 200 OK\r\n
Content-Type: multipart/x-mixed-replace; boundary=--SomeBoundary\r\n

The server-side generating images should maintain an open stream, such as through an infinite loop. This loop will continuously produce new images, convert them to suitable formats like JPEG or even more optimized WEBP, and send them to the HTTP stream as byte sets.

--SomeBoundary\r\n
Content-Type: image/jpeg\r\n
Content-Length: 100\r\n\r\n 
<Image-Bytes-Go-Here>
\r\n

For example, to display a video comprised of 3 frames, the resulting HTTP response would resemble this structure.

HTTP/1.1 200 OK\r\n
Content-Type: multipart/x-mixed-replace; boundary=--SomeBoundary\r\n

--SomeBoundary\r\n
Content-Type: image/jpeg\r\n
Content-Length: 100\r\n\r\n 
<Image-Bytes-Go-Here>\r\n

--SomeBoundary\r\n
Content-Type: image/jpeg\r\n
Content-Length: 100\r\n\r\n 
<Image-Bytes-Go-Here>\r\n

--SomeBoundary\r\n
Content-Type: image/jpeg\r\n
Content-Length: 100\r\n\r\n 
<Image-Bytes-Go-Here>\r\n

Optimization

  • Simple shapes can be created using pure CSS
  • Rendering a main view with numerous dynamic shapes is best achieved with SkiaSharp canvas
  • Text rendering in SkiSharp may experience some slowness. SVG or plain HTML could be the preferred options here

Memory Leaks

An additional challenge is the gradual increase in memory usage when images are requested via HTTP stream by the img tag.

<img src="http://127.0.0.1/stream" />

Surprisingly, swapping out the img tag with an iframe resolves the memory leak issue, presumably because frames and browser windows do not cache images as aggressively as the img tag, or the cache is cleared more effectively.

<iframe src="http://127.0.0.1/stream" />

For further insights on this concept, refer to the links provided below.

A real-time charting application implemented as a reusable Blazor control.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Step-by-step guide on displaying a window containing text when hovering over a CSS class

As a beginner in css, html, and js, I created an html page with a table of athletes. Each row is identified by the css class "athlete-name", like this: <div id="message-hide" style="display: none"> Hello world! </div> <t ...

JavaScript resets the timer whenever the page is refreshed

Is there a way to maintain the timer in a quiz even after refreshing the page? <html><h1>Js Timer</h1> <div style="font-weight: bold;" id="quiz-time-left"></div> <script type="text/javascript"> var total_seconds = ...

Managing the css @print feature within the WordPress admin interface

When attempting to use 'window.print()' to print only a specific div inside the WordPress admin area, I tried enqueueing CSS to load on the desired page and hide all elements except for the target div. However, the issue arises when the text form ...

Modify website styling using JavaScript to edit external CSS/SCSS files

I am looking to 'modify' a file that is stored on my server, for example: <link rel="stylesheet" href="css/plugin.scss"> Not only that, but I also want to specifically edit a line within the SASS file. In SASS, you can declare variables i ...

What is the best way to implement CSS chat messages with rounded borders?

I am currently compiling a list of messages sent and received on our chat platform. Here is the current layout: Check out the preview However, I would like to revamp this structure to something like the following: Take a look at the new preview here I ...

I encountered an issue with my h3 element's margin not being applied properly when I attempted to add

I'm facing an issue with the margin for <h3> tag in my HTML code. I want to create some space between the form and the h3 element. Here is the CSS: *{ margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; } body{ background-ima ...

Something seems off with Chrome

I am facing a unique issue that I need help with. Unfortunately, the code is too long to post here but essentially it involves creating a menu for a website. The menu works perfectly and looks great on all browsers except for Chrome. This is unusual as Ch ...

What is the best way to apply a CSS class to a ComponentRef that has been generated in Angular 5

I am attempting to dynamically add a CSS class to a component right after its creation by utilizing ViewContainerRef and ComponentFactoryResolver. My goal is to determine the class based on which other Components have already been added to myViewContainerR ...

Having issues with my toggler functionality. I attempted to place the JavaScript CDN both at the top and bottom of the code, but unfortunately, it is still not

I recently attempted to place the JavaScript CDN at the top of my code, but unfortunately, it did not have the desired effect. My intention was to make the navigation bar on my website responsive and I utilized a toggler in the process. While the navbar di ...

When I hover over one menu item, it interferes with my CSS transitions because the other menu items are hidden

I've been attempting to create a menu with very specific behavior: 1) Submenu transitions in when its corresponding menu item is hovered over 2) Submenu remains visible for a moment after moving the mouse away before transitioning out 3) If another me ...

What is the best way to enable scrolling in nested div elements when the parent container is too small on the x-axis

I am attempting to create a nested div with a fixed width inside a parent div that has a relative width. The goal is for the nested div to always maintain a fixed width. If the parent div has a smaller width, the nested div should display a horizontal scr ...

Is there a way to include a button at the top of the Notiflix.Loading() overlay for closing or stopping it?

I've integrated the "notiflix" library into my project, and I'm currently using notiflix.loading.pulse() for a lengthy process. While this works perfectly fine, I would like to add a button (for closing/stopping the process) on top of the loading ...

What is the best way to utilize a color picker to apply CSS color to a parent element?

When the pencil glyphicon is clicked, a color picker appears. I only want to apply the selected color from the color picker to the list elements that are the grand parent of the pencil glyphicon. Here's a snippet of my Ruby front-end code: <% cat ...

When the user clicks on a checkbox, jQuery should have the ability to retrieve the data from a table with 9000 rows

I am in need of a straightforward example that demonstrates how jQuery can fetch the contents of a table with more than 9000 rows. When the user clicks on the checkbox next to a table row, the checked rows should be displayed on the same view page. Can you ...

How to Deactivate List Items in ASP.NET

I am attempting to dynamically deactivate a bulleted list based on the result of an IF statement. Here is the HTML snippet: <asp:PlaceHolder ID="tab1_placeholder" runat="server"> <li class="active" runat="server" id="tab1"> <a h ...

Is it possible to adjust the background color based on the current time of day?

I have successfully designed a visually appealing website using HTML5, CSS, and Bootstrap. I am interested in finding a way to automatically change the background color and navigation bar selection color based on the time of day - blue during the day and d ...

Tips for crafting a perpetually looping animated shape using canvas

Lately, I've been experimenting with canvas and have encountered a challenge that I can't seem to solve. I've mastered creating shapes, animating them, and looping them across the canvas. However, I'm struggling to figure out how to spa ...

Looking to modify the HTML layout in order to be compatible with a specific script

Utilizing a form validation script with required:true data-validation will stop the form from submitting and highlight invalid fields in red by adding "has-error" to the parent container when the user submits the form. In the code snippet below, "has-erro ...

Is it possible to maintain consistent numbering for ordered lists using only CSS, even when the lists are separate from each other?

Example: https://jsfiddle.net/jacobgoh101/uqrkaodc/3/ <ol> <li>a</li> </ol> <ul> <li>b</li> </ul> <ol> <li>c</li> <li>d</li> <li>e</li> </ol> ol li ...

Make all cells in bootstrap table appear in bold font

Is it possible to have normal text in the cells of a Bootstrap 4 table without bold formatting? Using font-weight doesn't seem to be working for me. <div class="row col-md-10 px-4 py-3 "> <table id="ServiceTable" class="table table-hover ...