简体   繁体   English

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

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

I want to add emoji to my site, but hide them if they're not supported on the platform, rather than showing little squares.我想将表情符号添加到我的网站,但如果平台不支持它们,则隐藏它们,而不是显示小方块。

I have a feeling that this isn't possible, but does anybody disagree?我觉得这是不可能的,但有人不同意吗? How can this be done?如何才能做到这一点?

Paint a glyph (in the Emoji range that is the one most popular by vendors, in the range of Emojis by the Unicode Consortium like Happy face, Kiss, Sad face etc) to canvas and read a pixel using getImageData .绘制一个字形(在供应商最流行的表情符号范围内,在 Unicode 联盟的表情符号范围内,如快乐脸、亲吻、悲伤脸等)以canvas并使用getImageData读取像素。 If the pixel's Alpha channel data[3] you're interested-in is not transparent (like for example in the center of ???) , else, it might be an Emoji 😗如果您感兴趣的像素的 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() );

or something like that...或类似的东西...

Tested the above in Chrome, Firefox, IE11, Edge, Safari在 Chrome、Firefox、IE11、Edge、Safari 中测试了上述内容
Safari returns false and IE11 although has Emoji but without colors returned true . Safari 返回false ,IE11 虽然有 Emoji 但没有颜色返回true


Edit:编辑:
(As pointed in comments) Modernizr has a similar detection for Emoji - so you might give it also a go (正如评论中所指出的) Modernizr对表情符号有类似的检测- 所以你也可以试一试

The flag emoji are a bit of an edge case to the answers posted here.旗帜表情符号是这里发布的答案的一个边缘案例。 Since if the flag emoji is not supported on a device, a fallback of the country code is rendered instead.由于如果设备不支持标志表情符号,则会呈现国家/地区代码的后备。 Eg the union jack flag (🇬🇧) will become -> GB.例如,英国国旗 (🇬🇧) 将变为 -> GB。

Windows 10 doesn't support the Emoji Flags. Windows 10 不支持表情符号标志。

This script uses a similar method to the existing answer, but instead checks to see if the canvas is greyscale.此脚本使用与现有答案类似的方法,但会检查画布是否为灰度。 If there are colours in the canvas, we know an emoji was rendered.如果画布中有颜色,我们就知道渲染了一个表情符号。

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

The accepted answer isn't working on my system (Windows 10/chrome).接受的答案不适用于我的系统(Windows 10/chrome)。 It returns true for the unsupported glyphs, and it does not appear to be accurate for emojis that don't cover the center pixel but are in fact rendered (☹).对于不受支持的字形,它返回 true,对于不覆盖中心像素但实际上已渲染 (☹) 的表情符号,它似乎不准确。

The unsupported glyphs that my system paints, seemingly interchangeably, are :我的系统绘制的不受支持的字形,似乎可以互换,是: 在此处输入图片说明 and在此处输入图片说明 . . Certainly the center pixel of the first is opaque, perhaps that's why.当然第一个的中心像素是不透明的,也许这就是原因。

An alternate method would be to paint the unsupported glyph into a canvas (you can use \￿ which is a guaranteed non-character, see https://en.wikipedia.org/wiki/Specials_(Unicode_block) ), then "checksum" or really just sum the results of getImageData() , and check your emojis against those numbers.另一种方法是将不受支持的字形绘制到画布中(您可以使用 \￿ 这是一个有保证的非字符,请参阅https://en.wikipedia.org/wiki/Specials_(Unicode_block) ),然后“校验和”或者只是对getImageData()的结果求和,然后根据这些数字检查您的表情符号。 This way you aren't dependent on the implementation of the glyph, as long as the system is displays a 'not found' symbol.这样您就不会依赖于字形的实现,只要系统显示“未找到”符号。 Firefox appears to show a unique hex code of an unsupported emoji, so this method wouldn't work for that browser or similar configurations. Firefox 似乎显示不受支持的表情符号的唯一十六进制代码,因此此方法不适用于该浏览器或类似配置。

A second way, more accurate but far slower in my usage, would be to compare using toDataURL() :第二种方法,更准确但在我的使用中要慢得多,是使用toDataURL()进行比较:

I've included the "double unsupported" emoji as well in the snippet tests that run all three methods.我在运行所有三种方法的片段测试中也包含了“双重不受支持”的表情符号。 For the record, I'm using the "rgb sum" method right now in a demo on CodePen to make sure blank emojis don't appear in the output, and it doesn't filter out anything erroneously.作为记录,我现在在 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) }

In case if someone is looking for a library, then here is the one if-emoji .如果有人正在寻找图书馆,那么这里是一个if-emoji It uses the same approach Roko has used in his answer.它使用 Roko 在他的回答中使用的相同方法。

Here's a method that relies on the fact that emojis are almost always square aspect ratio (or close to it).这是一种依赖于表情符号几乎总是方形纵横比(或接近方形纵横比)这一事实的方法。 Browsers that don't support emojis will usually render them as a thin rectangle, "", or for grapheme cluster emojis, a sequence of characters, "♂".不支持表情符号的浏览器通常会将它们呈现为一个细长的矩形“”,或者对于字素簇表情符号,将其呈现为一系列字符“♂”。

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

As a side note, you may consider using the Noto Emoji font and not worry about checking for emoji support.作为旁注,您可以考虑使用Noto Emoji 字体,而不用担心检查表情符号支持。

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

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