ASP.Net MVC: Jak wyświetlić obraz tablicy bajtów z modelu

115

Mam model z plikiem obrazu tablicy bajtów, który chcę pokazać na stronie.

Jak mogę to zrobić bez wracania do bazy danych?

Wszystkie rozwiązania, które widzę, używają ActionResultdo powrotu do bazy danych w celu pobrania obrazu, ale mam już obraz na modelu ...

DK ALT
źródło
11
Przestań nazywać „ASP.NET MVC” po prostu „MVC”. Jeden to framework, a drugi to wzorzec projektowy niezależny od języka. To tak, jakby dzwonić do IE - „internetu”
tereško
MVC Jak wyświetlić obraz tablicy bajtów z modelu, gdy jest on pusty?
Chathz,

Odpowiedzi:

214

Coś takiego może działać ...

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

<img src="@imgSrc" />

Jak wspomniano w komentarzach poniżej, korzystaj z powyższych, mając świadomość, że chociaż może to odpowiedzieć na twoje pytanie, może nie rozwiązać twojego problemu . W zależności od problemu może to być rozwiązanie, ale nie wykluczałbym całkowicie dwukrotnego dostępu do bazy danych.

dav_i
źródło
6
Należy zauważyć, że spowoduje to osadzenie obrazu w kodzie HTML i obejdzie kilka standardowych technik buforowania obrazu.
Quintin Robinson
@QuintinRobinson Chociaż zmniejsz liczbę żądań:)
dav_i
8
@dav_i Zmniejsz liczbę początkowych żądań. Optymalizując wydajność sieci, niezwykle ważne jest zrozumienie mechanizmów działania serwerów, pośredniczących platform treści i klientów żądających informacji i przetwarzających je. Nie chcę wdawać się w nadzwyczajne szczegóły w komentarzu, ale chcę podkreślić potrzebę prawdziwego zrozumienia implikacji stosowania takiej techniki.
Quintin Robinson
1
Odpowiedź może być poprawna na pytanie, ale myślę, że problem, który próbujemy rozwiązać, ma wadę. Jeśli problemem jest uniemożliwienie dwóch wywołań bazy danych w celu pobrania danych, a następnie sekundy w celu uzyskania obrazu, myślę, że znacznie lepszym rozwiązaniem byłoby użycie rodzaju obsługi, która może implementować buforowanie, aby zmniejszyć ogólne obciążenie serwera. Kiedy próbujesz dowiedzieć się, dlaczego Twoja aplikacja się dławi, ponieważ próbujesz zrzucić ogromny plik przy użyciu kodowania Base64 do strumienia odpowiedzi strony, żałujesz, że nie pomyślałeś więcej o szerszym obrazie.
Nick Bork,
2
Świetnie, dodałem metodę do mojego modelu, aby użyć go ponownie: public string GetBase64 () {var base64 = Convert.ToBase64String (ContentImage); return String.Format ("dane: obraz / gif; base64, {0}", base64); }
Rodrigo Longo
40

To zadziałało dla mnie

<img src="data:image;base64,@System.Convert.ToBase64String(Model.CategoryPicture.Content)" width="80" height="80"/>     
NoloMokgosi
źródło
1
ten też działał dla mnie, uprzejmie powiedz Jak wyświetlić obraz tablicy bajtów z modelu, gdy jest on pusty?
Chathz,
Cześć Chathz, sugerowałbym sprawdzenie modelu w kontrolerze przed przejściem do widoku. Jeśli model jest zerowy,
podaj
26

Polecam coś w tym kierunku, nawet jeśli obraz znajduje się wewnątrz twojego modelu.

Zdaję sobie sprawę, że prosisz o bezpośredni dostęp do niego bezpośrednio z widoku, a wielu innych odpowiedziało na to i powiedziało ci, co jest nie tak w tym podejściu, więc jest to tylko kolejny sposób, który załaduje obraz w sposób asynchroniczny dla ciebie i dla mnie myślę, że jest lepszym podejściem.

Przykładowy 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.
}

Przykładowa metoda w kontrolerze:

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

    byte[] photoBack = item.InternalImage;

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

Widok

@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
źródło
2
Co to jest „Return File (...)”? Czy File nie jest klasą statyczną?
Ben Sewards
3
Powinien to być obiekt FileContentResult ( msdn.microsoft.com/en-us/library/… )
Louie Bacaj
13

Jednym ze sposobów jest dodanie tego do nowej klasy C # lub klasy 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 + "' />");
    }
}

możesz to zrobić w dowolnym widoku

@Html.Image(Model.ImgBytes)
Moji
źródło
Bardzo mi się to podoba - czyści w Modelu, a także w pliku .cshtml. ŚWIETNY!!
Ken,
10

Jeśli możesz zakodować bajty base-64, możesz spróbować użyć wyniku jako źródła obrazu. W swoim modelu możesz dodać coś takiego:

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

Twoim zdaniem:

<img ... src="@Model.ImageSource" />
Cᴏʀʏ
źródło
5

Jeśli obraz nie jest tak duży i istnieje duża szansa, że ​​będziesz go często używać ponownie i jeśli nie masz ich zbyt wiele i jeśli obrazy nie są tajne (co oznacza, że ​​nie są duże transakcję, gdyby jeden użytkownik mógł potencjalnie zobaczyć obraz innej osoby) ...

Jest tu dużo „jeśli”, więc istnieje duża szansa, że ​​to zły pomysł:

Możesz przechowywać bajty obrazu Cacheprzez krótki czas i utworzyć tag obrazu wskazujący na metodę akcji, która z kolei odczytuje z pamięci podręcznej i wypluwa obraz. Umożliwi to przeglądarce odpowiednie buforowanie obrazu.

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

Ma to dodatkową zaletę (a może jest to kula?) W przypadku pracy w starszych przeglądarkach, w których obrazy wbudowane nie działają w IE7 (lub IE8, jeśli są większe niż 32 kB).

Joe Enos
źródło
3

To jest zmodyfikowana wersja odpowiedzi Manoj, której używam w projekcie. Właśnie zaktualizowano, aby wziąć klasę, atrybuty html i użyć 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));
    }

Które można następnie wykorzystać w następujący sposób:

    @Html.Image(Model.Image, "img-cls", new { width="200", height="200" })
AlexH
źródło
3

Musisz mieć bajt [] w swojej bazie danych.

Mój bajt [] znajduje się w moim obiekcie Person:

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


Musisz przekonwertować swój bajt [] na łańcuch. Mam więc w swoim kontrolerze:

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


Następnie w moim pliku .cshtml mój Model to ViewModel. Oto, co mam w:

 public String Image { get; set; }


Używam go w ten sposób w moim pliku .cshtml:

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

„data: rozszerzenie pliku obrazu / obrazu ; base64, {0}, ciąg Twojego obrazu

Chciałbym, żeby to komuś pomogło!

Thorpe
źródło
1

Jeśli chcesz zaprezentować obraz, dodaj metodę jako klasę pomocniczą lub do samego modelu i pozwól metodzie przekonwertować obraz tablicy bajtów na format obrazu, taki jak PNG lub JPG, a następnie przekonwertuj na ciąg Base64. Gdy to zrobisz, powiąż wartość base64 w swoim widoku w formacie

„data: image / [rozszerzenie typu pliku obrazu] ; base64, [tutaj znajduje się ciąg base64]

Powyższe jest przypisane do atrybutu imgtagu src.

Jedynym problemem, jaki mam z tym, jest to, że ciąg base64 jest zbyt długi. Dlatego nie polecałbym tego w przypadku wielu modeli wyświetlanych w widoku.

mitch
źródło
Poruszasz problem i podajesz scenariusz przypadku użycia, który nie zaleca, ale nie ma rozwiązania scenariusza przypadku użycia. Dzięki temu twoja odpowiedź byłaby dużo przyjemniejsza / użyteczna i zawierałaby więcej informacji.
Ken
0

Stworzyłem metodę pomocniczą opartą na odpowiedzi poniżej i cieszę się, że ten pomocnik może pomóc jak największej liczbie osób.

Z modelem:

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

Pomocnikiem jest:

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

Widok otrzymuje obiekt: ICollection, więc musisz go użyć w widoku w instrukcji foreach:

 @foreach (var item in Model)
  @Html.GetBytes(itemP1 => item.Pic1, item.Graphics, "Idtag")
}
Jose Ortega
źródło