吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7504|回复: 64
收起左侧

[Python 原创] 9574个汉字的笔顺图及书写gif动画生成

    [复制链接]
FeiyuYip 发表于 2025-5-22 20:21
本帖最后由 FeiyuYip 于 2025-10-22 13:22 编辑

2025-10-22更新
更新开发了汉字书写动画及图片生成工具,是直接可用的工具,可去围观……
——————————————————————————————

在Github中看到makemeahanzi项目,里面提供了9574个汉字的svg笔顺内容和gif动画。许多朋友根据它衍生了一些有趣的应用

我这边也根据这里数据,实现了汉字的笔顺图和笔顺书写gif图,现将程序分享出来,有兴趣的朋友可以进行有趣的扩展
TIPs:部分代码由AI完善
一、原始数据
1.jpg 2.jpg
如上图,以“愛”字为例,它是以汉字的十进制编码命名,有两种格式,双击打开svg文件,可以看到效果如上图
二、笔顺图及书写动画实现
(一)笔顺图
[Python] 纯文本查看 复制代码
# 读取svgs生成笔顺图.py
import os
import json
import xml.etree.ElementTree as ET
import 获取笔顺
from concurrent.futures import ThreadPoolExecutor


def process_svg(svg, path, index, total_num):
    """处理单个SVG文件的函数"""
    try:
        char_number = svg.split('-')[0]
        dec_num = int(char_number)
        char = chr(dec_num)  # 转汉字
        svg_path = os.path.join(path, svg)

        # 读取SVG文件
        root = ET.parse(svg_path).getroot()

        # 使用命名空间来查找path元素
        ns = {'svg': 'http://www.w3.org/2000/svg'}
        path_elements = root.findall('.//svg:path', ns)
        svg_path_data = [path.attrib['d'] for path in path_elements]  # 获取笔顺内容

        print(f'{index} / {total_num} 正在生成 {char} 的笔顺图...')

        # 传入数据
        获取笔顺.main(svg_path_data, char)

    except Exception as e:
        print(f"处理 {svg} 时出错: {e}")


def main():
    path = r'makemeahanzi-master\svgs-still'
    svgs_list = os.listdir(path)
    total_num = len(svgs_list)

    # 创建线程池,max_workers设置并发线程数
    with ThreadPoolExecutor(max_workers=4) as executor:
        # 提交所有任务到线程池
        futures = []
        for index, svg in enumerate(svgs_list):
            futures.append(
                executor.submit(process_svg, svg, path, index, total_num)
            )

        # 等待所有任务完成
        for future in futures:
            future.result()  # 这里会抛出异常,如果有的话


if __name__ == '__main__':
    main()

[Python] 纯文本查看 复制代码
# 获取笔顺.py

from cairosvg import svg2png
import os
import re


def makedirs(path):
    if not os.path.exists(path):
        os.makedirs(path)


def ChangeSVG2png(svg_path, chinese):
    outputpath = f'strokeOrder/{chinese}'  # 笔顺保存路径
    makedirs(outputpath)

    # 如果笔顺图跟笔顺list相等,则说明已经生成过了
    png_files = sorted([f for f in os.listdir(outputpath)
                        if f.startswith(f'{chinese}_') and f.endswith('.png')])
    if len(png_files) == len(svg_path):
        print(f'*** {chinese} 的笔顺图已经生成,跳过***')
        return

    svg_output = {
        'width': '1024px',
        'height': '1024px',
        'xmlns': 'http://www.w3.org/2000/svg',
        "font_color": "#000000",  # 黑色
        "font_color_last": "#FF1111",  # 红色
        # "font_color_last": "#0000FF",  # 蓝色
        "output_address": outputpath,
        "output_filename": ''
    }

    if not os.path.exists(outputpath):  # 为每个汉字创建文件夹
        os.mkdir(outputpath)

    # Grid lines (米字格)
    # 在 ChangeSVG2png 函数中添加以下米字格定义(替换原来的 grid_lines)
    grid_lines = [
        # 对角线(长线,保持实线但更细)
        '<line x1="0" y1="0" x2="1024" y2="1024" style="stroke:#EEEEEE;stroke-width:4;stroke-dasharray:10,10"/>',
        '<line x1="1024" y1="0" x2="0" y2="1024" style="stroke:#EEEEEE;stroke-width:4;stroke-dasharray:10,10"/>',

        # 中心横竖线(虚线小线段)
        '<line x1="0" y1="512" x2="1024" y2="512" style="stroke:#EEEEEE;stroke-width:4;stroke-dasharray:10,10"/>',
        '<line x1="512" y1="0" x2="512" y2="1024" style="stroke:#EEEEEE;stroke-width:4;stroke-dasharray:10,10"/>',

        # 添加更多小线段作为辅助格子(可选)
        # '<line x1="256" y1="0" x2="256" y2="1024" style="stroke:#F5F5F5;stroke-width:2"/>',
        # '<line x1="768" y1="0" x2="768" y2="1024" style="stroke:#F5F5F5;stroke-width:2"/>',
        # '<line x1="0" y1="256" x2="1024" y2="256" style="stroke:#F5F5F5;stroke-width:2"/>',
        # '<line x1="0" y1="768" x2="1024" y2="768" style="stroke:#F5F5F5;stroke-width:2"/>'
    ]

    if len(svg_path) == 1:
        svg_code = []
        svg_code_temp = '<svg style="width:' + svg_output['width'] + '; height:' + svg_output['height'] + ';" xmlns="' + \
                        svg_output['xmlns'] + '">'
        svg_code.append(svg_code_temp)
        # Add grid lines
        svg_code.extend(grid_lines)
        svg_code_temp = '  <g transform="translate(0, 900) scale(1, -1)">'
        svg_code.append(svg_code_temp)
        svg_code_temp = '      <path d="' + svg_path[0] + '" style="fill:' + svg_output[
            'font_color_last'] + ';"></path>'
        svg_code.append(svg_code_temp)
        svg_code_temp = '   </g>'
        svg_code.append(svg_code_temp)
        svg_code_temp = '</svg>'
        svg_code.append(svg_code_temp)
        svgcode = '\n'.join(svg_code)
        svg_output['output_filename'] = svg_output['output_address'] + '/' + chinese + '1.png'
        try:
            svg2png(bytestring=svgcode, write_to=svg_output['output_filename'])
        except Exception as e:
            print('error:' + str(e))

        # 生成完整的笔顺图,生成svg图片
        svg_code = []
        svg_code_temp = '<svg style="width:' + svg_output['width'] + '; height:' + svg_output[
            'height'] + ';" xmlns="' + svg_output['xmlns'] + '">'
        svg_code.append(svg_code_temp)
        # Add grid lines
        # svg_code.extend(grid_lines)  # 这里确定是否在svg中添加米字格
        svg_code_temp = '<g transform="translate(0, 900) scale(1, -1)">'
        svg_code.append(svg_code_temp)
        for j in range(len(svg_path)):
            svg_code_temp = '    <path d="' + svg_path[j] + '" style="fill:' + svg_output[
                'font_color'] + ';"></path>'
            svg_code.append(svg_code_temp)
        svg_code_temp = ' </g>'
        svg_code.append(svg_code_temp)
        svg_code_temp = '</svg>'
        svg_code.append(svg_code_temp)
        svgcode = '\n'.join(svg_code)
        svg_output['output_filename'] = svg_output['output_address'] + '/' + chinese + '.svg'  # 修改文件扩展名为.svg
        try:
            with open(svg_output['output_filename'], 'w') as f:
                f.write(svgcode)
        except Exception as e:
            print('error:' + str(e))
    else:
        for i in range(len(svg_path)):
            svg_code = []
            svg_code_temp = '<svg style="width:' + svg_output['width'] + '; height:' + svg_output[
                'height'] + ';" xmlns="' + svg_output['xmlns'] + '">'
            svg_code.append(svg_code_temp)
            # Add grid lines
            svg_code.extend(grid_lines)
            svg_code_temp = '  <g transform="translate(0, 900) scale(1, -1)">'
            svg_code.append(svg_code_temp)
            for j in range(i + 1):
                if j == i:
                    svg_code_temp = '      <path d="' + svg_path[j] + '" style="fill:' + svg_output[
                        'font_color_last'] + ';"></path>'
                else:
                    svg_code_temp = '      <path d="' + svg_path[j] + '" style="fill:' + svg_output[
                        'font_color'] + ';"></path>'
                svg_code.append(svg_code_temp)
            svg_code_temp = '   </g>'
            svg_code.append(svg_code_temp)
            svg_code_temp = '</svg>'
            svg_code.append(svg_code_temp)
            svgcode = '\n'.join(svg_code)
            svg_output['output_filename'] = svg_output['output_address'] + '/' + chinese + '_' + str(i + 1) + '.png'
            try:
                svg2png(bytestring=svgcode, write_to=svg_output['output_filename'])
            except Exception as e:
                print('error:' + str(e))

        # 生成完整的笔顺图,生成svg图片
        svg_code = []
        svg_code_temp = '<svg style="width:' + svg_output['width'] + '; height:' + svg_output[
            'height'] + ';" xmlns="' + svg_output['xmlns'] + '">'
        svg_code.append(svg_code_temp)
        # Add grid lines
        # svg_code.extend(grid_lines)  # 这里确定是否在svg中添加米字格
        svg_code_temp = '<g transform="translate(0, 900) scale(1, -1)">'
        svg_code.append(svg_code_temp)
        for j in range(len(svg_path)):
            svg_code_temp = '    <path d="' + svg_path[j] + '" style="fill:' + svg_output[
                'font_color'] + ';"></path>'
            svg_code.append(svg_code_temp)
        svg_code_temp = ' </g>'
        svg_code.append(svg_code_temp)
        svg_code_temp = '</svg>'
        svg_code.append(svg_code_temp)
        svgcode = '\n'.join(svg_code)
        svg_output['output_filename'] = svg_output['output_address'] + '/' + chinese + '.svg'  # 修改文件扩展名为.svg
        try:
            with open(svg_output['output_filename'], 'w') as f:
                f.write(svgcode)
        except Exception as e:
            print('error:' + str(e))


def main(svg_path, chinese):
    ChangeSVG2png(svg_path, chinese)


if __name__ == '__main__':
    svg_data = '''
        <path d="M 443 715 Q 449 729 501 798 Q 513 811 498 827 Q 455 862 426 860 Q 414 860 416 844 Q 421 780 378 709 Q 357 673 321 635 Q 302 623 270 583 Q 265 573 269 570 Q 270 569 276 570 Q 341 581 428 694 L 443 715 Z" class="stroke1"/>
        <path d="M 531 559 Q 586 639 667 694 Q 682 703 678 714 Q 678 717 674 720 Q 664 730 615 758 Q 604 762 592 759 L 581 754 Q 576 754 488 725 Q 470 718 443 715 C 413 711 400 703 428 694 Q 442 686 480 690 Q 498 692 525 696 Q 551 700 557 698 Q 560 696 559 690 Q 534 610 490 552 L 490 551 C 473 526 514 534 531 559 Z" class="stroke2"/>
        <path d="M 314 527 Q 308 533 255 539 Q 246 539 241 537 Q 239 537 237 535 Q 233 529 237 521 L 243 511 Q 279 455 302 372 Q 309 345 326 329 Q 342 314 349 319 Q 351 321 353 325 L 355 339 L 349 374 L 323 488 C 316 517 314 527 314 527 Z" class="stroke3"/>
        <path d="M 700 406 Q 739 488 776 504 Q 798 523 782 545 Q 764 563 708 595 Q 688 606 663 598 Q 598 574 531 559 L 490 551 Q 402 535 314 527 C 284 524 294 479 323 488 Q 331 490 343 494 L 504 520 Q 562 533 624 543 Q 647 547 662 543 Q 670 540 674 535 Q 681 526 665 478 L 646 425 Q 645 423 643 419 C 632 391 687 379 700 406 Z" class="stroke4"/>
        <path d="M 425 348 L 580 366 L 705 374 Q 714 376 717 385 Q 717 392 700 406 L 643 419 L 636 419 Q 564 404 498 393 L 437 384 L 349 374 C 319 371 325 339 355 339 L 368 339 L 425 348 Z" class="stroke5"/>
        <path d="M 310 192 L 323 194 Q 412 213 472 223 Q 492 225 490 235 Q 490 237 488 241 Q 474 256 449 259 Q 421 261 368 243 Q 345 235 310 220 C 282 208 280 187 310 192 Z" class="stroke6"/>
        <path d="M 310 220 Q 310 295 308 296 Q 284 318 263 327 Q 251 332 242 331 Q 230 327 232 316 Q 265 251 262 157 L 261 143 Q 257 97 217 55 Q 208 41 210 25 L 210 24 L 212 18 Q 220 -8 231 -18 Q 239 -23 247 -19 Q 251 -16 255 -12 Q 276 18 449 118 Q 468 127 472 134 Q 476 144 468 145 Q 457 145 323 94 Q 309 89 306 96 Q 304 98 304 106 Q 308 143 310 192 L 310 220 Z" class="stroke7"/>
        <path d="M 741 333 L 739 325 Q 737 295 662 247 Q 604 210 589 199 C 564 182 559 171 588 180 Q 657 201 690 216 Q 765 250 796 254 Q 816 257 813 274 L 813 278 Q 806 299 784 318 Q 762 337 752 337 Q 743 338 741 333 Z" class="stroke8"/>
        <path d="M 589 199 Q 593 247 600 287 Q 602 300 599 306 Q 597 311 592 314 Q 581 326 557 335 Q 544 339 535 334 Q 529 331 531 322 Q 546 253 546 237 Q 544 126 547 99 Q 548 82 553 61 Q 558 38 580 20 Q 637 -27 757 -18 Q 780 -16 800 -12 Q 823 -7 836 -3 Q 872 9 911 37 Q 923 47 919 61 Q 919 63 916 69 Q 907 87 894 165 Q 894 177 888 182 Q 885 184 883 179 Q 882 179 879 171 Q 848 99 838 71 Q 823 55 790 45 Q 741 30 684 38 Q 652 43 635 50 Q 609 61 600 80 Q 583 115 587 166 L 588 180 L 589 199 Z" class="stroke9"/>
        '''
    stroke_order = []
    for line in svg_data.split('\n'):
        if line.strip():
            match = re.search(r'd="([^"]+)"', line)
            if match:
                path_data = match.group(1)
                stroke_order.append(path_data)

    # 生成笔顺图
    chinese = '&#15499;'  # 修改为您要生成的汉字
    svg_path = [x for x in stroke_order]
    print(svg_path)
    print(len(svg_path))
    main(svg_path, chinese)

注:需要安装cairosvg程序(gtk3-runtime-3.24.31-2022-01-04-ts-win64),我会在附件中提供
此程序会生成笔顺图png(旧笔顺为黑色、新笔顺为红色),并生成一个完整的svg文件(全黑)
(二)书写动画gif生成
[Python] 纯文本查看 复制代码
# 生成gif.py
import os
import asyncio
from playwright.async_api import async_playwright
import subprocess
import math
from concurrent.futures import ThreadPoolExecutor


async def svg_to_gif(char, unhandled_num, svg_path, gif_path, frame_rate=12):
    """将 SVG 动画转换为 GIF,并替换蓝色为红色"""
    frames_dir = os.path.join(os.path.dirname(gif_path), f"{char}_frames")
    os.makedirs(frames_dir, exist_ok=True)

    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page()
        await page.set_viewport_size({"width": 1024, "height": 1024})

        # 读取 SVG 并替换颜色
        with open(svg_path, 'r', encoding='utf-8') as f:
            svg_content = f.read()

        # 关键修改:替换蓝色为红色
        svg_content = svg_content.replace("stroke: blue", "stroke: #FF1111")

        await page.set_content(f"""
            <!DOCTYPE html>
            <html>
            <head>
                <style>
                    body {{ margin: 0; background: transparent; }}
                    svg {{
                        width: 1024px;
                        height: 1024px;
                        position: absolute;
                        left: 0;
                        top: 0;
                    }}
                </style>
            </head>
            <body>
                {svg_content}
            </body>
            </html>
        """)

        # 计算动画时长(保持不变)
        await page.wait_for_selector('svg')
        await page.wait_for_timeout(500)
        total_duration = await page.evaluate("""() => {
            const anims = Array.from(document.querySelectorAll('*'))
               .flatMap(el => el.getAnimations?.() || []);
            return anims.length? Math.max(...anims.map(a => {
                const timing = a.effect.getComputedTiming();
                return timing.endTime || timing.delay + timing.duration;
            })) / 1000 : 0;
        }""")

        if not total_duration or math.isnan(total_duration):
            print("使用默认动画时长 5 秒")
            total_duration = 5.0

        total_frames = int(total_duration * frame_rate)
        print(f"处理 {os.path.basename(svg_path)}: 时长 {total_duration:.2f}s, 总帧数 {total_frames}")

        # 捕获帧
        for frame in range(total_frames):
            current_time = (frame / total_frames) * total_duration * 1000
            await page.evaluate("""(time) => {
                document.getAnimations().forEach(anim => anim.currentTime = time);
            }""", current_time)

            await page.screenshot(
                path=os.path.join(frames_dir, f"frame_{frame:04d}.png"),
                type="png",
                omit_background=True,
                clip={"x": 0, "y": 0, "width": 1024, "height": 1024}
            )
            print(f"\r{os.path.basename(svg_path)} 渲染进度: {frame + 1}/{total_frames}", end='')

        await browser.close()

    # 生成 GIF
    print(f"\n{os.path.basename(svg_path)} 生成 GIF...")
    try:
        subprocess.run([
            "ffmpeg", "-y",
            "-framerate", str(frame_rate),
            "-i", os.path.join(frames_dir, "frame_%04d.png"),
            "-vf", "split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse",
            "-loop", "0",
            gif_path
        ], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        print(f"{unhandled_num} {os.path.basename(svg_path)} GIF 已生成: {gif_path}")
    except subprocess.CalledProcessError as e:
        print(f" {os.path.basename(svg_path)} FFmpeg 错误: {e}")

    # 清理临时文件
    for file in os.listdir(frames_dir):
        os.remove(os.path.join(frames_dir, file))
    os.rmdir(frames_dir)


def process_single(svg_path, char, unhandled_num, char_gif_path):
    """处理单个文件"""

    char_gif_path_name = os.path.join(char_gif_path, f'{char}.gif')

    asyncio.run(svg_to_gif(char, unhandled_num, svg_path, char_gif_path_name, frame_rate=15))


def main(svg_dir, max_workers=4):
    """多线程主函数"""
    svg_files = []
    svg_list = os.listdir(svg_dir)
    # 保存路径
    char_gif_path = f'Gifs'
    os.makedirs(char_gif_path, exist_ok=True)
    gifs_list = [gif.split('.')[0] for gif in os.listdir(char_gif_path) if gif.endswith('.gif')]

    # 比对未保存的,拿来使用
    svg_unhandled_list = []
    for tmp in svg_list:
        char_code = int(os.path.splitext(tmp)[0])
        char = chr(char_code)
        if not char in gifs_list:
            svg_unhandled_list.append(tmp)

    unhandled_num = len(svg_unhandled_list)
    for svg in svg_unhandled_list:
        try:
            char_code = int(os.path.splitext(svg)[0])
            char = chr(char_code)
            svg_files.append((os.path.join(svg_dir, svg), char))
        except ValueError:
            print(f"跳过非数字文件名: {svg}")

    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = []
        for svg_path, char in svg_files:
            futures.append(executor.submit(process_single, svg_path, char, unhandled_num, char_gif_path))

        for future in futures:
            try:
                future.result()  # 等待任务完成
            except Exception as e:
                print(f"处理出错: {e}")


if __name__ == '__main__':
    # 在txt中保存进度
    svg_dir = r'makemeahanzi-master\svgs'
    main(svg_dir, max_workers=4)  # 设置同时处理4个文件

三、效果图
3.jpg
4.jpg 愛.gif
四、分享链接
通过网盘分享的文件:汉字笔顺图及书写动画
链接: https://pan.baidu.com/s/1ns8ETsQHY8qeAbCj7tNQ9Q 提取码: 8j8y

免费评分

参与人数 36威望 +1 吾爱币 +46 热心值 +32 收起 理由
yucanhai000 + 1 谢谢@Thanks!
qinghg2013 + 1 + 1 如何使用
大毛孩 + 1 谢谢@Thanks!
amouer + 1 + 1 我很赞同!
shuangxi520 + 1 热心回复!
Gwen0 + 1 谢谢@Thanks!
lideshan + 1 + 1 我很赞同!
gezhonglunta + 1 + 1 我很赞同!
Rogers5 + 1 + 1 我很赞同!
ae86111 + 1 + 1 谢谢@Thanks!
苏紫方璇 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
jiaopianjun + 1 热心回复!
fozi000 + 1 + 1 谢谢@Thanks!
liu101816 + 2 + 1 我很赞同!
fengfeel + 1 + 1 谢谢@Thanks!
fessicon + 1 很赞!夸宝https://pan.quark.cn/s/681261be0e40
明月相照 + 1 + 1 谢谢@Thanks!
wanfon + 1 + 1 热心回复!
ddfzl + 1 + 1 谢谢@Thanks!
yp17792351859 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
newhopegroup + 1 + 1 我很赞同!
观弈山人 + 1 谢谢@Thanks!
yanglinman + 1 谢谢@Thanks!
pojiecainiao + 1 + 1 谢谢@Thanks!
Hameel + 1 热心回复!
laozhang4201 + 1 + 1 热心回复!
jj131028 + 1 谢谢@Thanks!
kinalon + 1 谢谢@Thanks!
Grid + 1 + 1 谢谢@Thanks!
qiujunjian1 + 1 + 1 谢谢@Thanks!
xy425068 + 1 + 1 谢谢@Thanks!
快乐的小驹 + 1 谢谢@Thanks!
keithu + 1 我很赞同!
海水很咸 + 1 + 1 我很赞同!
pyjiujiu + 1 我很赞同!
SU150228 + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

破解粉丝 发表于 2025-5-23 10:02
我用万彩微影软件,里面就有一项,可以自己手动去描每个字的笔顺,加入字库后,就会自动生成WordStock.xml文件,因为我前段时间误删除了这个文件,真是可惜了,里面是我花了整整一个月的时间手动去描这个方正楷体字笔顺的字库文件,有好几千个常用字,现在又要重新手动去描这个笔顺了,真是太累了,如果有一款软件,能自动处理再生成这个WordStock.xml文件,就好太多了,这样软件就可以调用这个带有笔顺的字库文件了,不知有哪位高手能设计出这款软件来吗?
吾爱-路人甲 发表于 2025-5-22 20:37
能不能做成压缩包,百度网盘最多转存500,你这个远远超过了。
 楼主| FeiyuYip 发表于 2025-5-22 20:40
吾爱-路人甲 发表于 2025-5-22 20:37
能不能做成压缩包,百度网盘最多转存500,你这个远远超过了。

您也可以去github下载
 楼主| FeiyuYip 发表于 2025-5-22 20:43
吾爱-路人甲 发表于 2025-5-22 20:37
能不能做成压缩包,百度网盘最多转存500,你这个远远超过了。

已上传了,请重新访问
吾爱-路人甲 发表于 2025-5-22 20:46
FeiyuYip 发表于 2025-5-22 20:43
已上传了,请重新访问

好的,谢谢
 楼主| FeiyuYip 发表于 2025-5-22 21:00
ddfzl 发表于 2025-5-22 20:58
感谢,转存超出限制了,有别的盘吗

那个文件夹别存了,下载压缩包解压就行
ddfzl 发表于 2025-5-22 21:01
FeiyuYip 发表于 2025-5-22 20:43
已上传了,请重新访问

看见了,有压缩文件
afti 发表于 2025-5-22 21:14
给孩子学习笔顺不错
dysunb 发表于 2025-5-22 21:38
这个软件好,自从有了电脑,感觉不会写的字越来越多了
zimu007 发表于 2025-5-22 21:42
很有意思的东西,没事可以看看,温故知新
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-5-15 11:45

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表