IsChinaByEmoji – A way for browser to detect if a user is from China

phantomathkg1 pts0 comments

isChinaUser/src/isChinaByEmoji.ts at main · yArna/isChinaUser · GitHub

//blob/show" data-turbo-transient="true" />

Skip to content

Search or jump to...

Search code, repositories, users, issues, pull requests...

-->

Search

Clear

Search syntax tips

Provide feedback

--><br>We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Cancel

Submit feedback

Saved searches

Use saved searches to filter your results more quickly

-->

Name

Query

To see all available qualifiers, see our documentation.

Cancel

Create saved search

Sign in

//blob/show;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up

Appearance settings

Resetting focus

You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

{{ message }}

yArna

isChinaUser

Public

Notifications<br>You must be signed in to change notification settings

Fork<br>15

Star<br>420

FilesExpand file tree

main

/isChinaByEmoji.ts

Copy path

Blame<br>More file actions

Blame<br>More file actions

Latest commit

History<br>History<br>History

101 lines (86 loc) · 3.07 KB

main

/isChinaByEmoji.ts

Copy path

Top

File metadata and controls<br>Code

Blame

101 lines (86 loc) · 3.07 KB

Raw<br>Copy raw file<br>Download raw file

Open symbols panelEdit and raw actions

10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34

35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br>53<br>54<br>55<br>56<br>57<br>58<br>59<br>60<br>61<br>62<br>63<br>64<br>65<br>66<br>67<br>68<br>69<br>70<br>71<br>72<br>73<br>74<br>75<br>76<br>77<br>78<br>79<br>80<br>81<br>82<br>83<br>84<br>85<br>86<br>87<br>88<br>89<br>90<br>91<br>92<br>93<br>94<br>95<br>96<br>97

98<br>99<br>100<br>101

/** 通过 Emoji 判断当前设备是否是中国大陆用户

* 如果 🇹🇼 字符无法彩色显示(渲染为黑白字母或完全不渲染),说明更像中国大陆设备

* 为了避免误报,会先用 😀 做对照:

* 如果设备连普通 Emoji 都无法彩色渲染(如无彩色 Emoji 字体的 Linux、

* 开启指纹保护的浏览器),返回 null 表示无法判断,而不是误报为 true

* 如果是 Windows 环境,不能通过此方法判断,因为 Windows 所有国旗 Emoji 都不支持显示 */

export function isChinaByEmoji(): boolean | null {

if (typeof document === "undefined") return null;

if (isWindows()) return null;

try {

// 对照组:😀 在所有支持彩色 Emoji 的设备上都应渲染为彩色

const control = getCharColors("😀");

if (control.opaquePixelCount === 0 || control.isMono) {

// 设备本身不支持彩色 Emoji 渲染(或 canvas 被指纹保护干扰),无法判断

return null;

const flag = getCharColors("🇹🇼");

if (flag.opaquePixelCount === 0) {

// 对照组正常但旗帜完全不渲染 → 系统屏蔽了该 Emoji

return true;

// 渲染为黑白(通常是 "TW" 字母回退)→ 系统屏蔽了旗帜图案

return flag.isMono;

} catch {

// canvas 不可用(如某些无头环境)时返回无法判断,而不是抛错

return null;

function getCharColors(char: string): {

colors: number[][];

isMono: boolean;

opaquePixelCount: number;

} {

const canvas = document.createElement("canvas");

const ctx = canvas.getContext("2d");

const fontSize = 100;

if (!ctx) {

throw new Error("Canvas context not supported");

canvas.width = fontSize;

canvas.height = fontSize;

// 使用系统字体渲染

ctx.font = `${fontSize}px sans-serif`;

ctx.fillStyle = "black";

ctx.textBaseline = "top";

// 渲染字符到画布

ctx.clearRect(0, 0, canvas.width, canvas.height);

ctx.fillText(char, 0, 0);

const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

const colorSet = new Setstring>();

let isMono = true;

let opaquePixelCount = 0;

for (let i = 0; i imageData.data.length; i += 4) {

const r = imageData.data[i];

const g = imageData.data[i + 1];

const b = imageData.data[i + 2];

const a = imageData.data[i + 3];

if (a > 0) {

opaquePixelCount++;

const color = `${r},${g},${b}`;

colorSet.add(color);

// 判断颜色是否为黑白(即 R、G、B 值相同)

if (isMono && !(r === g && g === b)) {

isMono = false;

// 转换 Set 为二维颜色数组

const colors = Array.from(colorSet).map((color) =>

color.split(",").map(Number),

);

canvas.remove();

return {

colors,

isMono,

opaquePixelCount,

};

/** 判断是否为 Windows 系统 */

function isWindows(): boolean {

if (navigator.platform?.startsWith("Win")) return true;

// navigator.platform 已被废弃,部分浏览器可能返回空,回退到 userAgent

return /Windows/i.test(navigator.userAgent ?? "");

You can’t perform that action at this time.

const canvas return emoji ismono data

Related Articles