On this page |
fileResponse(file_path, content_type=None, delete_file=False, download_as_filename=None):
→ hwebserver.Response
-
ディスク上のファイルの内容を送信する場合はいつでも、その内容を文字列として読み込んで返すのではなく、この関数を使用してください。
-
静的なファイル(such as for CSS、JavaScript、画像、動画ファイルなど)に関しては、hwebserver.registerStaticFilesDirectoryを使用してサーバーをセットアップすると、Pythonハンドラーでそれらのファイルを用意しなくても、自動的に用意されます。この手法で静的ファイルを用意する方がパフォーマンスが良くて、Pythonが不要です。
-
ファイルの内容は一度にすべて読み込まれません。
file_path
クライアントへダウンロードするディスク上のファイルパス。
content_type
レスポンスのMIMEコンテンツタイプ。
これがNone
(デフォルト)の場合、この関数はmimetypes.guess_type()
を使用して、ディスクファイルの拡張子からMIMEタイプが推測されます。
delete_file
これがTrue
の場合、サーバーは、ファイルをクライアントに送信した後にそのファイルを削除します。
これは、一時ファイルには便利ですが、コードの挙動を変更してこれを無効にするのを忘れてしまった場合には非常に危険です。
download_as_filename
オプションで、クライアントがダウンロードするファイルのファイル名を指定することができます。
サーバーは、Content-Disposition
ヘッダを送信します。
import hou import hwebserver @hwebserver.urlHandler("/textures", prefix=True) def texture_download(request): path = request.path() assert path.startswith("/textures") parm_name = path[10:] if not parm_name: return hwebserver.notFoundResponse(request) node = hou.node("/mat/my_material") texture_parm = node.parm(parm_name) texture_path = texture_parm.evalAsString() return hwebserver.fileResponse(request, texture_path)
関連ファイルの用意 ¶
時折、ハンドラーを含んだPythonスクリプトファイル関連のパスを使用してファイルを用意したい場合があります。
通常では、__file__
変数には、現在実行中のファイルのパスが入るので、os.path.dirname(__file__)
を使用することで、そのファイルが含まれているディレクトリを取得することができます。
しかし、コマンドラインからPythonスクリプトを使ってHoudiniを起動した場合などでは、__file__
は定義されていません。
これを補足するには、以下の関数を使用すると良いでしょう:
webutils.py
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 import hou import hwebserver @hwebserver.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 hwebserver.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ウェブビューアのサンプル ¶
このサンプルは、GLTF ROPを使用してCragテストジオメトリをGLTFフォーマットに保存し、Babylon.jsを使用してブラウザでそれを表示します。
server.py
import os import tempfile import json import hou import hwebserver import webutils OUTPUT_DIR = os.path.join(webutils.script_file_dir(), "static", "temp") @hwebserver.urlHandler("/") def index_view(request): return hwebserver.redirect(request, "/static/index.html") @hwebserver.urlHandler("/static/output/model.gltf") def gltf_view(request): frame = float(request.GET().get("frame", 1)) # GLTF ROPを使用して一時GLTFファイルを書き出します。 # これは、処理中に.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 hwebserver.fileResponse( gltf_temp_file, "application/json", delete_file=True) @hwebserver.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 = hwebserver.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() hwebserver.registerStaticFilesDirectory( os.path.join(webutils.script_file_dir(), "static")) hwebserver.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 |