为什么IE中的图像会变成x？

在网上我们经常看见以`.jpg`为扩展名的文件，却有着`gif`图片的特征，绘声绘色的在浏览器里帧帧重绘。当然这是在理想的情况下，如果我们使用IE浏览器，就会发现图片只能显示成一个小红x，任凭怎样刷新都无法显示。

![ddd.png](https://qiita-image-store.s3.amazonaws.com/0/10408/1db16904-272e-cc3f-c113-6925f8a29be1.png)

![ddddd.png](https://qiita-image-store.s3.amazonaws.com/0/10408/944d8f05-592e-46f3-cefe-04045a0181c3.png)

造成这样的结果并不是一种原因，当我们将文件的后缀名修改时，实际上文件内容并没有发生改变，比如用笔记本打开修改扩展名为JPG的GIF文件，会发现它们都拥有相同的文件头，`GIF87a`，而这是GIF文件通用的文件头。

![wfeeeee.png](https://qiita-image-store.s3.amazonaws.com/0/10408/f682f2ff-e0f1-19a4-f010-d37a7be822f3.png)


不过有幸我们能够通过webkit-like浏览器打开这张修改扩展名的gif图片，查看webkit源码我们就能发现，在webkit的[ImageDecoder][4]模块，使用的正是写死文件头的方法进行判断图片解码：

```cpp
bool matchesGIFSignature(char* contents)
{
    return !memcmp(contents, "GIF87a", 6) || !memcmp(contents, "GIF89a", 6);
}

bool matchesPNGSignature(char* contents)
{
    return !memcmp(contents, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8);
}

bool matchesJPEGSignature(char* contents)
{
    return !memcmp(contents, "\xFF\xD8\xFF", 3);
}

if (matchesGIFSignature(contents))
    return new GIFImageDecoder(alphaOption, gammaAndColorProfileOption);
```

而对比之下，firefox采用的Gecko引擎的判定方式就变得更加“web”了，它首先通过`imgLoader.cpp`通过比对文件头方式确定文件类型，然后再赋予他们一个MIMEType常量：

```cpp
if (aLength >= 6 && (!nsCRT::strncmp(aContents, "GIF87a", 6) ||
                   !nsCRT::strncmp(aContents, "GIF89a", 6)))
{
                   aContentType.AssignLiteral("image/gif");
}

/* or a PNG? */
else if (aLength >= 8 && ((unsigned char)aContents[0]==0x89 &&
               (unsigned char)aContents[1]==0x50 &&
               (unsigned char)aContents[2]==0x4E &&
               (unsigned char)aContents[3]==0x47 &&
               (unsigned char)aContents[4]==0x0D &&
               (unsigned char)aContents[5]==0x0A &&
               (unsigned char)aContents[6]==0x1A &&
               (unsigned char)aContents[7]==0x0A))
{ 
               aContentType.AssignLiteral("image/png");
}
```    

最后再通过`Image.cpp`判断MIMETYPE常量判断应该使用哪种解码器去解析，虽然使用MIMETYPE是非常“web”的方式，firefox也曾经声称自己的存在对web更有必要，但这显然是一个脱裤子放屁式的举动，尤其是当你看到Image目录结构和webkit条理清晰的Decoder/Encoder安排之后：

```cpp
Image::GetDecoderType(const char *aMimeType)
{
        // By default we don't know
        eDecoderType rv = eDecoderType_unknown;

        // PNG
        if (!strcmp(aMimeType, "image/png"))
        rv = eDecoderType_png;
        else if (!strcmp(aMimeType, "image/x-png"))
        rv = eDecoderType_png;

        // GIF
        else if (!strcmp(aMimeType, "image/gif"))
        rv = eDecoderType_gif;


        // JPEG
        else if (!strcmp(aMimeType, "image/jpeg"))
        rv = eDecoderType_jpeg;
        else if (!strcmp(aMimeType, "image/pjpeg"))
        rv = eDecoderType_jpeg;
        else if (!strcmp(aMimeType, "image/jpg"))
        rv = eDecoderType_jpeg;

        // BMP
        else if (!strcmp(aMimeType, "image/bmp"))
        rv = eDecoderType_bmp;
        else if (!strcmp(aMimeType, "image/x-ms-bmp"))
        rv = eDecoderType_bmp;


        // ICO
        else if (!strcmp(aMimeType, "image/x-icon"))
        rv = eDecoderType_ico;
        else if (!strcmp(aMimeType, "image/vnd.microsoft.icon"))
        rv = eDecoderType_ico;

        // Icon
        else if (!strcmp(aMimeType, "image/icon"))
        rv = eDecoderType_icon;

        return rv;
}
```    

了解了其他两种方式之后，我们再来看IE。虽然是黑盒我们看不到答案的来龙去脉，但获取头文件确定解码方式是现行的两种浏览器的主流方式，显然IE并没有这么做。通过右键图片属性的，很可能是通过文件协议直接读取扩展名，导致了原本是GIF的文件却通过JPG的编码方式读取，得到的结果必然是一张小红叉。

以上情况在IE6 - IE10中均有存在，当然国内使用IE8内核的360安全浏览器里也有这样的情况了。

 [1]: http://lerous.com/blog/wp-content/uploads/2013/03/ddd.png
 [2]: http://lerous.com/blog/wp-content/uploads/2013/03/ddddd.png
 [3]: http://lerous.com/blog/wp-content/uploads/2013/03/wfeeeee.png
 [4]:http://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/WebCore/platform/image-decoders/ImageDecoder.cpp&sq=package:chromium