Google Fontが拡充されたので、Cloudinaryに全フォントファイルをアップロードする

#はじめに
最近、Google Fontsにたくさんの日本語フォントが追加になりました。[^2]
[^2]: https://fonts.google.com/?subset=japanese


画像加工のクラウドサービスCloudinaryで新しい日本語を使えるようにするために、全ファイルをアップロードしました。

その時に使ったスクリプトを共有します


#おさらい
Cloudnaryは画像を保存して配信するサービスです。画像を配信するときに、変形や文字入れの加工ができます。

[詳しくはこちらへ](https://qiita.com/kanaxx/items/7d88948c9f8f43cdf760)


Cloudinaryは文字入れ（オーバーレイ変換）をするときにフォントを指定することができるのですが、サポートされている日本語フォントがいまいちです。はっきり言ってしょぼいです。

フォントの種類が足りない場合は、フォントファイルをアップロードすることができるようになっています。[^1]
面倒なので、Google Fontsにある日本語フォントファイルを全部アップロードしてしまいます。


#使ったもの
- PHP (5.6)
- Google Fonts API
- Coudinary api + node SDK

```
"c:\Program Files\php-5.6.39-Win32-VC11-x64\php.exe" -v
PHP 5.6.39 (cli) (built: Dec  5 2018 21:24:55)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
```

CloudinaryのPHP SDKがPHP5.6を使えと言っているため。いまさら5.6で実施[^3]
[^3]: https://github.com/cloudinary/cloudinary_php#setup

## やること
1. google font apiで日本語のフォントを探す
1. フォントファイル(.ttf/.otf)をダウンロードする
1. Cloudinaryにアップロードする

Google Fonts APIは無料で使えます。GoogleアカウントでAPIのトークンをとっておく必要があるので、自分でとりましょう。

https://developers.google.com/fonts/docs/developer_api

フォントファイルを持ってくる部分と、Cloudinaryにアップロードする部分を2つにわけました。

## 準備
composer.jsonを作ってSDKをインストール

```json:composer.json
{
    "require": {
      "cloudinary/cloudinary_php": "^2"
    },
    "config": {
        "platform": {
            "php": "5.6.39" 
        }
    }
}
```

Cloudinaryのマニュアルには`require`しか書いてないけど、PHPのバージョンを指定してインストール

```bash:コマンドライン
composer install
```


##コード1 (google font api)

Google Fonts APIからデータを持ってくる部分。
このAPIはパラメータで絞り込みができないので、全フォントデータを持ってきてからデータをフィルタする実装です。

日本語対応かどうかは、`subsets`の配列の中に`japanese`が入っているかで判断しています。
1つのフォントに複数のスタイルが設定されている場合、フォントファイルも複数になるので`files`の配列から全部持ってきます。

フォントファイルの名前は以下のルールにします。この名前がそのままCloudinaryのpublic_idになり、URLで指定するフォント名となります。
`font family`-`font style`.`拡張子(ttf or otf)`

ただし、スタイル名がregularのときは、付けると長くなるので省略します。


```php:get_google_font_api.php

<?php
$google_api_token = 'Your TOKEN';
$font_api_url = 'https://www.googleapis.com/webfonts/v1/webfonts?key=' . $google_api_token ;

$font_json = file_get_contents($font_api_url);
$font_list = json_decode($font_json, true);

foreach($font_list['items'] as $n=>$font){
    echo ($n+1).'/'.count($font_list['items']) . " " . $font['family'] . PHP_EOL;

    //日本語フォントだけ
    if( in_array('japanese', $font['subsets'] )){
        echo $font['family'] . PHP_EOL;
        echo count($font['files']) . PHP_EOL;
        $file_name_font_family = $font['family'];

        foreach($font['files'] as $style=>$url){
            echo " $style : $url" . PHP_EOL;

            //スタイルがregularではない時だけ、ファイル名に付ける
            $file_name_font_style = '';
            if($style !== 'regular'){
                $file_name_font_style = '_'.$style;
            }

            //ファイル名の拡張子は最後の.以降の文字
            $splitted_url = explode('.', $url);
            $file_name_ext = end($splitted_url);

            //ファイル名完成
            $file_name = "${file_name_font_family}${file_name_font_style}.${file_name_ext}";

            //ファイルをとってきて保存
            $font_data = file_get_contents($url);
            $bytes = file_put_contents('fonts/' . $file_name, $font_data);
        }
    }
}

```

これを実行すると、`getGoogleFont.js`の下に`/fonts`フォルダが作られて、フォントファイルがダウンロードします。

2021/9/18時点だと、78ファイルをダウンロードできました。

##コード2 (Cloudinary)

ローカルディスクにあるフォントファイルを順番にアップロードする部分。
Google Fontsに無いフォントでも、`fonts`フォルダ内におけばアップロードします。

```php:upload_fonts_cloudinary.php

<?php
require_once "vendor/autoload.php";
use Cloudinary\Cloudinary;
$cloudinary = new Cloudinary('cloudinary://apikey:secret@cloudname');

foreach( glob('fonts/*') as $file){
    $file_name = pathinfo($file)['basename'];
    echo "uploading $file_name..." . PHP_EOL;

    $api_options = ['resource_type'=>'raw','type'=>'authenticated', 'public_id'=>$file_name];
    try{
        $result = $cloudinary->uploadApi()->upload($file, $api_options);
        echo "uploaded. public_id is " . $result['public_id'] . PHP_EOL;

    }catch(Exception $ex){
        echo "error" . PHP_EOL . $ex->getMessage() . PHP_EOL;
    }
}
```

フォントファイルのサイズが大きすぎてエラーになるものがあります。
Cloudinaryの仕様上、1ファイルの最大が10485760バイト（10メガバイト）なのであきらめましょう。

```
[2021-09-18 20:23:49] cloudinary.CRITICAL: Request to Cloudinary server returned an error {"statusCode":400,"message":"File size too large. Got 33153716. Maximum is 10485760."} []
[2021-09-18 20:23:49] cloudinary.CRITICAL: Async request failed {"code":0,"message":"File size too large. Got 33153716. Maximum is 10485760."} []
[2021-09-18 20:23:49] cloudinary.CRITICAL: Single Chunk Async POST request failed {"code":0,"message":"File size too large. Got 33153716. Maximum is 10485760."} []
error
File size too large. Got 33153716. Maximum is 10485760.
```

しっぽり明朝系は全滅でした。残念。


#アップロードしたフォントを使ってみる

9回オーバーレイをするとこんな感じです。

<img src="https://res.cloudinary.com/kanaxx/g_north_west,co_rgb:FFF,l_text:M%20PLUS%20Rounded%201c.ttf_80:%E5%B7%A6%E4%B8%8A/g_north,co_rgb:FFF,l_text:Dela%20Gothic%20One.ttf_80:%E4%B8%8A/g_north_east,co_rgb:FFF,l_text:Hachi%20Maru%20Pop.ttf_80:%E5%8F%B3%E4%B8%8A/g_west,co_rgb:FFF,l_text:Hina%20Mincho.ttf_50:%E3%81%B2%E3%81%A0%E3%82%8A/g_center,co_rgb:FFF,l_text:Kaisei%20Decol.ttf_50:%E3%81%BE%E3%82%93%E3%81%AA%E3%81%8B/g_east,co_rgb:FFF,l_text:Kaisei%20HarunoUmi.ttf_50:%E3%81%BF%E3%81%8E/g_south_west,co_rgb:FFF,l_text:Kiwi%20Maru-500.ttf_30:%E3%83%92%E3%83%80%E3%83%AA%E3%82%B7%E3%82%BF/g_south,co_rgb:FFF,l_text:Kosugi%20Maru.ttf_30:%E3%82%B7%E3%82%BF/g_south_east,co_rgb:FFF,l_text:Potta%20One.ttf_30:%E3%83%9F%E3%82%AE%E3%82%B7%E3%82%BF/600x500.png">

##URL 
上のURL。実際は1行で書きます。

https\://res.cloudinary.com/kanaxx
/g_north_west,co_rgb:FFF,l_text:**M%20PLUS%20Rounded%201c.ttf**_80:%E5%B7%A6%E4%B8%8A
/g_north,co_rgb:FFF,l_text:**Dela%20Gothic%20One.ttf**_80:%E4%B8%8A
/g_north_east,co_rgb:FFF,l_text:**Hachi%20Maru%20Pop.ttf**_80:%E5%8F%B3%E4%B8%8A
/g_west,co_rgb:FFF,l_text:**Hina%20Mincho.ttf**_50:%E3%81%B2%E3%81%A0%E3%82%8A
/g_center,co_rgb:FFF,l_text:**Kaisei%20Decol.ttf**_50:%E3%81%BE%E3%82%93%E3%81%AA%E3%81%8B
/g_east,co_rgb:FFF,l_text:**Kaisei%20HarunoUmi.ttf**_50:%E3%81%BF%E3%81%8E
/g_south_west,co_rgb:FFF,l_text:**Kiwi%20Maru-500.ttf**_30:%E3%83%92%E3%83%80%E3%83%AA%E3%82%B7%E3%82%BF
/g_south,co_rgb:FFF,l_text:**Kosugi%20Maru.ttf**_30:%E3%82%B7%E3%82%BF
/g_south_east,co_rgb:FFF,l_text:**Potta%20One.ttf**_30:%E3%83%9F%E3%82%AE%E3%82%B7%E3%82%BF
/600x500.png

デコードすると

https\://res.cloudinary.com/kanaxx
/g_north_west,co_rgb:FFF,l_text:M PLUS Rounded 1c.ttf_80:左上
/g_north,co_rgb:FFF,l_text:Dela Gothic One.ttf_80:上
/g_north_east,co_rgb:FFF,l_text:Hachi Maru Pop.ttf_80:右上
/g_west,co_rgb:FFF,l_text:Hina Mincho.ttf_50:ひだり
/g_center,co_rgb:FFF,l_text:Kaisei Decol.ttf_50:まんなか
/g_east,co_rgb:FFF,l_text:Kaisei HarunoUmi.ttf_50:みぎ
/g_south_west,co_rgb:FFF,l_text:Kiwi Maru-500.ttf_30:ヒダリシタ
/g_south,co_rgb:FFF,l_text:Kosugi Maru.ttf_30:シタ
/g_south_east,co_rgb:FFF,l_text:Potta One.ttf_30:ミギシタ
/600x500.png

# Cloudinary SDKを使うとエラーになるとき
このエラーが出るときは、たぶんPHPのバージョンが違います。

>PHP Fatal error:  Declaration of Cloudinary\Log\LoggerDecorator::emergency($message, array $context = []) must be compatible with Psr\Log\LoggerInterface::emergency(Stringable|string $message, array $context = []): void in C:\work\cloudinary-font\vendor\cloudinary\cloudinary_php\src\Log\LoggerDecorator.php on line 195

PHP8にCloudnarySDKをインストールして使ったらエラーになりました。
[GithubのREADME](https://github.com/cloudinary/cloudinary_php#setup)にv5.6って書いてあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/00a86468-bb3c-0f9e-785a-90e693427108.png)

[^1]: https://cloudinary.com/documentation/layers#custom_fonts