C# 使用 WebClient 获取远程图像产生颗粒状 GIF 且无法处理 PNG+BMP

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/499210/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 05:45:34  来源:igfitidea点击:

Using WebClient to get Remote Images Produces Grainy GIFs and Can't Handle PNG+BMP

c#asp.netwebclient

提问by Bullines

Greetings!

你好!

I'm creating a web form prototype (ImageLaoder.aspx) that will return an image so that it may be used like this simple example other Web Forms/web pages:

我正在创建一个 Web 表单原型 (ImageLaoder.aspx),它将返回一个图像,以便它可以像这个简单的示例一样使用其他 Web 表单/网页:

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

So far, it loads JPGs with no problems, however GIFs look "grainy" compared to the orignals and BMPs and PNGs result in the following exception:

到目前为止,它加载 JPG 没有问题,但是与原始图像相比,GIF 看起来“有颗粒感”,而 BMP 和 PNG 会导致以下异常:

System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+

System.Runtime.InteropServices.ExternalException:GDI+ 中发生一般错误

My code thus far looks like this:

到目前为止,我的代码如下所示:

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

Any ideas why GIFs are grainy and PNGs and BMPs cause exceptions?

任何想法为什么 GIF 是颗粒状的,而 PNG 和 BMP 会导致异常?

采纳答案by Jon Skeet

A few points about your GetImage method:

关于您的 GetImage 方法的几点:

  • When you use Image.FromStream you shouldn't close (or dispose) the stream
  • If you're calling Dispose on a stream (with the using statement) you don't need to call Close
  • You're writing to the stream, but then not "rewinding it" so l_image doesn't actually get any data as far as I can see (unless Image.FromStream resets the position itself). (It could be that the gif/jpg decoders rewind the stream but bmp/png don't, hence the error.)
  • Why don't you just use the MemoryStream constructor which takes a byte array?
  • 当您使用 Image.FromStream 时,您不应关闭(或处置)流
  • 如果您在流上调用 Dispose(使用 using 语句),则不需要调用 Close
  • 您正在写入流,但没有“倒带”,因此 l_image 实际上并没有获得任何数据,就我所见(除非 Image.FromStream 重置位置本身)。(可能是 gif/jpg 解码器倒带流但 bmp/png 没有,因此出现错误。)
  • 为什么不直接使用带有字节数组的 MemoryStream 构造函数?

In short, I believe your GetImage method can be replaced with:

简而言之,我相信您的 GetImage 方法可以替换为:

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

Now, more importantly - why are you loading the image at all? Why don't you just serve the file itself as a response, setting the content type as you're already doing - or possibly just based on the extension? In other words, all of your code would become:

现在,更重要的是 - 你为什么要加载图像?为什么不直接将文件本身作为响应提供,像您已经在做的那样设置内容类型 - 或者可能仅基于扩展名?换句话说,您的所有代码都将变为:

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

A bit more error handling (including "is this a reasonable extension?") would be nice, but other than that I think it's okay. The only benefit of actually loading the image yourself is that you get to validate that it really isan image rather than a virus or something like that.

多一点错误处理(包括“这是一个合理的扩展吗?”)会很好,但除此之外我认为还可以。自己实际加载图像的唯一好处是您可以验证它确实图像而不是病毒或类似的东西。

EDIT: Just out of interest, do you have a good reason why you'd wantimage requests to go through your server? Why would the web page author write:

编辑:出于兴趣,您是否有充分的理由希望图像请求通过您的服务器?为什么网页作者会写:

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

instead of

代替

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

There aresome reasons why it might be useful, but in many cases it's just a waste.

这里一些原因,这可能是有用的,但在许多情况下,它只是一个浪费。