diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 594f3c94..0fed4df0 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -96,6 +96,10 @@ jobs: run: | sudo xcode-select -s /Library/Developer/CommandLineTools + - name: Remove problematic SDKs + run: | + sudo rm -rf /Library/Developer/CommandLineTools/SDKs/MacOSX15*.sdk + - name: Install dependencies run: | brew bundle diff --git a/apps/src/Packager.cpp b/apps/src/Packager.cpp index 910bcb01..64df5170 100644 --- a/apps/src/Packager.cpp +++ b/apps/src/Packager.cpp @@ -47,6 +47,7 @@ struct VolumeInfo { Flip flipOption{Flip::None}; vc::Metadata meta; bool compress{false}; + bool forceWrite{false}; }; static bool DoAnalyze{true}; @@ -99,7 +100,8 @@ auto main(int argc, char* argv[]) -> int po::options_description all("Usage"); all.add(helpOpts).add_options()( - "analyze", po::value()->default_value(true), "Analyze volume"); + "analyze", po::value()->default_value(true), "Analyze volume") + ("force-write", "Force writing new TIFF files even if they could be copied"); // clang-format on // Parse the command line and separate out flags for volumes @@ -194,6 +196,7 @@ auto main(int argc, char* argv[]) -> int ///// Add Volumes ///// for (const auto& v : vargs) { VolumeInfo info = GetVolumeInfo(v); + info.forceWrite = args.count("force-write") > 0; AddVolume(volpkg, info); } } @@ -475,7 +478,7 @@ void AddVolume(vc::VolumePkg::Pointer& volpkg, const VolumeInfo& info) auto& slice = pair.second; // Convert or flip if (slice.needsConvert() || slice.needsScale() || needsFlip || - info.compress) { + info.compress || info.forceWrite) { // Override slice min/max with volume min/max if (slice.needsScale()) { slice.setScale(volMax, volMin); diff --git a/core/include/vc/core/util/MemMap.hpp b/core/include/vc/core/util/MemMap.hpp index c4146f8d..7230dd49 100644 --- a/core/include/vc/core/util/MemMap.hpp +++ b/core/include/vc/core/util/MemMap.hpp @@ -9,6 +9,15 @@ namespace volcart { +namespace endian +{ +/** Returns whether the system is little endian */ +auto little() -> bool; + +/** Returns whether the system is big endian */ +auto big() -> bool; +} // namespace endian + /** @brief Memmap record */ struct mmap_info { /** Whether this is a valid mapping */ diff --git a/core/src/MemMap.cpp b/core/src/MemMap.cpp index 04881ce1..df7afd45 100644 --- a/core/src/MemMap.cpp +++ b/core/src/MemMap.cpp @@ -5,6 +5,14 @@ namespace vc = volcart; namespace fs = vc::filesystem; +auto vc::endian::little() -> bool +{ + constexpr int i{1}; + return *reinterpret_cast(&i) == 1; +} + +auto vc::endian::big() -> bool { return not little(); } + vc::mmap_info::operator bool() const { return addr and size > 0; } vc::auto_mmap_info::auto_mmap_info(const mmap_info& rhs) : mmap_info(rhs) {} diff --git a/core/src/TIFFIO.cpp b/core/src/TIFFIO.cpp index f7605db7..ace668f7 100644 --- a/core/src/TIFFIO.cpp +++ b/core/src/TIFFIO.cpp @@ -80,6 +80,7 @@ struct TIFFHeader { std::uint16_t config = 0; std::uint64_t* stripOffsets{nullptr}; tio::Compression compression{tio::Compression::NONE}; + bool bigEndian{false}; }; auto ReadHeader(lt::TIFF* tif) @@ -95,6 +96,7 @@ auto ReadHeader(lt::TIFF* tif) TIFFGetField(tif, TIFFTAG_COMPRESSION, &hdr.compression); TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &hdr.rowsPerStrip); TIFFGetField(tif, TIFFTAG_STRIPOFFSETS, &hdr.stripOffsets); + hdr.bigEndian = lt::TIFFIsBigEndian(tif) != 0; return hdr; } @@ -144,13 +146,15 @@ auto ReadImage(lt::TIFF* tif, const TIFFHeader& hdr) -> cv::Mat // Returns whether this TIFF file is encoded for memory mapping auto CanMMap(const TIFFHeader& hdr) -> bool { - auto res = hdr.config == PLANARCONFIG_CONTIG; - res &= hdr.type == SAMPLEFORMAT_UINT; - res &= hdr.depth == 16 and hdr.channels == 1; - res &= hdr.compression == tio::Compression::NONE; - // important: full image is in a single strip - res &= hdr.rowsPerStrip == hdr.height; - return res; + const auto isContig = hdr.config == PLANARCONFIG_CONTIG; + const auto isUint = hdr.type == SAMPLEFORMAT_UINT; + const auto is16bpc = hdr.depth == 16; + const auto isMono = hdr.channels == 1; + const auto uncompressed = hdr.compression == tio::Compression::NONE; + const auto singleStrip = hdr.rowsPerStrip == hdr.height; + const auto endianMatch = hdr.bigEndian == vc::endian::big(); + return isContig and isUint and is16bpc and isMono and uncompressed and + singleStrip and endianMatch; } // Memory mapp the tiff