Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ __pycache__/
# exclude "cmake-build-directory"
/cmake-build-*/

/build
/build*
/Src/Build/VS
/out/Src/Build/Doxygen/
/out/
Expand Down
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ option(LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_EIGEN3 "Prefer an Eigen3-package pres
# See here: https://discourse.cmake.org/t/findzstd/3506
option(LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_ZSTD "Prefer a ZSTD-package present on the system" OFF)

# When this option is ON, libCZI is built with libjxl (JPEG XL) for provisional subblock compression id 7 (lossless).
option(LIBCZI_BUILD_WITH_LIBJXL "Build with libjxl for JPEG XL lossless subblocks (experimental)" OFF)

# When this option is ON, we try to use an existing RapidJSON-library. Otherwise, we download a private
# copy of RapidJSON during the CMake-run. This option is only relevant if building CZICmd.
option(LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_RAPIDJSON "Prefer an RapidJSON-package present on the system" ON)
Expand Down
4 changes: 4 additions & 0 deletions Src/CZICmd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ set (CZICMDSRCFILES
BitmapGenFreeType.h
cmdlineoptions.h
executeCreateCzi.cpp
executeReEncodeCzi.cpp
executeReEncodeCzi.h
IBitmapGen.h
SaveBitmap.h
utils.h
Expand All @@ -67,6 +69,8 @@ set (CZICMDSRCFILES
CZIcmd.cpp
executePlaneScan.h
executePlaneScan.cpp
executeCompareImages.h
executeCompareImages.cpp
executeBase.h
executeBase.cpp
CZIcmd.manifest # the manifest is needed to allow long paths on windows, see https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd
Expand Down
51 changes: 45 additions & 6 deletions Src/CZICmd/cmdlineoptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,9 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
{ "ScalingChannelComposite", Command::ScalingChannelComposite },
{ "ExtractAttachment", Command::ExtractAttachment},
{ "CreateCZI", Command::CreateCZI },
{ "ReEncodeCZI", Command::ReEncodeCZI },
{ "PlaneScan", Command::PlaneScan },
{ "CompareImages", Command::CompareImages },
};

const static PlaneCoordinateValidator plane_coordinate_validator;
Expand Down Expand Up @@ -567,6 +569,7 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
Command argument_command;
string argument_source_filename;
string argument_output_filename;
string argument_compare_filename;
string argument_plane_coordinate;
string argument_rect;
string argument_display_settings;
Expand Down Expand Up @@ -602,7 +605,7 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
// editorconfig-checker-disable
cli_app.add_option("-c,--command", argument_command,
R"(COMMAND can be one of 'PrintInformation', 'ExtractSubBlock', 'SingleChannelTileAccessor', 'ChannelComposite',
'SingleChannelPyramidTileAccessor', 'SingleChannelScalingTileAccessor', 'ScalingChannelComposite', 'ExtractAttachment' and 'CreateCZI'.
'SingleChannelPyramidTileAccessor', 'SingleChannelScalingTileAccessor', 'ScalingChannelComposite', 'ExtractAttachment', 'CreateCZI', 'ReEncodeCZI' and 'CompareImages'.
\N'PrintInformation' will print information about the CZI-file to the console. The argument 'info-level' can be used
to specify which information is to be printed.
\N'ExtractSubBlock' will write the bitmap contained in the specified sub-block to the OUTPUTFILE.
Expand All @@ -618,7 +621,9 @@ 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 (synthetic tiles; use --createbounds; -s is not used for pixels).
\N'ReEncodeCZI' reads the CZI given with -s and writes a new CZI to -o with the same metadata, attachments, subblock layout, and per-subblock metadata/attachments; only the pixel payload is re-encoded per --compressionopts (e.g. jxl:, zstd1:, uncompressed:).)
\N'CompareImages' reads two CZIs (-s and --compare), pairs subblocks by tile layout (dimension coordinate, logical rect, physical size, pixel type, M-index), decodes each pair, and reports RMSD over all scalar samples. Directory index order may differ between files.)
\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
Expand All @@ -641,6 +646,9 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
cli_app.add_option("-o,--output", argument_output_filename,
"Specifies the output-filename. A suffix will be appended to the name given here depending on the type of the file.")
->option_text("OUTPUTFILE");
cli_app.add_option("--compare", argument_compare_filename,
"Second CZI file for 'CompareImages' (decoded pixels are compared to -s in subblock order). Uses the same stream class and property bag as -s when set.")
->option_text("COMPAREFILE");
// editorconfig-checker-disable
cli_app.add_option("-p,--plane-coordinate", argument_plane_coordinate,
R"(Uniquely select a 2D-plane from the document. It is given in the form [DimChar][number], where 'DimChar' specifies a dimension and
Expand Down Expand Up @@ -715,7 +723,8 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
->option_text("CHANNELCOMPOSITIONFORMAT")
->check(channelcompositionformat_validator);
cli_app.add_option("--createbounds", arguments_createbounds,
"Only used for 'CreateCZI': specify the range of coordinates used to create a CZI. Format is e.g. 'T0:3Z0:3C0:2'.")
"Required for 'CreateCZI': dimension ranges for which synthetic tiles are written. Format is e.g. 'T0:3Z0:3C0:2' "
"(dimension letter, start index, colon, count). CreateCZI does not copy image data from -s.")
->option_text("BOUNDS")
->check(createbounds_validator);
cli_app.add_option("--createsubblocksize", arguments_createsubblocksize,
Expand Down Expand Up @@ -752,9 +761,10 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
->option_text("KEY_VALUE_SUBBLOCKMETADATA")
->check(createsubblockmetadata_validator);
cli_app.add_option("--compressionopts", argument_compressionoptions,
"Only used for 'CreateCZI': a string in a defined format which states the compression-method and (compression-method specific) "
"Used for 'CreateCZI' and 'ReEncodeCZI': a string in a defined format which states the compression-method and (compression-method specific) "
"parameters. The format is \"compression_method: key=value; ...\". It starts with the name of the compression-method, followed by a colon, "
"then followed by a list of key-value pairs which are separated by a semicolon. Examples: \"zstd0:ExplicitLevel=3\", \"zstd1:ExplicitLevel=2;PreProcess=HiLoByteUnpack\".")
"then followed by a list of key-value pairs which are separated by a semicolon. Examples: \"zstd0:ExplicitLevel=3\", \"zstd1:ExplicitLevel=2;PreProcess=HiLoByteUnpack\", "
"\"jxl:\" or \"jxl:Effort=7;Modular=true;DecodingSpeed=0;Responsive=0\" for JPEG XL (requires LIBCZI_BUILD_WITH_LIBJXL), \"uncompressed:\" for raw pixels on ReEncodeCZI.")
->option_text("COMPRESSIONDESCRIPTION")
->check(compressionoptions_validator);
cli_app.add_option("--generatorpixeltype", argument_generatorpixeltype,
Expand Down Expand Up @@ -836,6 +846,11 @@ CCmdLineOptions::ParseResult CCmdLineOptions::Parse(int argc, char** argv)
this->SetOutputFilename(convertUtf8ToWide(argument_output_filename));
}

if (!argument_compare_filename.empty())
{
this->compareCziFilename = convertUtf8ToWide(argument_compare_filename);
}

if (!argument_plane_coordinate.empty())
{
this->planeCoordinate = libCZI::CDimCoordinate::Parse(argument_plane_coordinate.c_str());
Expand Down Expand Up @@ -1023,7 +1038,7 @@ bool CCmdLineOptions::CheckArgumentConsistency() const
return false;
}

if (cmd != Command::PrintInformation)
if (cmd != Command::PrintInformation && cmd != Command::CompareImages)
{
auto str = this->MakeOutputFilename(nullptr, nullptr);
if (str.empty())
Expand All @@ -1034,6 +1049,13 @@ bool CCmdLineOptions::CheckArgumentConsistency() const
}
}

if (cmd == Command::CompareImages && this->compareCziFilename.empty())
{
ss << ERRORPREFIX << "CompareImages requires --compare <second CZI file>";
this->GetLog()->WriteLineStdErr(ss.str());
return false;
}

switch (cmd)
{
case Command::ScalingChannelComposite:
Expand Down Expand Up @@ -1084,6 +1106,22 @@ bool CCmdLineOptions::CheckArgumentConsistency() const
break;
}

if (cmd == Command::CreateCZI && this->createBounds.IsEmpty())
{
ss << ERRORPREFIX << "CreateCZI requires --createbounds (for example: --createbounds \"C0:1\" or \"C0:1T0:3\"). "
"If bounds are empty, no subblocks are written. The source file (-s) is not read for CreateCZI; "
"tiles are generated only by the bitmap generator for the coordinate ranges you specify.";
this->GetLog()->WriteLineStdErr(ss.str());
return false;
}

if (cmd == Command::ReEncodeCZI && this->compressionMode == libCZI::CompressionMode::Invalid)
{
ss << ERRORPREFIX << "ReEncodeCZI requires --compressionopts (for example: \"jxl:\", \"jxl:Effort=5\", \"zstd1:ExplicitLevel=3\", or \"uncompressed:\").";
this->GetLog()->WriteLineStdErr(ss.str());
return false;
}

// TODO: there is probably more to be checked

return true;
Expand All @@ -1092,6 +1130,7 @@ bool CCmdLineOptions::CheckArgumentConsistency() const
void CCmdLineOptions::Clear()
{
this->command = Command::Invalid;
this->compareCziFilename.clear();
this->useDisplaySettingsFromDocument = true;
this->calcHashOfResult = false;
this->drawTileBoundaries = false;
Expand Down
6 changes: 6 additions & 0 deletions Src/CZICmd/cmdlineoptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ enum class Command

CreateCZI,

ReEncodeCZI,

ReadWriteCZI,

PlaneScan,

CompareImages,
};

enum class InfoLevel : std::uint32_t
Expand Down Expand Up @@ -143,6 +147,7 @@ class CCmdLineOptions

Command command;
std::wstring cziFilename;
std::wstring compareCziFilename;
std::string source_stream_class;
std::map<int, libCZI::StreamsFactory::Property> property_bag_for_stream_class;
libCZI::CDimCoordinate planeCoordinate;
Expand Down Expand Up @@ -224,6 +229,7 @@ class CCmdLineOptions
std::shared_ptr<ILog> GetLog() const { return this->log; }
Command GetCommand() const { return this->command; }
const std::wstring& GetCZIFilename() const { return this->cziFilename; }
const std::wstring& GetCompareCziFilename() const { return this->compareCziFilename; }
const std::string& GetInputStreamClassName() const { return this->source_stream_class; }
const std::map<int, libCZI::StreamsFactory::Property>& GetInputStreamPropertyBag() const { return this->property_bag_for_stream_class; }
const libCZI::CDimCoordinate& GetPlaneCoordinate() const { return this->planeCoordinate; }
Expand Down
8 changes: 8 additions & 0 deletions Src/CZICmd/execute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
#include "execute.h"
#include "executeBase.h"
#include "executeCreateCzi.h"
#include "executeReEncodeCzi.h"
#include "executePlaneScan.h"
#include "executeCompareImages.h"
#include "inc_libCZI.h"
#include "SaveBitmap.h"
#include "utils.h"
Expand Down Expand Up @@ -1141,9 +1143,15 @@ bool execute(const CCmdLineOptions& options)
case Command::CreateCZI:
success = executeCreateCzi(options);
break;
case Command::ReEncodeCZI:
success = executeReEncodeCzi(options);
break;
case Command::PlaneScan:
success = executePlaneScan(options);
break;
case Command::CompareImages:
success = executeCompareImages(options);
break;
default:
break;
}
Expand Down
9 changes: 7 additions & 2 deletions Src/CZICmd/executeBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,21 @@ using namespace std;
using namespace libCZI;

std::shared_ptr<ICZIReader> CExecuteBase::CreateAndOpenCziReader(const CCmdLineOptions& options)
{
return CreateAndOpenCziReaderForPath(options.GetCZIFilename().c_str(), options);
}

std::shared_ptr<ICZIReader> CExecuteBase::CreateAndOpenCziReaderForPath(const wchar_t* path, const CCmdLineOptions& options)
{
shared_ptr<IStream> stream;
if (options.GetInputStreamClassName().empty())
{
stream = CExecuteBase::CreateStandardFileBasedStreamObject(options.GetCZIFilename().c_str());
stream = CExecuteBase::CreateStandardFileBasedStreamObject(path);
}
else
{
stream = CExecuteBase::CreateInputStreamObject(
options.GetCZIFilename().c_str(),
path,
options.GetInputStreamClassName(),
&options.GetInputStreamPropertyBag());
}
Expand Down
1 change: 1 addition & 0 deletions Src/CZICmd/executeBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class CExecuteBase
{
protected:
static std::shared_ptr<libCZI::ICZIReader> CreateAndOpenCziReader(const CCmdLineOptions& options);
static std::shared_ptr<libCZI::ICZIReader> CreateAndOpenCziReaderForPath(const wchar_t* path, const CCmdLineOptions& options);
static std::shared_ptr<libCZI::IStream> CreateStandardFileBasedStreamObject(const wchar_t* fileName);
static std::shared_ptr<libCZI::IStream> CreateInputStreamObject(const wchar_t* uri, const std::string& class_name, const std::map<int, libCZI::StreamsFactory::Property>* property_bag);
static libCZI::IntRect GetRoiFromOptions(const CCmdLineOptions& options, const libCZI::SubBlockStatistics& subBlockStatistics);
Expand Down
Loading
Loading