检测WebP支持


99

如何通过Javascript检测对WebP的支持?如果可能,我想使用功能检测而不是浏览器检测,但是我找不到方法。Modernizr(www.modernizr.com)不会对其进行检查。


1
如果将此类图像加载到Image元素中,然后在支持该格式的浏览器中检查宽度和高度,您得到了什么吗?
Pointy

(我的意思是“图像对象”,而不是元素;例如“ new Image()” ...)
Pointy

看起来不错。我可以这样获得“我确实支持WebP”。但是我找不到“我不支持WebP”。
dieki 2011年

3
我已经发布了一个类似的问题:Google检测WebP浏览器支持的“正式”建议是什么?在WebP Google组中。
Mike

2
@Simon_Weaver的问题和评论都已经有好几年了。旧问题很少以任何重要方式“维持”;不过,您始终可以随意添加新答案。
尖尖的

Answers:


118

这是我的解决方案-大约需要6毫秒,而且我认为WebP只是现代浏览器的一项功能。使用canvas.toDataUrl()函数而不是图像使用另一种方法来检测特征:

function support_format_webp()
{
 var elem = document.createElement('canvas');

 if (!!(elem.getContext && elem.getContext('2d')))
 {
  // was able or not to get WebP representation
  return elem.toDataURL('image/webp').indexOf('data:image/webp') == 0;
 }
 else
 {
  // very old browser like IE 8, canvas not supported
  return false;
 }
}

7
这应该是一个可以接受的答案,因为所有其他对象都由于指向网络资源或数据URI而有延迟
imal hasaranga perera

6
简化版:webp = e => document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
安东尼奥·阿尔梅达

39
在支持显示webp的Firefox 65中,此功能不起作用,但不能从canvas元素创建webp数据URL。
carlcheel

4
喜欢它,因为它是同步的,但是@carlcheel是正确的。FF 65(确实具有webp支持)在此处仍然返回false :-(
RoccoB

13
,如果它的工作对FF65和Edge18是巨大的。他们俩都支持webp,但使用“ data:image / png”序列化画布
undefinederror

55

我认为这样可能有效:

var hasWebP = false;
(function() {
  var img = new Image();
  img.onload = function() {
    hasWebP = !!(img.height > 0 && img.width > 0);
  };
  img.onerror = function() {
    hasWebP = false;
  };
  img.src = 'http://www.gstatic.com/webp/gallery/1.webp';
})();

在Firefox和IE中,如果无法理解图像,则根本不会调用“ onload”处理程序,而是会调用“ onerror”。

您没有提到jQuery,但是作为如何处理该检查的异步性质的示例,您可以返回jQuery“ Deferred”对象:

function hasWebP() {
  var rv = $.Deferred();
  var img = new Image();
  img.onload = function() { rv.resolve(); };
  img.onerror = function() { rv.reject(); };
  img.src = 'http://www.gstatic.com/webp/gallery/1.webp';
  return rv.promise();
}

然后,您可以编写:

hasWebP().then(function() {
  // ... code to take advantage of WebP ...
}, function() {
  // ... code to deal with the lack of WebP ...
});

这是一个jsfiddle示例。


更高级的检查器:http : //jsfiddle.net/JMzj2/29/。这是从数据URL加载图像并检查是否成功加载。由于WebP现在还支持无损图像,因此您可以检查当前浏览器是否仅支持有损WebP或无损WebP。(注意:这也隐式检查数据URL支持。)

var hasWebP = (function() {
    // some small (2x1 px) test images for each feature
    var images = {
        basic: "data:image/webp;base64,UklGRjIAAABXRUJQVlA4ICYAAACyAgCdASoCAAEALmk0mk0iIiIiIgBoSygABc6zbAAA/v56QAAAAA==",
        lossless: "data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA="
    };

    return function(feature) {
        var deferred = $.Deferred();

        $("<img>").on("load", function() {
            // the images should have these dimensions
            if(this.width === 2 && this.height === 1) {
                deferred.resolve();
            } else {
                deferred.reject();
            }
        }).on("error", function() {
            deferred.reject();
        }).attr("src", images[feature || "basic"]);

        return deferred.promise();
    }
})();

var add = function(msg) {
    $("<p>").text(msg).appendTo("#x");
};

hasWebP().then(function() {
    add("Basic WebP available");
}, function() {
    add("Basic WebP *not* available");
});

hasWebP("lossless").then(function() {
    add("Lossless WebP available");
}, function() {
    add("Lossless WebP *not* available");
});

太棒了!该功能可在FF,Chrome和IE 9中使用。由于某些原因,它在IE8或IE7中不起作用。
dieki 2011年

它在IE7中对我有效-试试我刚刚链接到答案结尾的jsFiddle。
Pointy

好吧,我原来的答案只有“ onload”-我什至不知道Image对象还有“ onerror” :-)
Pointy

哦,du 我使用了data:url而不是图像,而IE7不支持该图像。:P
dieki 2011年

1
我刚刚意识到,我可以使IE8正确处理数据:URL,并让IE7为其引发错误。问题是他们不直接在javascript中支持它们。请参阅:jsfiddle.net/HaLXz
dieki 2011年

37

首选解决方案 HTML5

<picture>
  <source srcset="/path/to/image.webp" type="image/webp">
  <img src="/path/to/image.jpg" alt="insert alt text here">
</picture>

W3C上的Wiki


2
完美运作,type="image/webp"对于浏览器跳过未知格式至关重要!
adrianTNT

7
这很好,但不适用于背景图像,如果您要将Webp改装为站点,则需要修改html,这也意味着修改css中引用img标签的所有位置。
kloddant

1
是的,这是解决该问题的最佳方法。谢谢
Janith '20

所有支持webp的浏览器是否也支持图片元素?
molerat

尽管最好使用本机HTML5,但大多数浏览器都会同时加载JPG和WEBP,这会对下载时间产生负面影响。在深度:smashingmagazine.com/2013/05/...
扬Werkhoven

25

Google的官方方式:

由于某些旧的浏览器部分支持webp,因此最好更具体地说明您要使用哪种Webp功能并检测该特定功能,这是Google对于如何检测特定Webp功能的官方建议

// check_webp_feature:
//   'feature' can be one of 'lossy', 'lossless', 'alpha' or 'animation'.
//   'callback(feature, isSupported)' will be passed back the detection result (in an asynchronous way!)
function check_webp_feature(feature, callback) {
    var kTestImages = {
        lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",
        lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",
        alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",
        animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"
    };
    var img = new Image();
    img.onload = function () {
        var result = (img.width > 0) && (img.height > 0);
        callback(feature, result);
    };
    img.onerror = function () {
        callback(feature, false);
    };
    img.src = "data:image/webp;base64," + kTestImages[feature];
}

用法示例:

check_webp_feature('lossy', function (feature, isSupported) {
    if (isSupported) {
        // webp is supported, 
        // you can cache the result here if you want
    }
});

请注意,图像加载是非阻塞且异步的。这意味着依赖于WebP支持的任何代码最好都应放在回调函数中。

另请注意,其他同步解决方案不适用于Firefox 65



13

这是James Westgate在ES6中答案的一个版本。

function testWebP() {
    return new Promise(res => {
        const webP = new Image();
        webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
        webP.onload = webP.onerror = () => {
            res(webP.height === 2);
        };        
    })
};

testWebP().then(hasWebP => console.log(hasWebP));

FF64:错误

FF65:是的

铬:真

我喜欢来自Rui Marques的同步答案,但是不幸的是,尽管FF65能够显示WebP,但它仍然返回false。


8

这是无需请求图像的代码。更新了qwerty的新提琴。

http://jsfiddle.net/z6kH9/

function testWebP(callback) {
    var webP = new Image();
    webP.onload = webP.onerror = function () {
        callback(webP.height == 2);
    };
    webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
};

testWebP(function(support) {
    document.body.innerHTML = support ? 'Yeah man!' : 'Nope';
});

5
这对我来说完全是残破的。我将其分叉并使其工作:jsfiddle.net/z6kH9
qwerty

可以在所有浏览器中使用吗?我指的是Safari + FF65 +中其他解决方案的问题。
molerat

我认为这是最好的解决方案。仍然希望在较旧的浏览器以及不支持webp的浏览器上看到测试。
Kostanos

5

WebPJS使用更智能的WebP支持检测,无需外部图像:http://webpjs.appspot.com/


无需实际使用文件即可使用他们用于加载文件的脚本。如果没有WebP支持,则用您想做的任何事情替换内部。
tgrosinger

1
看来他们使用的是数据网址,这是我最终使用的网址。
dieki 2012年

5

我发现当JavaScript繁重时,webp支持功能检测需要300毫秒以上的时间。所以我写了一个具有缓存功能的脚本

  • 脚本缓存
  • 本地存储缓存

用户首次访问该页面时,它将仅检测一次。

/**
 * @fileOverview WebP Support Detect.
 * @author ChenCheng<sorrycc@gmail.com>
 */
(function() {

  if (this.WebP) return;
  this.WebP = {};

  WebP._cb = function(isSupport, _cb) {
    this.isSupport = function(cb) {
      cb(isSupport);
    };
    _cb(isSupport);
    if (window.chrome || window.opera && window.localStorage) {
      window.localStorage.setItem("webpsupport", isSupport);
    }
  };

  WebP.isSupport = function(cb) {
    if (!cb) return;
    if (!window.chrome && !window.opera) return WebP._cb(false, cb);
    if (window.localStorage && window.localStorage.getItem("webpsupport") !== null) {
      var val = window.localStorage.getItem("webpsupport");
      WebP._cb(val === "true", cb);
      return;
    }
    var img = new Image();
    img.src = "data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA";
    img.onload = img.onerror = function() {
      WebP._cb(img.width === 2 && img.height === 2, cb);
    };
  };

  WebP.run = function(cb) {
    this.isSupport(function(isSupport) {
      if (isSupport) cb();
    });
  };

})();

3

/* Here's a one-liner hack that works (without the use/need of any 
   externals...save bytes)...

Your CSS... */

body.no-webp .logo {
  background-image: url('logo.png');
}

body.webp .logo {
  background-image: url('logo.webp');
}
...
<body>
  <!--
  The following img tag is the *webp* support checker. I'd advise you use any 
  (small-sized) image that would be utilized on the current page eventually 
  (probably an image common to all your pages, maybe a logo) so that when 
  it'll be (really) used on the page, it'll be loaded from cache by the 
  browser instead of making another call to the server (for some other image 
  that won't be).

  Sidebar: Using 'display: none' so it's not detected by screen readers and 
  so it's also not displayed (obviously). :)
  -->
  <img 
    style='display: none'
    src='/path/to/low-sized-image.webp'
    onload="this.parentNode.classList.add('webp')"
    onerror="this.parentNode.classList.add('no-webp')"
  />
  ...
</body>


   <!-- PS. It's my first answer on SO. Thank you. :) -->


2

有一种方法可以立即测试webP支持。它是同步且准确的,因此无需等待回调即可渲染图像。

function testWebP = () => {
    const canvas = typeof document === 'object' ? 
    document.createElement('canvas') : {};
    canvas.width = canvas.height = 1;
    return canvas.toDataURL ? canvas.toDataURL('image/webp').indexOf('image/webp') === 5 : false;
}

这种方法极大地改善了我的渲染时间


5
在Firefox上不起作用...支持image/webp但在这种情况下返回false(但在Safari和Chrome上均可正常使用)
a14m

2

这是一个基于Pointy响应的Promise的简单功能

let webpSupport = undefined // so we won't have to create the image multiple times
const webp1Px = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA'

function isWebpSupported () {
  if (webpSupport !== undefined) {
    return Promise.resolve(webpSupport)
  }

  return new Promise((resolve, _reject) => {
    const img = new Image()
    img.onload = () => {
      webpSupport = !!(img.height > 0 && img.width > 0);
      resolve(webpSupport)
    }
    img.onerror = () => {
      webpSupport = false
      resolve(webpSupport)
    }
    img.src = webp1Px
  })
}

尽管此代码可以回答问题,但提供有关如何和/或为什么解决问题的其他上下文将提高​​答案的长期价值。
Nic3500 '18

我认为这很清楚,我们尝试从base64字符串(宽1px,高1px)加载webp图像,如果我们正确加载(调用onload)支持它,如果不加载(调用onerror)则不支持,我只是包装了它在一个诺言中。
Liron Navon

2

我的简短版本。我用它来给浏览器提供webP或jpg / png。

谷歌吃了这个,旧的iPhone(f̶u̶c̶k̶i̶n̶g̶̶s̶h̶e̶e̶t̶-safari)也很棒!

function checkWebP(callback) {
    var webP = new Image();
    webP.onload = webP.onerror = function () {
        callback(webP.height == 2);
    };
    webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
};

checkWebP(function(support) {
      if(support) {
          //Do what you whant =)
         console.log('work webp');
      }else{
          //Do what you whant =)
         console.log('not work, use jgp/png')
      }
      
})


1

带有htaccess的WebP图像

将以下内容放置在.htaccess文件中,如果在同一文件夹中找到jpg / png图像,则会将其替换为WebP图像。

<IfModule mod_rewrite.c>
  RewriteEngine On

  # Check if browser support WebP images
  RewriteCond %{HTTP_ACCEPT} image/webp

  # Check if WebP replacement image exists
  RewriteCond %{DOCUMENT_ROOT}/$1.webp -f

  # Serve WebP image instead
  RewriteRule (.+)\.(jpe?g|png)$ $1.webp [T=image/webp,E=accept:1]
</IfModule>

<IfModule mod_headers.c>
  Header append Vary Accept env=REDIRECT_accept
</IfModule>

<IfModule mod_mime.c>
  AddType image/webp .webp
</IfModule>

在这里阅读更多


1

Webp扩展检测和替换JavaScript:

 async function supportsWebp() {
  if (!self.createImageBitmap) return false;

  const webpData = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=';
  const blob = await fetch(webpData).then(r => r.blob());
  return createImageBitmap(blob).then(() => true, () => false);
}

(async () => {
  if(await supportsWebp()) {
    console.log('webp does support');
  }
  else {
    $('#banners .item').each(function(){
        var src=$(this).find('img').attr('src');
        src = src.replace(".webp", ".jpg");
        $(this).find('img').attr('src',src);
    });
    console.log('webp does not support');
  }
})();

1

改进的版本可处理基于Rui Marques的Firefox。我根据该答案的注释添加了对不同字符串的扫描。

如果社区接受了这种改进,则应将其编辑为该答案。

function canUseWebP()
{
    var elem = document.createElement('canvas');

    if (!!(elem.getContext && elem.getContext('2d')))
    {
        var testString = (!(window.mozInnerScreenX == null)) ? 'png' : 'webp';
        // was able or not to get WebP representation
        return elem.toDataURL('image/webp').indexOf('data:image/' + testString) == 0;
    }

    // very old browser like IE 8, canvas not supported
    return false;
}

0

使用@Pointy的答案是为了Angular 2+

import { Injectable } from '@angular/core';
import { Subject }    from 'rxjs/Subject';

@Injectable()
export class ImageService {
    private isWebpEnabledSource = new Subject<boolean>();

    isWebpEnabledAnnounced$ = this.isWebpEnabledSource.asObservable();

    isWebpEnabled() {
        let webpImage = new Image();

        webpImage.src = 'data:image/webp;base64,UklGRjIAAABXRUJQVlA4ICYAAACyAgCdASoCAAEALmk0mk0iIiIiIgBoSygABc6zbAAA/v56QAAAAA==';

        webpImage.onload = () => {
            if (webpImage.width === 2 && webpImage.height === 1) {
                this.isWebpEnabledSource.next(true);
            } else {
                this.isWebpEnabledSource.next(false);
            }
        }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.