WebP desteğini algılama


96

Javascript aracılığıyla WebP desteğini nasıl tespit edebilirim? Mümkünse tarayıcı algılaması yerine özellik algılamayı kullanmak istiyorum, ancak bunu yapmanın bir yolunu bulamıyorum. Modernizr ( www.modernizr.com ) bunu kontrol etmez.


1
Bir Görüntü öğesinin içine böyle bir resim yüklemek ve sonra bir tarayıcıda genişliğini ve yüksekliğini kontrol ederse vermez biçimini destekleyen, bir şey alabilirim?
Sivri

("Resim nesnesi " ni kastetmiştim , öğe değil; "yeni Resim ()" gibi ...)
Sivri

İyi görünüyor. Bu şekilde "WebP'yi destekliyorum" alabilirim; ancak "WebP'yi desteklemiyorum" alamıyorum.
kar fırtınası

3

2
@Simon_Weaver soru ve yorumların hepsi birkaç yaşında. Eski sorular nadiren herhangi bir önemli şekilde "tutulur"; ancak her zaman yeni bir cevap eklemekte özgürsünüz.
Sivri

Yanıtlar:


117

Bu benim çözümüm - yaklaşık 6ms sürüyor ve WebP'nin yalnızca modern bir tarayıcı için bir özellik olduğunu düşünüyorum. Özelliği algılamanın yolu olarak image yerine canvas.toDataUrl () işlevini kullanarak farklı bir yaklaşım kullanır:

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
Kabul edilen cevap bu olmalı, çünkü diğerlerinin tümü bir ağ kaynağına veya veri
URI'sine

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

35
Bu, webp'yi görüntülemeyi destekleyen ancak bir tuval öğesinden webp veri url'si oluşturmayan Firefox 65'te çalışmaz.
carlcheel

4
Eşzamanlı olduğu için bunu seviyorum, ancak @carlcheel doğru. FF 65 (webp desteğine sahip) burada hala yanlış döndürüyor :-(
RoccoB

11
Bu olur o FF65 ve Edge18 çalıştı eğer harika olur. İkisi de webp'yi destekliyor ancak tuvali "data: image / png" ile seri hale getiriyor
undefinederror

55

Sanırım böyle bir şey işe yarayabilir:

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 ve IE'de, görüntü anlaşılamıyorsa "yüklenme" işleyicisi hiçbir şekilde çağrılmaz ve bunun yerine "onerror" çağrılır.

JQuery'den bahsetmediniz, ancak bu kontrolün eşzamansız doğasıyla nasıl başa çıkılacağına dair bir örnek olarak bir jQuery "Ertelenmiş" nesnesi döndürebilirsiniz:

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

O zaman yazabilirsin:

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

İşte bir jsfiddle örneği.


Daha gelişmiş bir denetleyici: http://jsfiddle.net/JMzj2/29/ . Bu, görüntüleri bir veri URL'sinden yükler ve başarıyla yüklenip yüklenmediğini kontrol eder. WebP artık kayıpsız görüntüleri de desteklediğinden, mevcut tarayıcının yalnızca kayıplı WebP'yi veya kayıpsız WebP'yi destekleyip desteklemediğini kontrol edebilirsiniz. (Not: Bu, dolaylı olarak veri URL desteğini de kontrol eder.)

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

Harika! Bu, FF, Chrome ve IE 9'da çalışır. Bazı nedenlerden dolayı IE8 veya IE7'de çalışmıyor.
Snostorm

Benim için IE7'de çalışıyor - cevabın sonuna bağladığım jsFiddle'ı deneyin.
Sivri

Orijinal cevabımda "yüklenme" vardı - Resim nesneleri için bir "hata" olduğunu bile bilmiyordum :-)
Sivri

Ah, ha. Bir resim yerine bir data: url kullandım ve IE7 bunu desteklemiyor. : P
snostorm

1
IE8'in data: urls ile düzgün çalışmasını sağlayabileceğimi ve bunun için bir hata atması için IE7'yi alabileceğimi yeni fark ettim; sorun, onları doğrudan javascript'te desteklememeleriydi. Bakınız: jsfiddle.net/HaLXz
snostorm

36

İçinde tercih edilen çözüm HTML5

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

W3C'de Wiki


2
Mükemmel çalışıyor, type="image/webp"tarayıcının bilinmeyen format varsa atlaması için kritik öneme sahip!
adrianTNT

6
Bu iyidir, ancak arka plan resimleri için işe yaramaz ve webp'yi bir siteye uyarlıyorsanız ve html'nizi değiştirmeyi gerektirir, bu da css'nizde img etiketine başvuran tüm yerleri değiştirmek anlamına gelir.
kloddant

1
Evet, sorun için en iyi çözüm budur. Teşekkürler
Janith

Webp'yi destekleyen tüm tarayıcılar da resim öğesini destekliyor mu?
molerat

24

Google'ın resmi yolu:

Bazı eski tarayıcıların webp için kısmi desteği olduğundan , bu belirli özelliği kullanmaya ve algılamaya çalıştığınız webp özelliğini daha spesifik olmanız daha iyidir ve işte Google'ın belirli bir webp özelliğini nasıl algılayacağınıza dair resmi önerisi :

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

Örnek Kullanım:

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

Görüntü yüklemenin engellemez ve asenkron olduğunu unutmayın . Bu, WebP desteğine bağlı herhangi bir kodun tercihen geri arama işlevine yerleştirilmesi gerektiği anlamına gelir.

Ayrıca diğer zaman uyumlu çözümlerin Firefox 65 ile iyi çalışmayacağını unutmayın .



12

İşte James Westgate'in ES6'daki cevabının bir versiyonu.

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: yanlış

FF65: doğru

Chrome: doğru

Rui Marques'in eşzamanlı cevabını seviyorum, ancak ne yazık ki FF65, WebP'yi görüntüleme yeteneğine sahip olmasına rağmen hala yanlış döndürüyor.


8

İşte bir görüntü talep etmek zorunda kalmadan kod. Qwerty'nin yeni kemanıyla güncellendi.

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
Bu benim için tamamen kırıldı. Çatalladım
qwerty

Bu tüm tarayıcılarda çalışacak mı? Safari + FF65 + 'daki diğer çözümlerin sorunlarına atıfta bulunuyorum.
molerat

Bunun en iyi çözüm olduğunu düşünüyorum. Yine de eski tarayıcılarda ve webp'yi desteklemeyen tarayıcılarda testleri görmek isterim.
Kostanos

5

WebPJS, harici görüntü gerektirmeden daha akıllı WebP desteği algılaması kullanır: http://webpjs.appspot.com/


Dosyalarını yüklemek için kullandıkları komut dosyası, aslında dosyalarını kullanmadan kullanılabilir. WebP desteği yoksa, içini yapmak istediğiniz şeyle değiştirin.
tgrosinger

1
Görünüşe göre veri url'leri kullanıyorlar, ben de bunu kullandım.
snostorm

4

Sayfa JavaScript ağır olduğunda webp destek özelliği algılamanın 300 + ms gerektirdiğini buldum. Bu yüzden önbelleğe alma özellikleri olan bir komut dosyası yazdım :

  • komut dosyası önbelleği
  • yerel depolama önbelleği

Kullanıcı sayfaya ilk eriştiğinde yalnızca bir kez algılar.

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

WebP desteğini anında test etmenin bir yolu var . Senkronize ve doğrudur, bu nedenle görüntüleri oluşturmak için geri aramayı beklemeye gerek yoktur.

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

Bu yöntem, oluşturma süremi önemli ölçüde iyileştirdi


5
Firefox'ta çalışmıyor ... image/webpbu durumda destekliyor ancak yanlış döndürüyor (ancak hem Safari hem de Chrome'da doğru çalışıyor)
a14m

2

İşte Pointy'nin yanıtına dayalı Promise ile basit bir işlev

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

Bu kod soruyu yanıtlayabilirken, sorunu nasıl ve / veya neden çözdüğüne ilişkin ek bağlam sağlamak, yanıtın uzun vadeli değerini artıracaktır.
Nic3500

Oldukça açık olduğunu düşündüm, bir webp görüntüsünü base64 dizesinden (1px genişliğinde ve yüksek) yüklemeye çalışıyoruz, eğer onu düzgün bir şekilde yüklediysek (onload çağrıldı) destekleniyor, değilse (onerror çağrılır) değil, sadece paketledim bir sözde.
Liron Navon

2

Kısa versiyonum. Tarayıcıya webP veya jpg / png vermek için kullandım.

Google bunu yer ve eski iphone (f̶u̶c̶k̶i̶n̶g̶ ̶s̶h̶e̶e̶t̶ -safari) da harika çalışıyor!

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

Htaccess ile WebP görüntüleri

Aşağıdakileri .htaccessdosyanıza yerleştirin ve jpg / png resimleri, aynı klasörde bulunursa WebP resimleri ile değiştirilecektir.

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

Daha fazlasını buradan okuyun


1

Webp uzantısı Algılama ve Değiştirme JavaScript'i:

 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

@ Pointy'nin cevabını kullanmak için bu 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

Firefox'u Rui Marques'e dayalı olarak işlemek için geliştirilmiş sürüm. Bu yanıta yapılan yorumlara göre farklı dizeler için taramayı ekledim.

Bu gelişme topluluk tarafından kabul edilirse, bu cevaba göre düzenlenmelidir.

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.