Javascript를 통해 WebP에 대한 지원을 어떻게 감지 할 수 있습니까? 가능하면 브라우저 감지 대신 기능 감지를 사용하고 싶지만 방법을 찾을 수 없습니다. Modernizr ( www.modernizr.com )는 그것을 확인하지 않습니다.
Javascript를 통해 WebP에 대한 지원을 어떻게 감지 할 수 있습니까? 가능하면 브라우저 감지 대신 기능 감지를 사용하고 싶지만 방법을 찾을 수 없습니다. Modernizr ( www.modernizr.com )는 그것을 확인하지 않습니다.
답변:
이것은 내 솔루션입니다-약 6ms가 걸리고 WebP는 최신 브라우저의 기능 일 뿐이라고 생각합니다. 기능을 감지하는 방법으로 이미지 대신 canvas.toDataUrl () 함수를 사용하는 다른 접근 방식을 사용합니다.
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;
}
}
webp = e => document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
나는 이것이 효과가 있다고 생각합니다.
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 "Deferred"객체를 반환 할 수 있습니다.
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");
});
선호하는 솔루션 HTML5
<picture>
<source srcset="/path/to/image.webp" type="image/webp">
<img src="/path/to/image.jpg" alt="insert alt text here">
</picture>
type="image/webp"
브라우저가 형식을 알 수없는 경우 건너 뛰기 위해서는는 매우 중요합니다!
Google의 공식 방법 :
일부 오래된 브라우저는 webp를 부분적으로 지원하므로이 특정 기능을 사용하고 감지하려는 webp 기능을 더 구체적으로 지정하는 것이 좋습니다 . 특정 webp 기능을 감지하는 방법에 대한 Google의 공식 권장 사항 은 다음과 같습니다 .
// 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];
}
사용 예 :
check_webp_feature('lossy', function (feature, isSupported) {
if (isSupported) {
// webp is supported,
// you can cache the result here if you want
}
});
이미지 로딩은 비 차단적이고 비동기 적 입니다. 이는 WebP 지원에 의존하는 모든 코드를 콜백 함수에 넣는 것이 바람직하다는 것을 의미합니다.
또한 다른 동기식 솔루션은 Firefox 65에서 제대로 작동하지 않습니다.
이것은 오래된 질문이지만 Modernizr는 이제 Webp 탐지를 지원합니다.
http://modernizr.com/download/
img-webp
비 핵심 감지 항목을 찾습니다 .
다음은 ES6에서 James Westgate의 답변 버전입니다.
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 : 거짓
FF65 : 참
크롬 : 참
나는 Rui Marques의 동기식 대답을 좋아하지만 불행히도 FF65는 WebP를 표시 할 수있는 기능이 있음에도 불구하고 여전히 false를 반환합니다.
다음은 이미지를 요청하지 않아도되는 코드입니다. qwerty의 새로운 바이올린으로 업데이트되었습니다.
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';
});
WebPJS는 외부 이미지없이 더 스마트 한 WebP 지원 감지 기능을 사용합니다. http://webpjs.appspot.com/
webp 지원 기능 감지는 페이지가 JavaScript가 많을 때 300 + ms가 필요하다는 것을 발견했습니다. 그래서 캐싱 기능이 있는 스크립트 를 작성 했습니다 .
사용자가 페이지에 처음 액세스 할 때 한 번만 감지합니다.
/**
* @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();
});
};
})();
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;
}
이 방법은 렌더링 시간을 크게 향상 시켰습니다.
image/webp
하지만이 경우 false를 반환합니다 (그러나 Safari와 Chrome에서 올바르게 작동 함)
다음은 Pointy의 응답을 기반으로 Promise를 사용한 간단한 기능입니다.
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
})
}
내 짧은 버전. 브라우저 webP 또는 jpg / png를 제공하는 데 사용됩니다.
구글은 이것을 먹고, 오래된 아이폰 (f̶u̶c̶k̶i̶n̶g̶ ̶s̶h̶e̶e̶t̶ -safari)도 잘 작동합니다!
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')
}
})
/* 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. :) -->
htaccess가있는 WebP 이미지
다음을 .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}/$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>
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의 대답을 사용하면 다음과 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);
}
}
}
}
Rui Marques를 기반으로 Firefox를 처리하도록 개선 된 버전. 그 대답에 대한 주석을 기반으로 다른 문자열에 대한 스캔을 추가했습니다.
이 개선 사항이 커뮤니티에서 수락되면 해당 답변에서 편집해야합니다.
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;
}