Mendeteksi dukungan WebP


96

Bagaimana cara mendeteksi dukungan untuk WebP melalui Javascript? Saya ingin menggunakan deteksi fitur daripada deteksi browser jika memungkinkan, tetapi saya tidak dapat menemukan cara untuk melakukannya. Modernizr ( www.modernizr.com ) tidak memeriksanya.


1
Jika Anda memuat gambar seperti itu ke dalam elemen Image, dan kemudian memeriksa lebar dan tinggi di browser yang tidak mendukung formatnya, apakah Anda mendapatkan sesuatu?
Pointy

(Maksud saya " Objek gambar ", bukan elemen; seperti, "Gambar baru ()" ...)
Pointy

Kelihatan bagus. Saya bisa mendapatkan "Saya mendukung WebP" dengan cara ini; tapi saya tidak bisa mendapatkan "Saya tidak mendukung WebP".
snostorm

3
Saya telah memposting pertanyaan serupa: Apa rekomendasi "resmi" Google untuk mendeteksi dukungan browser WebP? di grup Google WebP.
Mike

2
@Simon_Weaver pertanyaan dan komentar semua berumur beberapa tahun. Pertanyaan lama jarang "dipertahankan" dengan cara yang signifikan; Anda selalu bebas menambahkan jawaban baru.
Pointy

Jawaban:


117

Ini adalah solusi saya - memakan waktu sekitar 6ms dan saya menganggap WebP hanyalah fitur untuk browser modern. Menggunakan pendekatan berbeda menggunakan fungsi canvas.toDataUrl () sebagai ganti gambar sebagai cara untuk mendeteksi fitur tersebut:

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
Ini harus menjadi jawaban yang diterima, karena semua yang lain memiliki penundaan karena menunjuk ke sumber daya jaringan atau URI data
imal hasaranga perera

6
Versi sederhana:webp = e => document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
António Almeida

35
Ini tidak berfungsi di Firefox 65 yang mendukung tampilan webp, tetapi tidak membuat url data webp dari elemen kanvas.
carlcheel

4
Suka ini karena sinkron, namun @carlcheel benar. FF 65 (yang memang memiliki dukungan webp) masih mengembalikan false di sini :-(
RoccoB

11
Ini akan bagus jika berfungsi untuk FF65 dan Edge18. Keduanya mendukung webp tetapi membuat serial kanvas dengan "data: image / png"
undefinederror

55

Saya pikir sesuatu seperti ini mungkin berhasil:

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

Di Firefox dan IE, penangan "onload" tidak akan dipanggil sama sekali jika gambar tidak dapat dipahami, dan "onerror" yang dipanggil.

Anda tidak menyebutkan jQuery, tetapi sebagai contoh cara menangani sifat asinkron dari pemeriksaan tersebut, Anda dapat mengembalikan objek 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();
}

Kemudian Anda bisa menulis:

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

Berikut adalah contoh jsfiddle.


Pemeriksa yang lebih canggih: http://jsfiddle.net/JMzj2/29/ . Yang ini memuat gambar dari URL data dan memeriksa apakah berhasil memuat. Karena WebP sekarang juga mendukung gambar lossless, Anda dapat memeriksa apakah browser saat ini hanya mendukung WebP lossy atau juga WebP lossless. (Catatan: Ini secara implisit juga memeriksa dukungan URL data.)

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

Hebat! Ini berfungsi di FF, Chrome, dan IE 9. Untuk beberapa alasan, ini tidak berfungsi di IE8 atau IE7.
snostorm

Ini berfungsi untuk saya di IE7 - coba jsFiddle yang baru saja saya tautkan ke akhir jawaban.
Pointy

Jawaban awal saya baru saja "onload" - Saya tidak tahu bahwa ada "onerror" untuk objek Gambar :-)
Pointy

Oh, ya. Saya menggunakan data: url alih-alih gambar, dan IE7 tidak mendukungnya. : P
snostorm

1
Saya baru menyadari bahwa saya dapat membuat IE8 bekerja dengan baik dengan data: url, dan membuat IE7 membuat kesalahan; masalahnya adalah mereka tidak mendukungnya secara langsung dalam javascript. Lihat: jsfiddle.net/HaLXz
snostorm

36

Solusi pilihan dalam HTML5

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

Wiki di W3C


2
Bekerja dengan sempurna, type="image/webp"sangat penting agar browser melewatkannya jika formatnya tidak diketahui!
adrianTNT

6
Ini bagus, tetapi tidak berfungsi untuk gambar latar belakang, dan jika Anda menyesuaikan webp ke situs, dan itu memerlukan modifikasi html Anda, yang juga berarti memodifikasi semua tempat di css Anda yang mereferensikan tag img.
kloddant

1
Ya ini adalah solusi terbaik untuk masalah tersebut. Terima kasih
Janith

Apakah semua browser yang mendukung webp mendukung elemen gambar juga?
molerat

24

Cara resmi oleh Google:

Karena beberapa browser lama memiliki dukungan parsial untuk webp , jadi lebih baik untuk lebih spesifik fitur webp mana yang Anda coba gunakan & deteksi fitur khusus ini, dan berikut adalah rekomendasi resmi Google untuk cara mendeteksi fitur webp tertentu:

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

Contoh Penggunaan:

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

Perhatikan bahwa pemuatan gambar tidak memblokir dan tidak sinkron . Ini berarti bahwa kode apa pun yang bergantung pada dukungan WebP sebaiknya ditempatkan dalam fungsi callback.

Perhatikan juga bahwa solusi sinkron lainnya tidak akan berfungsi dengan baik dengan Firefox 65



12

Berikut adalah versi jawaban James Westgate di 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: salah

FF65: benar

Chrome: benar

Saya suka jawaban sinkron dari Rui Marques, tetapi sayangnya FF65 masih mengembalikan false meskipun memiliki kemampuan untuk menampilkan WebP.


8

Berikut adalah kode tanpa harus meminta gambar. Diperbarui dengan biola baru 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
Itu benar-benar rusak bagiku. Saya mem
qwerty

Akankah ini berfungsi di semua browser? Saya mengacu pada masalah solusi lain di Safari + FF65 +.
molerat

Saya rasa ini adalah solusi terbaik. Masih ingin melihat pengujian di browser lama, dan browser yang tidak mendukung webp.
Kostanos

5

WebPJS menggunakan deteksi dukungan WebP yang lebih cerdas tanpa memerlukan gambar eksternal: http://webpjs.appspot.com/


Skrip yang mereka gunakan untuk memuat file mereka dapat digunakan tanpa benar-benar menggunakan file mereka. Cukup ganti bagian dalamnya dengan apa pun yang ingin Anda lakukan jika tidak ada dukungan WebP.
tgrosinger

1
Sepertinya mereka menggunakan url data, dengan itulah yang akhirnya saya gunakan.
snostorm

4

Saya telah menemukan fitur dukungan webp mendeteksi membutuhkan 300 + md saat halaman JavaScript berat. Jadi saya menulis skrip dengan fitur caching:

  • cache skrip
  • cache penyimpanan lokal

Ini hanya akan mendeteksi sekali saat pengguna pertama kali mengakses halaman.

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

Ada cara untuk menguji dukungan webP secara instan . Ini sinkron dan akurat, jadi tidak perlu menunggu panggilan balik untuk merender gambar.

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

Metode ini meningkatkan waktu rendering saya secara dramatis


5
tidak berfungsi di Firefox ... yang mendukung image/webp tetapi mengembalikan false dalam kasus ini (tetapi berfungsi di Safari dan Chrome dengan benar)
a14m

2

di sini adalah fungsi sederhana dengan Janji berdasarkan respons 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
  })
}

Meskipun kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang bagaimana dan / atau mengapa kode ini memecahkan masalah akan meningkatkan nilai jawaban jangka panjang.
Nic3500

Saya pikir itu cukup jelas, kami mencoba memuat gambar webp dari string base64 (yang lebarnya 1px dan tinggi), jika kami memuatnya dengan benar (disebut onload) itu didukung, jika tidak (disebut onerror) tidak, saya cukup membungkusnya dalam janji.
Liron Navon

2

Versi singkat saya. Saya menggunakannya untuk memberikan webP atau jpg / png browser.

Google makan ini, dan iphone lama (f̶u̶c̶k̶i̶n̶g̶ ̶s̶h̶e̶e̶t̶ -safari) bekerja dengan baik juga!

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

Gambar WebP dengan htaccess

Tempatkan berikut ini di .htaccessfile Anda dan gambar jpg / png akan diganti dengan gambar WebP jika ditemukan di folder yang sama.

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

Baca lebih lanjut di sini


1

Ekstensi Webp Mendeteksi Dan Penggantian 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');
  }
})();

0

Menggunakan jawaban @ Pointy ini untuk 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

Versi yang ditingkatkan untuk menangani Firefox berdasarkan Rui Marques. Saya menambahkan pemindaian untuk string berbeda berdasarkan komentar ke jawaban itu.

Jika perbaikan ini diterima oleh masyarakat, harus diedit untuk jawaban itu.

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;
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.