diff --git a/.gitignore b/.gitignore index 0cd20816e3375a8a97df93c45205003dfa43bf78..ef7d6d066680ad1da8a8203a9eb10b86a94c4f13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.pyc *.bak +*.blend[1-9] /temp/ /docs/site/ diff --git a/packages/flamenco-worker-python/flamenco_worker/merge-exr.blend b/packages/flamenco-worker-python/flamenco_worker/merge-exr.blend index fc4dbb90713bc25107e5351c20f69fe852ff1c54..2dda49f47950de3bc5f9a6959b62dab5c3b27b59 100644 Binary files a/packages/flamenco-worker-python/flamenco_worker/merge-exr.blend and b/packages/flamenco-worker-python/flamenco_worker/merge-exr.blend differ diff --git a/packages/flamenco-worker-python/flamenco_worker/runner.py b/packages/flamenco-worker-python/flamenco_worker/runner.py index 526bd96b9bd8bef5bd10ec3324d36bf81c179f5d..5a656c64754a2156987ebf9477331086b79dae91 100644 --- a/packages/flamenco-worker-python/flamenco_worker/runner.py +++ b/packages/flamenco-worker-python/flamenco_worker/runner.py @@ -15,6 +15,26 @@ from . import worker # Timeout of subprocess.stdout.readline() call. SUBPROC_READLINE_TIMEOUT = 3600 # seconds +MERGE_EXR_PYTHON = """\ +import bpy +scene = bpy.context.scene +nodes = scene.node_tree.nodes +image1 = bpy.data.images.load("%(input1)s") +image2 = bpy.data.images.load("%(input2)s") + +nodes["image1"].image = image1 +nodes["image2"].image = image2 +nodes["weight1"].outputs[0].default_value = %(weight1)i +nodes["weight2"].outputs[0].default_value = %(weight2)i + +nodes["output"].base_path = "%(tmpdir)s" +scene.render.resolution_x, scene.render.resolution_y = image1.size +scene.render.tile_x, scene.render.tile_y = image1.size +scene.render.filepath = "%(tmpdir)s/preview.jpg" + +bpy.ops.render.render(write_still=True) +""" + command_handlers = {} @@ -201,7 +221,7 @@ class AbstractCommand(metaclass=abc.ABCMeta): return None - def _setting(self, settings: dict, key: str, is_required: bool, valtype=str) -> ( + def _setting(self, settings: dict, key: str, is_required: bool, valtype: typing.Type = str) -> ( typing.Any, typing.Optional[str]): """Parses a setting, returns either (value, None) or (None, errormsg)""" @@ -561,18 +581,36 @@ class MergeExrCommand(AbstractSubprocessCommand): return 'blender_cmd %r does not exist' % cmd[0] settings['blender_cmd'] = cmd - _, err = self._setting(settings, 'input1', True, str) + input1, err = self._setting(settings, 'input1', True, str) + if err: return err + if '"' in input1: + return 'Double quotes are not allowed in filenames: %r' % input1 + if not Path(input1).exists(): + return 'Input 1 %r does not exist' % input1 + input2, err = self._setting(settings, 'input2', True, str) if err: return err - _, err = self._setting(settings, 'input2', True, str) + if '"' in input2: + return 'Double quotes are not allowed in filenames: %r' % input2 + if not Path(input2).exists(): + return 'Input 2 %r does not exist' % input2 + + output, err = self._setting(settings, 'output', True, str) if err: return err + if '"' in output: + return 'Double quotes are not allowed in filenames: %r' % output + _, err = self._setting(settings, 'weight1', True, int) if err: return err + _, err = self._setting(settings, 'weight2', True, int) if err: return err async def execute(self, settings: dict): - import shlex - await self.subprocess(shlex.split(settings['cmd'])) + from pathlib import Path + import shutil + import tempfile + + blendpath = Path(__file__).with_name('merge-exr.blend') cmd = settings['blender_cmd'][:] cmd += [ @@ -580,11 +618,26 @@ class MergeExrCommand(AbstractSubprocessCommand): '--enable-autoexec', '-noaudio', '--background', + str(blendpath), ] - # TODO: set up node properties and render settings. + # set up node properties and render settings. + output = Path(settings['output']) + output.mkdir(parents=True, exist_ok=True) - await self.worker.register_task_update(activity='Starting Blender') - await self.subprocess(cmd) + with tempfile.TemporaryDirectory(dir=str(output)) as tmpdir: + tmppath = Path(tmpdir) + assert tmppath.exists() + + settings['tmpdir'] = tmpdir + cmd += [ + '--python-expr', MERGE_EXR_PYTHON % settings + ] + + await self.worker.register_task_update(activity='Starting Blender to merge EXR files') + await self.subprocess(cmd) + + # move output files into the correct spot. + shutil.move(str(tmppath / 'merged0001.exr'), str(output)) + shutil.move(str(tmppath / 'preview.jpg'), str(output.with_suffix('.jpg'))) - # TODO: move output files into the correct spot. diff --git a/packages/flamenco-worker-python/tests/Corn field-1k.exr b/packages/flamenco-worker-python/tests/Corn field-1k.exr new file mode 100644 index 0000000000000000000000000000000000000000..cd51fdc35a2905a2b3e47192cd1b7137e6538629 Binary files /dev/null and b/packages/flamenco-worker-python/tests/Corn field-1k.exr differ diff --git a/packages/flamenco-worker-python/tests/Deventer-1k.exr b/packages/flamenco-worker-python/tests/Deventer-1k.exr new file mode 100644 index 0000000000000000000000000000000000000000..78a6166870b98cac8354c2a976d339c887ab946c Binary files /dev/null and b/packages/flamenco-worker-python/tests/Deventer-1k.exr differ diff --git a/packages/flamenco-worker-python/tests/abstract_worker_test.py b/packages/flamenco-worker-python/tests/abstract_worker_test.py index a2def8c6764fcbf4958b51ef340ea5d1d4c171f6..582a8a152da8720228efa257888a649345311744 100644 --- a/packages/flamenco-worker-python/tests/abstract_worker_test.py +++ b/packages/flamenco-worker-python/tests/abstract_worker_test.py @@ -10,3 +10,19 @@ class AbstractWorkerTest(unittest.TestCase): level=logging.DEBUG, format='%(asctime)-15s %(levelname)8s %(name)s %(message)s', ) + + def find_blender_cmd(self): + import os + import platform + + if platform.system() == 'Windows': + blender = 'blender.exe' + else: + blender = 'blender' + + for path in os.getenv('PATH').split(os.path.pathsep): + full_path = path + os.sep + blender + if os.path.exists(full_path): + return full_path + + self.fail('Unable to find "blender" executable on $PATH') diff --git a/packages/flamenco-worker-python/tests/test_runner_merge_exr.py b/packages/flamenco-worker-python/tests/test_runner_merge_exr.py new file mode 100644 index 0000000000000000000000000000000000000000..294ba88742c15a236d36e65d7fcc0d3d4a333957 --- /dev/null +++ b/packages/flamenco-worker-python/tests/test_runner_merge_exr.py @@ -0,0 +1,44 @@ +from pathlib import Path + +from test_runner import AbstractCommandTest + + +class MergeExrCommandTest(AbstractCommandTest): + def setUp(self): + super().setUp() + + from flamenco_worker.runner import MergeExrCommand + import tempfile + + self.tmpdir = tempfile.TemporaryDirectory() + self.mypath = Path(__file__).parent + + self.cmd = MergeExrCommand( + worker=self.fworker, + task_id='12345', + command_idx=0, + ) + + def tearDown(self): + super().tearDown() + del self.tmpdir + + def test_happy_flow(self): + output = Path(self.tmpdir.name) / 'merged.exr' + + settings = { + 'blender_cmd': self.find_blender_cmd(), + 'input1': str(self.mypath / 'Corn field-1k.exr'), + 'input2': str(self.mypath / 'Deventer-1k.exr'), + 'weight1': 20, + 'weight2': 100, + 'output': str(output) + } + + task = self.cmd.run(settings) + ok = self.loop.run_until_complete(task) + self.assertTrue(ok) + + # Assuming that if the files exist, the merge was ok. + self.assertTrue(output.exists()) + self.assertTrue(output.with_suffix('.jpg').exists())