web-dev-qa-db-fra.com

MVC Comment afficher une image de tableau d'octets à partir d'un modèle

J'ai un modèle avec un fichier image de tableau d'octets que je veux montrer sur la page.

Comment puis-je faire cela sans retourner à la base de données?

Toutes les solutions que je vois utilisent un ActionResult pour revenir à la base de données afin de récupérer l'image, mais j'ai déjà l'image sur le modèle ...

98
DK ALT

Quelque chose comme ça peut marcher ...

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

<img src="@imgSrc" />

Comme mentionné dans les commentaires ci-dessous, veuillez utiliser ce qui précède, armé de la connaissance que bien que cela puisse répondre à votre question, il se peut qu'il ne résolve pas votre problème. En fonction de votre problème, cela peut être la solution, mais je ne voudrais pas exclure complètement l'accès à la base de données deux fois.

188
dav_i

Cela a fonctionné pour moi

<img src="data:image;base64,@System.Convert.ToBase64String(Model.CategoryPicture.Content)" width="80" height="80"/>     
34
NoloMokgosi

Je recommande quelque chose dans ce sens, même si l’image habite à l’intérieur de votre modèle.

Je me rends compte que vous demandez un moyen direct d'y accéder directement depuis la vue. Beaucoup d'autres ont répondu à cette question et vous ont dit ce qui ne va pas dans cette approche. C'est donc une autre façon de charger le l'image de manière asynchrone pour vous et je pense que c'est une meilleure approche.

Exemple de modèle:

[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.
}

Exemple de méthode dans le contrôleur:

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

    byte[] photoBack = item.InternalImage;

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

Voir

@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>
26
Louie Bacaj

Une solution consiste à ajouter ceci à une nouvelle classe c # ou HtmlExtensions.

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 + "' />");
    }
}

alors vous pouvez le faire dans n'importe quelle vue

@Html.Image(Model.ImgBytes)
12
Moji

Si vous pouvez coder vos octets en base 64, vous pouvez utiliser le résultat comme source d’image. Dans votre modèle, vous pouvez ajouter quelque chose comme:

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);
    }
}

Et à votre avis:

<img ... src="@Model.ImageSource" />
9
Cᴏʀʏ

Si l'image n'est pas si grande et s'il y a de bonnes chances que vous utilisiez souvent l'image de nouveau, et si vous n'en avez pas beaucoup, et si les images ne sont pas secrètes (ce qui signifie que ce n'est pas grave). traiter si un utilisateur peut potentiellement voir l’image d’une autre personne) ...

Il y a beaucoup de "si" ici, donc il y a de bonnes chances que ce soit une mauvaise idée:

Vous pouvez stocker les octets de l'image dans Cache pendant un court instant et faire en sorte qu'une balise d'image soit dirigée vers une méthode d'action, qui lit à son tour dans le cache et recrache votre image. Cela permettra au navigateur de mettre l’image en cache de manière appropriée.

// 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");
}

Cela présente l'avantage supplémentaire (ou est-ce une béquille?) De fonctionner dans des navigateurs plus anciens, où les images en ligne ne fonctionnent pas dans IE7 (ou IE8 si elles sont supérieures à 32 Ko).

5
Joe Enos

Ceci est une version modifiée de la réponse de Manoj que j'utilise dans un projet. Juste mis à jour pour prendre une classe, les attributs HTML et utiliser le 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));
    }

Ce qui peut être utilisé ensuite comme suit:

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

Vous devez avoir un octet [] dans votre base de données.

Mon octet [] est dans mon objet Personne:

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


Vous devez convertir votre octet [] en chaîne. Donc, j'ai dans mon contrôleur:

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


Ensuite, dans mon fichier .cshtml, mon modèle est un ViewModel. C'est ce que j'ai dans:

 public String Image { get; set; }


Je l'utilise comme ceci dans mon fichier .cshtml:

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

"data: image/extension du fichier image; base64, {0}, votre chaîne d'image"

J'espère que ça va aider quelqu'un!

2
Thorpe

Si vous souhaitez présenter l'image, ajoutez une méthode en tant que classe d'assistance ou au modèle lui-même et laissez-la convertir le tableau d'octets en un format d'image tel que PNG ou JPG, puis le convertir en chaîne Base64. Une fois que vous avez cela, liez la valeur base64 de votre vue au format

"data: image/[extension du type de fichier image]; base64, [votre chaîne base64 va ici]"

Ce qui précède est attribué à l'attribut img de la balise src.

Le seul problème que j'ai avec ceci est que la chaîne base64 est trop longue. Donc, je ne le recommanderais pas pour plusieurs modèles affichés dans une vue.

1
mitch

J'ai créé une méthode d'assistance basée sur la réponse ci-dessous et je suis plutôt heureux que cette aide puisse aider le plus grand nombre possible.

Avec un modèle:

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

L'assistant est:

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));
    }

La vue reçoit un objet: ICollection. Vous devez donc l'utiliser dans la vue dans une instruction foreach:

 @foreach (var item in Model)
  @Html.GetBytes(itemP1 => item.Pic1, item.Graphics, "Idtag")
}
0
Jose Ortega