アズマオオズアリの頭部とキーボードを模したアイコンとjonnityという文字

Synfig Studioのlottie出力時にPythonのエラーに遭った話

個人開発 トラブルシュート

2024/9/8


要約

  • Synfig Studioには、lottie形式で出力する機能がプラグインとして実装されている (コードでいうとこのへん)
  • このプラグインはPythonで実行されていて、lottieのプレビュー用のHTMLを出力する際に、JavascriptのコードがUTF-8で書かれているファイルを読み込んで書き込むような処理がある?
  • Pythonがシステムのlocaleからデフォルトのエンコード設定を変えるような動きをするので、日本語環境でそのまま使おうとするとShift JISでは読み込めない旨のエラーが発生する
  • 回避策として、コントロール パネル\時計と地域から「地域」→「システムロケールの変更」→「ベータ: ワールドワイド言語サポートでUnicode UTF-8を使用」にチェックしたら、動作するようになった

エラーの詳細

まず、Synfig Studioで発生した具体的なエラーは以下の通り。

  • Synfig Studioのver.1.4.5およびver.1.5.3で確認
    • 1.4.5では、「プラグイン」→「Export to lottie format」から実行
    • 1.5.3では、「ファイル」→「Export...」からフォーマットをLottie HTML Preview (*.html)あるいはLottie HTML Preview without variable widths (*.html)を選択して「保存」
  • 中心に円を追加しただけの.sifzファイルを使用 (.sifファイルでも同様の結果となった)
  • 以下のようなエラーダイアログが表示される (エラー発生箇所の行数だけ異なる)
1Traceback (most recent call last):
2  File "{installedPath}\share\synfig\plugins\lottie-exporter\lottie-exporter.py", line 167 (1.5.3では"line 147"), in <module>
3    out = gen_html(out)
4  File "{installedPath}\share\synfig\plugins\lottie-exporter\lottie-exporter.py", line 92 (1.5.3では"line 75"), in gen_html
5    bodymovin_script = f.read()
6UnicodeDecodeError: 'cp932' codec can't decode byte 0x93 in position 30346: illegal multibyte sequence

f.read()UnicodeDecodeErrorが起きているとのことなので、以下のコードの動作を確認してみた。 utf8.txtshiftJIS.txtはそれぞれ、bodymovin_scriptという変数から、HTML出力に成功した際のscriptタグの中身を入力した。

encodingTest.py
1import locale
2print("encoding: ", locale.getencoding())
3
4print("--- utf-8 ---")
5try:
6  print("start reading")
7  utf8File = open("./utf8.txt", "r")
8  utf8File.read(-1)
9  print("finish reading")
10except UnicodeDecodeError as e:
11  print("error: ", type(e))
12  print("utf-8 error: ", e)
13finally:
14  utf8File.close()
15
16print("--- shift JIS ---")
17try:
18  print("start reading")
19  shiftJisFile = open("./shiftJIS.txt", "r")
20  shiftJisFile.read(-1)
21  print("finish reading")
22except UnicodeDecodeError as e:
23  print("error: ", type(e))
24  print("shift JIS error: ", e)
25finally:
26  shiftJisFile.close()

結果として、「ベータ: ワールドワイド言語サポートでUnicode UTF-8を使用」が未設定のときには↓のようになり、

1{workingDir}> python .\encodingTest.py
2encoding:  cp932
3--- utf-8 ---
4start reading
5error:  <class 'UnicodeDecodeError'>
6utf-8 error:  'cp932' codec can't decode byte 0x93 in position 31312: illegal multibyte sequence
7--- shift JIS ---
8start reading
9finish reading

チェックを付けると↓のように変わった。

1encoding:  cp65001
2--- utf-8 ---
3start reading
4finish reading
5--- shift JIS ---
6start reading
7finish reading

ということで、

  • locale.getencoding()の結果はcp932cp65001
    • cp932はShift JIS規格のエンコーディング (cpは"code page"を意味するらしい)
    • cp65001はWindows内でutf-8を表すエンコーディング? (ちゃんとした情報が見つからなくてよくわかってない)
  • cp932 (Shift JIS) のエンコーディングになっているときには、'cp932' codec can't decode byte 0x93という、Synfigで起きているエラーと同じエラーが発生している
  • cp65001 (utf-8?)になっているときには、いずれのファイルもエラーなく読み込めている (Synfigと動作が同じ)

という結果となった。 このことから、やはりPythonのf.read()はシステムのロケール情報からデフォルトのエンコーディング設定を変えており、それがSynfig Studioの動作に影響を与えていると見てよさそう。

Synfigのことを調べててもどうしようもなく、Python (環境) 側で対処しないといけないのは不親切では?

と思ったので、Synfigにissueとして報告してみた: #3418

Pythonでファイル読込してるところでエンコーディングを指定すれば、Python側のことは考慮不要になるんだろうなと思ってはいる。 どこを直すべきなのかも頑張ってコード読めばわかる気はするんだよな (このこと考えるにあたってちらっと読んだときには、なんかライブラリ通じて読み込んでる?からよくわかんなくなった)。 なので、「日本語環境のことなんか日本人が直せばいいじゃん」と言われてしまったら、自力で直しにかかってみようかな。 けっこうSynfigのこと好きになってきてるし、OSSにcontributeしてみたいし!