Skip to content

Instantly share code, notes, and snippets.

@wyf9
Last active April 20, 2026 10:05
Show Gist options
  • Select an option

  • Save wyf9/1c713a5b531fa6c95844c979621ccd25 to your computer and use it in GitHub Desktop.

Select an option

Save wyf9/1c713a5b531fa6c95844c979621ccd25 to your computer and use it in GitHub Desktop.
NextBridge CQFace 导出指引

cqface export

Step 1

首先打开你的 QQ 数据目录,导航到 .../nt_qq_xxx/nt_data/Emoji/BaseEmojiSyastems/EmojiSystermResource/

Tip

比如在我的机器上: /home/wyf9/.config/QQ/nt_qq_5a3d****98c3/nt_data/Emoji/BaseEmojiSyastems/EmojiSystermResource/
实测也可以从下面两个目录找到,但目录结构不同以及:

  • .../Tencent Files/nt_qq/global/nt_data/Emoji/emoji-resource/sysface_res/apng/ - 不全
  • resources/app/resource/default-emojis/ - 尺寸较小,不全

确保你已经安装了 Python3,将本 gist 的 export-apng.py 复制到此处,然后执行下面的命令:

python3 export-apng.py --ranges 419-470

Tip

--ranges 用于指定要复制的图片区间
其他可用参数见文件注释 / --help

为什么要用这个脚本? 1. 方便整合
2. 铸币 QQ 把 APNG 和 PNG 混在一起了,都是 .png 文件名,脚本能把它们分开 (这样检测扩展名的 converter 不会报错)
图片

Step 2

打开生成的 _export_png 文件夹,应为如下结构:

图片

接下来打开 https://conv.krnl64.win/ (src: ntkrnl64/krnlconvert)

  1. 使用下图设置:
图片
  1. 将文件夹中所有图片文件拖入上传框
  2. 点击 全部转换
  3. 转换完成后,点击 全部下载 (ZIP),如图
图片

打开 zip 压缩包,其中即为 数字.gif 格式图片.

关于 unicode map

推荐这个工具 (如果社交平台 / 输入法自带找不到): https://emojistime.com/zh

End.

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import re
import shutil
import struct
from pathlib import Path
def is_apng(file_path: Path) -> bool:
"""检测PNG文件是否为APNG(动画PNG)。"""
try:
with open(file_path, "rb") as f:
# PNG signature
sig = f.read(8)
if sig != b"\x89PNG\r\n\x1a\n":
return False
# 检查是否存在 acTL chunk(APNG的标记)
while True:
length_bytes = f.read(4)
if not length_bytes:
break
length = struct.unpack(">I", length_bytes)[0]
chunk_type = f.read(4)
if chunk_type == b"acTL":
return True
if chunk_type == b"IEND":
return False
f.seek(length + 4, 1) # skip chunk data and CRC
except Exception:
return False
return False
def parse_ranges(text: str) -> list[int]:
"""
解析类似: 1-3,8,10-12
返回去重并排序后的数字列表。
"""
result = set()
for part in re.split(r"[,\s]+", text.strip()):
if not part:
continue
if "-" in part:
a, b = part.split("-", 1)
start, end = int(a), int(b)
if start > end:
start, end = end, start
result.update(range(start, end + 1))
else:
result.add(int(part))
return sorted(result)
def main() -> None:
parser = argparse.ArgumentParser(
description="从指定数字文件夹的 apng/*.png 收集到一个输出目录。"
)
parser.add_argument(
"--ranges",
required=True,
help='数字范围,如 "1-3,8,10-12"(数字可不连续)',
)
parser.add_argument(
"--src",
default=".",
help="源根目录(包含数字文件夹),默认当前目录",
)
parser.add_argument(
"--out",
default="./_export_png",
help="输出目录,默认 ./_export_png",
)
args = parser.parse_args()
src_root = Path(args.src).expanduser().resolve()
out_dir = Path(args.out).expanduser().resolve()
out_dir.mkdir(parents=True, exist_ok=True)
folder_nums = parse_ranges(args.ranges)
copied_apng = 0
copied_png = 0
missing_dirs = []
for n in folder_nums:
folder = src_root / str(n)
apng_dir = folder / "apng"
if not apng_dir.is_dir():
missing_dirs.append(str(n))
continue
for png_file in sorted(apng_dir.glob("*.png")):
# 检测是否为APNG,用扩展名区分
if is_apng(png_file):
target = out_dir / png_file.name.replace(".png", ".apng")
copied_apng += 1
else:
target = out_dir / png_file.name
copied_png += 1
shutil.copy2(png_file, target)
print(f"源目录: {src_root}")
print(f"输出目录: {out_dir}")
print(f"目标数字文件夹数: {len(folder_nums)}")
print(f"成功复制 APNG 数: {copied_apng}")
print(f"成功复制静态 PNG 数: {copied_png}")
if missing_dirs:
print(f"\n以下目录不存在或无 apng 子目录:{', '.join(missing_dirs)}")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment