ASP.Net MVC: So zeigen Sie ein Byte-Array-Bild aus dem Modell an

115

Ich habe ein Modell mit einer Byte-Array-Bilddatei, die ich auf der Seite anzeigen möchte.

Wie kann ich das tun, ohne zur Datenbank zurückzukehren?

Alle Lösungen, die ich sehe, verwenden ein ActionResult, um zur Datenbank zurückzukehren und das Bild abzurufen, aber ich habe das Bild bereits auf dem Modell ...

DK ALT
quelle
11
Bitte hören Sie auf, "ASP.NET MVC" einfach als "MVC" zu bezeichnen. Eines ist ein Framework, während das andere ein sprachunabhängiges Entwurfsmuster ist. Es ist, als würde man IE - "das Internet"
tereško
MVC Wie wird ein Byte-Array-Bild aus dem Modell angezeigt, wenn es null ist?
Chathz

Antworten:

214

So etwas könnte funktionieren ...

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

<img src="@imgSrc" />

Wie in den Kommentaren unten erwähnt, verwenden Sie bitte die oben genannten Informationen mit dem Wissen, dass dies zwar Ihre Frage beantworten kann, Ihr Problem jedoch möglicherweise nicht löst . Abhängig von Ihrem Problem kann dies die Lösung sein, aber ich würde nicht ausschließen, zweimal auf die Datenbank zuzugreifen.

dav_i
quelle
6
Es sollte beachtet werden, dass dies das Bild in den HTML-Code einbettet und mehrere Standard-Bild-Caching-Techniken umgeht.
Quintin Robinson
@QuintinRobinson Reduzieren Sie jedoch die Anzahl der Anfragen :)
dav_i
8
@dav_i Reduzieren der Anzahl von anfänglichen Anfragen. Bei der Optimierung der Webleistung ist es unglaublich wichtig, die Mechanismen der Server, zwischengeschalteten Inhaltsplattformen und der Clients zu verstehen, die die Informationen anfordern und verarbeiten. Ich möchte in einem Kommentar nicht auf außergewöhnliche Details eingehen, aber ich möchte die Notwendigkeit betonen, die Auswirkungen der Verwendung einer solchen Technik wirklich zu verstehen.
Quintin Robinson
1
Die Antwort mag für die Frage richtig sein, aber ich denke, dass das Problem, das wir zu lösen versuchen, einen Fehler aufweist. Wenn das vorliegende Problem darin besteht, zwei Aufrufe der Datenbank zu verhindern, um Daten abzurufen, und dann einen zweiten, um das Image abzurufen, wäre meiner Meinung nach eine weitaus bessere Lösung die Verwendung eines Handlers, der das Caching implementieren kann, um die Gesamtlast auf dem Server zu verringern. Wenn Sie herausfinden möchten, warum Ihre Anwendung erstickt, weil Sie versuchen, eine große Datei mit Base64-Codierung in den Seitenantwort-Stream zu kopieren, hätten Sie gerne mehr über das Gesamtbild nachgedacht.
Nick Bork
2
Großartig, ich habe meinem Modell eine Methode hinzugefügt, um es wiederzuverwenden: public string GetBase64 () {var base64 = Convert.ToBase64String (ContentImage); return String.Format ("data: image / gif; base64, {0}", base64); }
Rodrigo Longo
40

Das hat bei mir funktioniert

<img src="data:image;base64,@System.Convert.ToBase64String(Model.CategoryPicture.Content)" width="80" height="80"/>     
NoloMokgosi
quelle
1
Dieser hat auch für mich funktioniert. Sagen Sie bitte, wie ein Byte-Array-Bild aus dem Modell angezeigt wird, wenn es null ist.
Chathz
Hallo Chathz, ich würde vorschlagen, dass Sie das Modell im Controller validieren, bevor Sie zur Ansicht übergehen. Wenn das Modell null ist, übergeben Sie ein Standardbild
NoloMokgosi
26

Ich empfehle etwas in diese Richtung, auch wenn das Bild in Ihrem Modell lebt.

Mir ist klar, dass Sie nach einem direkten Weg fragen, um direkt aus der Ansicht darauf zuzugreifen, und viele andere haben darauf geantwortet und Ihnen gesagt, was an diesem Ansatz falsch ist. Dies ist also nur ein weiterer Weg, der das Bild für Sie und mich asynchron lädt denke ist ein besserer Ansatz.

Beispielmodell:

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

Beispielmethode im Controller:

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

    byte[] photoBack = item.InternalImage;

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

Aussicht

@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>
Louie Bacaj
quelle
2
Was ist "Datei zurückgeben (...)"? Ist File nicht eine statische Klasse?
Ben Sewards
3
Es sollte ein FileContentResult-Objekt sein ( msdn.microsoft.com/en-us/library/… )
Louie Bacaj
13

Eine Möglichkeit besteht darin, dies einer neuen c # -Klasse oder HtmlExtensions-Klasse hinzuzufügen

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

dann können Sie dies in jeder Ansicht tun

@Html.Image(Model.ImgBytes)
Moji
quelle
Ich mag das wirklich am besten - macht es sauber im Modell und auch in der .cshtml-Datei. GROSSARTIG!!
Ken
10

Wenn Sie Ihre Bytes mit Base-64 codieren können, können Sie versuchen, das Ergebnis als Bildquelle zu verwenden. In Ihrem Modell können Sie Folgendes hinzufügen:

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

Und aus Ihrer Sicht:

<img ... src="@Model.ImageSource" />
Cᴏʀᴏʀ
quelle
5

Wenn das Bild nicht so groß ist und eine gute Chance besteht, werden Sie das Bild häufig wiederverwenden, wenn Sie nicht zu viele davon haben und wenn die Bilder nicht geheim sind (was bedeutet, dass es nicht groß ist) Deal, wenn ein Benutzer möglicherweise das Bild einer anderen Person sehen könnte) ...

Viele "Wenn" sind hier, also besteht eine gute Chance, dass dies eine schlechte Idee ist:

Sie können die Bildbytes Cachefür kurze Zeit speichern und ein Bild-Tag erstellen, das auf eine Aktionsmethode verweist, die wiederum aus dem Cache liest und Ihr Bild ausspuckt. Dadurch kann der Browser das Bild entsprechend zwischenspeichern.

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

Dies hat den zusätzlichen Vorteil (oder ist es eine Krücke?), In älteren Browsern zu arbeiten, in denen die Inline-Bilder in IE7 (oder IE8, wenn sie größer als 32 KB sind) nicht funktionieren.

Joe Enos
quelle
3

Dies ist eine modifizierte Version von Manojs Antwort, die ich für ein Projekt verwende. Gerade aktualisiert, um eine Klasse, HTML-Attribute und den TagBuilder zu verwenden.

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

Welches kann dann wie folgt verwendet werden:

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

Sie müssen ein Byte [] in Ihrer Datenbank haben.

Mein Byte [] befindet sich in meinem Personenobjekt:

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


Sie müssen Ihr Byte [] in einen String konvertieren. Also habe ich in meinem Controller:

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


Als nächstes ist mein Modell in meiner CSHTML-Datei ein ViewModel. Das habe ich in:

 public String Image { get; set; }


Ich benutze es so in meiner .cshtml-Datei:

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

"Daten: Bild / Bilddateierweiterung ; base64, {0}, Ihre Bildzeichenfolge "

Ich wünschte, es würde jemandem helfen!

Thorpe
quelle
1

Wenn Sie das Bild präsentieren möchten, fügen Sie eine Methode als Hilfsklasse oder zum Modell selbst hinzu und lassen Sie die Methode das Byte-Array-Bild in ein Bildformat wie PNG oder JPG konvertieren und dann in eine Base64-Zeichenfolge konvertieren. Sobald Sie das haben, binden Sie den base64-Wert in Ihrer Ansicht im Format

"data: image / [Erweiterung des Bilddateityps] ; base64, [Ihre base64-Zeichenfolge wird hier angezeigt] "

Das Obige ist dem Attribut des imgTags zugeordnet src.

Das einzige Problem, das ich damit habe, ist, dass die base64-Zeichenfolge zu lang ist. Daher würde ich es nicht empfehlen, wenn mehrere Modelle in einer Ansicht angezeigt werden.

Mitchell
quelle
Sie sprechen ein Problem an und geben ein Anwendungsfallszenario an, in dem keine, aber keine Lösung für Ihr Anwendungsfallszenario empfohlen wird. Das hätte Ihre Antwort viel schöner / nützlicher und informativer gemacht.
Ken
0

Ich habe eine Hilfsmethode erstellt, die auf der folgenden Antwort basiert, und ich bin ziemlich froh, dass dieser Helfer so vielen wie möglich helfen kann.

Mit einem Modell:

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

Der Helfer ist:

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

Die Ansicht empfängt ein: ICollection-Objekt, sodass Sie es in der Ansicht in einer foreach-Anweisung verwenden müssen:

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