ASP.Net MVC: come visualizzare un'immagine di matrice di byte dal modello


115

Ho un modello con un file immagine di matrice di byte che voglio mostrare sulla pagina.

Come posso farlo senza tornare al database?

Tutte le soluzioni che vedo usano una ActionResultper tornare al database per recuperare l'immagine, ma ho già l'immagine sul modello ...


11
Per favore, smettila di fare riferimento a "ASP.NET MVC" semplicemente come "MVC". Uno è un framework, mentre l'altro è un modello di progettazione indipendente dalla lingua. È come chiamare IE - "Internet"
tereško

MVC Come visualizzare un'immagine di array di byte dal modello quando è nullo?
Chathz

Risposte:


214

Qualcosa del genere potrebbe funzionare ...

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

<img src="@imgSrc" />

Come accennato nei commenti qui sotto, ti preghiamo di utilizzare quanto sopra armato della consapevolezza che sebbene questo possa rispondere alla tua domanda, potrebbe non risolvere il tuo problema . A seconda del problema, questa potrebbe essere la soluzione, ma non escluderei completamente l'accesso due volte al database.


6
Va notato che questo incorporerà l'immagine nell'HTML e aggirerà diverse tecniche di memorizzazione nella cache delle immagini standard.
Quintin Robinson

@QuintinRobinson Anche se ridurre il numero di richieste:)
dav_i

8
@dav_i Riduci il numero di richieste iniziali . Quando si ottimizzano le prestazioni web è incredibilmente importante comprendere i meccanismi dei server, delle piattaforme di contenuto intermedie e dei client che richiedono ed elaborano le informazioni. Non voglio entrare in dettagli straordinari in un commento, ma voglio sottolineare la necessità di comprendere veramente le implicazioni dell'utilizzo di una tale tecnica.
Quintin Robinson

1
La risposta potrebbe essere corretta per la domanda, ma penso che il problema che stiamo cercando di risolvere abbia un difetto. Se il problema in questione è impedire due chiamate al database per ottenere i dati e poi un secondo per ottenere l'immagine, penso che una soluzione di gran lunga migliore sarebbe quella di utilizzare un gestore di ordinamento in grado di implementare la memorizzazione nella cache per ridurre il carico complessivo sul server. Quando stai cercando di capire perché la tua applicazione sta soffocando perché stai cercando di scaricare un file enorme usando la codifica Base64 nel flusso di risposta della pagina, vorresti aver pensato di più al quadro più grande.
Nick Bork

2
Ottimo, ho aggiunto un metodo sul mio modello per riutilizzarlo: public string GetBase64 () {var base64 = Convert.ToBase64String (ContentImage); return String.Format ("data: image / gif; base64, {0}", base64); }
Rodrigo Longo

40

Questo ha funzionato per me

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

1
questo ha funzionato anche per me, gentilmente dire Come visualizzare un'immagine di array di byte dal modello quando è nullo?
Chathz

Ciao Chathz, ti suggerirei di validare il modello nel controller prima di passare alla visualizzazione. Se il modello è nullo, passare un'immagine predefinita
NoloMokgosi

26

Consiglio qualcosa in questo senso, anche se l'immagine vive all'interno del tuo modello.

Mi rendo conto che stai chiedendo un modo diretto per accedervi direttamente dalla vista e molti altri hanno risposto e ti hanno detto cosa c'è di sbagliato in quell'approccio, quindi questo è solo un altro modo che caricherà l'immagine in modo asincrono per te e me pensare è un approccio migliore.

Modello campione:

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

Metodo di esempio nel controller:

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

    byte[] photoBack = item.InternalImage;

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

Visualizza

@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>

2
Che cos'è "file di ritorno (...)"? File non è una classe statica?
Ben Sewards

3
Dovrebbe essere un oggetto FileContentResult ( msdn.microsoft.com/en-us/library/… )
Louie Bacaj

13

Un modo è aggiungerlo a una nuova classe c # o 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 + "' />");
    }
}

quindi puoi farlo in qualsiasi vista

@Html.Image(Model.ImgBytes)

Mi piace davvero di più: lo rende pulito nel modello e anche nel file .cshtml. GRANDE!!
Ken il

10

Se puoi codificare in base 64 i tuoi byte, potresti provare a utilizzare il risultato come sorgente dell'immagine. Nel tuo modello potresti aggiungere qualcosa come:

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

E secondo te:

<img ... src="@Model.ImageSource" />

5

Se l'immagine non è così grande e se ci sono buone possibilità che la riutilizzerai spesso, se non ne hai troppe e se le immagini non sono segrete (il che significa che non è grande trattare se un utente potrebbe potenzialmente vedere l'immagine di un'altra persona) ...

Molti "se" sono qui, quindi ci sono buone probabilità che questa sia una cattiva idea:

È possibile memorizzare i byte dell'immagine Cacheper un breve periodo e creare un tag immagine puntato verso un metodo di azione, che a sua volta legge dalla cache e sputa l'immagine. Ciò consentirà al browser di memorizzare nella cache l'immagine in modo appropriato.

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

Questo ha il vantaggio aggiuntivo (o è una stampella?) Di lavorare con browser meno recenti, dove le immagini in linea non funzionano in IE7 (o IE8 se più grandi di 32kB).


3

Questa è una versione modificata della risposta di Manoj che uso su un progetto. Appena aggiornato per prendere una classe, attributi html e utilizzare 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));
    }

Che può essere utilizzato quindi come segue:

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

3

Devi avere un byte [] nel tuo DB.

Il mio byte [] è nel mio oggetto Person:

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


Devi convertire il tuo byte [] in una stringa. Quindi, ho nel mio controller:

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


Successivamente, nel mio file .cshtml, il mio modello è un ViewModel. Questo è quello che ho in:

 public String Image { get; set; }


Lo uso in questo modo nel mio file .cshtml:

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

"dati: estensione file immagine / immagine ; base64, {0}, stringa immagine "

Vorrei che aiutasse qualcuno!


1

Se vuoi presentare l'immagine, aggiungi un metodo come classe helper o al modello stesso e consenti al metodo di convertire l'immagine della matrice di byte in un formato immagine come PNG o JPG, quindi converti in stringa Base64. Una volta ottenuto ciò, associa il valore base64 alla visualizzazione nel formato

"data: image / [estensione del tipo di file immagine] ; base64, [la tua stringa base64 va qui] "

Quanto sopra è assegnato all'attributo imgdel tag src.

L'unico problema che ho con questo è che la stringa base64 è troppo lunga. Quindi, non lo consiglierei per più modelli visualizzati in una vista.


Si solleva un problema e si dichiara uno scenario di caso d'uso che consiglia di non farlo, ma nessuna soluzione allo scenario del caso d'uso. Ciò avrebbe reso la tua risposta molto più carina / utile e più istruttiva.
Ken

0

Ho creato un metodo di supporto basato nella risposta di seguito e sono abbastanza contento che questo aiuto possa aiutare il maggior numero possibile.

Con un modello:

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

L'aiutante è:

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 vista sta ricevendo un oggetto: ICollection quindi è necessario utilizzarlo nella vista in un'istruzione foreach:

 @foreach (var item in Model)
  @Html.GetBytes(itemP1 => item.Pic1, item.Graphics, "Idtag")
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.