如何在 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 returns false
和 IE11 虽然有 Emoji 但没有颜色返回 true
.
编辑:
(正如评论中所指出的)Modernizr has a similar detection 表情符号 - 所以你也可以试一试
如果有人正在寻找图书馆,那么这里就是 if-emoji
。它使用的方法与 Roko 在他的回答中使用的方法相同。
国旗表情符号对于此处发布的答案来说有点极端。因为如果设备不支持国旗表情符号,则会呈现国家代码的回退。例如。英国国旗 () 将变为 -> GB。
Windows10不支持Emoji Flags
此脚本使用与现有答案类似的方法,但会检查 canvas 是否为灰度。如果 canvas 中有颜色,我们就知道呈现了表情符号。
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)。它 returns 对于不受支持的字形是正确的,对于不覆盖中心像素但实际上已呈现 (☹) 的表情符号似乎并不准确。
我的系统绘制的不受支持的字形,看似可以互换,是: and 。当然第一个的中心像素是不透明的,也许这就是原因。
另一种方法是将不受支持的字形绘制成 canvas(您可以使用 \uFFFF,它是一个保证非字符,请参阅 https://en.wikipedia.org/wiki/Specials_(Unicode_block)),然后是“校验和”或实际上只需对 getImageData()
的结果求和,然后根据这些数字检查您的表情符号。这样您就不会依赖字形的实现,只要系统显示 'not found' 符号即可。 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)
}
我想将表情符号添加到我的网站,但如果平台不支持它们,则隐藏它们,而不是显示小方块。
我觉得这不可能,但有人不同意吗?如何做到这一点?
绘制一个字形(在供应商最流行的表情符号范围内,在 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 returns false
和 IE11 虽然有 Emoji 但没有颜色返回 true
.
编辑:
(正如评论中所指出的)Modernizr has a similar detection 表情符号 - 所以你也可以试一试
如果有人正在寻找图书馆,那么这里就是 if-emoji
。它使用的方法与 Roko 在他的回答中使用的方法相同。
国旗表情符号对于此处发布的答案来说有点极端。因为如果设备不支持国旗表情符号,则会呈现国家代码的回退。例如。英国国旗 () 将变为 -> GB。
Windows10不支持Emoji Flags
此脚本使用与现有答案类似的方法,但会检查 canvas 是否为灰度。如果 canvas 中有颜色,我们就知道呈现了表情符号。
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)。它 returns 对于不受支持的字形是正确的,对于不覆盖中心像素但实际上已呈现 (☹) 的表情符号似乎并不准确。
我的系统绘制的不受支持的字形,看似可以互换,是:
另一种方法是将不受支持的字形绘制成 canvas(您可以使用 \uFFFF,它是一个保证非字符,请参阅 https://en.wikipedia.org/wiki/Specials_(Unicode_block)),然后是“校验和”或实际上只需对 getImageData()
的结果求和,然后根据这些数字检查您的表情符号。这样您就不会依赖字形的实现,只要系统显示 'not found' 符号即可。 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)
}