Node.jsからFBX SDK Pythonを呼べるDockerイメージ作った

# Node.jsからFBX SDK Pythonを呼べるDockerイメージ作った
とある事情により、Node.jsからFBX SDK Pythonを呼ぶ必要があったので、Dockerイメージを作りました。

作ったDockerイメージは以下に公開しました。
https://hub.docker.com/r/seguropus/fbx-sdk-python-nodejs



# サンプルコード

サンプルコードを以下に置きます。
https://github.com/segurvita/docker-fbx-sdk-python-nodejs



# サンプルコードの使い方

```bash
# Dockerイメージをビルド
docker-compose build

# Dockerコンテナを起動
docker-compose up
```

これで、以下のような表示が出れば成功です。

```
fbx-sdk-python-nodejs    | # FBX SDK can read the following formats.
fbx-sdk-python-nodejs    | 00 FBX (*.fbx)
fbx-sdk-python-nodejs    | 01 AutoCAD DXF (*.dxf)
fbx-sdk-python-nodejs    | 02 Alias OBJ (*.obj)
fbx-sdk-python-nodejs    | 03 3D Studio 3DS (*.3ds)
fbx-sdk-python-nodejs    | 04 Collada DAE (*.dae)
fbx-sdk-python-nodejs    | 05 Alembic ABC (*.abc)
fbx-sdk-python-nodejs    | 06 Biovision BVH (*.bvh)
fbx-sdk-python-nodejs    | 07 Motion Analysis HTR (*.htr)      
fbx-sdk-python-nodejs    | 08 Motion Analysis TRC (*.trc)      
fbx-sdk-python-nodejs    | 09 Acclaim ASF (*.asf)
fbx-sdk-python-nodejs    | 10 Acclaim AMC (*.amc)
fbx-sdk-python-nodejs    | 11 Vicon C3D (*.c3d)
fbx-sdk-python-nodejs    | 12 Adaptive Optics AOA (*.aoa)      
fbx-sdk-python-nodejs    | 13 Superfluo MCD (*.mcd)
fbx-sdk-python-nodejs    | 14 (*.zip)
fbx-sdk-python-nodejs exited with code 0
```

表示されているのは、FBX SDKが読み込み可能なファイル形式の一覧です。

これが表示されたということは、無事にFBX SDK Pythonにアクセスできているということになります。



# 何が起きてるのか？

まず、 `docker-compose up` でDockerコンテナーが起動します。

Dockerコンテナーは、起動したらNode.jsのコード `index.js` を実行します。

`index.js` はPythonのコード `main.py` を呼びます。

`main.py` はFBX SDK Pythonから対応フォーマット一覧を取得して、表示します。



# Dockerfile

PythonとNode.jsが同居したDockerイメージを公開している方がいたので、そちらをもとに `Dockerfile` を作成してみました。

```Dockerfile:Dockerfile
# Python 2.7とNode.js 12が入ったAlpine
FROM nikolaik/python-nodejs:python2.7-nodejs12-alpine

# apkでライブラリ更新
RUN apk update && \
    apk add \
    curl \
    libxml2 \
    libstdc++

# FBX SDKをダウンロード
RUN curl -L \
    https://damassets.autodesk.net/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxpythonsdk_linux.tar.gz \
    -o /tmp/fbx20195_fbxpythonsdk_linux.tar.gz

# インストール先フォルダ作成
RUN mkdir -p /python-fbx/install

# FBX SDKを解凍
RUN tar -zxvf \
    /tmp/fbx20195_fbxpythonsdk_linux.tar.gz \
    -C /python-fbx && \
    printf "yes\nn" | \
    /python-fbx/fbx20195_fbxpythonsdk_linux \
    /python-fbx/install

# FBX SDKをインストール
RUN cp /python-fbx/install/lib/Python27_ucs4_x64/* \
    /usr/local/lib/python2.7/site-packages/

# python-shellをインストール
RUN npm install -g python-shell

# 一時ファイルを削除
RUN rm -r /python-fbx
RUN rm /tmp/fbx20195_fbxpythonsdk_linux.tar.gz

# 環境変数NODE_PATHを設定
ENV NODE_PATH /usr/local/lib/node_modules
```

`python-shell` というのは、Node.jsからPythonを呼ぶためのライブラリです。

グローバル領域にインストールしたので、index.jsが `require` で取得できるように、環境変数 `NODE_PATH` を設定しています。



# docker-compose.yml

`docker-compose.yml` はこんな感じです。

```docker-compose.yml
version: '3'
services:
  fbx-sdk-python-nodejs:
    image: 'seguropus/fbx-sdk-python-nodejs'
    container_name: 'fbx-sdk-python-nodejs'
    build:
      context: ./
      dockerfile: ./Dockerfile
    volumes:
      - .:/src
    working_dir: /src
    command: node index.js
```

Dockerコンテナー起動時に `index.js` が実行されます。




# index.js

index.jsはこんな感じです。

```index.js
const pythonShell = require('python-shell');

// python-shellのオプション
const pyOption = {
    mode: 'text',
    pythonPath: '/usr/local/bin/python',
    pythonOptions: ['-u'],
    scriptPath: '/src',
}

// main.pyを実行
const pyShell = new pythonShell.PythonShell('main.py', pyOption);

// Pythonの標準出力を表示
pyShell.on('message', (message) => {
    console.log(message);
});

// 終了処理
pyShell.end(function (err, code, signal) {
    if (err) {
        console.error(err);
    }
    console.log('The exit code was: ' + code);
});
```

`python-shell` で `main.py` を呼んでいます。



# main.py

`main.py` はこんな感じです。

```main.py
from fbx import *


def list_reader_format(manager):
    print('# FBX SDK can read the following formats.')
    for formatIndex in range(manager.GetIOPluginRegistry().GetReaderFormatCount()):
        description = manager.GetIOPluginRegistry().GetReaderFormatDescription(formatIndex)
        print(formatIndex, description)


def main():
    # Create
    manager = FbxManager.Create()
    scene = FbxScene.Create(manager, "fbxScene")

    # List
    list_reader_format(manager)

    # Destroy
    scene.Destroy()
    manager.Destroy()


if __name__ == '__main__':
    main()
```

`from fbx import *` でFBX SDK Pythonを読み込んでいます。
`list_reader_format()` という関数で、FBX SDK Pythonが読み込み可能なファイル形式の一覧を標準出力に表示しています。

無事にNode.jsからFBX SDK Pythonを呼べるDockerイメージを作ることができました！



# Docker Hubに公開してみる

せっかくなので、Docker Hubに公開してみます。

```bash
# ログインする
docker login

# Dockerイメージをプッシュする
docker push seguropus/fbx-sdk-python-nodejs
```

以下に公開されました。
https://hub.docker.com/r/seguropus/fbx-sdk-python-nodejs




# さいごに

本記事作成にあたり、以下のページを参考にしました。ありがとうございました。

- https://hub.docker.com/r/lerignoux/python-fbx
- https://hub.docker.com/r/nikolaik/python-nodejs
- [Node.jsからPythonのコードを呼び出すPython-shellを使ってみた](https://qiita.com/Ayumu_walker/items/fae0e368d635c6b70fea)
- [FBX SDK Pythonが対応しているファイル形式一覧](https://qiita.com/segur/items/75428cb98b8a28c687e3)
- [Node.js グローバルインストールでハマった](https://qiita.com/shintarogit/items/70f193829f4360dca771)