Inline Images with ASP.NET Core

The most common way to show an image in an HTML page is to use the <img> tag to load an external resource. Another option is to use a URL that is a Base64 encoded version of the image. There are some aspects worth considering:

  1. Using this approach the HTML will become larger, because it will also contain the image as a Base64 encoded string
  2. There is no need to load external resources together with the HTML page, which may make the loading faster
  3. The images can be cached together with the page
  4. Of course, if the Base64 string is hardcoded in the page, to change the image, we must change the page

I am a big fan of ASP.NET Core’s tag helpers, and I already wrote about them. This time, I propose a tag helper for rendering a Base64 image from a local file!

Here is the code

[HtmlTargetElement("inline-img")]
public class InlineImage : TagHelper
{
private readonly IWebHostEnvironment _environment
    public InlineImage(IWebHostEnvironment environment)
    {
        this._environment = environment;
}

[HtmlAttributeName("id")]
public string Id { get; set; }

[HtmlAttributeName("src")]
    public string Src { get; set; }

    [HtmlAttributeName("style")]
    public string Style { get; set; } 

   [HtmlAttributeName("class")]
    public string Class { get; set; }

    [HtmlAttributeName("width")]
    public string Width { get; set; } 

   [HtmlAttributeName("height")] 
   public string Height { get; set; } 

    [HtmlAttributeName("title")]
    public string Title { get; set; }

    [HtmlAttributeName("alt")] 
   public string Alt { get; set; } 

    public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) 
   {
     if (!string.IsNullOrWhiteSpace(this.Src)) 
        {
          string absoluteSrc;

            if (this.Src.StartsWith("~/"))
            {
                absoluteSrc = this.Src.Replace("~/", this._environment.WebRootPath);
            }
            else 
            {
                var src = this.Src.StartsWith("/") ? this.Src.Substring(1) : this.Src;
                absoluteSrc = Path.Combine(this._environment.WebRootPath, src);
            }

            var img = File.ReadAllBytes(absoluteSrc); 
            var ext = Path.GetExtension(absoluteSrc).Substring(1);
            var urlEncoded = $"data:image/{ext};base64, {Convert.ToBase64String(img)}";

            output.TagName = "img";      
      output.TagMode = TagMode.SelfClosing;     
        output.Attributes.Add("src", urlEncoded);

if (!string.IsNullOrWhiteSpace(this.Id)) 
            {            
     output.Attributes.Add("id", this.Id);
            }

            if (!string.IsNullOrWhiteSpace(this.Style)) 
            { 
                output.Attributes.Add("style", this.Style); 
            }   

          if (!string.IsNullOrWhiteSpace(this.Class)) 
            {  
               output.Attributes.Add("class", this.Class); 
            } 

            if (!string.IsNullOrWhiteSpace(this.Width)) 
            { 
                output.Attributes.Add("width", this.Width); 
            }

if (!string.IsNullOrWhiteSpace(this.Height)) 
            { 
                output.Attributes.Add("Height", this.Height); 
            } 

            if (!string.IsNullOrWhiteSpace(this.Title)) 
            { 
                output.Attributes.Add("title", this.Title); 
            } 

            if (!string.IsNullOrWhiteSpace(this.Alt)) 
            { 
                output.Attributes.Add("alt", this.Alt); 
            } 
        } 

        return base.ProcessAsync(context, output); 
    }
}

First, this code has absolutely no error checking, you can add it as an exercise!

This class inherits from the TagHelper base class. It is declared as being triggered by an <inline-img> tag, and it requires a property Source to be passed and then checks to see if its relative to the virtual path (starts with ~/), in which case, it replaces it by the actual path. Otherwise, it considers it relative to the root folder.

There are a few properties that sometimes come in handy when dealing with images: Id, Style, Class, Width, Height, Alt and Title, all optional. Feel free to add others.

To use this, you need to register this tag helper, possibly on the _ViewImports.cshtml file:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, MyWebApplication

Just replace MyWebApplication by the full name of your assembly. After this, it’s just a matter of declaring an <inline-img> element on a Razor view:

<inline-img src="my.logo.png" />

And, presto, you will end up with something like this:

<img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEU…………." />

Hope you enjoy this trick! Winking smile

Published by

Ricardo Peres

Team Leader at Dixons Carphone. Microsoft MVP.

Leave a Reply

Your email address will not be published. Required fields are marked *