From c09ce4c4f851cdb4d9d815b0af29b4c72c3cc308 Mon Sep 17 00:00:00 2001 From: senikm Date: Thu, 11 Jul 2024 12:27:49 +0200 Subject: [PATCH] TRPX prints all the warnings and exits when there is an incompatible TIFF format --- .gitignore | 4 +-- include/Grey_tif.hpp | 42 ++++++++++++++++-------- src/prolix.cpp | 8 ++--- src/terse.cpp | 76 +++++++++++++++++++------------------------- 4 files changed, 67 insertions(+), 63 deletions(-) diff --git a/.gitignore b/.gitignore index a4a1bdf..0349712 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ ..idea/ -..vscode/ +.vscode/ cmake-build-debug/ -.build/ +build/ html/ \ No newline at end of file diff --git a/include/Grey_tif.hpp b/include/Grey_tif.hpp index 4e7c993..878929a 100644 --- a/include/Grey_tif.hpp +++ b/include/Grey_tif.hpp @@ -33,7 +33,7 @@ namespace jpa { * - Compact code, optimized for high-speed performance and minimal memory foorprint. * - Accommodating images with varying types and sizes. * - Support for signed and unsigned integral values, and float and double values. - * - Flexible bit depths: 8, 16, 32, or (four double precision values) 64 bits. + * - Flexible bit depths: 8, 16, 32, or (for double precision values) 64 bits. * - Accomodates raw TIFF data with runtinme pixel type identification. * - Allows regularizing pixel types to a compile-time determined type. * - The first (or only) image managed by a Grey_tif object is directly available as a readonly std::span @@ -242,7 +242,7 @@ class Grey_tif_image : public std::span { POD_type_traits const& type() const noexcept {return d_image_type;} private: - Grey_tif_image(POD_type_traits const& image_type, std::array const& dim, std::span const& data) noexcept : + Grey_tif_image(POD_type_traits const& image_type, std::array const& dim, std::span const& data) : std::span(data), d_image_type(image_type), d_dim(dim) {} @@ -308,7 +308,7 @@ class Grey_tif_image { } private: - Grey_tif_image(POD_type_traits const& image_type, std::array const& dim, std::span const& data) noexcept : + Grey_tif_image(POD_type_traits const& image_type, std::array const& dim, std::span const& data) : d_data(reinterpret_cast(&data.begin()[0])), d_image_type(image_type), d_dim(dim) { } @@ -361,7 +361,7 @@ class Grey_tif : public Grey_tif_image { * * @param is The input stream containing TIFF data. */ - Grey_tif(std::istream& is) noexcept : Grey_tif() { + Grey_tif(std::istream& is) : Grey_tif() { is.seekg(0, std::ios::end); std::streampos fileSize = is.tellg(); is.seekg(0, std::ios::beg); @@ -381,7 +381,7 @@ class Grey_tif : public Grey_tif_image { * @param other The Grey_tif object to be swapped. */ template - void swap(Grey_tif&& other) noexcept { + void swap(Grey_tif&& other) { d_last_ifd_offset = other.d_last_ifd_offset = 4; std::swap(d_tif, other.d_tif); f_scan_images(); @@ -401,7 +401,7 @@ class Grey_tif : public Grey_tif_image { * @param other The Grey_tif object to be swapped. */ template - void swap(Grey_tif& other) noexcept { swap(std::move(other)); } + void swap(Grey_tif& other) { swap(std::move(other)); } /** * @brief Read/write accessor to images from a single or multi-image Grey_tif object. @@ -528,8 +528,8 @@ class Grey_tif : public Grey_tif_image { reinterpret_cast(d_tif[d_last_ifd_offset]) = index; reinterpret_cast(d_tif[index]) = 7; index += 2; - f_set_ifd(index, 0x0100, 3, static_cast(dim[0])); - f_set_ifd(index, 0x0101, 3, static_cast(dim[1])); + f_set_ifd(index, 0x0100, 3, static_cast(dim[1])); + f_set_ifd(index, 0x0101, 3, static_cast(dim[0])); f_set_ifd(index, 0x0102, 3, 8 * (std::is_same_v ? sizeof(CT) : sizeof(T))); f_set_ifd(index, 0x0103, 3, 1); f_set_ifd(index, 0x0106, 3, 1); @@ -708,7 +708,8 @@ class Grey_tif : public Grey_tif_image { } template - void f_make_Image(std::uint32_t& index) noexcept { + void f_make_Image(std::uint32_t& index) { + bool compatible_tif = true; std::array dim = {0,0}; std::size_t bits_per_pixel = 0; std::byte* cursor = d_tif.data() + index; @@ -754,15 +755,23 @@ class Grey_tif : public Grey_tif_image { else if (tag == 0x0102 ) { if ((val == 8 || val == 16 || val == 32 || val == 64)) bits_per_pixel = val; - else + else { std::cerr << "Warning: Grey_tif can only read greyscale tiff files with 8-, 16-, 32-, or 64-bit pixels" << std::endl; + compatible_tif = false; + } } - else if (tag == 0x0103 && val != 1) + else if (tag == 0x0103 && val != 1) { std::cerr << "Warning: Grey_tif cannot read compressed tiff files"<< std::endl; - else if (tag == 0x0106 && val > 1) + compatible_tif = false; + } + else if (tag == 0x0106 && val > 1) { std::cerr << "Warning: Grey_tif cannot read colour tiff files"<< std::endl; - else if ((tag == 0x0107 || tag == 0x0108 || tag == 0x0109 || tag == 0x010A) && val != 1) + compatible_tif = false; + } + else if ((tag == 0x0107 || tag == 0x0108 || tag == 0x0109 || tag == 0x010A) && val != 1) { std::cerr << "Warning: Grey_tif cannot read black & white tiff files"<< std::endl; + compatible_tif = false; + } else if (tag == 0x0111) { if (count == 1) strip_offsets[0] = val; else { @@ -772,8 +781,10 @@ class Grey_tif : public Grey_tif_image { strip_offsets[i] = f_int32(p); } } - else if (tag == 0x0115 && val != 1) + else if (tag == 0x0115 && val != 1) { std::cerr << "Warning: Grey_tif cannot read RGB colour tiff files"<< std::endl; + compatible_tif = false; + } else if (tag == 0x0116) rows_per_strip = val; else if (tag == 0x0117) { if (count == 1) strip_byte_counts[0] = val; @@ -793,8 +804,11 @@ class Grey_tif : public Grey_tif_image { if (strip_byte_counts[i] != strip_offsets[i + 1] - strip_offsets[i]) { std::cerr << "Warning: Grey_tif cannot read tiff files with non-consecutive strips" << std::endl; std::cerr << " most likely the tiff file is corrupted" << std::endl; + compatible_tif = false; break; } + if (!compatible_tif) + throw std::runtime_error("Incompatible TIFF file\n"); d_last_ifd_offset = static_cast(cursor - d_tif.data()); index = f_int32(cursor); if constexpr (!NATIVE) { diff --git a/src/prolix.cpp b/src/prolix.cpp index 5f9aed5..d7d125a 100644 --- a/src/prolix.cpp +++ b/src/prolix.cpp @@ -69,25 +69,25 @@ int main(int argc, char const* argv[]) { if (trpx_data.bits_per_val() <= 16 && trpx_data.is_signed()) { for (int i = 0; i != trpx_data.number_of_frames(); ++i) { tif_data.push_back(dim); - trpx_data.prolix(tif_data.image(i)); + trpx_data.prolix(tif_data.image(i), i); } } else if (trpx_data.bits_per_val() <= 16 && !trpx_data.is_signed()) { for (int i = 0; i != trpx_data.number_of_frames(); ++i) { tif_data.push_back(dim); - trpx_data.prolix(tif_data.image(i)); + trpx_data.prolix(tif_data.image(i), i); } } else if (trpx_data.bits_per_val() <= 32 && trpx_data.is_signed()) { for (int i = 0; i != trpx_data.number_of_frames(); ++i) { tif_data.push_back(dim); - trpx_data.prolix(tif_data.image(i)); + trpx_data.prolix(tif_data.image(i), i); } } else if (trpx_data.bits_per_val() <= 32 && !trpx_data.is_signed()) { for (int i = 0; i != trpx_data.number_of_frames(); ++i) { tif_data.push_back(dim); - trpx_data.prolix(tif_data.image(i)); + trpx_data.prolix(tif_data.image(i), i); } } else { diff --git a/src/terse.cpp b/src/terse.cpp index a4a4bef..518f67d 100644 --- a/src/terse.cpp +++ b/src/terse.cpp @@ -42,64 +42,54 @@ int main(int argc, char const* argv[]) { // Loop over all input file names for (fs::path tif_filename : input.params()) { - - // Only tif files will be compressed if (fs::is_regular_file(tif_filename) && (tif_filename.extension() == ".tiff" || tif_filename.extension() == ".tif" || tif_filename.extension() == ".TIFF" || tif_filename.extension() == ".TIF")) { + try { + auto start_IO_time = std::chrono::high_resolution_clock::now(); + std::ifstream tif_file(tif_filename, std::ios::binary); + if (!tif_file.is_open()) { + std::cerr << "Failed to open input file " << tif_filename << std::endl; + continue; // Skip to next file + } - // Start the IO timer and open the next file - auto start_IO_time = std::chrono::high_resolution_clock::now(); - std::ifstream tif_file(tif_filename, std::ios::binary); - if (!tif_file.is_open()) - std::cerr << "Failed to open input file " << tif_filename << std::endl; - else { - - // A tiff file was opened. Read its data. It may contain one or more images in a stack. jpa::Grey_tif tif_data(tif_file); tif_file.close(); - + total_tiff_size += tif_data.raw_data_size(); - - // stop the IO timer, start the user timer - IO_time += std::chrono::high_resolution_clock::now() - start_IO_time; auto start_user_time = std::chrono::high_resolution_clock::now(); - + Terse compressed; - - for (int i = 0; i != tif_data.image_stack_size(); ++i) - if (tif_data.dim() == tif_data.image(i).dim()) - Terse_pushback(compressed, tif_data.image(i)); - else { - std::cerr << "Tiff file " << tif_filename << " contains a stack of images with varying sizes." << std::endl; - std::cerr << "Terse cannot process such tiff-stacks. First unstack this tiff file and compress the images separately." << std::endl; - return 0; + for (int i = 0; i != tif_data.image_stack_size(); ++i) { + if (tif_data.dim() != tif_data.image(i).dim()) { + throw std::runtime_error("TIFF file contains a stack of images with varying sizes."); } - total_trpx_size += compressed.terse_size(); - - // Stop the user timer, start the IO timer - user_time += std::chrono::high_resolution_clock::now() - start_user_time; - start_IO_time = std::chrono::high_resolution_clock::now(); - - // Write the compressed data to the trpx file - auto trpx_filename = tif_filename; - std::ofstream trpx_file(trpx_filename.replace_extension(".trpx"), std::ios::binary); - if (!trpx_file.is_open()) - std::cerr << "Failed to open trpx file " << trpx_filename << std::endl; - else { - compressed.write(trpx_file); - trpx_file.close(); - fs::remove(tif_filename); - ++compressed_files; + Terse_pushback(compressed, tif_data.image(i)); + } + total_trpx_size += compressed.terse_size(); + + fs::path trpx_filename = tif_filename; + trpx_filename.replace_extension(".trpx"); + std::ofstream trpx_file(trpx_filename, std::ios::binary); + if (!trpx_file.is_open()) { + throw std::runtime_error("Failed to open trpx file for output."); } + + compressed.write(trpx_file); + trpx_file.close(); + std::cout << "Deleting original TIFF file: " << tif_filename << std::endl; + fs::remove(tif_filename); + ++compressed_files; + + auto end_user_time = std::chrono::high_resolution_clock::now(); + user_time += end_user_time - start_user_time; + IO_time += start_user_time - start_IO_time; + } catch (const std::exception& e) { + std::cerr << "Error processing " << tif_filename << ": " << e.what() << std::endl; } - - // stop the IO timer - IO_time += std::chrono::high_resolution_clock::now() - start_IO_time; } } - // If required, provide verbose output if (input.option("-verbose").found()) { for (fs::path tif_filename : input.params())