WebP 지원 감지


95

Javascript를 통해 WebP에 대한 지원을 어떻게 감지 할 수 있습니까? 가능하면 브라우저 감지 대신 기능 감지를 사용하고 싶지만 방법을 찾을 수 없습니다. Modernizr ( www.modernizr.com )는 그것을 확인하지 않습니다.


1
이러한 이미지를 Image 요소에로드 한 다음 해당 형식을 지원 하지 않는 브라우저에서 너비와 높이를 확인 하면 아무것도 얻지 못합니까?
Pointy

( 요소가 아닌 "이미지 객체 "를 의미 합니다 . "new Image ()"와 같이 ...)
Pointy

좋아 보인다. 이 방법으로 "WebP를 지원합니다"를 얻을 수 있습니다. 하지만 "WebP를 지원하지 않습니다"라는 메시지가 표시되지 않습니다.
snostorm 2011


2
@Simon_Weaver 질문과 의견은 모두 몇 년 전입니다. 오래된 질문은 중요한 방식으로 거의 "유지"되지 않습니다. 그러나 항상 새로운 답변을 추가 할 수 있습니다.
Pointy

답변:


118

이것은 내 솔루션입니다-약 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;
 }
}

7
때문에 네트워크 리소스 또는 데이터 URI를 가리키는 지연이 다른 모든 때문에, 허용 대답해야한다
imal hasaranga 페레라

6
단순화 된 버전 :webp = e => document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
António Almeida

35
webp 표시를 지원하는 Firefox 65에서는 작동하지 않지만 canvas 요소에서 webp 데이터 URL을 만들지 않습니다.
carlcheel

4
동기식이기 때문에 이것을 좋아하지만 @carlcheel은 정확합니다. (WebP 형식 지원을 가지고) FF (65)는 여전히 :-( 여기 false를 반환
RoccoB

11
은 FF65 및 Edge18 근무하면 좋을. 둘 다 webp를 지원하지만 "data : image / png"로 캔버스를 직렬화합니다.
undefinederror

55

나는 이것이 효과가 있다고 생각합니다.

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

다음은 jsfiddle 예제입니다.


고급 검사기 : 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");
});

대박! 이것은 FF, Chrome 및 IE 9에서 작동합니다. 어떤 이유로 IE8 또는 IE7에서는 작동하지 않습니다.
snostorm

IE7에서 저에게 효과적입니다-방금 답변의 끝에 연결된 jsFiddle을 사용해보십시오.
Pointy

글쎄, 내 원래 대답은 "onload"였습니다.
Pointy

오, 이런. 이미지 대신 data : url을 사용했는데 IE7은이를 지원하지 않습니다. : P
snostorm 2011

1
나는 IE8이 data : urls로 제대로 작동하도록 할 수 있다는 것을 깨달았습니다. 그리고 IE7이 그것에 대한 오류를 던지도록합니다. 문제는 그들이 자바 스크립트에서 직접 지원하지 않는다는 것입니다. 참조 : jsfiddle.net/HaLXz
snostorm 2011

36

선호하는 솔루션 HTML5

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

W3C의 위키


2
완벽하게 작동합니다. type="image/webp"브라우저가 형식을 알 수없는 경우 건너 뛰기 위해서는는 매우 중요합니다!
adrianTNT 2018

6
이것은 좋지만 배경 이미지에는 작동하지 않으며 webp를 사이트에 개조하고 html을 수정해야하는 경우 img 태그를 참조하는 CSS의 모든 위치를 수정해야합니다.
kloddant

1
예, 이것이 문제에 대한 최상의 솔루션입니다. 감사합니다
Janith

webp를 지원하는 모든 브라우저가 그림 요소도 지원합니까?
molerat

22

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에서 제대로 작동하지 않습니다.



12

다음은 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를 반환합니다.


8

다음은 이미지를 요청하지 않아도되는 코드입니다. 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
그것은 나를 위해 완전히 망가졌습니다. 나는 그것을 포크와 만든 그것은 작동 : jsfiddle.net/z6kH9
쿼티

모든 브라우저에서 작동합니까? Safari + FF65 +의 다른 솔루션 문제를 언급하고 있습니다.
molerat

이것이 최선의 해결책이라고 생각합니다. 그래도 이전 브라우저 및 webp를 지원하지 않는 브라우저에서 테스트를보고 싶습니다.
Kostanos

5

WebPJS는 외부 이미지없이 더 스마트 한 WebP 지원 감지 기능을 사용합니다. http://webpjs.appspot.com/


파일을로드하는 데 사용하는 스크립트는 실제로 파일을 사용하지 않고도 사용할 수 있습니다. WebP 지원이 없으면 내부를 원하는대로 교체하십시오.
tgrosinger 2011

1
그들이 데이터 URL을 사용하고있는 것 같습니다.
snostorm

4

webp 지원 기능 감지는 페이지가 JavaScript가 많을 때 300 + ms가 필요하다는 것을 발견했습니다. 그래서 캐싱 기능이 있는 스크립트 를 작성 했습니다 .

  • 스크립트 캐시
  • localstorage 캐시

사용자가 페이지에 처음 액세스 할 때 한 번만 감지합니다.

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

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

이 방법은 렌더링 시간을 크게 향상 시켰습니다.


5
Firefox에서 작동하지 않습니다 ... 지원 image/webp하지만이 경우 false를 반환합니다 (그러나 Safari와 Chrome에서 올바르게 작동 함)
a14m

2

다음은 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
  })
}

이 코드가 질문에 답할 수 있지만 문제를 해결하는 방법 및 / 또는 이유에 대한 추가 컨텍스트를 제공하면 답변의 장기적인 가치가 향상됩니다.
Nic3500

나는 그것이 매우 명확하다고 생각했고, 우리는 base64 문자열 (폭이 1px이고 높이가 1px)에서 webp 이미지를로드하려고 시도합니다. 올바르게로드하면 (onload 호출 됨) 지원됩니다. 그렇지 않은 경우 (onerror 호출 됨) 그렇지 않으면 단순히 래핑했습니다. 약속에.
Liron Navon 19

2

내 짧은 버전. 브라우저 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')
      }
      
})


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

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>

여기에서 더 많은 것을 읽으 십시오


1

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

0

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

0

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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.