Detecting WebP support
Asked Answered
P

22

131

How can I detect support for WebP via Javascript? I'd like to use feature detection rather than browser detection if possible, but I can't find a way to do so. Modernizr (www.modernizr.com) doesn't check for it.

Pines answered 6/4, 2011 at 21:20 Comment(10)
If you load such an image into an Image element, and then check width and height in a browser that doesn't support the format, do you get anything?Same
(I meant "Image object", not element; like, "new Image()" ... )Same
Looks good. I can get a "I do support WebP" this way; but I can't get a "I do not support WebP".Pines
I have posted a similar question: What is Google's "official" recommendation for detecting WebP browser support? on the WebP Google group.Tel
This is better: queryj.wordpress.com/2012/06/11/detecting-webp-supportBastion
@Tel There is an official Google Dev Note for this now.Macdermot
If you'd like Firefox to implement native WebP, you could vote for this issue in their bug tracker.Clad
These answers are absolutely nuts. This is the modern web is it?!Cyst
@Cyst the question and comments are all several years old. Old questions are rarely "maintained" in any significant way; you're always free to add a new answer however.Same
I don't know if it's new, but modernizer check for it now: modernizr.com/download?webp-setclasses&q=webpTruc
A
173

This is my solution - is taking around 6ms and I'm considering WebP is only a feature for a modern browser. Uses a different approach using canvas.toDataUrl() function instead of image as the way to detect the feature:

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;
 }
}
Angleaangler answered 1/12, 2014 at 16:23 Comment(17)
Great! Was using it for canvas anyway, so this is a fast + useful test.Newlywed
This is hands down the best solution. If you are a npm modules kinda guy (or girl), I published a shortened version on this as supports-webpSpook
This should be the accepted answer, because all the others has a delay because of pointing to a network resource or a data URIFlaherty
You should set width and height 1px or toDataURL will be very long in Chrome and Opera.Bonilla
Simplified version: webp = e => document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;Morrismorrison
this is brilliantDribble
This doesn't work in Firefox 65 which supports displaying webp, but not creating a webp data url from a canvas element.Extensometer
Love this because it's synchronous, however @Extensometer is correct. FF 65 (that does have webp support) still returns false here :-(Terryl
This would be great if it worked for FF65 and Edge18. They both support webp but serialize the canvas with "data:image/png"Yuzik
As of macOS BigSur, that adds support for WebP in Safari, this unfortunately also doesn't work in Safari, just like FF65+ the toDataURL('image/webp') produces a PNG.Trager
I looks like this only works on Chrome, this is not very useful...Cosher
this doesn't work with Safari 14. Safari 14 supports webp but this function returns falseCalculate
@Rui - You mentioned this took about 6ms, you can get it down to 1ms by setting the width and height of the canvas to 1 before encoding. For those concerned about safari- TMK some versions of safari which are still widely used (15.?) have webp support but it fails for some images. It was fixed in a later release. For now, I end up skipping webp on Safari in general.Harkness
this method doesn't work on firefox. check out my answer https://mcmap.net/q/172802/-detecting-webp-supportWellthoughtof
does this work in mobile? it returns false to me in all my browser on an iphoneNaturalistic
It doesn't work for safari, because toDataUrl type 'image/webp' is not supported. But safari can show webp images. So this solution is wrong and not the answer. caniuse.com/…Aegospotami
iOS 16 safari returns falsePatio
V
58

Official way by Google:

Since some old browsers have partial support for webp, so it is better to be more specific which webp feature you are trying to use & detect this specific feature, and here is Google's official recommendation for how to detect a specific webp feature:

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

Example Usage:

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

Note that image-loading is non-blocking and asynchronous. This means that any code that depends on WebP support should preferably be put in the callback function.

Also note that other synchronous solutions won't work well with Firefox 65

Valued answered 11/2, 2019 at 12:57 Comment(0)
S
56

I think something like this might work:

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 and IE, the "onload" handler just won't be called at all if the image can't be understood, and the "onerror" is called instead.

You didn't mention jQuery, but as an example of how to deal with the asynchronous nature of that check you could return a jQuery "Deferred" object:

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

Then you could write:

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

Here is a jsfiddle example.


A more advanced checker: http://jsfiddle.net/JMzj2/29/. This one loads images from a data URL and checks whether it loads successfully. Since WebP now also supports lossless images, you could check whether the current browser supports just lossy WebP or also lossless WebP. (Note: This implicitly also checks for data URL support.)

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");
});
Same answered 6/4, 2011 at 21:52 Comment(13)
Awesome! This works in FF, Chrome, and IE 9. For some reason it isn't working in IE8 or IE7.Pines
It works for me in IE7 - try the jsFiddle I just linked to the end of the answer.Same
Well my original answer just had the "onload" - I didn't know there even was an "onerror" for Image objects :-)Same
Oh, duh. I used a data: url instead of an image, and IE7 doesn't support that. :PPines
Oh well that'd do it :-) I'm a little surprised it didn't bother to call the error handler, but then we're talking about IE7 and it's somewhat amazing when it manages to do anything at all.Same
Well, this answers my original question. But do you have any ideas on detecting this with pure javascript, without the need for the image? That's what I was trying to do with the data: url.Pines
Hmm well my example pulls the real image from Google, and since it's their format they might not mind :-) But no, since the IE's won't understand data URLs, and of course they don't have any way to explicitly tell you they don't know about something invented since they were released, I can't think of any way to do it than by directly trying an image. It's possible that those browsers will cache the image data even though they can't make an image from it ...Same
I just realized that I can get IE8 to work properly with data: urls, and get IE7 to throw an error for it; the problem was that they don't support them directly in javascript. See: jsfiddle.net/HaLXzPines
Hm, alright. I wanted to write a patch to add support to Modernizr, but it has to be JS-only for that. :)Pines
@Pointy: Your deferred code could be tuned quite a bit to only "detect" once (as opposed to every call) by memoizing itself (so it always returns the same promise, instead of generating a new one every time). Just a thought...Rader
@Rader yes that's true; or it could be incorporated into something like Modernizr that would do the memoizing itself.Same
This doesn't seem to be working for Safari on OSX. The below answer does though.Vullo
@SamTolton well this answer is eight years old :)Same
A
53

Preferred solution 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 on W3C

Arlettearley answered 28/10, 2017 at 18:15 Comment(5)
Works perfectly, the type="image/webp" is critical in order for browser to skip it if unknown format !Shameful
This is good, but it doesn't work for background images, and if you are retrofitting webp to a site, and it requires modifying your html, which then also means modifying all the places in your css that reference the img tag.Breast
Yes this is the best solution for the problem. ThanksReshape
Do all browsers that support webp support the picture-element as well?Mendoza
Though the native HTML5 is preferable, most browsers load both the JPG and WEBP, which negatively impacts download times. In depth: smashingmagazine.com/2013/05/…Capitation
G
22

This is an old question, but Modernizr now supports Webp detection.

http://modernizr.com/download/

Look for img-webp under Non-core detects.

Groin answered 23/6, 2014 at 22:5 Comment(3)
The source is useful to see what they did github.com/Modernizr/Modernizr/blob/…Cyst
For me it has worked quite reliably and it allows you to work with css classes .webp and .no-webp for more flexibility.Mendoza
Had to use some custom checking instead of modernizr since I could not find a way how to make it work on modern stack like angular cli (even with ngx-build-plus)Blate
T
19

Here's a version of James Westgate's answer 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: false

FF65: true

Chrome: true

I love the synchronous answer from Rui Marques, but unfortunately FF65 still returns false despite having the ability to display WebP.

Terryl answered 10/1, 2019 at 1:24 Comment(0)
D
12

Here is code without having to request an image. Updated with qwerty's new fiddle.

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';
});
Davison answered 7/6, 2012 at 10:58 Comment(3)
That was completely broken for me. I forked it and made it work: jsfiddle.net/z6kH9Jared
Will this work in all browsers? I'm referring to the issues of other solutions in Safari + FF65+.Mendoza
I think this one is the best solution. Still would like to see the tests on older browsers, and browsers that are not supporting webp.Brendanbrenden
W
5

WebPJS uses smarter WebP support detection with no external images required: http://webpjs.appspot.com/

Windmill answered 20/11, 2011 at 7:35 Comment(2)
The script that they use to load their file can be used without actually using their file. Just replace the inside with whatever you would like to do if there is no WebP support.Rhyolite
It looks like they're using data urls, with is what I ended up using.Pines
P
5

I've found webp support feature detect requires 300+ms when the page is JavaScript heavy. So I wrote a script with caching features:

  • script cache
  • localstorage cache

It will only detect once when user first accessing the page.

/**
 * @fileOverview WebP Support Detect.
 * @author ChenCheng<[email protected]>
 */
(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();
    });
  };

})();
Punchdrunk answered 9/4, 2013 at 9:25 Comment(0)
G
5

/* 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. :) -->
Gotham answered 10/8, 2020 at 9:32 Comment(0)
A
2

WebP images with htaccess

Place the following in your .htaccess file and jpg/png images will be replaced with WebP images if found in the same folder.

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

Read more here

Arlettearley answered 28/10, 2017 at 18:11 Comment(0)
K
2

here is a simple function with Promise based on Pointy's response

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
  })
}
Keslie answered 5/8, 2018 at 13:27 Comment(2)
While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value.Flak
I thought it's pretty clear, we try to load a webp image from base64 string (which is 1px wide and high), if we loaded it properly (onload called) it's supported, if not (onerror called) it's not, I simply wrapped it in a promise.Keslie
T
2

My short version. I'm used it to give browser webP or jpg/png.

Google eat this, and old iphone ( suck-fari ) work great too!

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')
      }
      
})
Twittery answered 6/8, 2019 at 16:58 Comment(0)
P
2

This is a hybrid HTML/Javascript method that will let you determine supported image types in order of preference (your preference). In this example it will return the first supported image type in the browser and checks AVIF, WebP, JpegXL and JPG.

<picture style="display:none;">
<source type=image/avif srcset="data:image/avif;base64,AAAAFGZ0eXBhdmlmAAAAAG1pZjEAAACgbWV0YQAAAAAAAAAOcGl0bQAAAAAAAQAAAB5pbG9jAAAAAEQAAAEAAQAAAAEAAAC8AAAAGwAAACNpaW5mAAAAAAABAAAAFWluZmUCAAAAAAEAAGF2MDEAAAAARWlwcnAAAAAoaXBjbwAAABRpc3BlAAAAAAAAAAQAAAAEAAAADGF2MUOBAAAAAAAAFWlwbWEAAAAAAAAAAQABAgECAAAAI21kYXQSAAoIP8R8hAQ0BUAyDWeeUy0JG+QAACANEkA= 1x">
<source type=image/webp srcset="data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA 1x">
<source type=image/jxl srcset="data:image/jxl;base64,/woAEBAJCAQBACwASxLFgoUJEP3D/wA= 1x">
<img onload=console.log(this.currentSrc.substring(this.currentSrc.indexOf(':')+1,this.currentSrc.indexOf(';'))) src="data:image/jpg;base64,/9j/4AAQSkZJRgABAQIAHAAcAAD/2wBDAAMDAwMDAwMDAwMEBAQEBAYFBQUFBgkGBwYHBgkOCAoICAoIDgwPDAsMDwwWEQ8PERYZFRQVGR4bGx4mJCYyMkP/wgALCAABAAEBAREA/8QAFAABAAAAAAAAAAAAAAAAAAAACf/aAAgBAQAAAABU/wD/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAE/AH//2Q==">
</picture>

You can replace the log function with whatever you need.

Benefits of this approach will be:

  1. you don't have to create and query a bunch of objects in Javascript so it is efficient
  2. The browser doesn't have to fetch any images, they are encoded inline, so it is fast and synchronous. You can stick this in anywhere and have the answer in the next line without callbacks.
  3. The browser will only create an image result for the first supported line, so it is efficient.
  4. It's easy to add future image support by adding one line.
  5. You can order the images for whatever priority you will be using in your application.
  6. You can turn this into individual tests by pruning image types you don't care about.
  7. This should work even when the PICTURE element is not supported, but requires currentSrc, so IE11 will fail.. in which case just test for currentSrc in img or else assume JPG support is baked in always.

EDIT: removed the line break that got into the example, thanks.

Petrochemistry answered 24/2, 2021 at 21:52 Comment(2)
there is an extra line break in the avif example that breaks the functionalityPanamerican
Yeah, but doesn't work for other attributes. e.g. video poster elements.Reginiaregiomontanus
K
1

There is a way to test webP support instantly. It's sync and accurate, so there is no need to wait for a callback to render images.

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

This method improved my rendering time dramatically

Keele answered 9/4, 2018 at 11:20 Comment(1)
doesn't work on Firefox... which supports image/webp but returns false in this case (but works on both Safari and Chrome correctly)Retuse
K
1

Webp extension Detect And Replacement 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');
  }
})();
Kenti answered 9/7, 2018 at 16:46 Comment(0)
B
1

Improved version to handle Firefox based on Rui Marques. I added the scan for the different strings based on comments to that answer.

If this improvement is accepted by the community, it should be edited in to that answer.

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;
}
Bowers answered 15/3, 2020 at 23:11 Comment(2)
Try "elem.toDataURL('image/blablabla')". This also returns png, so this is not a Firefox solution.Sufflate
Also, testString is not defined.Doth
T
1

Great news. It works in Safari.

document.addEventListener('DOMContentLoaded', function() {
  testWebP(document.body)
})

function testWebP(elem) {
  const webP = new Image();
  webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
  webP.onload = webP.onerror = function () {
    webP.height === 2 ? elem.classList.add('webp-true') : elem.classList.add('webp-false')
  }
  console.log(webP)
}

A source: https://gist.github.com/Protoff/d6643387f03d47b44b2d7c3cf7b3e0a0

Tarlatan answered 2/9, 2021 at 10:25 Comment(0)
I
1

Official Google version using async:

// check_webp_feature:
//   'feature' can be one of 'lossy', 'lossless', 'alpha' or 'animation'.
async function check_webp_feature(feature) {
  const kTestImages = {
    lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",
    lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",
    alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",
    animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA",
  };
  const img = new Image();
  return new Promise(resolve => {
    img.addEventListener("load", () => resolve(img.width > 0 && img.height > 0));
    img.addEventListener("error", () => resolve(false));
    img.src = "data:image/webp;base64," + kTestImages[feature];
  });
}

Example usage:

if (await check_webp_feature("lossy")) {
  // webp is supported
});

Official version with more explanation:

https://developers.google.com/speed/webp/faq#in_your_own_javascript

Inclinable answered 29/7, 2023 at 13:12 Comment(0)
M
0

Using @Pointy's answer this is for 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);
            }
        }
    }
}
My answered 9/5, 2018 at 5:52 Comment(0)
A
0

The above solutions may not work in safari and firefox. So I started looking for a more robust solution and stumbled upon a great library about webp support: webp-hero We can take only detectWebpSupport function from this library:

var __awaiter = (this && this.__awaiter) || function(thisArg, _arguments, P, generator) {
  function adopt(value) {
    return value instanceof P ? value : new P(function(resolve) {
      resolve(value);
    });
  }
  return new(P || (P = Promise))(function(resolve, reject) {
    function fulfilled(value) {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    }

    function rejected(value) {
      try {
        step(generator["throw"](value));
      } catch (e) {
        reject(e);
      }
    }

    function step(result) {
      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
    }
    step((generator = generator.apply(thisArg, _arguments || [])).next());
  });
};
var __generator = (this && this.__generator) || function(thisArg, body) {
  var _ = {
      label: 0,
      sent: function() {
        if (t[0] & 1) throw t[1];
        return t[1];
      },
      trys: [],
      ops: []
    },
    f, y, t, g;
  return g = {
    next: verb(0),
    "throw": verb(1),
    "return": verb(2)
  }, typeof Symbol === "function" && (g[Symbol.iterator] = function() {
    return this;
  }), g;

  function verb(n) {
    return function(v) {
      return step([n, v]);
    };
  }

  function step(op) {
    if (f) throw new TypeError("Generator is already executing.");
    while (_) try {
      if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
      if (y = 0, t) op = [op[0] & 2, t.value];
      switch (op[0]) {
        case 0:
        case 1:
          t = op;
          break;
        case 4:
          _.label++;
          return {
            value: op[1],
            done: false
          };
        case 5:
          _.label++;
          y = op[1];
          op = [0];
          continue;
        case 7:
          op = _.ops.pop();
          _.trys.pop();
          continue;
        default:
          if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
            _ = 0;
            continue;
          }
          if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
            _.label = op[1];
            break;
          }
          if (op[0] === 6 && _.label < t[1]) {
            _.label = t[1];
            t = op;
            break;
          }
          if (t && _.label < t[2]) {
            _.label = t[2];
            _.ops.push(op);
            break;
          }
          if (t[2]) _.ops.pop();
          _.trys.pop();
          continue;
      }
      op = body.call(thisArg, _);
    } catch (e) {
      op = [6, e];
      y = 0;
    } finally {
      f = t = 0;
    }
    if (op[0] & 5) throw op[1];
    return {
      value: op[0] ? op[1] : void 0,
      done: true
    };
  }
};

function detectWebpSupport() {
  return __awaiter(this, void 0, void 0, function() {
    var testImageSources, testImage, results;
    return __generator(this, function(_a) {
      switch (_a.label) {
        case 0:
          testImageSources = [
            "data:image/webp;base64,UklGRjIAAABXRUJQVlA4ICYAAACyAgCdASoCAAEALmk0mk0iIiIiIgBoSygABc6zbAAA/v56QAAAAA==",
            "data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA="
          ];
          testImage = function(src) {
            return new Promise(function(resolve, reject) {
              var img = document.createElement("img");
              img.onerror = function(error) {
                return resolve(false);
              };
              img.onload = function() {
                return resolve(true);
              };
              img.src = src;
            });
          };
          return [4 /*yield*/ , Promise.all(testImageSources.map(testImage))];
        case 1:
          results = _a.sent();
          return [2 /*return*/ , results.every(function(result) {
            return !!result;
          })];
      }
    });
  });
}

detectWebpSupport().then(d => console.log('does it support?', d))
Amandaamandi answered 17/9, 2021 at 13:2 Comment(0)
M
0

//* WebP support checking import { useState, useEffect } from "react";

const WebpSupportCheck = (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];
}

const IsWebpSupported = () => {
    const [state, setState] = useState()
    useEffect(() => {

        WebpSupportCheck('lossy', function (feature, isSupported) {
            if (isSupported) {
                setState(true)
            } else {
                setState(false)
            }
        })

    }, [state])
    return state
}

export default IsWebpSupported
Masked answered 23/10, 2021 at 10:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.