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.

Snostorm
quelle
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;
 }
}
Rui Marques
quelle
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");
});
Spitze
quelle
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

Andrei Krasutski
quelle
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

AbdelHady
quelle
17

Dies ist eine alte Frage, aber Modernizr unterstützt jetzt die Webp-Erkennung.

http://modernizr.com/download/

Suchen Sie img-webpunter Nicht-Kern-Erkennungen.

Jake Wilson
quelle
1
Die Quelle ist nützlich, um zu sehen, was sie getan haben github.com/Modernizr/Modernizr/blob/…
Simon_Weaver
Für mich hat es ziemlich zuverlässig funktioniert und es ermöglicht Ihnen, mit den CSS-Klassen .webp und .no-webp für mehr Flexibilität zu arbeiten.
Molerat
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.

RoccoB
quelle
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';
});
James Westgate
quelle
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/

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

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

Guy Sopher
quelle
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
  })
}
Liron Navon
quelle
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')
      }
      
})

Alexander Sanik
quelle
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. :) -->

Sunday Power Inemesit
quelle
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

Andrei Krasutski
quelle
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');
  }
})();
Grenzenlose isa
quelle
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);
            }
        }
    }
}
Serj Sagan
quelle
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;
}
Jeffrey Simon
quelle