diff --git a/czi-format/czi-parser/CMakeLists.txt b/czi-format/czi-parser/CMakeLists.txt index f9ee73eb48f24dd75f0a3c59f91093d2de439827..f6fab4b2aa55f2abeb712e401f546771e6ea836a 100644 --- a/czi-format/czi-parser/CMakeLists.txt +++ b/czi-format/czi-parser/CMakeLists.txt @@ -22,4 +22,4 @@ target_link_libraries (czi-parser ${CMAKE_THREAD_LIBS_INIT}) set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) -include(CPack) +include(CPack) \ No newline at end of file diff --git a/czi-format/czi-parser/compression/rle.h b/czi-format/czi-parser/compression/rle.h new file mode 100644 index 0000000000000000000000000000000000000000..eed9860af20fae4fef144a1cf49b9903fedd73a8 --- /dev/null +++ b/czi-format/czi-parser/compression/rle.h @@ -0,0 +1,110 @@ +#pragma once +#include "../custom_types.h" +#include "../utilities/vector_utilities.h" +#include "../image/z_order.h" + +constexpr size_t MAX_LITERAL_COUNT = 255; +constexpr size_t MAX_RUN_COUNT = 255; + +// Run-Length encode bytes and return compressed bytes. +std::vector<byte> rle_encode(const std::vector<byte> &bytes) +{ + std::vector<byte> compressed; + byte literalBuffer[MAX_LITERAL_COUNT]; + size_t literalCount = 0; + size_t runCount = 0; + + size_t uncompresseddBufferSize = bytes.size(); + + for (size_t bufferIndex = 0; bufferIndex < uncompresseddBufferSize;) + { + byte symbol = bytes[bufferIndex]; + runCount = 1; + + // Encode run. + while ((runCount < MAX_RUN_COUNT) && + (bytes[bufferIndex + runCount] == symbol) && + (runCount < (uncompresseddBufferSize - bufferIndex))) + { + ++runCount; + } + + if ((runCount > 1) || + (literalCount == MAX_LITERAL_COUNT) || + ((bufferIndex == (uncompresseddBufferSize - 1)) && literalCount > 0)) + { + // Write literal buffer. + byte literalCountBYTE = (byte)literalCount; + always_assert(literalCountBYTE == literalCount); + + compressed.push_back(literalCountBYTE); + for (size_t literalBufferIndex = 0; literalBufferIndex < literalCount; literalBufferIndex++) + { + compressed.push_back(literalBuffer[literalBufferIndex]); + } + literalCount = 0; + + // Write run sequence. + byte runCountBYTE = (byte)runCount; + always_assert(runCountBYTE == runCount); + compressed.push_back(runCountBYTE); + compressed.push_back(symbol); + + bufferIndex += runCount; + } + else + { + // Encode literal symbol. + literalBuffer[literalCount++] = symbol; + ++bufferIndex; + } + } + + return compressed; +} + +// Decode Run-Length encoded bytes. +std::vector<byte> rle_decode(const std::vector<byte> &compressed) +{ + std::vector<byte> uncompressed; + uncompressed.reserve(compressed.size()); + + size_t compressedBufferSize = compressed.size(); + size_t bufferIndex = 0; + + byte literalCount, runCount, runSymbol; + while (bufferIndex < compressedBufferSize) + { + literalCount = compressed[bufferIndex++]; + while (literalCount--) + { + uncompressed.push_back(compressed[bufferIndex++]); + } + + runCount = compressed[bufferIndex++]; + runSymbol = compressed[bufferIndex++]; + while (runCount--) + { + uncompressed.push_back(runSymbol); + } + } + + return uncompressed; +} + +void rle_test() +{ + std::vector<byte> data = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 20, 30, 40, 45, 48, 46, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 0, 0, 1, 2, 3, 8, 8, 8, 8, 9, 6, 5, 4}; + + // 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 20, 30, 40, 45, 48, 46, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 0, 1, 2, 3, 8, 8, 8, 8, 9, 6, 5, 4 + // 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 20, 30, 40, 45, 48, 46, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 0, 1, 2, 3, 8, 8, 8, 8, 9, 6, 5, 4 + + auto compressed = rle_encode(data); + auto uncompressed = rle_decode(compressed); + + bool same = are_same_vectors(data, uncompressed); + + always_assert(same); +} \ No newline at end of file diff --git a/czi-format/czi-parser/image/z_order.h b/czi-format/czi-parser/image/z_order.h index 95357ca34590cdb23fc90b00e19091d6875b3123..45d1fe21d56ecb1fc3bac14118e0f0d958903bae 100644 --- a/czi-format/czi-parser/image/z_order.h +++ b/czi-format/czi-parser/image/z_order.h @@ -45,15 +45,17 @@ struct PointWithIndex { uint x; uint y; + ulong bufferPosition; ulong z; PointWithIndex() {} // Create interleaved Z order index from X and Y coordinate. - PointWithIndex(uint _x, uint _y) + PointWithIndex(uint _x, uint _y, ulong _bufferPosition) { x = _x; y = _y; + bufferPosition = _bufferPosition; z = interleave(x, y); } @@ -75,7 +77,8 @@ std::vector<PointWithIndex> generate_ordered_z_order_indices(const uint width, c { for (uint x = 0; x < width; x++) { - result[index++] = PointWithIndex(x, y); + result[index] = PointWithIndex(x, y, index); + index++; } } diff --git a/czi-format/czi-parser/main.cpp b/czi-format/czi-parser/main.cpp index 94f3b93c300b545c99e4e94d8544ae3ec05953e4..bf1f7cbe3c589fca4762a86e377454f97b6acbc2 100644 --- a/czi-format/czi-parser/main.cpp +++ b/czi-format/czi-parser/main.cpp @@ -1,8 +1,12 @@ #include "czi_parser.h" #include "file_system.h" +#include "compression/rle.h" int main(int argc, char **argv) { + rle_test(); + return 0; + std::string cziFile = (argc > 1) ? argv[1] : "/home/mor0146/gitlab/data_project/czi-format/data/CZT-Stack-Anno.czi"; //"/home/mor0146/gitlab/data_project/czi-format/data/m2/exampleSingleChannel.czi"; if (cziFile == "-v" || cziFile == "--version") { diff --git a/czi-format/czi-parser/utilities/vector_utilities.h b/czi-format/czi-parser/utilities/vector_utilities.h index 8706e11855562a2922589c60840a708d9f47e3a0..4ba0cfe0933ff71798506098caf803bdd1cd6126 100644 --- a/czi-format/czi-parser/utilities/vector_utilities.h +++ b/czi-format/czi-parser/utilities/vector_utilities.h @@ -1,3 +1,4 @@ +#pragma once #include <vector> template <typename T>