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

问题描述 投票:0回答:5

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

我感觉这是不可能的,但是有人不同意吗?这怎么办?

javascript emoji
5个回答
30
投票

将字形(在供应商最流行的表情符号范围内,在 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对于表情符号有类似的检测 - 所以你也可以尝试一下


9
投票

旗帜表情符号对于此处发布的答案来说有点边缘情况。因为如果设备不支持标志表情符号,则会呈现国家/地区代码的回退。例如。英国国旗 (🇬🇧) 将变成 -> 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;
}
console.log(supportsFlagEmoji())


4
投票

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

我的系统绘制的不受支持的字形,看似可以互换,是:。当然,第一个的中心像素是不透明的,也许这就是原因。

另一种方法是将不受支持的字形绘制到画布中(您可以使用 \uFFFF 这是一个有保证的非字符,请参阅https://en.wikipedia.org/wiki/Specials_(Unicode_block)),然后“校验和”或者实际上只是将

getImageData()
的结果相加,然后根据这些数字检查你的表情符号。这样,只要系统显示“未找到”符号,您就不必依赖于字形的实现。 Firefox 似乎显示了不受支持的表情符号的唯一十六进制代码,因此此方法不适用于该浏览器或类似的配置。

第二种方法,更准确,但在我的使用中速度慢得多,是使用

toDataURL()
:

进行比较

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

var c = document.createElement("canvas")
var ctx = c.getContext("2d");
const em = 16;
c.width = em;
c.height = em;

["\uFFFF", "\uFFFF\uFFFF", "🖤", "☺", "☹", "💀", "☠", "🩴"].forEach(e => console.log(e + " isSupported (center pixel method):" + supports(e) + ", (checksum method):" + supports2(e) + ", (toDataURL method):" + 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 = ["\uFFFF", "\uFFFF\uFFFF"].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('\uFFFF', 0, em);
  let bad1 = c.toDataURL()
  ctx.clearRect(0, 0, em, em);
  ctx.fillText('\uFFFF\uFFFF', 0, em);
  let bad2 = c.toDataURL()

  return (emo != bad1) && (emo != bad2)
}


1
投票

如果有人正在寻找图书馆,那么这里就是

if-emoji
。它使用 Roko 在他的答案中使用的相同方法。


0
投票

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

/** 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 字体,而不必担心检查表情符号支持。

© www.soinside.com 2019 - 2024. All rights reserved.