การตรวจจับการรองรับ WebP


99

ฉันจะตรวจสอบการรองรับ WebP ผ่าน Javascript ได้อย่างไร ฉันต้องการใช้การตรวจจับคุณสมบัติมากกว่าการตรวจจับเบราว์เซอร์หากเป็นไปได้ แต่ฉันหาวิธีทำไม่ได้ Modernizr ( www.modernizr.com ) ไม่ได้ตรวจสอบ


1
หากคุณโหลดภาพดังกล่าวลงในองค์ประกอบรูปภาพจากนั้นตรวจสอบความกว้างและความสูงในเบราว์เซอร์ที่ไม่รองรับรูปแบบคุณจะได้อะไรไหม
Pointy

(ฉันหมายถึง " วัตถุรูปภาพ" ไม่ใช่องค์ประกอบเช่น "รูปภาพใหม่ ()" ... )
Pointy

ดูดี. ฉันสามารถขอรับ "ฉันสนับสนุน WebP" ด้วยวิธีนี้ แต่ฉันไม่สามารถรับ "ฉันไม่รองรับ WebP"
dieki


2
@Simon_Weaver คำถามและความคิดเห็นทั้งหมดมีอายุหลายปี คำถามเก่า ๆ มักไม่ค่อย "คงไว้" ในลักษณะสำคัญใด ๆ อย่างไรก็ตามคุณสามารถเพิ่มคำตอบใหม่ได้ตลอดเวลา
Pointy

คำตอบ:


120

นี่คือวิธีแก้ปัญหาของฉัน - ใช้เวลาประมาณ 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 perera

6
เวอร์ชันย่อ:webp = e => document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
António Almeida

41
สิ่งนี้ใช้ไม่ได้ใน Firefox 65 ซึ่งรองรับการแสดง webp แต่จะไม่สร้าง url ข้อมูล webp จากองค์ประกอบ canvas
carlcheel

4
รักสิ่งนี้เพราะมันซิงโครนัส แต่ @carlcheel ถูกต้อง FF 65 (ที่รองรับ webp) ยังคงแสดงผลเท็จที่นี่ :-(
RoccoB

13
สิ่งนี้จะดีมากถ้ามันใช้ได้กับ 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 ที่สูญหายหรือไม่ (หมายเหตุ: สิ่งนี้จะตรวจสอบการรองรับ 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
dieki

มันใช้ได้กับฉันใน IE7 - ลองใช้ jsFiddle ที่ฉันเพิ่งเชื่อมโยงไปยังจุดสิ้นสุดของคำตอบ
Pointy

คำตอบเดิมของฉันมีเพียง "onload" - ฉันไม่รู้ว่ามี "onerror" สำหรับวัตถุรูปภาพด้วยซ้ำ :-)
Pointy

โอ้ duh. ฉันใช้ data: url แทนรูปภาพและ IE7 ไม่รองรับ : P
dieki

1
ฉันเพิ่งรู้ว่าฉันสามารถทำให้ IE8 ทำงานอย่างถูกต้องกับ data: urls และรับ IE7 เพื่อส่งข้อผิดพลาด ปัญหาคือพวกเขาไม่สนับสนุนโดยตรงในจาวาสคริปต์ ดู: jsfiddle.net/HaLXz
dieki

38

โซลูชันที่ต้องการใน HTML5

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

Wiki บน W3C


2
ทำงานได้อย่างสมบูรณ์type="image/webp"เป็นสิ่งสำคัญเพื่อให้เบราว์เซอร์ข้ามไปหากไม่ทราบรูปแบบ!
adrianTNT

7
นี่เป็นสิ่งที่ดี แต่ใช้ไม่ได้กับภาพพื้นหลังและหากคุณกำลังติดตั้ง webp ไปยังไซต์และจำเป็นต้องแก้ไข html ของคุณซึ่งหมายถึงการแก้ไขสถานที่ทั้งหมดใน css ของคุณที่อ้างอิงแท็ก img
kloddant

1
ใช่นี่เป็นทางออกที่ดีที่สุดสำหรับปัญหา ขอบคุณ
Janith

เบราว์เซอร์ทั้งหมดที่รองรับ webp รองรับ picture-element ด้วยหรือไม่
Molerat

1
แม้ว่า HTML5 ดั้งเดิมจะดีกว่า แต่เบราว์เซอร์ส่วนใหญ่จะโหลดทั้ง JPG และ WEBP ซึ่งส่งผลเสียต่อเวลาในการดาวน์โหลด เจาะลึก: smashingmagazine.com/2013/05/…
Jan Werkhoven

25

วิธีอย่างเป็นทางการโดย Google:

เนื่องจากเบราว์เซอร์รุ่นเก่าบางตัวมีการรองรับ webp บางส่วนดังนั้นจึงเป็นการดีกว่าที่จะระบุคุณลักษณะ webp ที่คุณพยายามใช้และตรวจพบคุณลักษณะเฉพาะนี้ให้เจาะจงมากขึ้นและนี่คือคำแนะนำอย่างเป็นทางการของ Googleสำหรับวิธีตรวจหาคุณลักษณะ webp ที่เฉพาะเจาะจง:

// 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ได้ไม่ดี


17

นี่เป็นคำถามเก่า แต่ Modernizr รองรับการตรวจจับ Webp แล้ว

http://modernizr.com/download/

มองหาimg-webpภายใต้การตรวจจับที่ไม่ใช่คอร์


1
แหล่งที่มามีประโยชน์ในการดูว่าพวกเขาทำอะไรgithub.com/Modernizr/Modernizr/blob/…
Simon_Weaver

สำหรับฉันมันทำงานได้ค่อนข้างน่าเชื่อถือและช่วยให้คุณสามารถทำงานกับคลาส css .webp และ. no-webp เพื่อความยืดหยุ่นมากขึ้น
Molerat

13

นี่คือคำตอบของ James Westgate ใน 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: เท็จ

FF65: จริง

Chrome: จริง

ฉันชอบคำตอบแบบซิงโครนัสจาก Rui Marques แต่น่าเสียดายที่ FF65 ยังคงส่งคืนเท็จแม้ว่าจะมีความสามารถในการแสดง WebP


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
qwerty

สิ่งนี้จะใช้ได้กับทุกเบราว์เซอร์หรือไม่ ฉันกำลังอ้างถึงปัญหาของโซลูชันอื่น ๆ ใน Safari + FF65 +
Molerat

ฉันคิดว่าอันนี้เป็นทางออกที่ดีที่สุด ยังคงต้องการดูการทดสอบบนเบราว์เซอร์รุ่นเก่าและเบราว์เซอร์ที่ไม่รองรับ webp
Kostanos

5

WebPJS ใช้การตรวจจับการสนับสนุน WebP ที่ชาญฉลาดขึ้นโดยไม่ต้องใช้ภาพภายนอก: http://webpjs.appspot.com/


สคริปต์ที่ใช้โหลดไฟล์สามารถใช้ได้โดยไม่ต้องใช้ไฟล์จริงๆ เพียงแค่แทนที่ด้านในด้วยสิ่งที่คุณต้องการทำหากไม่มีการรองรับ WebP
tgrosinger

1
ดูเหมือนว่าพวกเขากำลังใช้ data url ด้วยคือสิ่งที่ฉันใช้
dieki

5

ฉันพบว่าคุณสมบัติการสนับสนุน webp ตรวจจับต้องใช้ 300 + ms เมื่อหน้า JavaScript หนัก ดังนั้นฉันจึงเขียนสคริปต์ที่มีคุณสมบัติการแคช:

  • แคชสคริปต์
  • แคช 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

/* 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. :) -->


2

ไม่มีทางที่จะทดสอบการสนับสนุน 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แต่ส่งคืนเท็จในกรณีนี้ (แต่ใช้ได้ทั้งบน Safari และ Chrome อย่างถูกต้อง)
a14m

2

นี่คือฟังก์ชั่นง่ายๆที่มี Promise ตามการตอบสนองของ 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
  })
}

แม้ว่ารหัสนี้อาจตอบคำถามได้ แต่การให้บริบทเพิ่มเติมเกี่ยวกับวิธีการและ / หรือเหตุผลในการแก้ปัญหาจะช่วยเพิ่มมูลค่าในระยะยาวของคำตอบ
Nic3500

ฉันคิดว่ามันค่อนข้างชัดเจนเราพยายามโหลดภาพ webp จากสตริง base64 (ซึ่งกว้างและสูง 1px) ถ้าเราโหลดอย่างถูกต้อง (เรียกว่า onload) มันได้รับการสนับสนุนถ้าไม่ (เรียกว่า onerror) มันไม่ใช่ฉันก็แค่ห่อมัน ในสัญญา
Liron Navon

2

ฉบับย่อของฉัน ฉันใช้มันเพื่อให้ webP เบราว์เซอร์หรือ jpg / png

Google กินสิ่งนี้และ iPhone รุ่นเก่า (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')
      }
      
})


1

ภาพ 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}/$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');
  }
})();

1

เวอร์ชันปรับปรุงเพื่อรองรับ Firefox ที่ใช้ Rui Marques ฉันเพิ่มการสแกนสำหรับสตริงต่างๆตามความคิดเห็นของคำตอบนั้น

หากการปรับปรุงนี้ได้รับการยอมรับจากชุมชนควรแก้ไขในคำตอบนั้น

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

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);
            }
        }
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.