diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index e8d2a39..685c509 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -58,6 +58,9 @@ jobs: # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages steps: + + - name: run apt-get update + run: sudo apt-get -y update - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/ubuntu_address_sanitizer.yml b/.github/workflows/ubuntu_address_sanitizer.yml index 5c6326d..5537a9a 100644 --- a/.github/workflows/ubuntu_address_sanitizer.yml +++ b/.github/workflows/ubuntu_address_sanitizer.yml @@ -27,6 +27,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove openexr run: sudo apt-get --purge remove libopenexr-dev -y @@ -70,6 +73,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove openexr run: sudo apt-get --purge remove libopenexr-dev -y diff --git a/.github/workflows/ubuntu_arm_debug.yml b/.github/workflows/ubuntu_arm_debug.yml index 1621bca..6f63db1 100644 --- a/.github/workflows/ubuntu_arm_debug.yml +++ b/.github/workflows/ubuntu_arm_debug.yml @@ -27,6 +27,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: install ilmbase run: sudo apt-get -y install libilmbase-dev @@ -52,6 +55,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove ilmbase run: sudo apt-get --purge remove libilmbase-dev -y @@ -108,6 +114,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove ilmbase run: sudo apt-get --purge remove libilmbase-dev -y diff --git a/.github/workflows/ubuntu_arm_release.yml b/.github/workflows/ubuntu_arm_release.yml index 73c82f1..91639be 100644 --- a/.github/workflows/ubuntu_arm_release.yml +++ b/.github/workflows/ubuntu_arm_release.yml @@ -58,6 +58,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove ilmbase run: sudo apt-get --purge remove libilmbase-dev -y @@ -102,6 +105,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove ilmbase run: sudo apt-get --purge remove libilmbase-dev -y @@ -157,6 +163,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove ilmbase run: sudo apt-get --purge remove libilmbase-dev -y @@ -212,6 +221,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove ilmbase run: sudo apt-get --purge remove libilmbase-dev -y diff --git a/.github/workflows/ubuntu_debug.yml b/.github/workflows/ubuntu_debug.yml index 0bfd6e9..9a6df23 100644 --- a/.github/workflows/ubuntu_debug.yml +++ b/.github/workflows/ubuntu_debug.yml @@ -27,6 +27,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: install ilmbase run: sudo apt-get -y install libilmbase-dev @@ -52,6 +55,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove ilmbase run: sudo apt-get --purge remove libilmbase-dev -y @@ -108,6 +114,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove ilmbase run: sudo apt-get --purge remove libilmbase-dev -y diff --git a/.github/workflows/ubuntu_no_libtiff.yml b/.github/workflows/ubuntu_no_libtiff.yml index 5f0b849..a01f713 100644 --- a/.github/workflows/ubuntu_no_libtiff.yml +++ b/.github/workflows/ubuntu_no_libtiff.yml @@ -27,6 +27,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove libtiff run: sudo apt-get --purge remove libtiff-dev -y @@ -52,6 +55,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove libtiff-dev run: sudo apt-get --purge remove libtiff-dev -y diff --git a/.github/workflows/ubuntu_release.yml b/.github/workflows/ubuntu_release.yml index cfb649c..2f63bf3 100644 --- a/.github/workflows/ubuntu_release.yml +++ b/.github/workflows/ubuntu_release.yml @@ -27,6 +27,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: install libtiff run: sudo apt-get -y install libtiff-dev @@ -55,6 +58,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove ilmbase run: sudo apt-get --purge remove libilmbase-dev -y @@ -98,6 +104,9 @@ jobs: runs-on: ubuntu-latest steps: + + - name: run apt-get update + run: sudo apt-get -y update - name: remove ilmbase run: sudo apt-get --purge remove libilmbase-dev -y @@ -154,6 +163,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove ilmbase run: sudo apt-get --purge remove libilmbase-dev -y @@ -209,6 +221,9 @@ jobs: steps: + - name: run apt-get update + run: sudo apt-get -y update + - name: remove ilmbase run: sudo apt-get --purge remove libilmbase-dev -y diff --git a/ctlrender/exr_file.cc b/ctlrender/exr_file.cc index c61d199..c1fd254 100644 --- a/ctlrender/exr_file.cc +++ b/ctlrender/exr_file.cc @@ -64,6 +64,20 @@ #include #include +void exr_read_standard_attributes(Imf::InputFile *file, format_t *format) +{ + format->exr_standard_attributes.dataWindow = file->header().dataWindow(); + format->exr_standard_attributes.displayWindow = file->header().displayWindow(); + format->exr_standard_attributes.pixelAspectRatio = file->header().pixelAspectRatio(); + format->exr_standard_attributes.screenWindowCenter = file->header().screenWindowCenter(); + format->exr_standard_attributes.screenWindowWidth = file->header().screenWindowWidth(); + format->exr_standard_attributes.lineOrder = file->header().lineOrder(); + format->exr_standard_attributes.compression = file->header().compression(); + + format->is_exr_standard_attributes_set = true; + return; +} + bool exr_read(const char *name, float scale, ctl::dpx::fb *pixels, format_t *format) { std::ifstream ins; @@ -92,7 +106,9 @@ bool exr_read(const char *name, float scale, ctl::dpx::fb *pixels, ////////////////////////// Imf::InputFile file(name); - Imath::Box2i dw = file.header().dataWindow(); + // read the exr standard attributes for potential later use in exr_write() + exr_read_standard_attributes(&file, format); + Imath::Box2i dw = format->exr_standard_attributes.dataWindow; if (file.header().channels().begin().channel().type == Imf::HALF) format->src_bps=16; @@ -112,30 +128,34 @@ bool exr_read(const char *name, float scale, ctl::dpx::fb *pixels, Imf::FrameBuffer frameBuffer; frameBuffer.insert ("R", - Imf::Slice (pixelType, + Imf::Slice::Make (pixelType, (char *) pixels->ptr(), + dw, xstride, ystride, 1, 1, 0.0)); frameBuffer.insert ("G", - Imf::Slice (pixelType, + Imf::Slice::Make (pixelType, (char *) (pixels->ptr()+1), + dw, xstride, ystride, 1, 1, 0.0)); frameBuffer.insert ("B", - Imf::Slice (pixelType, + Imf::Slice::Make (pixelType, (char *) (pixels->ptr()+2), + dw, xstride, ystride, 1, 1, 0.0)); if (has_alpha){ frameBuffer.insert ("A", - Imf::Slice (pixelType, + Imf::Slice::Make (pixelType, (char *) (pixels->ptr()+3), + dw, xstride, ystride, 1, 1, 1.0)); @@ -166,8 +186,8 @@ void exr_write(const char *name, float scale, const ctl::dpx::fb &pixels, bool is_half = format->bps == 16 ? true : false; int depth = pixels.depth(); - float width = pixels.width(); - float height = pixels.height(); + int width = pixels.width(); + int height = pixels.height(); float const* pixelPtr = pixels.ptr(); // Do any scaling on a full float buffer @@ -189,13 +209,33 @@ void exr_write(const char *name, float scale, const ctl::dpx::fb &pixels, Imf::PixelType pixelType = is_half ? Imf::HALF : Imf::FLOAT; Imf::Header header(width, height); - header.compression() = (Imf::Compression)compression->exrCompressionScheme; + + if (format->is_exr_standard_attributes_set) { + header.dataWindow() = format->exr_standard_attributes.dataWindow; + header.displayWindow() = format->exr_standard_attributes.displayWindow; + header.pixelAspectRatio() = format->exr_standard_attributes.pixelAspectRatio; + header.screenWindowCenter() = format->exr_standard_attributes.screenWindowCenter; + header.screenWindowWidth() = format->exr_standard_attributes.screenWindowWidth; + header.lineOrder() = format->exr_standard_attributes.lineOrder; + if (true == format->is_compression_set) { + // the user specified a specific compression type + header.compression() = (Imf::Compression)compression->exrCompressionScheme; + } + else { + header.compression() = format->exr_standard_attributes.compression; + } + } + else { + header.compression() = (Imf::Compression)compression->exrCompressionScheme; + } + Imath::Box2i dataWindow = header.dataWindow(); header.channels().insert("R", Imf::Channel(pixelType)); header.channels().insert("G", Imf::Channel(pixelType)); header.channels().insert("B", Imf::Channel(pixelType)); - if (depth == 4) - header.channels().insert("A", Imf::Channel(pixelType)); + if (depth == 4) { + header.channels().insert("A", Imf::Channel(pixelType)); + } Imf::OutputFile file(name, header); Imf::FrameBuffer frameBuffer; @@ -219,27 +259,32 @@ void exr_write(const char *name, float scale, const ctl::dpx::fb &pixels, int ystride = sizeof(*halfPixelPtr) * depth * width; // Insert the half buffer into the framebuffer - frameBuffer.insert("R", Imf::Slice(pixelType, (char*)halfPixelPtr, xstride, ystride)); - frameBuffer.insert("G", Imf::Slice(pixelType, (char*)(halfPixelPtr + 1), xstride, ystride)); - frameBuffer.insert("B", Imf::Slice(pixelType, (char*)(halfPixelPtr + 2), xstride, ystride)); - if (depth == 4) - frameBuffer.insert("A", Imf::Slice(pixelType, (char*)(halfPixelPtr + 3), xstride, ystride)); + frameBuffer.insert("R", Imf::Slice::Make(pixelType, (char*)(halfPixelPtr + 0), dataWindow, xstride, ystride)); + frameBuffer.insert("G", Imf::Slice::Make(pixelType, (char*)(halfPixelPtr + 1), dataWindow, xstride, ystride)); + frameBuffer.insert("B", Imf::Slice::Make(pixelType, (char*)(halfPixelPtr + 2), dataWindow, xstride, ystride)); + if (depth == 4) { + frameBuffer.insert("A", Imf::Slice::Make(pixelType, (char*)(halfPixelPtr + 3), dataWindow, xstride, ystride)); + } + } else { // No conversion needed so insert the float buffer into the frambuffer int xstride = sizeof(*pixelPtr) * depth; int ystride = sizeof(*pixelPtr) * depth * width; - frameBuffer.insert("R", Imf::Slice(pixelType, (char*)pixelPtr, xstride, ystride)); - frameBuffer.insert("G", Imf::Slice(pixelType, (char*)(pixelPtr + 1), xstride, ystride)); - frameBuffer.insert("B", Imf::Slice(pixelType, (char*)(pixelPtr + 2), xstride, ystride)); - if (depth == 4) - frameBuffer.insert("A", Imf::Slice(pixelType, (char*)(pixelPtr + 3), xstride, ystride)); + frameBuffer.insert("R", Imf::Slice::Make(pixelType, (char*)(pixelPtr + 0), dataWindow, xstride, ystride)); + frameBuffer.insert("G", Imf::Slice::Make(pixelType, (char*)(pixelPtr + 1), dataWindow, xstride, ystride)); + frameBuffer.insert("B", Imf::Slice::Make(pixelType, (char*)(pixelPtr + 2), dataWindow, xstride, ystride)); + if (depth == 4) { + frameBuffer.insert("A", Imf::Slice::Make(pixelType, (char*)(pixelPtr + 3), dataWindow, xstride, ystride)); + } + } file.setFrameBuffer(frameBuffer); - file.writePixels(height); + file.writePixels(dataWindow.max.y - dataWindow.min.y + 1); + return; } #else diff --git a/ctlrender/format.cc b/ctlrender/format.cc index 3ee7b6c..30a471f 100644 --- a/ctlrender/format.cc +++ b/ctlrender/format.cc @@ -59,6 +59,10 @@ format_t::format_t() { bps=0; squish=0; descriptor=0; + is_compression_set = false; +#if defined(HAVE_OPENEXR) + is_exr_standard_attributes_set = false; +#endif }; format_t::format_t(const char *_ext, uint8_t _bps) { @@ -66,4 +70,8 @@ format_t::format_t(const char *_ext, uint8_t _bps) { bps=_bps; squish=0; descriptor=0; + is_compression_set = false; +#if defined(HAVE_OPENEXR) + is_exr_standard_attributes_set = false; +#endif }; diff --git a/ctlrender/format.hh b/ctlrender/format.hh index f7a9309..2dd7e88 100644 --- a/ctlrender/format.hh +++ b/ctlrender/format.hh @@ -57,6 +57,22 @@ #include +#if defined(HAVE_OPENEXR) + #include + #include + #include + +struct exr_standard_attributes_t { + Imath::Box2i dataWindow; + Imath::Box2i displayWindow; + float pixelAspectRatio; + Imath::V2f screenWindowCenter; + float screenWindowWidth; + Imf::LineOrder lineOrder; + Imf::Compression compression; +}; +#endif + // Used to pass in parameters through the transform function (see transform.hh) // into the file writers. struct format_t { @@ -75,6 +91,11 @@ struct format_t { // 160 - RA // 161 - GA // 162 - BA + bool is_compression_set; +#if defined(HAVE_OPENEXR) + bool is_exr_standard_attributes_set; + exr_standard_attributes_t exr_standard_attributes; +#endif }; #endif diff --git a/ctlrender/main.cc b/ctlrender/main.cc index 91aefca..721fa22 100644 --- a/ctlrender/main.cc +++ b/ctlrender/main.cc @@ -340,6 +340,7 @@ int main(int argc, const char **argv) if (!strcmp(compression.name, Compression::no_compression.name)) { fprintf(stderr, "Unrecognized compression scheme '%s'. Turning off compression.\n", scheme); } + desired_format.is_compression_set = true; argv++; argc--; } @@ -672,6 +673,9 @@ int main(int argc, const char **argv) exit(1); } actual_format.squish = noalpha; + if (true == desired_format.is_compression_set) { + actual_format.is_compression_set = true; + } transform(inputFile, outputFile, input_scale, output_scale, &actual_format, &compression, ctl_operations, global_ctl_parameters); input_image_files.pop_front(); } diff --git a/unittest/ctlrender/CMakeLists.txt b/unittest/ctlrender/CMakeLists.txt index 7da97a6..66ff314 100644 --- a/unittest/ctlrender/CMakeLists.txt +++ b/unittest/ctlrender/CMakeLists.txt @@ -68,6 +68,17 @@ if(OpenEXR_FOUND) add_test(NAME "ctlrender-EXR_RGBA16->EXR_RGBA_32" COMMAND ${CTLRENDER_PATH} -ctl "${TEST_FILES}/unity_with_alpha.ctl" -format exr32 -force "${TEST_FILES}/colorbars_nuke_rgba_exr16.exr" "${CTLRENDER_OUTPUT_FOLDER}/bars_rgba_exr16_to_exr32.exr") add_test(NAME "ctlrender-EXR_RGBA32->EXR_RGBA_16" COMMAND ${CTLRENDER_PATH} -ctl "${TEST_FILES}/unity_with_alpha.ctl" -format exr16 -force "${TEST_FILES}/colorbars_nuke_rgba_exr32.exr" "${CTLRENDER_OUTPUT_FOLDER}/bars_rgba_exr32_to_exr16.exr") add_test(NAME "ctlrender-EXR_RGBA32->EXR_RGBA_32" COMMAND ${CTLRENDER_PATH} -ctl "${TEST_FILES}/unity_with_alpha.ctl" -format exr32 -force "${TEST_FILES}/colorbars_nuke_rgba_exr32.exr" "${CTLRENDER_OUTPUT_FOLDER}/bars_rgba_exr32_to_exr32.exr") + + # EXR compression tests + add_test(NAME "ctlrender-EXR16->EXR16-COMPRESSION-NONE" COMMAND ${CTLRENDER_PATH} -ctl "${TEST_FILES}/unity.ctl" -format exr16 -force -compression none "${TEST_FILES}/colorbars_nuke_rgb_exr16.exr" "${CTLRENDER_OUTPUT_FOLDER}/bars_rgb_exr16_to_exr16_compression_none.exr") + add_test(NAME "ctlrender-EXR16->EXR16-COMPRESSION-RLE" COMMAND ${CTLRENDER_PATH} -ctl "${TEST_FILES}/unity.ctl" -format exr16 -force -compression rle "${TEST_FILES}/colorbars_nuke_rgb_exr16.exr" "${CTLRENDER_OUTPUT_FOLDER}/bars_rgb_exr16_to_exr16_compression_rle.exr") + add_test(NAME "ctlrender-EXR16->EXR16-COMPRESSION-ZIPS" COMMAND ${CTLRENDER_PATH} -ctl "${TEST_FILES}/unity.ctl" -format exr16 -force -compression zips "${TEST_FILES}/colorbars_nuke_rgb_exr16.exr" "${CTLRENDER_OUTPUT_FOLDER}/bars_rgb_exr16_to_exr16_compression_zips.exr") + add_test(NAME "ctlrender-EXR16->EXR16-COMPRESSION-ZIP" COMMAND ${CTLRENDER_PATH} -ctl "${TEST_FILES}/unity.ctl" -format exr16 -force -compression zip "${TEST_FILES}/colorbars_nuke_rgb_exr16.exr" "${CTLRENDER_OUTPUT_FOLDER}/bars_rgb_exr16_to_exr16_compression_zip.exr") + add_test(NAME "ctlrender-EXR16->EXR16-COMPRESSION-PIZ" COMMAND ${CTLRENDER_PATH} -ctl "${TEST_FILES}/unity.ctl" -format exr16 -force -compression piz "${TEST_FILES}/colorbars_nuke_rgb_exr16.exr" "${CTLRENDER_OUTPUT_FOLDER}/bars_rgb_exr16_to_exr16_compression_piz.exr") + add_test(NAME "ctlrender-EXR16->EXR16-COMPRESSION-PXR24" COMMAND ${CTLRENDER_PATH} -ctl "${TEST_FILES}/unity.ctl" -format exr16 -force -compression pxr24 "${TEST_FILES}/colorbars_nuke_rgb_exr16.exr" "${CTLRENDER_OUTPUT_FOLDER}/bars_rgb_exr16_to_exr16_compression_pxr24.exr") + add_test(NAME "ctlrender-EXR16->EXR16-COMPRESSION-B44" COMMAND ${CTLRENDER_PATH} -ctl "${TEST_FILES}/unity.ctl" -format exr16 -force -compression b44 "${TEST_FILES}/colorbars_nuke_rgb_exr16.exr" "${CTLRENDER_OUTPUT_FOLDER}/bars_rgb_exr16_to_exr16_compression_b44.exr") + add_test(NAME "ctlrender-EXR16->EXR16-COMPRESSION-B44A" COMMAND ${CTLRENDER_PATH} -ctl "${TEST_FILES}/unity.ctl" -format exr16 -force -compression b44a "${TEST_FILES}/colorbars_nuke_rgb_exr16.exr" "${CTLRENDER_OUTPUT_FOLDER}/bars_rgb_exr16_to_exr16_compression_b44a.exr") + endif() #ACES tests