From f749be7bd3bbd4f27898e752928cbdca17858789 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Thu, 21 Oct 2021 23:46:01 -0700 Subject: [PATCH] oiiotool --dumpdata:C=name (#3136) New ":C=name" modifier for --dumpdata will cause the dumped image data to be formatted with the syntax of a C array, that can be dropped right into source code. $ oiiotool --dumpdata:C=foo image.exr // image.exr : 256 x 256, 4 channel, float openexr float foo[256][256][4] = { { /* (0, 0): */ { 0.517036676, 0.261921108, 0.017822538, 0.912108004 }, /* (1, 0): */ { 0.653315008, 0.527794302, 0.359594107, 0.277836263 }, ... }; Without this modifier, --dumpdata will keep the same formatting it always had. This works pretty well for ordinary boring flat, single subimage, non-MIPmap images. The option should probably not be used (or at least is very unpolished) for multi-subimage, MIP-mapped, deep, or other oddball cases (but you probably don't want to shove those into a single C array anyway). --- src/doc/oiiotool.rst | 24 ++++++++++++-- src/oiiotool/oiiotool.cpp | 5 ++- src/oiiotool/oiiotool.h | 6 ++++ src/oiiotool/printinfo.cpp | 58 +++++++++++++++++++++++++++------- testsuite/oiiotool/ref/out.txt | 15 +++++++++ testsuite/oiiotool/run.py | 4 +++ 6 files changed, 97 insertions(+), 15 deletions(-) diff --git a/src/doc/oiiotool.rst b/src/doc/oiiotool.rst index 634860875f..981164f70a 100644 --- a/src/doc/oiiotool.rst +++ b/src/doc/oiiotool.rst @@ -1110,14 +1110,34 @@ These are all non-positional flags that affect how all images are read in the .. option:: --dumpdata - Print the numerical values of every pixel, for each input image as it is - read. + Print to the console the numerical values of every pixel, for each input + image as it is read. Optional appended modifiers include: + - `C=` *name* : If present, will cause the output of the data to be + in the correct syntax of declaring a C array with the given name. + (This was added in OpenImageIO v2.3.9.) + - `empty=` *verbose* : If 0, will cause deep images to skip printing of information about pixels with no samples. + Examples:: + + $ oiiotool --dumpdata image.exr + image.exr : 256 x 256, 4 channel, float openexr + Pixel (0, 0): 0.517036676 0.261921108 0.017822538 0.912108004 + Pixel (1, 0): 0.653315008 0.527794302 0.359594107 0.277836263 + ... + + $ oiiotool --dumpdata:C=foo image.exr + // image.exr : 256 x 256, 4 channel, float openexr + float foo[256][256][4] = + { + /* (0, 0): */ { 0.517036676, 0.261921108, 0.017822538, 0.912108004 }, + /* (1, 0): */ { 0.653315008, 0.527794302, 0.359594107, 0.277836263 }, + ... + }; .. _sec-oiiotool-o: diff --git a/src/oiiotool/oiiotool.cpp b/src/oiiotool/oiiotool.cpp index 51f05adffa..0e573f5fad 100644 --- a/src/oiiotool/oiiotool.cpp +++ b/src/oiiotool/oiiotool.cpp @@ -112,6 +112,7 @@ Oiiotool::clear_options() printstats = false; dumpdata = false; dumpdata_showempty = true; + dumpdata_C = false; hash = false; updatemode = false; autoorient = false; @@ -517,6 +518,8 @@ set_dumpdata(cspan argv) auto options = ot.extract_options(command); ot.dumpdata = true; ot.dumpdata_showempty = options.get_int("empty", 1); + ot.dumpdata_C_name = options.get_string("C"); + ot.dumpdata_C = ot.dumpdata_C_name.size(); } @@ -5510,7 +5513,7 @@ getargs(int argc, char* argv[]) ap.arg("--stats", &ot.printstats) .help("Print pixel statistics of all inputs files"); ap.arg("--dumpdata") - .help("Print all pixel data values of input files (options: empty=0)") + .help("Print all pixel data values of input files (options: empty=1, C=arrayname)") .action(set_dumpdata); ap.arg("--hash", &ot.hash) .help("Print SHA-1 hash of each input image"); diff --git a/src/oiiotool/oiiotool.h b/src/oiiotool/oiiotool.h index 238e40ad03..4b78f17e9a 100644 --- a/src/oiiotool/oiiotool.h +++ b/src/oiiotool/oiiotool.h @@ -51,6 +51,8 @@ struct print_info_options { bool compute_stats = false; bool dumpdata = false; bool dumpdata_showempty = true; + bool dumpdata_C = false; + std::string dumpdata_C_name; std::string metamatch; std::string nometamatch; std::string infoformat; @@ -76,6 +78,7 @@ class Oiiotool { bool printstats; bool dumpdata; bool dumpdata_showempty; + bool dumpdata_C; bool hash; bool updatemode; bool autoorient; @@ -91,6 +94,7 @@ class Oiiotool { bool eval_enable; // Enable evaluation of expressions bool skip_bad_frames = false; // Just skip a bad frame, don't exit bool nostderr = false; // If true, use stdout for errors + std::string dumpdata_C_name; std::string full_command_line; std::string printinfo_metamatch; std::string printinfo_nometamatch; @@ -583,6 +587,8 @@ inline print_info_options::print_info_options(const Oiiotool& ot) , compute_stats(ot.printstats) , dumpdata(ot.dumpdata) , dumpdata_showempty(ot.dumpdata_showempty) + , dumpdata_C(ot.dumpdata_C) + , dumpdata_C_name(ot.dumpdata_C_name) , metamatch(ot.printinfo_metamatch) , nometamatch(ot.printinfo_nometamatch) { diff --git a/src/oiiotool/printinfo.cpp b/src/oiiotool/printinfo.cpp index b6ac876c6b..1d2f18ae09 100644 --- a/src/oiiotool/printinfo.cpp +++ b/src/oiiotool/printinfo.cpp @@ -76,7 +76,8 @@ compute_sha1(Oiiotool& ot, ImageInput* input, int subimage) template static void -print_nums(std::ostream& out, int n, const T* val, string_view sep = " ") +print_nums(std::ostream& out, int n, const T* val, string_view sep = " ", + bool C_formatting = false) { if (std::is_floating_point::value || std::is_same::value) { // Ensure uniform printing of NaN and Inf on all platforms @@ -95,11 +96,11 @@ print_nums(std::ostream& out, int n, const T* val, string_view sep = " ") // not floating point -- print the int values, then float equivalents for (int i = 0; i < n; ++i) Strutil::print(out, "{}{}", i ? sep : "", val[i]); - Strutil::print(out, " ("); + Strutil::print(out, " {}(", C_formatting ? "/* " : ""); for (int i = 0; i < n; ++i) Strutil::print(out, "{}{}", i ? sep : "", convert_type(val[i])); - Strutil::print(out, ")"); + Strutil::print(out, "){}", C_formatting ? " */" : ""); } } @@ -117,8 +118,22 @@ dump_flat_data(std::ostream& out, ImageInput* input, input->geterror()); return false; } + if (opt.dumpdata_C) { + if (spec.depth == 1 && spec.z == 0) + Strutil::print(out, "{}{} {}[{}][{}][{}] =\n{{\n", spec.format, + spec.format.is_floating_point() ? "" : "_t", + opt.dumpdata_C_name, spec.height, spec.width, + spec.nchannels); + else + Strutil::print(out, "{}{} {}[{}][{}][{}][{}] =\n{{\n", spec.format, + spec.format.is_floating_point() ? "" : "_t", + opt.dumpdata_C_name, spec.depth, spec.height, + spec.width, spec.nchannels); + } const T* ptr = &buf[0]; for (int z = 0; z < spec.depth; ++z) { + if (opt.dumpdata_C && (spec.depth > 1 || spec.z != 0) && z == 0) + Strutil::print(out, " }} /* slice {} */\n", z); for (int y = 0; y < spec.height; ++y) { for (int x = 0; x < spec.width; ++x, ptr += spec.nchannels) { if (!opt.dumpdata_showempty) { @@ -129,15 +144,30 @@ dump_flat_data(std::ostream& out, ImageInput* input, continue; } if (spec.depth > 1 || spec.z != 0) - Strutil::print(out, " Pixel ({}, {}, {}): ", x + spec.x, - y + spec.y, z + spec.z); + Strutil::print(out, " {}{} ({}, {}, {}): {}", + opt.dumpdata_C && x == 0 ? "{ " : " ", + opt.dumpdata_C ? "/*" : "Pixel", x + spec.x, + y + spec.y, z + spec.z, + opt.dumpdata_C ? "*/ " : ""); else - Strutil::print(out, " Pixel ({}, {}): ", x + spec.x, - y + spec.y); - print_nums(out, spec.nchannels, ptr); - Strutil::print(out, "\n"); + Strutil::print(out, " {}{} ({}, {}): {}", + opt.dumpdata_C && x == 0 ? "{ " : " ", + opt.dumpdata_C ? "/*" : "Pixel", x + spec.x, + y + spec.y, opt.dumpdata_C ? "*/ { " : ""); + print_nums(out, spec.nchannels, ptr, + opt.dumpdata_C ? ", " : " ", opt.dumpdata_C); + Strutil::print(out, "{}{}\n", + opt.dumpdata_C && x == (spec.width - 1) ? " }" + : "", + opt.dumpdata_C ? " }," : ""); } } + if (opt.dumpdata_C && (spec.depth > 1 || spec.z != 0) + && z == spec.depth - 1) + Strutil::print(out, " }}{}\n", z < spec.depth - 1 ? "," : ""); + } + if (opt.dumpdata_C) { + Strutil::print(out, "}};\n"); } return true; } @@ -608,7 +638,9 @@ print_info_subimage(std::ostream& out, Oiiotool& ot, int current_subimage, std::string orig_line0 = lines[0]; if (current_subimage == 0) { if (filename.size()) - lines[0] = format("{}{} : {}", filename, padding, lines[0]); + lines[0] = format("{}{}{} : {}", + opt.dumpdata_C ? "// " : "", filename, + padding, lines[0]); } else lines[0] = format(" subimage {:2}: {}", current_subimage, lines[0]); @@ -719,9 +751,11 @@ print_info_subimage(std::ostream& out, Oiiotool& ot, int current_subimage, else if (img) mipspec = *img->spec(current_subimage, m); if (opt.filenameprefix) - Strutil::print(out, "{} : ", filename); + Strutil::print(out, "{}{} : ", opt.dumpdata_C ? "// " : "", + filename); if (nmip > 1 && opt.subimages) { - Strutil::print(out, " MIP {} of {} ({} x {}):\n", m, nmip, + Strutil::print(out, "{} MIP {} of {} ({} x {}):\n", + opt.dumpdata_C ? "// " : "", m, nmip, mipspec.width, mipspec.height); } if (input) diff --git a/testsuite/oiiotool/ref/out.txt b/testsuite/oiiotool/ref/out.txt index 6649c631d7..f6e4dce361 100644 --- a/testsuite/oiiotool/ref/out.txt +++ b/testsuite/oiiotool/ref/out.txt @@ -152,6 +152,21 @@ add_rgb_rgba.exr : 64 x 64, 4 channel, float openexr screenWindowWidth: 1 oiio:ColorSpace: "Linear" oiio:subimages: 1 +dumpdata: +dump.exr : 2 x 2, 3 channel, half openexr + Pixel (0, 0): 0.000000000 0.000000000 0.000000000 + Pixel (1, 0): 1.000000000 1.000000000 0.000000000 + Pixel (0, 1): 0.000000000 0.000000000 0.000000000 + Pixel (1, 1): 1.000000000 1.000000000 0.000000000 +dumpdata:C +// dump.exr : 2 x 2, 3 channel, half openexr +half data[2][2][3] = +{ + { /* (0, 0): */ { 0.000000000, 0.000000000, 0.000000000 }, + /* (1, 0): */ { 1.000000000, 1.000000000, 0.000000000 } }, + { /* (0, 1): */ { 0.000000000, 0.000000000, 0.000000000 }, + /* (1, 1): */ { 1.000000000, 1.000000000, 0.000000000 } }, +}; Comparing "filled.tif" and "ref/filled.tif" PASS Comparing "autotrim.tif" and "ref/autotrim.tif" diff --git a/testsuite/oiiotool/run.py b/testsuite/oiiotool/run.py index 3920dd74cd..d45048dcd4 100755 --- a/testsuite/oiiotool/run.py +++ b/testsuite/oiiotool/run.py @@ -255,6 +255,10 @@ # Test again using --missingfile checker command += oiiotool ("--missingfile checker box.tif missing.tif --over -o box_over_missing3.tif || true") +# Test --dumpdata +command += oiiotool ("--pattern fill:left=0,0,0:right=1,1,0 2x2 3 -d half -o dump.exr") +command += oiiotool ("-echo dumpdata: --dumpdata dump.exr") +command += oiiotool ("-echo dumpdata:C --dumpdata:C=data dump.exr") # To add more tests, just append more lines like the above and also add # the new 'feature.tif' (or whatever you call it) to the outputs list,