25 #include <OpenImageIO/filesystem.h>
26 #include <OpenImageIO/imageio.h>
67 unique_ptr<ImageInput>
in;
78 if (pass_name ==
"Depth" || pass_name ==
"IndexMA" || pass_name ==
"IndexOB" ||
96 size_t pos = in.rfind(
".");
97 if (
pos == string::npos) {
100 suffix = in.substr(
pos + 1);
101 in = in.substr(0,
pos);
109 string name,
string &renderlayer,
string &pass,
string &channel,
bool multiview_channels)
123 if (multiview_channels) {
124 renderlayer +=
"." +
view;
134 const ParamValue *multiview = in_spec.find_attribute(
"multiView");
135 const bool multiview_channels = (multiview && multiview->type().basetype == TypeDesc::STRING &&
136 multiview->type().arraylen >= 2);
143 map<string, MergeImageLayer> file_layers;
144 for (
int i = 0; i < in_spec.nchannels; i++) {
147 pass.
format = (in_spec.channelformats.size() > 0) ? in_spec.channelformats[i] : in_spec.format;
151 string layername, passname, channelname;
153 pass.
channel_name, layername, passname, channelname, multiview_channels)) {
163 file_layers[layername].passes.push_back(pass);
168 for (
auto &i : file_layers) {
169 const string &name = i.first;
176 if (layer.
name ==
"") {
180 string sample_string = in_spec.get_string_attribute(
"cycles." + name +
".samples",
"");
181 if (sample_string !=
"") {
182 if (!sscanf(sample_string.c_str(),
"%d", &layer.
samples)) {
183 error =
"Failed to parse samples metadata: " + sample_string;
191 "No sample number specified in the file for layer %s or on the command line",
196 layers.push_back(layer);
204 for (
const string &filepath : filepaths) {
205 unique_ptr<ImageInput> in(ImageInput::open(filepath));
207 error =
"Couldn't open file: " + filepath;
212 image.
in = std::move(in);
218 if (image.
layers.size() == 0) {
219 error =
"Could not find a render layer for merging";
223 if (image.
in->spec().deep) {
224 error =
"Merging deep images not supported.";
228 if (images.size() > 0) {
229 const ImageSpec &base_spec = images[0].in->spec();
230 const ImageSpec &spec = image.
in->spec();
232 if (base_spec.width != spec.width || base_spec.height != spec.height ||
233 base_spec.depth != spec.depth || base_spec.format != spec.format ||
234 base_spec.deep != spec.deep) {
235 error =
"Images do not have matching size and data layout.";
240 images.push_back(std::move(image));
254 string time_str = image.in->spec().get_string_attribute(name,
"");
259 time /= images.size();
267 const string &layer_name,
268 const string &time_name,
271 string name =
"cycles." + layer_name +
"." + time_name;
275 string time_str = image.in->spec().get_string_attribute(name,
"");
280 time /= images.size();
291 out_spec = images[0].in->spec();
294 out_spec.nchannels = 0;
295 out_spec.channelformats.clear();
296 out_spec.channelnames.clear();
304 for (
size_t i = 0; i < out_spec.nchannels; i++) {
307 channel_total_samples[i] += layer.
samples;
320 channel_total_samples.push_back(layer.
samples);
323 out_spec.channelformats.push_back(pass.
format);
324 out_spec.nchannels++;
333 map<string, int> layer_num_samples;
336 if (layer.
name !=
"") {
342 for (
const auto &i : layer_num_samples) {
343 string name =
"cycles." + i.first +
".samples";
344 out_spec.attribute(name, TypeDesc::STRING,
string_printf(
"%d", i.second));
354 const size_t width = spec.width;
355 const size_t height = spec.height;
356 const size_t num_channels = spec.nchannels;
358 const size_t num_pixels = (size_t)
width * (
size_t)
height;
359 pixels.
resize(num_pixels * num_channels);
363 const ImageSpec &out_spec,
369 memset(out_pixels.
data(), 0, out_pixels.
size() *
sizeof(
float));
377 if (!image.in->read_image(TypeDesc::FLOAT, pixels.
data())) {
378 error =
"Failed to read image: " + image.filepath;
382 for (
size_t li = 0; li < image.layers.size(); li++) {
385 const size_t stride = image.in->spec().nchannels;
386 const size_t out_stride = out_spec.nchannels;
387 const size_t num_pixels = pixels.
size();
390 size_t offset = pass.
offset;
397 for (; offset < num_pixels; offset +=
stride, out_offset += out_stride) {
398 out_pixels[out_offset] = pixels[offset];
402 for (; offset < num_pixels; offset +=
stride, out_offset += out_stride) {
403 out_pixels[out_offset] += pixels[offset];
409 const int total_samples = channel_total_samples[out_offset];
412 for (; offset < num_pixels; offset +=
stride, out_offset += out_stride) {
413 out_pixels[out_offset] +=
t * pixels[offset];
425 const ImageSpec &spec,
431 string extension = OIIO::Filesystem::extension(filepath);
432 string unique_name =
".merge-tmp-" + OIIO::Filesystem::unique_path();
433 string tmp_filepath = filepath +
unique_name + extension;
434 unique_ptr<ImageOutput> out(ImageOutput::create(tmp_filepath));
437 error =
"Failed to open temporary file " + tmp_filepath +
" for writing";
442 if (!out->open(tmp_filepath, spec)) {
443 error =
"Failed to open file " + tmp_filepath +
" for writing: " + out->geterror();
448 if (!out->write_image(TypeDesc::FLOAT, pixels.
data())) {
449 error =
"Failed to write to file " + tmp_filepath +
": " + out->geterror();
454 error =
"Failed to save to file " + tmp_filepath +
": " + out->geterror();
462 if (ok && !OIIO::Filesystem::rename(tmp_filepath, filepath, rename_error)) {
463 error =
"Failed to move merged image to " + filepath +
": " + rename_error;
468 OIIO::Filesystem::remove(tmp_filepath);
483 error =
"No input file paths specified.";
487 error =
"No output file path specified.";
typedef float(TangentPoint)[2]
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei stride
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
T * resize(size_t newsize)
#define CCL_NAMESPACE_END
static bool parse_channels(const ImageSpec &in_spec, vector< MergeImageLayer > &layers, string &error)
static bool parse_channel_name(string name, string &renderlayer, string &pass, string &channel, bool multiview_channels)
static void merge_channels_metadata(vector< MergeImage > &images, ImageSpec &out_spec, vector< int > &channel_total_samples)
static bool split_last_dot(string &in, string &suffix)
static bool open_images(const vector< string > &filepaths, vector< MergeImage > &images, string &error)
static void merge_layer_render_time(ImageSpec &spec, const vector< MergeImage > &images, const string &layer_name, const string &time_name, const bool average)
static void alloc_pixels(const ImageSpec &spec, array< float > &pixels)
static bool merge_pixels(const vector< MergeImage > &images, const ImageSpec &out_spec, const vector< int > &channel_total_samples, array< float > &out_pixels, string &error)
static void merge_render_time(ImageSpec &spec, const vector< MergeImage > &images, const string &name, const bool average)
static MergeChannelOp parse_channel_operation(const string &pass_name)
static bool save_output(const string &filepath, const ImageSpec &spec, const array< float > &pixels, string &error)
static void error(const char *str)
static void unique_name(bNode *node)
vector< MergeImagePass > passes
vector< MergeImageLayer > layers
unique_ptr< ImageInput > in
ccl_device_inline float average(const float2 &a)
bool string_startswith(const string &s, const char *start)
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
double time_human_readable_to_seconds(const string &time_string)
string time_human_readable_from_seconds(const double seconds)