Обнаружение файлов WebP поддерживает
Как я могу обнаружить поддержку WebP через Javascript? Я хотел бы использовать определение функции, а не обнаружение браузера, если это возможно, но я не могу найти способ сделать это. Modernizr (www.modernizr.com) не проверяет его.
12 ответов
Я думаю, что-то вроде этого может сработать:
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 и IE обработчик " onload "просто не будет вызываться вообще, если изображение не может быть понято, и вместо этого вызывается" onerror".
вы не упомянули jQuery, но в качестве примера того, как бороться с асинхронным характером этой проверки, вы можете вернуть объект jQuery "отложенный":
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();
}
тогда вы могли бы написать:
hasWebP().then(function() {
// ... code to take advantage of WebP ...
}, function() {
// ... code to deal with the lack of WebP ...
});
более продвинутая проверка:http://jsfiddle.net/JMzj2/29/. Он загружает изображения из URL-адреса данных и проверяет, успешно ли он загружается. Теперь с WebP также поддерживает сжатие без потерь изображений, вы могли бы проверить, является ли текущий браузер поддерживает только с потерями или без потерь файлов WebP также с WebP. (Примечание: это неявно также проверяет поддержку URL-адреса данных.)
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");
});
Это мое решение-занимает около 6 мс, и я считаю, что WebP - это только функция для современного браузера. Использует другой подход, используя canvas.функция toDataUrl () вместо изображения как способ обнаружения функции:
function canUseWebP() {
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;
}
}
Это старый вопрос, но Modernizr теперь поддерживает обнаружение Webp.
http://modernizr.com/download/
искать img-webp
под неосновным обнаруживает.
WebPJS использует интеллектуальное обнаружение поддержки WebP без внешних изображений: http://webpjs.appspot.com/
вот код без необходимости запрашивать изображение (частично взятое из webpjs.appspot.com)
function testWebP(callback) {
var webP = new Image();
webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
webP.onload = webP.onerror = function () {
callback(webP.height === 2);
};
};
function notify(supported) {
console.log((supported) ? "webP supported!" : "webP not supported.");
}
testWebP(notify);
Я обнаружил, что функция поддержки webp detect требует 300 + ms, когда страница тяжелая JavaScript. Так я написал скрипт с функциями кэширования:
- кэш скрипта
- кэш локального хранилища
он будет обнаруживать только один раз, когда пользователь впервые обращается к странице.
/**
* @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();
});
};
})();
предпочтительное решение в HTML5
<picture>
<source srcset="/path/to/image.webp" type="image/webp">
<img src="/path/to/image.jpg" alt="insert alt text here">
</picture>
WebP изображения с htaccess
поместите следующее в ваш .htaccess
изображения файлов и jpg / png будут заменены изображениями WebP, если они находятся в одной папке.
<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}/.webp -f
# Serve WebP image instead
RewriteRule (.+)\.(jpe?g|png)$ .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>
подробнее здесь
есть способ проверить поддержку webP мгновенно. Это синхронизация и точность, поэтому нет необходимости ждать обратного вызова для рендеринга изображений.
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;
}
этот метод значительно улучшил мое время рендеринга
используя ответ @Pointy, это для 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);
}
}
}
}
расширение Webp обнаружение и замена 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');
}
})();
вот простая функция с обещанием, основанным на ответе 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
})
}