ASP.Net MVC: Como exibir uma imagem de matriz de bytes do modelo

115

Tenho um modelo com um arquivo de imagem de matriz de bytes que desejo mostrar na página.

Como posso fazer isso sem voltar ao banco de dados?

Todas as soluções que vejo usam um ActionResultpara voltar ao banco de dados para recuperar a imagem, mas já tenho a imagem no modelo ...

DK ALT
fonte
11
Por favor, pare de se referir a "ASP.NET MVC" simplesmente como "MVC". Um é uma estrutura, enquanto o outro é um padrão de design independente de linguagem. É como chamar o IE - "a internet"
tereško
MVC Como exibir uma imagem de matriz de bytes do modelo quando é nulo?
Chathz de

Respostas:

214

Algo assim pode funcionar ...

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

<img src="@imgSrc" />

Conforme mencionado nos comentários abaixo, use o acima com o conhecimento de que, embora isso possa responder à sua pergunta, pode não resolver o seu problema . Dependendo do seu problema, esta pode ser a solução, mas eu não descartaria completamente o acesso ao banco de dados duas vezes.

dav_i
fonte
6
Deve-se notar que isso irá incorporar a imagem no HTML e contornar várias técnicas de armazenamento de imagem padrão.
Quintin Robinson
@QuintinRobinson Embora reduza o número de solicitações:)
dav_i
8
@dav_i Reduza o número de solicitações iniciais . Ao otimizar o desempenho da web é extremamente importante entender a mecânica dos servidores, plataformas de conteúdo intermediárias e os clientes que estão solicitando e processando as informações. Não quero entrar em detalhes extraordinários em um comentário, mas quero enfatizar a necessidade de entender verdadeiramente as implicações do uso de tal técnica.
Quintin Robinson
1
A resposta pode estar correta para a pergunta, mas acho que o problema que estamos tentando resolver tem uma falha. Se o problema em questão é evitar duas chamadas para o banco de dados para obter dados e, em seguida, um segundo para obter a imagem, acho que uma solução muito melhor seria usar um manipulador do tipo que pode implementar o cache para reduzir a carga geral no servidor. Quando você está tentando descobrir por que seu aplicativo está sufocando porque você está tentando despejar um arquivo enorme usando a codificação Base64 para o fluxo de resposta da página, você desejará ter pensado mais sobre o quadro maior.
Nick Bork
2
Ótimo, adicionei um método em meu modelo para reutilizá-lo: public string GetBase64 () {var base64 = Convert.ToBase64String (ContentImage); return String.Format ("dados: imagem / gif; base64, {0}", base64); }
Rodrigo Longo
40

Isso funcionou para mim

<img src="data:image;base64,@System.Convert.ToBase64String(Model.CategoryPicture.Content)" width="80" height="80"/>     
NoloMokgosi
fonte
1
este funcionou para mim também, por favor diga como exibir uma imagem de matriz de bytes do modelo quando for nulo?
Chathz de
Olá Chathz, gostaria de sugerir que você valide o modelo no controlador antes de passar para a visualização. Se o modelo for nulo, passe uma imagem padrão
NoloMokgosi
26

Recomendo algo nesse sentido, mesmo que a imagem viva dentro do seu modelo.

Sei que você está pedindo uma maneira direta de acessar diretamente do modo de exibição e muitos outros responderam e disseram o que há de errado com essa abordagem, então esta é apenas outra maneira que carregará a imagem de forma assíncrona para você e eu acho que é uma abordagem melhor.

Modelo de amostra:

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

Método de amostra no controlador:

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

    byte[] photoBack = item.InternalImage;

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

Visão

@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
fonte
2
O que é "return File (...)"? File não é uma classe estática?
Ben Sewards
3
Deve ser um objeto FileContentResult ( msdn.microsoft.com/en-us/library/… )
Louie Bacaj
13

Uma maneira é adicionar isso a uma nova classe c # ou classe 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 + "' />");
    }
}

então você pode fazer isso em qualquer vista

@Html.Image(Model.ImgBytes)
Moji
fonte
Eu realmente gosto disso - torna-o limpo no modelo e também no arquivo .cshtml. ÓTIMO!!
Ken
10

Se você pode codificar seus bytes em base 64, pode tentar usar o resultado como sua fonte de imagem. Em seu modelo, você pode adicionar algo como:

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 na sua opinião:

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

Se a imagem não for tão grande, e se houver uma boa chance de você reutilizá-la com frequência, e se você não tiver muitas delas e se as imagens não forem secretas (o que significa que não é grande negócio se um usuário pudesse ver a imagem de outra pessoa) ...

Muitos "se" estão aqui, então há uma boa chance de que seja uma má ideia:

Você pode armazenar os bytes da imagem Cachepor um curto período de tempo e fazer uma tag de imagem apontada para um método de ação, que por sua vez lê do cache e expele sua imagem. Isso permitirá que o navegador armazene a imagem em cache de maneira adequada.

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

Isso tem o benefício adicional (ou é uma muleta?) De funcionar em navegadores mais antigos, onde as imagens embutidas não funcionam no IE7 (ou IE8 se maior que 32kB).

Joe Enos
fonte
3

Esta é uma versão modificada da resposta de Manoj que uso em um projeto. Acabei de atualizar para pegar uma classe, atributos html e usar o 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));
    }

Que pode ser usado da seguinte maneira:

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

Você precisa ter um byte [] em seu banco de dados.

Meu byte [] está em meu objeto Person:

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


Você precisa converter seu byte [] em uma String. Então, eu tenho em meu controlador:

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


Em seguida, em meu arquivo .cshtml, meu Model é um ViewModel. Isso é o que eu tenho em:

 public String Image { get; set; }


Eu o uso assim no meu arquivo .cshtml:

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

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

Eu desejo que ajude alguém!

Thorpe
fonte
1

Se você deseja apresentar a imagem, adicione um método como uma classe auxiliar ou ao próprio modelo e permita que o método converta a imagem da matriz de bytes em um formato de imagem como PNG ou JPG e então converta para a string Base64. Depois de ter isso, vincule o valor base64 em sua visualização no formato

"data: image / [extensão de tipo de arquivo de imagem] ; base64, [sua string base64 vai aqui] "

O acima é atribuído ao atributo imgda tag src.

O único problema que tenho com isso é a string base64 ser muito longa. Portanto, eu não o recomendaria para vários modelos sendo mostrados em uma visualização.

mitch
fonte
Você levanta um problema e declara um cenário de caso de uso que não recomenda, mas nenhuma solução para seu cenário de caso de uso. Isso teria tornado sua resposta muito mais agradável / útil e mais informativa.
Ken de
0

Criei um método auxiliar com base no asnwer abaixo e estou muito feliz que este auxiliar possa ajudar o máximo possível.

Com um modelo:

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

O ajudante é:

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

A visualização está recebendo um objeto: ICollection, então você precisa usá-lo na visualização em uma instrução foreach:

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