繁体   English   中英

如何检测 JavaScript 中对表情符号的渲染支持?

[英]How can I detect rendering support for emoji in JavaScript?

我想将表情符号添加到我的网站,但如果平台不支持它们,则隐藏它们,而不是显示小方块。

我觉得这是不可能的,但有人不同意吗? 如何才能做到这一点?

绘制一个字形(在供应商最流行的表情符号范围内,在 Unicode 联盟的表情符号范围内,如快乐脸、亲吻、悲伤脸等)以canvas并使用getImageData读取像素。 如果您感兴趣的像素的 Alpha 通道data[3]不透明(例如在 ??? 的中心),否则,它可能是一个表情符号😗

 function supportsEmoji () { const ctx = document.createElement("canvas").getContext("2d"); ctx.canvas.width = ctx.canvas.height = 1; ctx.fillText("😗", -4, 4); return ctx.getImageData(0, 0, 1, 1).data[3] > 0; // Not a transparent pixel } console.log( supportsEmoji() );

或类似的东西...

在 Chrome、Firefox、IE11、Edge、Safari 中测试了上述内容
Safari 返回false ,IE11 虽然有 Emoji 但没有颜色返回true


编辑:
(正如评论中所指出的) Modernizr对表情符号有类似的检测- 所以你也可以试一试

旗帜表情符号是这里发布的答案的一个边缘案例。 由于如果设备不支持标志表情符号,则会呈现国家/地区代码的后备。 例如,英国国旗 (🇬🇧) 将变为 -> GB。

Windows 10 不支持表情符号标志。

此脚本使用与现有答案类似的方法,但会检查画布是否为灰度。 如果画布中有颜色,我们就知道渲染了一个表情符号。

 function supportsFlagEmoji () {
    var canvas = document.createElement("canvas");
    canvas.height = 10;
    canvas.width = canvas.height*2;
    var ctx = canvas.getContext("2d");
    ctx.font = canvas.height+"px Arial";
    ctx.fillText("🇬🇧", 0, canvas.height);
    var data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
    var i = 0;
    while(i<data.length) {
        if (data[i] !== data[i+1] || data[i] !== data[i+2]) return true;
        i+=4;
    }
    return false;
}

接受的答案不适用于我的系统(Windows 10/chrome)。 对于不受支持的字形,它返回 true,对于不覆盖中心像素但实际上已渲染 (☹) 的表情符号,它似乎不准确。

我的系统绘制的不受支持的字形,似乎可以互换,是: 在此处输入图片说明 在此处输入图片说明 . 当然第一个的中心像素是不透明的,也许这就是原因。

另一种方法是将不受支持的字形绘制到画布中(您可以使用 \￿ 这是一个有保证的非字符,请参阅https://en.wikipedia.org/wiki/Specials_(Unicode_block) ),然后“校验和”或者只是对getImageData()的结果求和,然后根据这些数字检查您的表情符号。 这样您就不会依赖于字形的实现,只要系统显示“未找到”符号。 Firefox 似乎显示不受支持的表情符号的唯一十六进制代码,因此此方法不适用于该浏览器或类似配置。

第二种方法,更准确但在我的使用中要慢得多,是使用toDataURL()进行比较:

我在运行所有三种方法的片段测试中也包含了“双重不受支持”的表情符号。 作为记录,我现在在 CodePen 的演示中使用“rgb sum”方法来确保输出中不会出现空白表情符号,并且不会错误地过滤掉任何内容。

 var c = document.createElement("canvas") var ctx = c.getContext("2d"); const em = 16; c.width = em; c.height = em; ["\￿", "\￿\￿", "🖤", "☺", "☹", "💀", "☠", "🩴"].forEach(e => console.log(e + ":using center pixel:" + supports(e) + ",using checksum:" + supports2(e) + ",using toDataURL:" + supports3(e))); //using center pixel detection function supports(e) { let ctx = document.createElement("canvas").getContext("2d"); ctx.fillText(e, -2, 4); return ctx.getImageData(0, 0, 1, 1).data[3] > 0; // Not a transparent pixel } //using checksum method function supports2(e) { //https://en.wikipedia.org/wiki/Specials_(Unicode_block) (NON-Character) var unsupported = ["\￿", "\￿\￿"].map(b => { ctx.clearRect(0, 0, em, em); ctx.fillText(b, 0, em); let d = ctx.getImageData(0, 0, em, em).data let sum = d.reduce((acc, cur) => { return acc + cur }) return sum }); ctx.clearRect(0, 0, em, em); ctx.fillText(e, 0, em); let d = ctx.getImageData(0, 0, em, em).data let sum = d.reduce((acc, cur) => { return acc + cur }) return !unsupported.some(b => b == sum) } //using toDataURL() method function supports3(e) { ctx.clearRect(0, 0, em, em); ctx.fillText(e, 0, em); let emo = c.toDataURL() ctx.clearRect(0, 0, em, em); ctx.fillText('\￿', 0, em); let bad1 = c.toDataURL() ctx.clearRect(0, 0, em, em); ctx.fillText('\￿\￿', 0, em); let bad2 = c.toDataURL() return (emo != bad1) && (emo != bad2) }

如果有人正在寻找图书馆,那么这里是一个if-emoji 它使用 Roko 在他的回答中使用的相同方法。

这是一种依赖于表情符号几乎总是方形纵横比(或接近方形纵横比)这一事实的方法。 不支持表情符号的浏览器通常会将它们呈现为一个细长的矩形“”,或者对于字素簇表情符号,将其呈现为一系列字符“♂”。

/** Check if browser probably supports native emoji rendering
 * @param {string} emoji - which emoji to use to test; a multicharacter emoji (grapheme
 *  cluster) will have lower chance of false positives; common emojis (smiley face),
 *  sometimes have unicode alternatives the browser will render
 * @returns {boolean}
 */
function supports_emoji(emoji="🤦🏼‍♂️"){
    const el = document.createElement("div");
    el.style = "position:absolute;visibility:hidden;";
    el.textContent = emoji;
    document.body.appendChild(el);
    const size = el.getBoundingClientRect();
    el.remove();
    // expecting a roughly square emoji; incorrectly rendered grapheme clusters will be
    // rendered as multiple characters (width > height), while single character emojis are
    // usually rendered as a thinner rectangle (height > width)
    const square = Math.abs(1-size.width/size.height);
    return square < .23;
}

作为旁注,您可以考虑使用Noto Emoji 字体,而不用担心检查表情符号支持。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM