On this page |
fileResponse(file_path, content_type=None, delete_file=False, download_as_filename=None):
→ hou.webServer.Response
-
ディスク上のファイルの内容を提供する時はいつでも、その内容を文字列として読み込んで返すのではなく、この関数を使用してください。
-
(CSS、JavaScript、画像、動画ファイルなどの)静的ファイルに関しては、Pythonハンドラーでそれらを提供するのではなく、hou.webServer.registerStaticFilesDirectory()を使用して、サーバー側でそれらのファイルを自動的に提供できるようにセットアップしてください。この手法を使って静的ファイルを提供する方がパフォーマンスが良くて、Pythonを呼び出す必要がありません。
-
ファイルの内容は一度にすべてメモリに読み込まれるわけではありません。
file_path
クライアントにダウンロードするディスク上のファイルのファイルパス。
content_type
レスポンスのMIMEコンテンツタイプ。
これがNone
(デフォルト)の場合、この関数はmimetypes.guess_type()
を使用して、ディスクファイルの拡張子からMIMEタイプを推測します。
delete_file
これがTrue
の場合、サーバーは、ファイルをクライアントに送信した後にそのファイルを削除します。
これは、一時ファイルには便利ですが、コードの挙動を変更した時にこれを無効にするのを忘れた場合に非常に危険になる場合があります。
download_as_filename
クライアントが名前を付けてダウンロードするファイルのファイル名文字列をオプションで指定することができます。
サーバーはContent-Disposition
ヘッダを送信します。
import hou @hou.webServer.urlHandler("/textures", prefix=True) def texture_download(request): path = request.path() assert path.startswith("/textures") parm_name = path[10:] if not parm_name: return hou.webServer.notFoundResponse(request) node = hou.node("/mat/my_material") texture_parm = node.parm(parm_name) texture_path = texture_parm.evalAsString() return fileResponse(request, texture_path)
相対ファイルを提供する方法 ¶
ハンドラーを含んだPythonスクリプトファイルを基準とした相対パスを使用してファイルを提供したい場合があります。
通常では、__file__
変数には現在実行されているPythonスクリプトファイルのパスが格納されるので、os.path.dirname(__file__)
を使用することで、そのPythonスクリプトファイルが含まれているディレクトリを取得することができます。
しかし、例えばコマンドラインからPythonスクリプトを使ってHoudiniを起動した場合などでは、__file__
が定義されていない場合があります。
これを補足するには、以下の関数を使用すると良いでしょう:
import os import inspect def script_file_dir(): try: file_path = __file__ except NameError: file_path = inspect.getfile(inspect.currentframe()) if not os.path.isabs(file_path): file_path = os.path.normpath(os.path.join(os.getcwd(), file_path))) return os.path.dirname(file_path)
画像をレンダリングするサンプル ¶
import os import tempfile @hou.webServer.urlHandler("/tommy.jpg") def tommy(request): """Mantraを使用して、Tommyテストジオメトリの画像をレンダリングします。""" rop = hou.node("/out/tommy_rop") if rop is None: rop = create_tommy_scene() rop.render() return hou.webServer.fileResponse(rop.evalParm("vm_picture")) def create_tommy_scene(): sop = hou.node("/obj").createNode("geo").createNode("testgeometry_tommy") cam = hou.node("/obj").createNode("cam", "tommy_cam") cam.parmTuple("t").set((0, 1.3, 2.3)) output_file = os.path.join(tempfile.gettempdir(), "tommy.jpg") rop = hou.node("/out").createNode("ifd", "tommy_rop") rop.parm("camera").set(cam.path()) rop.parm("vobject").set(sop.parent().name()) rop.parm("vm_picture").set(output_file) return rop
3D Webビューアのサンプル ¶
このサンプルでは、GLTF ROPを使用してCragテストジオメトリをGLTFフォーマットに保存し、 Babylon.jsを使用してブラウザでそのジオメトリを表示します。
server.py
import os import tempfile import json import hou import webutils OUTPUT_DIR = os.path.join(webutils.script_file_dir(), "static", "temp") @hou.webServer.urlHandler("/") def index_view(request): return hou.webServer.redirect(request, "/static/index.html") @hou.webServer.urlHandler("/static/output/model.gltf") def gltf_view(request): frame = float(request.GET().get("frame", 1)) # GLTF ROPを使用して、一時GLTFファイルを書き出します。 # このROPは、処理時に.binとテクスチャを生成します。 gltf_temp_file = temp_file_path(".gltf") hou.parm("/out/gltf1/file").set(gltf_temp_file) hou.node("/out/gltf1").render(frame_range=(frame, frame)) # ここではJSONを読み込んでURIを調整することもできたのですが、その必要がなかったことを注記しておきます。 return hou.webServer.fileResponse( gltf_temp_file, "application/json", delete_file=True) @hou.webServer.urlHandler("/static/output", is_prefix=True) def temp_output(request): # このURLハンドラーは、GLTF用に一時的に.binとテクスチャファイルを用意するために使用します。 bin_file_path = os.path.join(OUTPUT_DIR, os.path.basename(request.path())) response = hou.webServer.fileResponse( bin_file_path, "application/octet-stream", delete_file=True) return response def temp_file_path(suffix): with tempfile.NamedTemporaryFile( dir=OUTPUT_DIR, suffix=suffix) as temp_file: return temp_file.name def initialize_scene(): hou.node("/obj").createNode("geo").createNode("testgeometry_crag") hou.node("/out").createNode("gltf") def run_server(): if not os.path.exists(OUTPUT_DIR): os.makedirs(OUTPUT_DIR) initialize_scene() hou.webServer.registerStaticFilesDirectory( os.path.join(webutils.script_file_dir(), "static")) hou.webServer.run(8008, debug=True) if __name__ == "__main__": run_server()
static/index.html
<script src="https://cdn.babylonjs.com/viewer/babylon.viewer.js"></script> <script src="https://code.jquery.com/jquery-1.12.4.js"></script> <script src="/static/index.js"></script> <babylon id="babylon-viewer"></babylon> <br>Frame <input onchange="set_frame(parseInt(this.value, 10))" value="1" size="4">
static/index.js
var app = { frame: 1, viewer: null, }; BabylonViewer.viewerManager .getViewerPromiseById('babylon-viewer').then(function (viewer) { app.viewer = viewer; $(viewer.containerElement).css("height", "90%"); viewer.onEngineInitObservable.add(function (scene) { reload_model(); }); }); function set_frame(frame) { app.frame = frame; reload_model(); } function reload_model() { app.viewer.loadModel({url: "/static/output/model.gltf?frame=" + app.frame}); }
See also |