Phát hiện hỗ trợ WebP


96

Làm cách nào để phát hiện hỗ trợ cho WebP qua Javascript? Tôi muốn sử dụng phát hiện tính năng hơn là phát hiện trình duyệt nếu có thể, nhưng tôi không thể tìm ra cách để làm như vậy. Modernizr ( www.modernizr.com ) không kiểm tra nó.


1
Nếu bạn tải một hình ảnh như vậy vào phần tử Hình ảnh, sau đó kiểm tra chiều rộng và chiều cao trong trình duyệt không hỗ trợ định dạng, bạn có nhận được gì không?
Pointy

(Ý tôi là " Đối tượng hình ảnh ", không phải phần tử; như, "Hình ảnh mới ()" ...)
Pointy

Có vẻ tốt. Tôi có thể nhận được "Tôi hỗ trợ WebP" theo cách này; nhưng tôi không thể nhận được thông báo "Tôi không hỗ trợ WebP".
snostorm

3
Tôi đã đăng một câu hỏi tương tự: Khuyến nghị "chính thức" của Google để phát hiện hỗ trợ trình duyệt WebP là gì? trên nhóm WebP Google.
Mike

2
@Simon_Weaver câu hỏi và nhận xét đều có tuổi đời vài năm. Các câu hỏi cũ hiếm khi được "duy trì" theo bất kỳ cách nào đáng kể; Tuy nhiên, bạn luôn tự do thêm câu trả lời mới.
Pointy

Câu trả lời:


117

Đây là giải pháp của tôi - mất khoảng 6ms và tôi đang coi WebP chỉ là một tính năng cho trình duyệt hiện đại. Sử dụng một cách tiếp cận khác bằng cách sử dụng hàm canvas.toDataUrl () thay vì hình ảnh như một cách để phát hiện tính năng:

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
Điều này sẽ là câu trả lời được chấp nhận, bởi vì tất cả những người khác có một sự chậm trễ vì trỏ đến một nguồn tài nguyên mạng hoặc dữ liệu URI
imal hasaranga Perera

6
Phiên bản đơn giản hóa:webp = e => document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
António Almeida

35
Điều này không hoạt động trong Firefox 65 hỗ trợ hiển thị webp, nhưng không tạo url dữ liệu webp từ phần tử canvas.
carlcheel

4
Thích điều này vì nó đồng bộ, tuy nhiên @carlcheel là chính xác. FF 65 (mà không có hỗ trợ webp) vẫn trả về false đây :-(
RoccoB

11
Điều này sẽ tuyệt vời nếu nó hoạt động cho FF65 và Edge18. Cả hai đều hỗ trợ webp nhưng serialize vải với "dữ liệu: image / png"
undefinederror

55

Tôi nghĩ một cái gì đó như thế này có thể hoạt động:

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

Trong Firefox và IE, trình xử lý "onload" sẽ hoàn toàn không được gọi nếu không thể hiểu được hình ảnh và thay vào đó, "onerror" được gọi.

Bạn đã không đề cập đến jQuery, nhưng như một ví dụ về cách xử lý tính chất không đồng bộ của kiểm tra đó, bạn có thể trả về đối tượng 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();
}

Sau đó, bạn có thể viết:

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

Đây là một ví dụ về jsfiddle.


Trình kiểm tra nâng cao hơn: http://jsfiddle.net/JMzj2/29/ . Cái này tải hình ảnh từ một URL dữ liệu và kiểm tra xem nó có tải thành công hay không. Vì WebP hiện cũng hỗ trợ hình ảnh không mất dữ liệu, bạn có thể kiểm tra xem trình duyệt hiện tại chỉ hỗ trợ WebP mất dữ liệu hay WebP không mất dữ liệu. (Lưu ý: Điều này mặc nhiên cũng kiểm tra hỗ trợ URL dữ liệu.)

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

Tuyệt vời! Tính năng này hoạt động trên FF, Chrome và IE 9. Vì một số lý do, nó không hoạt động trong IE8 hoặc IE7.
snostorm

Nó hoạt động với tôi trong IE7 - hãy thử jsFiddle mà tôi vừa liên kết đến phần cuối của câu trả lời.
Pointy

Vâng câu trả lời ban đầu của tôi chỉ có "onload" - Tôi không biết có thậm chí là một "onerror" cho hình ảnh đối tượng :-)
chóp

Oh, duh. Tôi đã sử dụng data: url thay vì một hình ảnh và IE7 không hỗ trợ điều đó. : P
snostorm

1
Tôi chỉ nhận ra rằng tôi có thể làm cho IE8 hoạt động bình thường với dữ liệu: url và khiến IE7 gặp lỗi; vấn đề là họ không hỗ trợ chúng trực tiếp trong javascript. Xem: jsfiddle.net/HaLXz
snostorm

36

Giải pháp ưa thích trong HTML5

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

Wiki trên W3C


2
Hoạt động hoàn hảo, điều type="image/webp"quan trọng là để trình duyệt bỏ qua nó nếu định dạng không xác định!
adrianTNT 14/11/18

6
Điều này là tốt, nhưng nó không hoạt động đối với hình nền và nếu bạn đang trang bị thêm webp vào một trang web và nó yêu cầu sửa đổi html của bạn, điều đó cũng có nghĩa là sửa đổi tất cả các vị trí trong css của bạn tham chiếu đến thẻ img.
kloddant

1
Có đây là giải pháp tốt nhất cho vấn đề. Cảm ơn
Janith

Có phải tất cả các trình duyệt hỗ trợ webp cũng hỗ trợ phần tử hình ảnh không?
molrat

24

Cách chính thức của Google:

Vì một số trình duyệt cũ có hỗ trợ một phần cho webp , vì vậy tốt hơn là bạn nên nói rõ hơn tính năng webp nào bạn đang cố gắng sử dụng và phát hiện tính năng cụ thể này và đây là khuyến nghị chính thức của Google về cách phát hiện một tính năng webp cụ thể:

// 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];
}

Cách sử dụng ví dụ:

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

Lưu ý rằng tải hình ảnh là không chặn và không đồng bộ . Điều này có nghĩa là bất kỳ mã nào phụ thuộc vào sự hỗ trợ của WebP tốt hơn nên được đưa vào hàm gọi lại.

Cũng lưu ý rằng các giải pháp đồng bộ khác sẽ không hoạt động tốt với Firefox 65


17

Đây là một câu hỏi cũ, nhưng Modernizr hiện đã hỗ trợ phát hiện Webp.

http://modernizr.com/download/

Tìm img-webptrong phần Phát hiện không phải lõi.


1
Nguồn tin rất hữu ích để xem những gì họ đã làm github.com/Modernizr/Modernizr/blob/...
Simon_Weaver

Đối với tôi, nó hoạt động khá đáng tin cậy và nó cho phép bạn làm việc với các lớp css .webp và .no-webp để linh hoạt hơn.
molrat

12

Đây là phiên bản câu trả lời của James Westgate trong 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: sai

FF65: đúng

Chrome: true

Tôi thích câu trả lời đồng bộ từ Rui Marques, nhưng tiếc là FF65 vẫn trả về false mặc dù có khả năng hiển thị WebP.


8

Đây là mã mà không cần phải yêu cầu hình ảnh. Cập nhật với trò chơi mới của 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
Điều đó hoàn toàn bị phá vỡ đối với tôi. Tôi chia hai nó và làm cho nó hoạt động: jsfiddle.net/z6kH9
qwerty

Điều này sẽ hoạt động trên tất cả các trình duyệt? Tôi đang đề cập đến các vấn đề của các giải pháp khác trong Safari + FF65 +.
molrat

Tôi nghĩ đây là giải pháp tốt nhất. Vẫn muốn xem các thử nghiệm trên các trình duyệt cũ hơn và các trình duyệt không hỗ trợ webp.
Kostanos

5

WebPJS sử dụng phát hiện hỗ trợ WebP thông minh hơn mà không cần hình ảnh bên ngoài: http://webpjs.appspot.com/


Tập lệnh mà họ sử dụng để tải tệp của họ có thể được sử dụng mà không thực sự sử dụng tệp của họ. Chỉ cần thay thế bên trong bằng bất cứ thứ gì bạn muốn làm nếu không có hỗ trợ WebP.
tgrosinger

1
Có vẻ như họ đang sử dụng url dữ liệu, với những gì tôi đã sử dụng.
snostorm

4

Tôi thấy rằng tính năng phát hiện hỗ trợ webp yêu cầu 300 + ms khi trang có JavaScript nặng. Vì vậy, tôi đã viết một tập lệnh với các tính năng bộ nhớ đệm:

  • bộ đệm tập lệnh
  • bộ nhớ cache cục bộ

Nó sẽ chỉ phát hiện một lần khi người dùng truy cập trang lần đầu tiên.

/**
 * @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

Có một cách để kiểm tra hỗ trợ webP ngay lập tức . Nó đồng bộ và chính xác, vì vậy không cần đợi cuộc gọi lại để hiển thị hình ảnh.

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

Phương pháp này đã cải thiện đáng kể thời gian hiển thị của tôi


5
không hoạt động trên Firefox ... hỗ trợ image/webpnhưng trả về false trong trường hợp này (nhưng hoạt động chính xác trên cả Safari và Chrome)
a14m

2

đây là một chức năng đơn giản với Promise dựa trên phản hồi của Pointy

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

Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp thêm ngữ cảnh về cách và / hoặc lý do tại sao nó giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Nic3500,

Tôi nghĩ rằng nó khá rõ ràng, chúng tôi cố gắng tải một hình ảnh webp từ chuỗi base64 (rộng và cao 1px), nếu chúng tôi tải nó đúng cách (onload được gọi là) thì nó được hỗ trợ, nếu không (onerror được gọi) thì không, tôi chỉ gói nó trong một lời hứa.
Liron Navon

2

Phiên bản ngắn của tôi. Tôi đã sử dụng nó để cung cấp cho trình duyệt webP hoặc jpg / png.

Google ăn đứt điều này và iPhone cũ (f̶u̶c̶k̶i̶n̶g̶ ̶s̶h̶e̶e̶t̶ -safari) cũng hoạt động tốt!

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


2

/* 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. :) -->


1

Hình ảnh WebP với htaccess

Đặt phần sau vào .htaccesstệp của bạn và hình ảnh jpg / png sẽ được thay thế bằng hình ảnh WebP nếu được tìm thấy trong cùng một thư mục.

<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>

Đọc thêm tại đây


1

JavaScript mở rộng Webp Phát hiện và Thay thế:

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

0

Sử dụng câu trả lời của @ Pointy, câu trả lời này dành cho 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);
            }
        }
    }
}

0

Phiên bản cải tiến để xử lý Firefox dựa trên Rui Marques. Tôi đã thêm quá trình quét các chuỗi khác nhau dựa trên nhận xét cho câu trả lời đó.

Nếu cải tiến này được cộng đồng chấp nhận, nó nên được chỉnh sửa theo câu trả lời đó.

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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.