【CSS/Javascript】手書き風の文字を錬成して時代錯誤に立ち向かえ

## TL;DR
* 手書き文化は滅べ
* それっぽく対抗してみた
* 実運用は自己責任で…

## intro
わし「ES提出したるで～、OpenES(※)でいくらでも出したるわ」
企業「**手書き**ね＾＾」
わし「」

こういう非効率の塊みたいな企業が死滅することを祈りながら、技術的に解決することを試みる。

※OpenES: Web上で書いてそのまま提出できるES。ガクチカ(学生時代に力を入れていたこと)という9割の人間はろくに書けない質問などを提供してくれる


## 目標
ぱっとみ手書きっぽくないようなフォントの組み合わせとかを錬成。

## 使用フォント
* `ダーツフォント`
    * http://www.p-darts.jp/font/dartsfont/
    * ボールペンで書いたような細いフォント(公式ページより)
        * 見てもらうとわかるが、字が綺麗
    * `font-weight: bold`じゃないとめっちゃ細い
* `Kalam`
    * https://fonts.google.com/specimen/Kalam?selection.family=Kalam
    * Google Fontから適当に拝借
    * …したいところだが、そのままだと文字の太さバランスが合わないので少し調整が必要
        * https://google-webfonts-helper.herokuapp.com/fonts/kalam?subsets=latin
        * からフォントファイルをDL
    * ダーツフォントの方に文字幅を合わせるので、英語主体の文章だと違和感はある
        * 気になるならcssを分離したほうがいい

## 1: それっぽいフォントを組み合わせる
CSSを整備する。

```css
@font-face {
	font-family: 'Kalam';
	font-weight: bold; /* ここをboldに指定することで、標準の太さフォントを太字と誤認させる */
	src: local('Kalam'), local('Kalam-Regular'),
	     url('./fonts/kalam/kalam-v9-latin-regular.woff2') format('woff2'),
	     url('./fonts/kalam/kalam-v9-latin-regular.woff') format('woff');
}
@font-face {
	font-family: 'dartsfont';
	src: local('dartsfont'), 
	     url('./fonts/dartsfont/dartsfont.eot?#iefix') format('eot'),
		 url('./fonts/dartsfont/dartsfont.woff') format('woff');
}

/* 手書き風 */
.hw {
	font-family: 'Kalam', 'dartsfont';
	font-weight: bold;
	letter-spacing: -1px;         /* そのままだと若干幅が広い。お好みで */
	text-shadow: 0 0 1px #EEE;    /* 影をつけると文字が濃く見える。好み */
	color: #222;                  /* ここもお好み */
	transform: rotate(0.05deg);   /* Windows Chromeできれいに描画してもらうため */
}
```

フォントは`css`の中身見て適宜配置。これでひとまずそれっぽくなる。

この他に、行間とかを調整するために`p`を修飾する。

```css
p {
    white-space: pre-line;  /* コピペできるように */
    font-size: 1.4rem;      /* 文字サイズ。任意 */
    line-height: 1.3;       /* 行間。任意 */
    line-break: strict;     /* 禁則処理。あったほうが自然 */
    text-align: justify;    /* 両端揃え。これも多分あったほうがいい */
}
```

これで準備1は完了。
以上のCSSを使用して、文章をHTMLで書いてみるとこんな感じで表示される。
(文章は適当に[ここ](https://unistyleinc.com/techniques/103)から拝借)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/282132/6d407a54-de1b-8749-ef80-ca4890db84e8.png)

わりとそれっぽい。
半角数字は全体的に詰まってみえるため、1文字なら全角を使うことを推奨。
（上の画像でいうと「学生**１**位」の部分）

## 2: ランダム性を導入する
### コード
このままだとPCで出力した感がまだ残っている。
というのも、各フォントごとの文字の形が全く同じだからである。

これを解消するのに`Javascript`を使用する。
`jQuery`と`sugarjs`を使用して、こんな感じで書いてみた。

```javascript
Sugar.extend();

$(() => {
	var hws = $(".hw");
	hws.each((i,e) => {
		console.log(e.textContent.split(''));
		e.innerHTML = e.textContent.split('').map(t => {
			if(t === '\n') return `<br/>`;
			if(t === '\t') return ``;
			return `<span style="${generateRandomizeStyle()}">${t}</span>`;
		}).join("");
	});
});

function generateRandomizeStyle(){
	const CharBeautyRate = 500; // 文字の綺麗さ指数。だいたい100-1000の範囲
	var color = Number.random(0, 0x30);
	var colorRgb = [1,1,1].map(e => color);
	var tax = 1 + Number.random(-10, 10) / CharBeautyRate;
	var tby = 1 + Number.random(-10, 10) / CharBeautyRate;
	var tay = Number.random(-10, 10) / CharBeautyRate;
	var tbx = Number.random(-10, 10) / CharBeautyRate;
	var transfromLocate = [1,1].map(e => Number.random(-5, 5) / 10);
	var letterSpace = Number.random(-8, -5) / 5;
	return `
		display: inline-block;
		white-space: pre;
		color: rgb(${colorRgb});
		letter-spacing: ${letterSpace}px;
		transform: matrix(${tax},${tay},${tbx},${tby},${transfromLocate});
	`;
}
```

各文字ごとに`<span>`で囲み、それぞれについてランダムで少し文字を変形させる。
このとき、あんまり派手に変形させると変な文字になるので、微小にずらしている。
調整しているパラメーターは「色」「文字空白」「文字形状」の3つ。

### 文字形状の調整
色、空白はランダム化させるだけでいいが、形状はそこまで単純でもない。
今回は、`transform:matrix`を使用した。

`matrix`は行列形式で文字変形を指定する。
詳しくはググってもらうのが早いが、簡単に説明すると
`matrix(a, b, c, d, e, f)`と指定した場合、前半の`a～d`の部分が行列になる。

```math
\begin{matrix}
a & b \\
c & d 
\end{matrix}
```

一切の変換を施さない行列はというと、

```math
\begin{matrix}
1 & 0 \\
0 & 1 
\end{matrix}
```

になる。
今回は少しだけ動かしたいので、

```math
\begin{matrix}
1+δw & 0+δx \\
0+δy & 1+δz 
\end{matrix}
```

といったようにパラメーターを微小に動かす。
ここの値の動かし度合いで字の汚さを簡易的に指定することができる。

先程のコードでいうと

```javascript
var tax = 1 + Number.random(-10, 10) / CharBeautyRate;
var tby = 1 + Number.random(-10, 10) / CharBeautyRate;
var tay = Number.random(-10, 10) / CharBeautyRate;
var tbx = Number.random(-10, 10) / CharBeautyRate;
```
の`CharBeautyRate`の部分である。




### サンプル例
上記コードを当てはめると、こんな感じの文字になる。

`CharBeautyRate=500`
![CharBeautyRate=500](https://qiita-image-store.s3.amazonaws.com/0/282132/06526093-d1eb-33c1-f834-151eea3c82d6.png)

`CharBeautyRate=300`
![image.png](https://qiita-image-store.s3.amazonaws.com/0/282132/a5170e13-387f-03d6-208a-ea253a246fd7.png)

`CharBeautyRate=100`
![image.png](https://qiita-image-store.s3.amazonaws.com/0/282132/bf5be57c-9267-9c20-7ed0-b7b120c64ce6.png)

`CharBeautyRate=50`
![image.png](https://qiita-image-store.s3.amazonaws.com/0/282132/bd95f0cb-8db3-1bc6-cdea-199842879e5e.png)

`CharBeautyRate=50`ぐらいになるとどういった変形を施しているかが明確になる。
徐々に文字が変な形になることがわかるだろう。
手書き風かつ丁寧な文章にしたいので、200-500ぐらいが無難だろうか。

今回は`Number.random`で一様乱数を使っているが、正規分布に従わせるとよりそれっぽくなりそう。

## demo
つくりました。
https://arika0093.github.io/handwriting/tools.html

![image.png](https://qiita-image-store.s3.amazonaws.com/0/282132/3f536087-2f19-3b0a-8777-79ad77e5c5fd.png)
生成ボタンを押すたびに字の形状が毎回変わります。

## 課題
* フォントの太さが均一
    * `text-shadow`でうまいこと調整できるか
    * ボールペン字ならそこまで気にならないか
* とめはね等の調節
    * さすがに厳しい
* 文字変形の単純さ
    * うまい方法があまり思いつかない
* 字の「癖」の再現
    * `transform:matrix`を一様乱数でなくある程度の傾向をつける等？
* 実際のESに貼り付ける方法
    * `Word`等で位置を調節して印刷が一番無難？
* **いつ使うのか**
    * どうでもいい企業にしか使えないよね…

## 参考文献
https://xar.sh/post/95166529739/
https://sugarjs.com/docs/#/Number/random
https://qiita.com/junya/items/a1ad6126fa0315acc2aa
https://ginpen.com/2018/11/13/understanding-transform-matrix/
https://understanding-transform-matrix.ginpei.info/