135

I've a model with a byte array image file that I want to show on the page.

How can I do that without going back to the Database?

All the solutions that I see use an ActionResult to go back to the database to retrieve the image, but I already have the image on the model...

Luis Teijon
  • 4,769
  • 7
  • 36
  • 57
DK ALT
  • 2,153
  • 4
  • 18
  • 17

10 Answers10

256

Something like this may work...

@{
    var base64 = Convert.ToBase64String(Model.ByteArray);
    var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
}

<img src="@imgSrc" />

As mentioned in the comments below, please use the above armed with the knowledge that although this may answer your question it may not solve your problem. Depending on your problem this may be the solution but I wouldn't completely rule out accessing the database twice.

dav_i
  • 27,509
  • 17
  • 104
  • 136
  • 7
    It should be noted this will embed the image in the HTML and will circumvent several standard image caching techniques. – Quintin Robinson Jul 30 '13 at 16:40
  • @QuintinRobinson Though reduce the number of requests `:)` – dav_i Jul 30 '13 at 16:42
  • 8
    @dav_i Reduce the number of *initial* requests. When optimizing the web performance it is incredibly important to understand the mechanics of the servers, intermediary content platforms and the clients that are requesting and processing the information. I don't want to go into extraordinary detail in a comment but I want to stress the need to truly understand the implications of using such a technique. – Quintin Robinson Jul 30 '13 at 16:44
  • 2
    The answer may be correct for the question but I think that the problem we're trying to solve has a flaw. If the problem at hand is preventing two calls to the database to get Data and then a second to get the image I think a far better solution would be to use a handler of sort that can implement caching to reduce the overall load on the server. When you're trying to figure out why your application is choking because you're trying to dump out a huge file using Base64 encoding to the page response stream you'll wish you had thought more about the bigger picture. – Nick Bork Jul 30 '13 at 20:02
  • @NickBork Updated with caveats stated here. – dav_i Jul 30 '13 at 20:20
  • @dav_i I didn't mean to imply that your answer was wrong at all. I wanted the OP to realize that just because this does solve his immediate question for "how-to" it may not be the best solution for his overall goal. – Nick Bork Jul 30 '13 at 20:24
  • 3
    Great, I added a method on my model in order to re use it :public string GetBase64() { var base64 = Convert.ToBase64String(ContentImage); return String.Format("data:image/gif;base64,{0}", base64); } – Rodrigo Longo Jul 13 '16 at 21:51
  • This helped me, as i was creating chats and it was saving as image. So i convert it to bytes and then follow the same. it Worked :) – Atta H. Jul 10 '17 at 07:28
  • And how to bind PDF data i.e. data:image/pdf for display PDF in MVC View ? – Vaibhav_Welcomes_You Oct 27 '21 at 10:41
54

This worked for me

<img src="data:image;base64,@System.Convert.ToBase64String(Model.CategoryPicture.Content)" width="80" height="80"/>     
Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
NoloMokgosi
  • 1,678
  • 16
  • 10
  • 1
    this one worked for me too , kindly say How to display a byte array image from model when its null ? – Chathz Feb 19 '16 at 10:15
  • 3
    Hi Chathz, I would suggest you validate the model in the controller before passing to the view. If model is null, pass a default picture – NoloMokgosi Feb 16 '20 at 14:17
28

I recommend something along these lines, even if the image lives inside of your model.

I realize you are asking for a direct way to access it right from the view and many others have answered that and told you what is wrong with that approach so this is just another way that will load the image in an async fashion for you and I think is a better approach.

Sample Model:

[Bind(Exclude = "ID")]
public class Item
{
    [Key]
    [ScaffoldColumn(false)]
    public int ID { get; set; }

    public String Name { get; set; }

    public byte[] InternalImage { get; set; } //Stored as byte array in the database.
}

Sample Method in the Controller:

public async Task<ActionResult> RenderImage(int id)
{
    Item item = await db.Items.FindAsync(id);

    byte[] photoBack = item.InternalImage;

    return File(photoBack, "image/png");
}

View

@model YourNameSpace.Models.Item

@{
    ViewBag.Title = "Details";
}

<h2>Details</h2>

<div>
<h4>Item</h4>
<hr />
<dl class="dl-horizontal">
    <img src="@Url.Action("RenderImage", new { id = Model.ID})" />
</dl>
<dl class="dl-horizontal">
    <dt>
        @Html.DisplayNameFor(model => model.Name)
    </dt>

    <dd>
        @Html.DisplayFor(model => model.Name)
    </dd>
</dl>
</div>
iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
Louie Bacaj
  • 1,417
  • 13
  • 18
14

One way is to add this to a new c# class or HtmlExtensions class

public static class HtmlExtensions
{
    public static MvcHtmlString Image(this HtmlHelper html, byte[] image)
    {
        var img = String.Format("data:image/jpg;base64,{0}", Convert.ToBase64String(image));
        return new MvcHtmlString("<img src='" + img + "' />");
    }
}

then you can do this in any view

@Html.Image(Model.ImgBytes)
Moji
  • 5,720
  • 2
  • 38
  • 39
  • I really like this the best - makes it clean in the Model and also in the .cshtml file . GREAT!! – Ken Jul 16 '19 at 05:30
10

If you can base-64 encode your bytes, you could try using the result as your image source. In your model you might add something like:

public string ImageSource
{
    get
    {
        string mimeType = /* Get mime type somehow (e.g. "image/png") */;
        string base64 = Convert.ToBase64String(yourImageBytes);
        return string.Format("data:{0};base64,{1}", mimeType, base64);
    }
}

And in your view:

<img ... src="@Model.ImageSource" />
Cᴏʀʏ
  • 105,112
  • 20
  • 162
  • 194
6

You need to have a byte[] in your DB.

My byte[] is in my Person object:

public class Person
{
    public byte[] Image { get; set; }
}


You need to convert your byte[] in a String. So, I have in my controller :

String img = Convert.ToBase64String(person.Image);


Next, in my .cshtml file, my Model is a ViewModel. This is what I have in :

 public String Image { get; set; }


I use it like this in my .cshtml file:

<img src="@String.Format("data:image/jpg;base64,{0}", Model.Image)" />

"data:image/image file extension;base64,{0}, your image String"

I wish it will help someone !

Thorpe
  • 61
  • 1
  • 2
5

If the image isn't that big, and if there's a good chance you'll be re-using the image often, and if you don't have too many of them, and if the images are not secret (meaning it's no big deal if one user could potentially see another person's image)...

Lots of "if"s here, so there's a good chance this is a bad idea:

You can store the image bytes in Cache for a short time, and make an image tag pointed toward an action method, which in turn reads from the cache and spits out your image. This will allow the browser to cache the image appropriately.

// In your original controller action
HttpContext.Cache.Add("image-" + model.Id, model.ImageBytes, null,
    Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1),
    CacheItemPriority.Normal, null);

// In your view:
<img src="@Url.Action("GetImage", "MyControllerName", new{fooId = Model.Id})">

// In your controller:
[OutputCache(VaryByParam = "fooId", Duration = 60)]
public ActionResult GetImage(int fooId) {
    // Make sure you check for null as appropriate, re-pull from DB, etc.
    return File((byte[])HttpContext.Cache["image-" + fooId], "image/gif");
}

This has the added benefit (or is it a crutch?) of working in older browsers, where the inline images don't work in IE7 (or IE8 if larger than 32kB).

Joe Enos
  • 39,478
  • 11
  • 80
  • 136
3

This is an modified version of Manoj's answer that I use on a project. Just updated to take a class, html attributes and use the TagBuilder.

    public static IHtmlString Image(this HtmlHelper helper, byte[] image, string imgclass, 
                                     object htmlAttributes = null)
    {
        var builder = new TagBuilder("img");
        builder.MergeAttribute("class", imgclass);
        builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));

        var imageString = image != null ? Convert.ToBase64String(image) : "";
        var img = string.Format("data:image/jpg;base64,{0}", imageString);
        builder.MergeAttribute("src", img);

        return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing));
    }

Which can be used then as follows:

    @Html.Image(Model.Image, "img-cls", new { width="200", height="200" })
AlexH
  • 115
  • 13
1

If you want to present the image, add a method as a helper class or to the model itself and allow the method to convert the byte array image to a image format like PNG or JPG then convert to Base64 string. Once you have that, bind the base64 value on your view in the format

"data:image/[image file type extension];base64,[your base64 string goes here]"

The above is assigned to the img tag's src attribute.

The only issue I have with this is the base64 string being too long. So, I would not recommend it for multiple models being shown in a view.

mitch
  • 1,821
  • 14
  • 14
  • You bring up an issue, and state a use case scenario recommending not , but no solution to your use case scenario. That would have made your answer much nicer / useful and more informative. – Ken Aug 20 '19 at 16:42
0

I've created a helper method based in the asnwer below and I'm pretty glad that this helper can help as many as possible.

With a model:

 public class Images
 {
    [Key]
    public int ImagesId { get; set; }
    [DisplayName("Image")]
    public Byte[] Pic1 { get; set; }
  }

The helper is:

public static IHtmlString GetBytes<TModel, TValue>(this HtmlHelper<TModel> helper, System.Linq.Expressions.Expression<Func<TModel, TValue>> expression, byte[] array, string Id)
    {
        TagBuilder tb = new TagBuilder("img");
        tb.MergeAttribute("id", Id);
        var base64 = Convert.ToBase64String(array);
        var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
        tb.MergeAttribute("src", imgSrc);
        return MvcHtmlString.Create(tb.ToString(TagRenderMode.SelfClosing));
    }

The view is receiving a: ICollection object so you need to used it in the view in a foreach statement:

 @foreach (var item in Model)
  @Html.GetBytes(itemP1 => item.Pic1, item.Graphics, "Idtag")
}
Jose Ortega
  • 1,002
  • 13
  • 23