はじめに
AWS LambdaでPhantomJS日本語フォント対応では fontconfig をビルドしてデプロイパッケージに含めているが、 Lambdaの実行環境を確認したところ、fontconfig は導入されている。
したがって、フォントキャッシュさえ生成すれば、実行環境のfontconfigが利用できる。
なおLambdaの実行環境のfontconfigはXDGには対応していない。
検証時、fc-cache
のバージョンは 2.8.0 であった。
Lambda の実行時 LAMBDA_TASK_ROOT=/var/task/share/fonts
となっている。
fontconfig は
~/.fonts.conf
~/.fonts
~/.fontconfig
は見るので、HOME=$LAMBDA_TASK_ROOT
に設定して、これらが
$HOME/
.fontconfig
.fonts
.fonts.conf
というツリー構造で見えるようにデプロイパッケージに含めてやれば良い。
フォントキャッシュの生成
NotoSansCJK のパッケージから NotoSansCJK-Regular.ttc
を抽出して、.fonts に配置する。
Lambda の実行時に $LAMBDA_TASK_ROOT/.fontconfig
は書き込みできないため、そのままでは fc-cache の実行でキャッシュファイルの作成に失敗する。
いったん /tmp/cache/fontconfig
にキャッシュを生成して、デプロイパッケージでは .fontconfig
に配置する。
このため、次の内容で .fonts.conf
を作成する。
<fontconfig>
<cachedir>/tmp/cache/fontconfig</cachedir>
</fontconfig>
フォントキャッシュを生成する Lambda 関数は次の通り。
from __future__ import print_function
import subprocess
import sys
import os
import base64
import boto3
import logging
from os.path import join
logger = logging.getLogger()
logger.setLevel(logging.INFO)
BUCKET_NAME = 'バケット名'
def lambda_handler(event, context):
os.environ['HOME'] = os.environ['LAMBDA_TASK_ROOT']
try:
os.makedirs('/tmp/cache/fontconfig')
except OSError as e:
(errno, strerror) = e
print('OSError {}'.format(strerror))
args = [ 'fc-cache', '-v', join(os.environ['HOME'], '.fonts') ]
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
returncode = p.returncode
stdout_data, stderr_data = p.communicate()
print('stdout_data:\n' + stdout_data.decode('utf-8'))
print('stderr_data:\n' + stderr_data.decode('utf-8'))
s3bucket = boto3.resource('s3').Bucket(BUCKET_NAME)
tmp_fontconfig = '/tmp/cache/fontconfig'
for cache in os.listdir(tmp_fontconfig):
response = s3bucket.upload_file(join(tmp_fontconfig, cache), cache)
with open(join(tmp_fontconfig, cache), mode='rb') as f:
print("{}:\n{}\n".format(cache, base64.b64encode(f.read())))
デプロイパッケージの内容
% unzip -l fontcache.zip
Archive: fontcache.zip
Length Date Time Name
-------- ---- ---- ----
1116 10-16-17 15:34 fontcache.py
105 10-12-17 20:54 .fonts.conf
0 10-12-17 22:01 .fonts/
18748872 10-12-17 17:04 .fonts/NotoSansCJK-Regular.ttc
-------- -------
18750093 4 files
この Lambda 関数を実行すると、S3 にキャッシュファイルがアップロードされる。
テスト
先ほど生成したキャッシュファイルを .fontconfig に配置する。
phantomjs
のロードモジュールと rasterize.js
は bin
ディレクトリに配置する。
phantomjs でのスクリーンキャプチャーは、Screen Capture | PhantomJSを参考に、 rasterize.js 使用してテストプログラムを作成した。
from __future__ import print_function
import subprocess
import tempfile
import os
import boto3
def phantomjs(url, bucket, name):
from os.path import join
run_dir = os.environ['LAMBDA_TASK_ROOT']
bin_dir = join(run_dir, 'bin')
args = [ join(bin_dir, 'phantomjs'), join(bin_dir, 'rasterize.js'), url ]
with tempfile.NamedTemporaryFile(suffix='.png') as f:
args.append(f.name)
print('{}\n'.format(' '.join(args)))
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
returncode = p.returncode
stdout_data, stderr_data = p.communicate()
s3 = boto3.resource('s3')
bucket = s3.Bucket(bucket)
response = bucket.upload_file(f.name, name)
print('returncode {}\n'.format(returncode))
print('stdout:: \n{}\n'.format(stdout_data.decode('utf-8')))
print('stderr:: \n{}\n'.format(stderr_data.decode('utf-8')))
print('stderr:: \n{}\n'.format(stderr_data.decode('utf-8')))
print('response {}\n'.format(response))
def lambda_handler(event, context):
os.environ['HOME'] = os.environ['LAMBDA_TASK_ROOT']
os.chdir(os.environ['LAMBDA_TASK_ROOT'])
phantomjs('https://www.amazon.co.jp', 'バケット名', 'screenshot.png')
デプロイパッケージの内容
% unzip -l phantomjs.zip
Archive: phantomjs.zip
Length Date Time Name
-------- ---- ---- ----
1304 10-13-17 17:09 phantomjs.py
105 10-12-17 20:54 .fonts.conf
0 10-12-17 22:01 .fonts/
18748872 10-12-17 17:04 .fonts/NotoSansCJK-Regular.ttc
0 10-12-17 23:05 .fontconfig/
12792 10-12-17 22:27 .fontconfig/996789b4ba9d471a5fd80c008c2b2acf-le64.cache-3
67932064 01-25-16 10:01 bin/phantomjs
2241 10-12-17 23:19 bin/rasterize.js
-------- -------
86697378 8 files
この Lambda 関数を実行して、うまく画面がキャプチャーされていればよい。
phantomjs の実行のために、Lambda が使用するメモリを192MB以上にしておかないと、メモリ不足で処理が途中で打ち切られる。