• 汉字的书写效果的实现


    本文记录一下如何基于字体实现汉字svg描点的过程

    参考项目:

    1makemeahanzi     https://github.com/skishore/makemeahanzi

    2hanzi-writer-data    https://github.com/chanind/hanzi-writer-data

    3hanzi-writer    https://github.com/chanind/hanzi-writer

     

    生成dictionary.txt和graphics.txt文件

    生成这两个文件我们需要用到makemeahanzi

    运行Makemeahanzi-tools

    首先下载makemeahanzi项目的tools分支

    该项目是用meteor框架写的,那么我们想要运行该项目,需要安装Node环境和Meteor

    安装Node

    直接上官网怼吧 传送门:https://nodejs.org/en/download/,安装完成后记得配置一下环境变量,cmd输入node -v 显示版本号即为安装成功。

    安装Meteor

     

    说到安装Meteor,那么Meteor是什么?以下内容来自 https://www.w3cschool.cn/discovermeteor/rbj81jjm.html

    Meteor 是什么?

    Meteor 是一个构建在 Node.js 之上的平台,用来开发实时网页程序。Meteor 位于程序数据库和用户界面之间,保持二者之间的数据同步更新。

    因为 Meteor 是基于 Node.js 开发的,所以在客户端和服务器端都使用 JavaScript 作为开发语言。而且,Meteor 程序的代码还能在前后两端共用。

    Meteor 这个平台很强大,网页程序开发过程中的很多复杂、容易出错的功能都能抽象出来,实现起来很简单。

    为什么使用 Meteor?

    那么,你为什么要花时间学习 Meteor,而不去学其他框架呢?拨开 Meteor 的各种功能,我们认为原因只有一个:因为 Meteor 易于学习。

    而且,和其他框架不同,使用 Meteor,几小时之内就能开发出一个正常运行的实时网页程序。如果之前做过前端开发,对 JavaScript 已经有所了解,甚至都不用再学习一门新的编程语言。

    Meteor 可能就是你要找的理想框架,当然,也可能不是。既然只要几晚或一个周末就能上手,为什么不试试呢?

    因为丫自带一个MongoDB,可以前端后端一把梭,再也不用和后端攻城狮因为接口文档撕逼了。 

     

    安装环境参考Meteor官网 传送门:https://www.meteor.com/install,

    linux下使用命令

    curl https://install.meteor.com/ | sh

    windows环境下使用命令

    choco install meteor

    PSWTF???choco是什么鬼?

    choco其实是Chocolatey的命令,Chocolateywindows的包管理工具,类似yamapt-get

    如果没有安装Chocolatey,那么需要先安装Chocolatey。传送门:https://chocolatey.org/install

    依照文档有两种安装方式,cmdpowershell

     

    cmd安装:

    @"%SystemRoot%System32WindowsPowerShellv1.0powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%chocolateyin"

    powershell安装:

    Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

    PS:如果安装失败,可能是网络问题,需要梯子

    安装成功后再次执行choco install meteor,等待安装完成即可

    至于Meteor如何使用,可以阅读官方文档,这里不细说了,因为我也得看官方文档。传送门:https://guide.meteor.com/index.html

    运行项目

    Node和Meteor安装完成后,我们开始运行项目

    项目目录:

    运行项目之前先把public文件夹拷贝到.meteor文件夹里面,VSCODE打开项目,输入meteor,等待项目跑起来,然后浏览器输入 http://localhost:3000# 进入到server文件夹下输入meteor mongo可以打开mongo,mongo地址一般是localhost:3001端口

     

    如何使用

    你可能在使用的过程中会发现和我截图的有点不一样,比如只有AR PL KaitiM GB  AR PL UKai 这两个字体,是因为我在原有代码上进行了一些修改,后面我会讲到如何修改代码使之兼容任意字体。

    #后面输入汉字然后回车,例如http://localhost:3000/#猫

    这时候点击一下字体,你可以生成对应字体的文字,下面是我点了FZKTJW的效果

    那么现在是时候讲讲如何真正的使用了,他的使用方式是------->快捷键,哈哈哈哈。

    快捷键a:显示上一个字

    快捷键A:显示上一个未完成的字

    快捷键q:显示上一个完成的字

    快捷键d:显示下一个字

    快捷键D:显示下一个未完成的字

    快捷键e:显示下一个完成的字

    快捷键r:重置当前操作

    快捷键s:下一步操作

    快捷键w:上一步操作

    完成一个字需要六步操作,分别为:path, bridges, strokes, analysis, order, verified

    path:路径

    bridges:标记描点

    strokes:笔画

    通过更改描点可以控制笔画

    analysis:分析

    分析字的结构,偏旁部首等待,如果结构没有完成,下一步会先去完成结构

    对于“猫”这个字需要我们先完成“犭”和“苗”的构建,按s进入下一步

    我们完成了“犭”的部分,接下来按D回到未完成的“猫”继续下一步

    按s进入下一步完成苗的构建

    此处跳过N部,总之构建完所有依赖的结构后按D回到未完成的“猫”继续搞

    按s进入下一步

    order:顺序,笔顺

    这里可以调整笔画的顺序(直接拖动)和笔顺Reverse是调整方向

    verified:检查并且完成

    到此我们完成了对于猫这个字的所有构建,已经可以导出路径文件了,那么如何导出路径文件呢?

    导出路径文件和生成svg文件

    导出路径文件

    打开F12,切换到Console,然后输入

    Meteor.call("backup");

    进行一下备份,然后输入

    Meteor.call('export');就可以在项目文件夹里面的.meteor文件夹下生成dictionary.txt和graphics.txt文件,稍后再讲这俩文件怎么用

    生成svg文件

    F12,Console输入

    Meteor.call('exportSVGs');

    在项目文件夹.meteor文件夹下会生成.svg文件夹,里面就是字体的svg文件

    PS:如果生成的svg文件是空的,那么需要修改一下代码,将lib/animation.html 文件复制到private文件夹下并且覆盖原文件

    源码分析

    上面讲了一大坨,这里讲一下具体的实现原理

    首先是项目结构:

     

    .meteor:运行时的根目录

    .vscode:vscode的配置文件

    client:客户端文件

    dist:项目构建后的目录

    lib:公共库文件

    packages:npm包

    private:私有目录

    public:公开目录,里面存放字体和汉字语言库,这个文件夹需要拷贝到.meteor里面

    server:服务器文件

    项目里面的源码文件有很多,下面说几个用到的

    1、client/editor.js对应的是编辑页面的逻辑,快捷键,操作步骤定义都在这个文件里。

    2client/lib/path.js对应的是生成路径的逻辑,这里可以自己添加字体。添加字体的方法如下:

    Template.path_stage.helpers({

      alternative: () => Session.get('stages.path.alternative') || '?',

      options: () => [{font: 'arphic/gkai00mp.ttf', label: 'AR PL KaitiM GB'},

                      {font: 'arphic/UKaiCN.ttf', label: 'AR PL UKai'},

                      {font: 'arphic/simhei.ttf', label: 'simhei'},

                      {font: 'arphic/FZKTJW.TTF', label: 'FZKTJW'},

                      {font: 'arphic/FZLanTingYuanS-B-GB-TEST.ttf', label: 'FZLanTingYuanS-B-GB-TEST'},],

    });

     

    在options里面添加好字体后,将字体文件拷贝到.meteor/public/arphic/文件夹下即可

     

    修改path.js使之兼容各种字体

    本项目中用到的字体大小是1024的,如果一般字体没有这么大,比如256的,那么生成出来的字会很小,不能沾满整个画布,那么坐标也是无法使用的。我们可以修改path.js中的

     

    // We avoid arrow functions in this map so that this is bound to the template.

    Template.path_stage.events({

      'blur .value': function(event) {

        const text = $(event.target).text();

        const value = text.length === 1 && text !== '?' ? text : undefined;

        if (value === stage.alternative) {

          $(event.target).text(value || '?');

        } else {

          stage.alternative = value;

          stage.forceRefresh();

        }

      },

      'click .option': function(event) {

        const label = this.label;

        const character = stage.character;

        assert(character.length === 1);

        Session.set('modal.text', `Loading ${label}...`);

        Session.set('modal.value', 0);

        opentype.load(this.font, (error, font) => {

          stage.alternative = undefined;

          if (error) {

            stage.onGetPath(`Error loading ${label}: ${error}`);

            return;

          }

          Session.set('modal.text', `Extracting ${character} from ${label}...`);

          Session.set('modal.value', 0.5);

          const index = font.charToGlyphIndex(character);

          const glyph = font.glyphs.get(index);

          if (glyph.unicode !== character.codePointAt(0)) {

            stage.onGetPath(`${character} is not present in ${label}.`);

            return;

          }

          const commands = font.getPath(character,0,0,1024).commands;

          // TODO(skishore): We may want a try/catch around this call.

          // const path = svg.convertCommandsToPath(glyph.path.commands);

          const path = svg.convertCommandsToPath(commands);

          stage.onGetPath(undefined, path);

        });

      },

    });

    红色部分即为修改的部分,这时候字体大小就会变成1024的大小,那么接下来会发现字体是反的,这时候需要修改/client/lib/external/opentype/0.4.10/opentype.js

     

    Glyph.prototype.getPath = function(x, y, fontSize) {

        x = x !== undefined ? x : 0;

        y = y !== undefined ? y : 0;

        fontSize = fontSize !== undefined ? fontSize : 72;

        var scale = 1 / this.path.unitsPerEm * fontSize;

        var p = new path.Path();

        var commands = this.path.commands;

        for (var i = 0; i < commands.length; i += 1) {

            var cmd = commands[i];

            if (cmd.type === 'M') {

                p.moveTo(x + (cmd.x * scale), y + (cmd.y * scale));

            } else if (cmd.type === 'L') {

                p.lineTo(x + (cmd.x * scale), y + (cmd.y * scale));

            } else if (cmd.type === 'Q') {

                p.quadraticCurveTo(x + (cmd.x1 * scale), y + (cmd.y1 * scale),

                                   x + (cmd.x * scale), y + (cmd.y * scale));

            } else if (cmd.type === 'C') {

                p.curveTo(x + (cmd.x1 * scale), y + (cmd.y1 * scale),

                          x + (cmd.x2 * scale), y + (cmd.y2 * scale),

                          x + (cmd.x * scale), y + (cmd.y * scale));

            } else if (cmd.type === 'Z') {

                p.closePath();

            }

        }

     

        return p;

    };

     

    修改红色部分。这时候文字就会显示正常。

    OpenType.js

    这里简单介绍一下opentype.js 传送门:https://github.com/opentypejs/opentype.js

    opentype.js是TrueType和OpenType字体的JavaScript解析器和编写器。

    它可以让我们从浏览器或Node.js 访问文本的字体,具体使用方式直接看github就可以了,上面的说明还是比较清楚的。

    使用dictionary.txt和graphics.txt文件

    如何使用这两个文件,我们需要用到hanzi-writer-data hanzi-writer

    运行hanzi-writer-data

    下载hanzi-writer-data,解压后的目录结构:

    打开stroke_data_parse.py文件可以看到

    dictionary_file = os.path.join(root, 'vendor/makemeahanzi/dictionary.txt')

    graphics_file = os.path.join(root, 'vendor/makemeahanzi/graphics.txt')

    他是使用dictionary.txt和graphics.txt生成单个字独立的.json文件,以供hanzi-writer使用

    我们将刚才生成的dictionary.txt和graphics.txt拷贝到vendor/makemeahanzi/目录下

    然后打开cmd输入python stroke_data_parse.py 会看到data文件夹下有生成好的json文件

     

     

    打开文件的时候需要设置utf8编码,参考修改:

     

    with open(dictionary_file,'r',encoding='UTF-8') as f:

      lines = f.readlines()

      for line in lines:

        decoded_line = json.loads(line)

        dict_data[decoded_line['character']] = decoded_line

    with open(graphics_file,'r',encoding='UTF-8') as f:

      lines = f.readlines()

      for line in lines:

        decoded_line = json.loads(line)

        char = decoded_line.pop('character')

        graphics_data[char] = decoded_line

    # write out data

    for char in graphics_data:

      radical = get_radical_strokes(char)

      if radical:

        graphics_data[char]['radStrokes'] = radical

    for char, data in graphics_data.items():

      out_file = os.path.join(output_dir, f'{char}.json')

      with open(out_file, 'w',encoding="UTF-8") as f:

        f.write(json.dumps(data, ensure_ascii=False))

    with open(os.path.join(output_dir, 'all.json'), 'w',encoding="UTF-8") as f:

      f.write(json.dumps(graphics_data, ensure_ascii=False))

    PS:等等 没有python 命令怎么办? 简单啊,装Python,记得装3x以上的版本

    Python安装传送门:https://www.python.org/getit/

     

    hanzi-writer

    我们来看看怎么利用上面生成的json文件吧

    将刚才生成的json文件拷贝到hanzi-writer项目的demo文件夹,将里面的地址替换成刚才生成的all.json数据文件,然后打开后查找刚才我们自己构建的“猫”

    嗯,到这里就全部完成了,开心的撸吧

    部署

    meteor build dist --architecture=os.linux.x86_64

    tar xvf meteor-build-test.tar.gz

    export MONGO_URL='mongodb://**.**.**.**:27017/makeahanzi'

    export PORT=3000

    export ROOT_URL='http://**.**.**.**'

     
     
  • 相关阅读:
    数据库三大范式
    sql 外键 on update cascade 和 on delete cascade 作用区别?
    Mybatis入门简版(二)
    Mybatis入门简版(一)
    Mybatis入门简版(补充)
    SQL中ON和WHERE的区别
    MySQL基础(五)常见运算符
    MySQL基础(四)常用函数
    MySQL基础(三)多表查询(各种join连接详解)
    MySQL基础(二)
  • 原文地址:https://www.cnblogs.com/Shadow3627/p/11582651.html
Copyright © 2020-2023  润新知