Usando WebClient para obter imagens remotas Produz Granulado GIFs e não pode segurar PNG + BMP

StackOverflow https://stackoverflow.com/questions/499210

  •  20-08-2019
  •  | 
  •  

Pergunta

Saudações!

Estou criando um protótipo de formulário web (ImageLaoder.aspx) que irá retornar uma imagem para que ele possa ser usado como este simples exemplo de outros Web Forms / páginas web:

<img src="http://www.mydomain.com/ImageLoader.aspx?i=http://images.mydomain.com/img/a.jpg" />

Até agora, ele carrega JPGs sem problemas, no entanto GIFs olhar "granulada" em comparação com os orignals e BMPs e PNGs resultar na seguinte exceção:

System.Runtime.InteropServices.ExternalException: Ocorreu um erro genérico em GDI +

O meu código até agora se parece com isso:

protected void Page_Load(object sender, EventArgs e)
{
    string l_filePath = Request.QueryString["i"];

    System.Drawing.Image l_image = GetImage(l_filePath);
    if (l_image != null)
    {
        System.Drawing.Imaging.ImageFormat l_imageFormat = DetermineImageFormat(l_filePath);
        WriteImageAsReponse(l_image, l_imageFormat);
    }
}

private System.Drawing.Image GetImage(string filePath)
{
    WebClient l_WebClient = new WebClient();
    byte[] l_imageBytes = l_WebClient.DownloadData(filePath);

    System.Drawing.Image l_image = null;
    using (MemoryStream l_MemStream = new MemoryStream(l_imageBytes, 0, l_imageBytes.Length))
    {
        l_MemStream.Write(l_imageBytes, 0, l_imageBytes.Length);
        l_image = System.Drawing.Image.FromStream(l_MemStream, true);
        l_MemStream.Close();
    }

    return l_image;
}

private System.Drawing.Imaging.ImageFormat DetermineImageFormat(string filePath)
{
    if (filePath.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase))
        return System.Drawing.Imaging.ImageFormat.Jpeg;
    else if (filePath.EndsWith(".gif", StringComparison.OrdinalIgnoreCase))
        return System.Drawing.Imaging.ImageFormat.Gif;
    else if (filePath.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
        return System.Drawing.Imaging.ImageFormat.Png;
    else
        return System.Drawing.Imaging.ImageFormat.Bmp;
}

private void WriteImageAsReponse(System.Drawing.Image image, System.Drawing.Imaging.ImageFormat imageFormat)
{
    if (image == null)
        return;

    System.Drawing.Bitmap l_outputBitMap = new Bitmap(image);

    if (imageFormat == System.Drawing.Imaging.ImageFormat.Jpeg)
        Response.ContentType = "image/jpg";
    else if (imageFormat == System.Drawing.Imaging.ImageFormat.Gif)
        Response.ContentType = "image/gif";
    else if (imageFormat == System.Drawing.Imaging.ImageFormat.Png)
        Response.ContentType = "image/png";
    else
        Response.ContentType = "image/bmp";

    l_outputBitMap.Save(Response.OutputStream, imageFormat);
}

Todas as ideias por GIFs são grainy e PNGs e causar exceções BMPs?

Foi útil?

Solução

Alguns pontos sobre o seu método GetImage:

  • Quando você usa Image.FromStream você não deve fechar (ou descarte) o fluxo
  • Se você está chamando Dispose em um fluxo (com a instrução usando), você não precisa chamar Close
  • Você está escrevendo para o fluxo, mas depois não "rebobinando-o" para l_image não realmente obter todos os dados, tanto quanto eu posso ver (a menos que Image.FromStream redefine a própria posição). (Pode ser que o GIF / jpg decodificadores rebobinar o fluxo, mas bmp / ??png não, daí o erro.)
  • Por que você não apenas usar o construtor MemoryStream que leva uma matriz de bytes?

Em suma, creio que o seu método GetImage pode ser substituída por:

private Image GetImage(string filePath)
{
    WebClient l_WebClient = new WebClient();
    byte[] l_imageBytes = l_WebClient.DownloadData(filePath);
    MemoryStream l_stream = new MemoryStream(l_imageBytes);
    return Image.FromStream(l_stream);
}

Agora, mais importante - por que você carregar a imagem em tudo? Por que você não apenas servir o arquivo em si como uma resposta, definindo o tipo de conteúdo que você já está fazendo - ou, possivelmente, apenas com base na extensão? Em outras palavras, todo o seu código seria:

protected void Page_Load(object sender, EventArgs e)
{
    string filePath = Request.QueryString["i"];
    string extension = l_filePath.Substring(l_filePath.LastIndexOf('.') + 1);
    Response.ContentType = "image/" + extension;
    byte[] data = new WebClient.DownloadData(filePath);
    Response.OutputStream.Write(data, 0, data.Length);
    Response.End();
}

Um pouco mais o tratamento de erros (incluindo "isto é uma extensão razoável?") Seria bom, mas diferente do que eu acho que está tudo bem. O único benefício de realmente carregar a imagem de si mesmo é que você começa a validar que realmente é uma imagem em vez de um vírus ou algo parecido.

EDIT: Só por curiosidade, você tem uma boa razão para você deseja solicitações de imagem para ir até o seu servidor? Por que a escrita da página web do autor:

<img src="http://www.mydomain.com/ImageLoader.aspx?i=http://images.mydomain.com/img/a.jpg" />

em vez de

<img src="http://images.mydomain.com/img/a.jpg" />

Não são algumas razões pelas quais ele pode ser útil, mas em muitos casos é apenas um desperdício.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top