WebP-Unterstützung erkennen


93

Wie kann ich die Unterstützung für WebP über Javascript erkennen? Wenn möglich, würde ich lieber die Feature-Erkennung als die Browser-Erkennung verwenden, aber ich kann keinen Weg finden, dies zu tun. Modernizr ( www.modernizr.com ) prüft nicht darauf.


1
Wenn Sie ein solches Bild in ein Bildelement laden und dann Breite und Höhe in einem Browser überprüfen, der das Format nicht unterstützt, erhalten Sie etwas?
Pointy

(Ich meinte „Bildobjekt “, nicht Element, wie „neues Bild ()“ ...)
Zipfel

Sieht gut aus. Auf diese Weise kann ich ein "Ich unterstütze WebP" erhalten. Ich kann jedoch kein "Ich unterstütze WebP nicht" erhalten.
Snostorm

3
Ich habe eine ähnliche Frage gestellt: Was ist die "offizielle" Empfehlung von Google zum Erkennen der Unterstützung von WebP-Browsern? in der WebP Google-Gruppe.
Mike

2
@ Simon_Weaver die Frage und Kommentare sind alle mehrere Jahre alt. Alte Fragen werden selten in nennenswerter Weise "gepflegt"; Sie können jedoch jederzeit eine neue Antwort hinzufügen.
Pointy

Antworten:


117

Dies ist meine Lösung - dauert ungefähr 6 ms und ich denke, WebP ist nur eine Funktion für einen modernen Browser. Verwendet einen anderen Ansatz mit der Funktion canvas.toDataUrl () anstelle von image, um die Funktion zu erkennen:

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
Dies sollte die akzeptierte Antwort sein, da alle anderen eine Verzögerung haben, weil sie auf eine Netzwerkressource oder einen Daten-URI verweisen
hasalanga perera 2.

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

34
Dies funktioniert nicht in Firefox 65, das das Anzeigen von Webp unterstützt, aber keine Webp-Daten-URL aus einem Canvas-Element erstellt.
Carlcheel

4
Ich liebe das, weil es synchron ist, aber @carlcheel ist korrekt. FF 65 (das Webp-Unterstützung hat) gibt hier immer noch false zurück :-(
RoccoB

10
Dies wäre großartig, wenn es für FF65 und Edge18 funktionieren würde. Beide unterstützen webp, serialisieren aber die Zeichenfläche mit "data: image / png"
undefinederror

55

Ich denke so etwas könnte funktionieren:

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

In Firefox und IE wird der "Onload" -Handler überhaupt nicht aufgerufen, wenn das Bild nicht verstanden werden kann, und stattdessen wird der "Onerror" aufgerufen.

Sie haben jQuery nicht erwähnt, aber als Beispiel für den Umgang mit der Asynchronität dieser Prüfung können Sie ein jQuery-Objekt "Zurückgestellt" zurückgeben:

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

Dann könnten Sie schreiben:

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

Hier ist ein jsfiddle-Beispiel.


Ein erweiterter Prüfer: http://jsfiddle.net/JMzj2/29/ . Dieser lädt Bilder von einer Daten-URL und prüft, ob sie erfolgreich geladen wurden. Da WebP jetzt auch verlustfreie Bilder unterstützt, können Sie überprüfen, ob der aktuelle Browser nur verlustbehaftetes WebP oder auch verlustfreies WebP unterstützt. (Hinweis: Dies überprüft implizit auch die Unterstützung von Daten-URLs.)

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

Genial! Dies funktioniert in FF, Chrome und IE 9. Aus irgendeinem Grund funktioniert es nicht in IE8 oder IE7.
Snostorm

Es funktioniert für mich in IE7 - probieren Sie die jsFiddle, die ich gerade mit dem Ende der Antwort verknüpft habe.
Pointy

Nun, meine ursprüngliche Antwort hatte gerade die "Onload" - ich wusste nicht, dass es überhaupt einen "Fehler" für Bildobjekte gibt :-)
Pointy

Oh, duh. Ich habe eine data: url anstelle eines Bildes verwendet, und IE7 unterstützt das nicht. : P
Snostorm

1
Ich habe gerade festgestellt, dass ich IE8 dazu bringen kann, ordnungsgemäß mit data: urls zu arbeiten, und IE7 dazu bringen kann, einen Fehler dafür auszulösen. Das Problem war, dass sie sie nicht direkt in Javascript unterstützen. Siehe: jsfiddle.net/HaLXz
Snostorm

36

Bevorzugte Lösung in HTML5

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

Wiki auf W3C


2
Funktioniert einwandfrei, das type="image/webp"ist wichtig, damit der Browser es bei unbekanntem Format überspringen kann!
AdrianTNT

5
Dies ist gut, funktioniert jedoch nicht für Hintergrundbilder. Wenn Sie WebP an einer Site nachrüsten, müssen Sie Ihr HTML ändern. Dies bedeutet auch, dass Sie alle Stellen in Ihrem CSS ändern müssen, die auf das img-Tag verweisen.
Kloddant

1
Ja, dies ist die beste Lösung für das Problem. Danke
Janith

Unterstützen alle Browser, die webp unterstützen, auch das Bildelement?
Molerat

21

Offizieller Weg von Google:

Da einige alte Browser Webp teilweise unterstützen , ist es besser, genauer anzugeben, welche Webp-Funktion Sie verwenden und diese bestimmte Funktion erkennen möchten. Hier ist die offizielle Empfehlung von Google, wie eine bestimmte Webp-Funktion erkannt werden kann:

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

Anwendungsbeispiel:

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

Beachten Sie, dass das Laden von Bildern nicht blockierend und asynchron ist . Dies bedeutet, dass jeder Code, der von der WebP-Unterstützung abhängt, vorzugsweise in die Rückruffunktion eingefügt werden sollte.

Beachten Sie auch, dass andere synchrone Lösungen mit Firefox 65 nicht gut funktionieren



12

Hier ist eine Version von James Westgates Antwort in 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: falsch

FF65: wahr

Chrome: stimmt

Ich mag die synchrone Antwort von Rui Marques, aber leider gibt FF65 trotz der Fähigkeit, WebP anzuzeigen, immer noch false zurück.


8

Hier ist Code, ohne ein Bild anfordern zu müssen. Aktualisiert mit der neuen Geige von 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
Das war für mich völlig kaputt. Ich gabelte es und ließ es funktionieren: jsfiddle.net/z6kH9
qwerty

Funktioniert das in allen Browsern? Ich beziehe mich auf die Probleme anderer Lösungen in Safari + FF65 +.
Molerat

Ich denke, dies ist die beste Lösung. Ich würde immer noch gerne die Tests auf älteren Browsern und Browsern sehen, die WebP nicht unterstützen.
Kostanos

5

WebPJS verwendet eine intelligentere Erkennung der WebP-Unterstützung, ohne dass externe Bilder erforderlich sind: http://webpjs.appspot.com/


Das Skript, mit dem sie ihre Datei laden, kann verwendet werden, ohne ihre Datei tatsächlich zu verwenden. Ersetzen Sie einfach das Innere durch das, was Sie tun möchten, wenn keine WebP-Unterstützung vorhanden ist.
Tgrosinger

1
Es sieht so aus, als würden sie Daten-URLs verwenden, mit denen ich letztendlich gearbeitet habe.
Snostorm

4

Ich habe festgestellt, dass die Erkennung von Webp-Unterstützungsfunktionen 300 + ms erfordert, wenn die Seite JavaScript-lastig ist. Also habe ich ein Skript mit Caching-Funktionen geschrieben:

  • Skript-Cache
  • lokaler Speichercache

Es wird nur einmal erkannt, wenn der Benutzer zum ersten Mal auf die Seite zugreift.

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

Es gibt eine Möglichkeit, die webP-Unterstützung sofort zu testen . Es ist synchron und genau, sodass Sie nicht auf einen Rückruf warten müssen, um Bilder zu rendern.

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

Diese Methode hat meine Renderzeit dramatisch verbessert


5
funktioniert nicht mit Firefox ... das unterstützt, image/webpaber in diesem Fall false zurückgibt (funktioniert aber sowohl mit Safari als auch mit Chrome korrekt)
a14m

2

Hier ist eine einfache Funktion mit Promise, die auf Pointys Antwort basiert

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

Während dieser Code die Frage möglicherweise beantwortet, würde die Bereitstellung eines zusätzlichen Kontexts darüber, wie und / oder warum das Problem gelöst wird, den langfristigen Wert der Antwort verbessern.
Nic3500

Ich dachte, es ist ziemlich klar, wir versuchen, ein Webp-Image aus einer Base64-Zeichenfolge (die 1 Pixel breit und hoch ist) zu laden. Wenn wir es richtig geladen haben (Onload genannt), wird es unterstützt, wenn nicht (Onerror genannt), wird es einfach, ich habe es einfach verpackt in einem Versprechen.
Liron Navon

2

Meine Kurzversion. Ich habe es verwendet, um Browser webP oder jpg / png zu geben.

Google isst das und das alte iPhone (f̶u̶c̶k̶i̶n̶g̶ ̶s̶h̶e̶e̶t̶ -safari) funktioniert auch großartig!

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

WebP-Bilder mit htaccess

Fügen Sie Folgendes in Ihre .htaccessDatei ein, und JPG / PNG-Bilder werden durch WebP-Bilder ersetzt, wenn sie sich im selben Ordner befinden.

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

Lesen Sie hier mehr


1

Webp-Erweiterung JavaScript erkennen und ersetzen:

 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

Mit der Antwort von @ Pointy ist dies für 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

Verbesserte Version für Firefox basierend auf Rui Marques. Ich habe den Scan für die verschiedenen Zeichenfolgen basierend auf Kommentaren zu dieser Antwort hinzugefügt.

Wenn diese Verbesserung von der Community akzeptiert wird, sollte sie in dieser Antwort bearbeitet werden.

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;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.