Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/doc/oiiotool.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2385,6 +2385,14 @@ current top image.
name, nor value), then this will just leave the images as-is, without
any unnecessary expense or pointless copying of images in memory.

.. option:: --nchannels <n>

Replaces the top image with a new image whose channels are the the first *n*
channels of the input image. If *n* is less than the number of
channels in the input image, the extra channels will simply be ignored.
If *n* is greater than the number of channels in the input image, the
additional channels will be filled with 0 values.

.. option:: --chappend

Replaces the top two (or more) images on the stack with a single new
Expand Down
35 changes: 35 additions & 0 deletions src/oiiotool/oiiotool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2836,6 +2836,38 @@ action_channels(Oiiotool& ot, cspan<const char*> argv)



// --nchannels
static void
action_nchannels(Oiiotool& ot, cspan<const char*> argv)
{
if (ot.postpone_callback(1, action_nchannels, argv))
return;

// Get the requested number of channels
int n = Strutil::stoi(ot.express(argv[1]));
if (n < 1) {
ot.errorfmt(argv[0], "nchannels must be at least 1 (got {})", n);
return;
}

// We build the indices into a vector, then join them into a string.
std::vector<int> indices;
for (int i = 0; i < n; ++i)
indices.push_back(i);

// Convert to ustring to ensure the underlying char* is interned.
// This guarantees the pointer remains valid even if action_channels
// defers execution (postpones) beyond the scope of this function.
ustring channel_list(Strutil::join(indices, ","));

// Hand off to action_channels with our generated index list.
// this ensures we are always doing the same thing as --ch
const char* fake_argv[] = { argv[0], channel_list.c_str() };
action_channels(ot, fake_argv);
}



// --chappend
static void
action_chappend(Oiiotool& ot, cspan<const char*> argv)
Expand Down Expand Up @@ -7277,6 +7309,9 @@ Oiiotool::getargs(int argc, char* argv[])
ap.arg("--ch %s:CHANLIST")
.help("Select or shuffle channels (e.g., \"R,G,B\", \"B,G,R\", \"2,3,4\")")
.OTACTION(action_channels);
ap.arg("--nchannels %d:N")
.help("Force the current image to have N channels (padding with 0.0 as needed)")
.OTACTION(action_nchannels);
ap.arg("--chappend")
.help("Append the channels of the last two images")
.OTACTION(action_chappend);
Expand Down
12 changes: 12 additions & 0 deletions testsuite/oiiotool/ref/out.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ oiiotool ERROR: -o : Non-existent output directory: folder1/folder2
Full command line was:
> oiiotool --create 2x2 1 -o folder1/folder2/out.tif
folder1/folder2/out.tif : 2 x 2, 1 channel, float tiff
WARNING: --ch: Unknown channel name "R", filling with 0 (actual channels: "Y")
WARNING: --ch: Unknown channel name "R", filling with 0 (actual channels: "Y")
channel list: Y
channel list: R
Comparing "filled.tif" and "ref/filled.tif"
PASS
Comparing "autotrim.tif" and "ref/autotrim.tif"
Expand Down Expand Up @@ -204,3 +208,11 @@ Comparing "box_over_missing2.tif" and "ref/box_over_missing2.tif"
PASS
Comparing "box_over_missing3.tif" and "ref/box_over_missing3.tif"
PASS
Comparing "single_channel_black.tif" and "ref/single_channel_black.tif"
PASS
Comparing "single_channel_good.tif" and "ref/single_channel_good.tif"
PASS
Comparing "single_channel_good_y.exr" and "ref/single_channel_good_y.exr"
PASS
Comparing "single_channel_good_r.exr" and "ref/single_channel_good_r.exr"
PASS
Binary file added testsuite/oiiotool/ref/single_channel_black.tif
Binary file not shown.
Binary file added testsuite/oiiotool/ref/single_channel_good.tif
Binary file not shown.
Binary file added testsuite/oiiotool/ref/single_channel_good_r.exr
Binary file not shown.
Binary file added testsuite/oiiotool/ref/single_channel_good_y.exr
Binary file not shown.
22 changes: 22 additions & 0 deletions testsuite/oiiotool/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,24 @@
command += oiiotool (f"--create-dir --create 2x2 1 -o {root_folder}/folder2/out.tif")
command += oiiotool (f"--info {root_folder}/folder2/out.tif")


# in a tif the single channel doesn't really have a name so oiio gives it the name Y
# so if you naively do --ch R you'll get a black image (with a warning which we capture in out.txt)
command += oiiotool ("src/single_channel_tif.tif --ch R -o single_channel_black.tif")
# using nchannels 1 will always do the right thing
command += oiiotool ("src/single_channel_tif.tif --nchannels 1 -o single_channel_good.tif")
# exrs have explicit channel names, but you don't need to know the name if you are using nchannels
# so you can easily process a mix of frames without thinking about the name of the channels
# this can also be accomplished with --ch 0, but --nchannels 1 is a bit more intuitive
# and matches maketx
command += oiiotool ("src/single_channel_y.exr --nchannels 1 -o single_channel_good_y.exr")
command += oiiotool ("src/single_channel_r.exr --nchannels 1 -o single_channel_good_r.exr")

# the info -v will print out the channel names and make sure they came out good in the output
command += oiiotool ("--info -v single_channel_good_y.exr | grep 'channel list'")
command += oiiotool ("--info -v single_channel_good_r.exr | grep 'channel list'")


# 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,
# below.
Expand Down Expand Up @@ -312,6 +330,10 @@
"const5-rgb.tif",
"box_over_missing2.tif",
"box_over_missing3.tif",
"single_channel_black.tif",
"single_channel_good.tif",
"single_channel_good_y.exr",
"single_channel_good_r.exr",
"out.txt" ]

#print "Running this command:\n" + command + "\n"
Binary file added testsuite/oiiotool/src/single_channel_r.exr
Binary file not shown.
Binary file added testsuite/oiiotool/src/single_channel_tif.tif
Binary file not shown.
Binary file added testsuite/oiiotool/src/single_channel_y.exr
Binary file not shown.
Loading