Skip to content

Commit

Permalink
adding ability to use a cache with accessors (#84)
Browse files Browse the repository at this point in the history
* draft

* cosmetic

* add subblock-cache to ISingleChannelScalingTileAccessor

* add caching to CSingleChannelPyramidLevelTileAccessor

* cosmetic

* update

* cosmetic

* fix incompatibility with older GCC (8.3)

* update

* update

* update

* update

* cosmetic

* cosmetic

* bump version

* cosmetic, start with "plane-scan"

* update

* update

* update

* update - make option "cachesize" operational

* fix bug with parsing command line option "background"

* update

* cleanup

* cosmetic

* update

* cosmetic

* review

* cosmetic

* cosmetic

* version-history

* typo

* cosmetic

* add unittest

* linter

* documentation

* cosmetic

* cosmetic

* Update Src/libCZI/libCZI_Compositor.h

Co-authored-by: DaveyJonesBitPail <119518234+DaveyJonesBitPail@users.noreply.github.com>

* REUSE

* review

---------

Co-authored-by: DaveyJonesBitPail <119518234+DaveyJonesBitPail@users.noreply.github.com>
  • Loading branch information
ptahmose and DaveyJonesBitPail committed Dec 6, 2023
1 parent 5e5f8ab commit 8dbc3f0
Show file tree
Hide file tree
Showing 25 changed files with 1,355 additions and 375 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.15)
cmake_policy(SET CMP0091 NEW) # enable new "MSVC runtime library selection" (https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html)

project(libCZI
VERSION 0.56.0
VERSION 0.57.0
HOMEPAGE_URL "https://github.com/ZEISS/libczi"
DESCRIPTION "libCZI is an Open Source Cross-Platform C++ library to read and write CZI")

Expand Down
8 changes: 6 additions & 2 deletions Src/CZICmd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ endif()
FetchContent_Declare(
cli11
GIT_REPOSITORY https://github.com/CLIUtils/CLI11
GIT_TAG v2.2.0
GIT_TAG v2.3.2
)

if (NOT cli11_POPULATED)
Expand Down Expand Up @@ -94,7 +94,11 @@ set (CZICMDSRCFILES
inc_rapidjson.h
BitmapGenNull.h
CZIcmd.cpp
platform_defines.h)
platform_defines.h
executePlaneScan.h
executePlaneScan.cpp
executeBase.h
executeBase.cpp)

add_executable(CZIcmd ${CZICMDSRCFILES})

Expand Down
182 changes: 175 additions & 7 deletions Src/CZICmd/cmdlineoptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <iostream>
#include <utility>
#include <cstring>
#include <cmath>
#if defined(LINUXENV)
#include <libgen.h>
#endif
Expand Down Expand Up @@ -428,6 +429,47 @@ struct GeneratorPixelTypeValidator : public CLI::Validator
}
};

/// CLI11-validator for the option "--cachesize".
struct CachesizeValidator : public CLI::Validator
{
CachesizeValidator()
{
this->name_ = "CachesizeValidator";
this->func_ = [](const std::string& str) -> string
{
const bool parsed_ok = CCmdLineOptions::TryParseSubBlockCacheSize(str, nullptr);
if (!parsed_ok)
{
ostringstream string_stream;
string_stream << "Invalid subblock-cache-size given \"" << str << "\"";
throw CLI::ValidationError(string_stream.str());
}

return {};
};
}
};

struct TileSizeForPlaneScanValidator : public CLI::Validator
{
TileSizeForPlaneScanValidator()
{
this->name_ = "TileSizeForPlaneScanValidator";
this->func_ = [](const std::string& str) -> string
{
const bool parsed_ok = CCmdLineOptions::TryParseCreateSize(str, nullptr);
if (!parsed_ok)
{
ostringstream string_stream;
string_stream << "Invalid tile-size-plane-scan given \"" << str << "\"";
throw CLI::ValidationError(string_stream.str());
}

return {};
};
}
};

/// A custom formatter for CLI11 - used to have nicely formatted descriptions.
class CustomFormatter : public CLI::Formatter
{
Expand Down Expand Up @@ -497,6 +539,7 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
{ "ScalingChannelComposite", Command::ScalingChannelComposite },
{ "ExtractAttachment", Command::ExtractAttachment},
{ "CreateCZI", Command::CreateCZI },
{ "PlaneScan", Command::PlaneScan },
};

const static PlaneCoordinateValidator plane_coordinate_validator;
Expand All @@ -518,6 +561,8 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
const static CreateSubblockMetadataValidator createsubblockmetadata_validator;
const static CompressionOptionsValidator compressionoptions_validator;
const static GeneratorPixelTypeValidator generatorpixeltype_validator;
const static CachesizeValidator cachesize_validator;
const static TileSizeForPlaneScanValidator tile_size_for_plane_scan_validator;

Command argument_command;
string argument_source_filename;
Expand Down Expand Up @@ -546,9 +591,12 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
string argument_createczisubblockmetadata;
string argument_compressionoptions;
string argument_generatorpixeltype;
string argument_subblock_cachesize;
string argument_tilesize_for_scan;
bool argument_versionflag = false;
string argument_source_stream_class;
string argument_source_stream_creation_propbag;
bool argument_use_visibility_check_optimization = false;

// editorconfig-checker-disable
cli_app.add_option("-c,--command", argument_command,
Expand All @@ -569,7 +617,12 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
\N'ScalingChannelComposite' operates like the previous command, but in addition gets all channels and creates a multi-channel-composite from them
using display-settings.
\N'ExtractAttachment' allows to extract (and save to a file) the contents of attachments.)
\N'CreateCZI' is used to demonstrate the CZI-creation capabilities of libCZI.)")
\N'CreateCZI' is used to demonstrate the CZI-creation capabilities of libCZI.)
\N'PlaneScan' does the following: over a ROI given with the --rect option a rectangle of size given with
the --tilesize-for-plane-scan option is moved, and the image content of this rectangle is written out to
files. The operation takes place on a plane which is given with the --plane-coordinate option. The filenames of the
tile-bitmaps are generated from the filename given with the --output option, where a string _X[x-position]_Y[y-position]_W[width]_H[height]
is added.)")
->default_val(Command::Invalid)
->option_text("COMMAND")
->transform(CLI::CheckedTransformer(map_string_to_command, CLI::ignore_case));
Expand Down Expand Up @@ -708,6 +761,18 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
"'Bgr24' or 'Bgr48'. Default is 'Bgr24'.")
->option_text("PIXELTYPE")
->check(generatorpixeltype_validator);
cli_app.add_option("--cachesize", argument_subblock_cachesize,
"Only used for 'PlaneScan' - specify the size of the subblock-cache in bytes. The argument is to "
"be given with a suffix k, M, G, ...")
->option_text("CACHESIZE")
->check(cachesize_validator);
cli_app.add_option("--tilesize-for-plane-scan", argument_tilesize_for_scan,
"Only used for 'PlaneScan' - specify the size of ROI which is used for scanning the plane in "
"units of pixels. Format is e.g. '1600x1200' and default is 512x512.")
->option_text("TILESIZE")
->check(tile_size_for_plane_scan_validator);
cli_app.add_flag("--use-visibility-check-optimization", argument_use_visibility_check_optimization,
"Whether to enable the experimental \"visibility check optimization\" for the accessors.");
cli_app.add_flag("--version", argument_versionflag,
"Print extended version-info and supported operations, then exit.");

Expand Down Expand Up @@ -742,6 +807,7 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
this->calcHashOfResult = argument_calc_hash;
this->drawTileBoundaries = argument_drawtileboundaries;
this->command = argument_command;
this->useVisibilityCheckOptimization = argument_use_visibility_check_optimization;

try
{
Expand Down Expand Up @@ -901,6 +967,18 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
const bool b = TryParseGeneratorPixeltype(argument_generatorpixeltype, &this->pixelTypeForBitmapGenerator);
ThrowIfFalse(b, "--generatorpixeltype", argument_generatorpixeltype);
}

if (!argument_subblock_cachesize.empty())
{
const bool b = TryParseSubBlockCacheSize(argument_subblock_cachesize, &this->subBlockCacheSize);
ThrowIfFalse(b, "--cachesize", argument_subblock_cachesize);
}

if (!argument_tilesize_for_scan.empty())
{
const bool b = TryParseCreateSize(argument_tilesize_for_scan, &this->tilesSizeForPlaneScan);
ThrowIfFalse(b, "--tilesize-for-plane-scan", argument_tilesize_for_scan);
}
}
catch (runtime_error& exception)
{
Expand Down Expand Up @@ -1027,14 +1105,17 @@ void CCmdLineOptions::Clear()
this->sbBlkMetadataKeyValue.clear();
this->rectX = this->rectY = 0;
this->rectW = this->rectH = -1;;
this->zoom = -1;
this->zoom = 1;
this->pyramidLayerNo = -1;
this->pyramidMinificationFactor = -1;
this->createTileInfo.rows = this->createTileInfo.columns = 1;
this->createTileInfo.overlap = 0;
this->compressionMode = libCZI::CompressionMode::Invalid;
this->compressionParameters = nullptr;
this->pixelTypeForBitmapGenerator = libCZI::PixelType::Bgr24;
this->subBlockCacheSize = 0;
this->tilesSizeForPlaneScan = make_tuple(512, 512);
this->useVisibilityCheckOptimization = false;
}

bool CCmdLineOptions::IsLogLevelEnabled(int level) const
Expand Down Expand Up @@ -1458,13 +1539,15 @@ bool CCmdLineOptions::TryParseDisplaySettings(const std::string& s, std::map<int
{
if (color != nullptr)
{
*color = libCZI::RgbFloatColor{ f[0],f[0],f[0] };
*color = libCZI::RgbFloatColor{ f[0], f[0], f[0] };
}
}

if (color != nullptr)
else
{
*color = libCZI::RgbFloatColor{ f[0],f[1],f[2] };
if (color != nullptr)
{
*color = libCZI::RgbFloatColor{ f[0], f[1], f[2] };
}
}

return true;
Expand Down Expand Up @@ -2182,7 +2265,7 @@ void CCmdLineOptions::PrintHelpStreamsObjects()
// Here we parse the JSON-formatted string that contains the property bag for the input stream and
// construct a map<int, libCZI::StreamsFactory::Property> from it.

static constexpr struct
static constexpr struct
{
const char* name;
int stream_property_id;
Expand Down Expand Up @@ -2278,3 +2361,88 @@ void CCmdLineOptions::PrintHelpStreamsObjects()

return true;
}

/*static*/bool CCmdLineOptions::TryParseSubBlockCacheSize(const std::string& text, std::uint64_t* size)
{
// This regular expression is used to match strings that represent sizes in bytes, kilobytes, megabytes, gigabytes, terabytes, kibibytes, mebibytes, gibibytes, and tebibytes.
//
// Here is a breakdown of the regular expression:
//
// - ^\s*: Matches the start of the string, followed by any amount of whitespace.
// - ([+]?(?:[0-9]+(?:[.][0-9]*)?|[.][0-9]+)): Matches a positive number, which can be an integer or a decimal. The number may optionally be preceded by a plus sign.
// - \s*: Matches any amount of whitespace following the number.
// - (k|m|g|t|ki|mi|gi|ti): Matches one of the following units of size: k (kilobytes), m (megabytes), g (gigabytes), t (terabytes), ki (kibibytes), mi (mebibytes), gi (gibibytes), ti (tebibytes).
// - (?:b?): Optionally matches a 'b', which can be used to explicitly specify that the size is in bytes.
// - \s*$: Matches any amount of whitespace at the end of the string, followed by the end of the string.
//
// This regular expression is case-insensitive.
regex regex(R"(^\s*([+]?(?:[0-9]+(?:[.][0-9]*)?|[.][0-9]+))\s*(k|m|g|t|ki|mi|gi|ti)(?:b?)\s*$)", regex_constants::icase);
smatch match;
regex_search(text, match, regex);
if (match.size() != 3)
{
return false;
}

double number;

try
{
number = stod(match[1].str());
}
catch (invalid_argument&)
{
return false;
}
catch (out_of_range&)
{
return false;
}

uint64_t factor;
string suffix_string = match[2].str();
if (icasecmp(suffix_string, "k"))
{
factor = 1000;
}
else if (icasecmp(suffix_string, "ki"))
{
factor = 1024;
}
else if (icasecmp(suffix_string, "m"))
{
factor = 1000 * 1000;
}
else if (icasecmp(suffix_string, "mi"))
{
factor = 1024 * 1024;
}
else if (icasecmp(suffix_string, "g"))
{
factor = 1000 * 1000 * 1000;
}
else if (icasecmp(suffix_string, "gi"))
{
factor = 1024 * 1024 * 1024;
}
else if (icasecmp(suffix_string, "t"))
{
factor = 1000ULL * 1000 * 1000 * 1000;
}
else if (icasecmp(suffix_string, "ti"))
{
factor = 1024ULL * 1024 * 1024 * 1024;
}
else
{
return false;
}

const uint64_t memory_size = llround(number * static_cast<double>(factor));
if (size != nullptr)
{
*size = memory_size;
}

return true;
}
15 changes: 14 additions & 1 deletion Src/CZICmd/cmdlineoptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ enum class Command

CreateCZI,

ReadWriteCZI
ReadWriteCZI,

PlaneScan,
};

enum class InfoLevel : std::uint32_t
Expand Down Expand Up @@ -190,6 +192,11 @@ class CCmdLineOptions
libCZI::CompressionMode compressionMode;
std::shared_ptr<libCZI::ICompressParameters> compressionParameters;
libCZI::PixelType pixelTypeForBitmapGenerator;

std::uint64_t subBlockCacheSize; ///< The size of the sub-block cache in bytes.
std::tuple<std::uint32_t, std::uint32_t> tilesSizeForPlaneScan; ///< The size of the tiles in pixels for the plane scan operation.

bool useVisibilityCheckOptimization;
public:
/// Values that represent the result of the "Parse"-operation.
enum class ParseResult
Expand Down Expand Up @@ -257,6 +264,9 @@ class CCmdLineOptions
libCZI::CompressionMode GetCompressionMode() const { return this->compressionMode; }
std::shared_ptr<libCZI::ICompressParameters> GetCompressionParameters() const { return this->compressionParameters; }
libCZI::PixelType GetPixelGeneratorPixeltype() const { return this->pixelTypeForBitmapGenerator; }
std::uint64_t GetSubBlockCacheSize() const { return this->subBlockCacheSize; }
const std::tuple<std::uint32_t, std::uint32_t>& GetTileSizeForPlaneScan() const { return this->tilesSizeForPlaneScan; }
bool GetUseVisibilityCheckOptimization() const { return this->useVisibilityCheckOptimization; }
private:
friend struct RegionOfInterestValidator;
friend struct DisplaySettingsValidator;
Expand All @@ -276,6 +286,8 @@ class CCmdLineOptions
friend struct CreateSubblockMetadataValidator;
friend struct CompressionOptionsValidator;
friend struct GeneratorPixelTypeValidator;
friend struct CachesizeValidator;
friend struct TileSizeForPlaneScanValidator;

bool CheckArgumentConsistency() const;
void SetOutputFilename(const std::wstring& s);
Expand Down Expand Up @@ -307,6 +319,7 @@ class CCmdLineOptions
static bool TryParseCompressionOptions(const std::string& s, libCZI::Utils::CompressionOption* compression_option);
static bool TryParseGeneratorPixeltype(const std::string& s, libCZI::PixelType* pixel_type);
static bool TryParseInputStreamCreationPropertyBag(const std::string& s, std::map<int, libCZI::StreamsFactory::Property>* property_bag);
static bool TryParseSubBlockCacheSize(const std::string& text, std::uint64_t* size);

static void ThrowIfFalse(bool b, const std::string& argument_switch, const std::string& argument);
};
Loading

0 comments on commit 8dbc3f0

Please sign in to comment.