Skip to content
Snippets Groups Projects
Commit 533cf9ab authored by Sybren A. Stüvel's avatar Sybren A. Stüvel
Browse files

Added 'EXR sequence to JPEG' command

This is used for generating JPEG previews of EXR files. It is assumed that
the EXR files are named '######.exr', with any number of leading zeroes.

Gaps in the frame range are supported, and will be rendered as black
images.
parent c4d000a8
No related branches found
No related tags found
No related merge requests found
......@@ -8,6 +8,8 @@ changed functionality, fixed bugs).
- Changed how progressive rendering works. Nonuniform tasks are now supported. This requires
Flamenco Server 2.2 or newer. Progressive render jobs generated by older versions of Flamenco
Server are no longer supported.
- Added the `exr_sequence_to_jpeg` command. This command uses Blender to convert a sequence of
EXR files to JPEG files. This is used in progressive rendering to get intermediary previews.
## Version 2.2.1 (2019-01-14)
......
......@@ -1057,6 +1057,43 @@ class BlenderRenderAudioCommand(BlenderRenderCommand):
]
@command_executor('exr_sequence_to_jpeg')
class EXRSequenceToJPEGCommand(BlenderRenderCommand):
"""Convert an EXR sequence to JPEG files.
This assumes the EXR files are named '{frame number}.exr', where the
frame number may have any number of leading zeroes.
"""
pyscript = Path(__file__).parent / 'resources/exr_sequence_to_jpeg.py'
def validate(self, settings: Settings) -> typing.Optional[str]:
if not self.pyscript.exists():
raise FileNotFoundError(f'Resource script {self.pyscript} cannot be found')
exr_directory, err = self._setting(settings, 'exr_directory', True)
if err:
return err
if not exr_directory:
return '"exr_directory" may not be empty'
output_pattern, err = self._setting(settings, 'output_pattern', False,
default='preview-######.jpg')
if not output_pattern:
return '"output_pattern" may not be empty'
return super().validate(settings)
async def _build_blender_cmd(self, settings) -> typing.List[str]:
cmd = await super()._build_blender_cmd(settings)
return cmd + [
'--python-exit-code', '32',
'--python', str(self.pyscript),
'--',
'--exr-dir', settings['exr_directory'],
'--output-pattern', settings['output_pattern'],
]
class AbstractFFmpegCommand(AbstractSubprocessCommand, abc.ABC):
index_file: typing.Optional[pathlib.Path] = None
......
# This file is supposed to run inside Blender:
# blender thefile.blend --python /path/to/exr_sequence_to_jpeg.py -- --exr-dir /path/to/exr/files
import argparse
import pathlib
import sys
import bpy
# Find the EXR files to process.
dashdash_index = sys.argv.index('--')
parser = argparse.ArgumentParser()
parser.add_argument('--exr-dir')
parser.add_argument('--output-pattern')
cli_args, _ = parser.parse_known_args(sys.argv[dashdash_index + 1:])
imgdir = pathlib.Path(cli_args.exr_dir)
exr_files = list(imgdir.glob('*.exr'))
if not exr_files:
raise ValueError(f'No *.exr files found in {cli_args.exr_dir}')
# Create a copy of the scene without data, so we can fill the sequence editor
# with an image sequence.
bpy.ops.scene.new(type='EMPTY')
scene = bpy.context.scene
se = scene.sequence_editor_create()
# Place files at the correct frame, based on their filename.
# This makes the rendering consistent w.r.t. gaps in the frames.
# This assumes the files are named '000020.exr' etc.
min_frame = float('inf')
max_frame = float('-inf')
for file in exr_files:
frame_num = int(file.stem, 10)
min_frame = min(min_frame, frame_num)
max_frame = max(max_frame, frame_num)
se.sequences.new_image(file.name, str(file), 1, frame_num)
scene.frame_start = min_frame
scene.frame_end = max_frame
render = scene.render
render.use_sequencer = True
render.filepath = str(imgdir / cli_args.output_pattern)
render.image_settings.file_format = 'JPEG'
render.image_settings.quality = 90
render.use_overwrite = True # overwrite lesser quality previews
bpy.ops.render.render(animation=True, use_viewport=False)
bpy.ops.wm.quit_blender()
......@@ -57,6 +57,7 @@ class ZipCommand(Command):
add_to_root(Path('README.md'))
add_to_root(Path('CHANGELOG.md'))
add_to_root(Path('flamenco_worker/resources/merge-exr.blend'))
add_to_root(Path('flamenco_worker/resources/exr_sequence_to_jpeg.py'))
paths = collections.deque([Path('system-integration')])
while paths:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment