diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 5af0aa2..3fd5ebe 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,6 +1,6 @@ set (libSourceFiles - include/function.h - src/function.cpp + "include/function.h" + "src/function.cpp" "src/mexFunctions.h" "src/errorcodes.h" "src/errorcodes.cpp" @@ -45,8 +45,16 @@ set (libSourceFiles "src/functions/func_getsinglechannelscalingtilecomposite.cpp" "src/functions/func_close.cpp" "src/functions/func_close.h" - - "src/functions/func_getdefaultdisplaysettings.cpp" "src/functions/func_getdefaultdisplaysettings.h" "src/functions/func_getsubblock.cpp" "src/functions/func_getsubblock.h") + "src/functions/func_getdefaultdisplaysettings.cpp" + "src/functions/func_getdefaultdisplaysettings.h" + "src/functions/func_getsubblock.cpp" + "src/functions/func_getsubblock.h" + "src/functions/func_createcziwriter.cpp" + "src/functions/func_createcziwriter.h" + "src/functions/func_addsubblock.cpp" + "src/functions/func_addsubblock.h" + "src/functions/func_closecziwriter.cpp" + "src/functions/func_closecziwriter.h") if(CMAKE_BUILD_TYPE MATCHES Debug) set(lib_ENABLE_LOGGING 1) diff --git a/lib/src/functions/func_addsubblock.cpp b/lib/src/functions/func_addsubblock.cpp new file mode 100644 index 0000000..bd605c8 --- /dev/null +++ b/lib/src/functions/func_addsubblock.cpp @@ -0,0 +1,157 @@ +#include "func_addsubblock.h" +//#include "libraryInfo.h" +#include "../implementation/CziWriterManager.h" +#include +#include +#include + +#include "../implementation/argsutils.h" +#include "../implementation/dbgprint.h" +//#include "mexapi.h" +#include "../implementation/utils.h" + +using namespace std; + + +void MexFunction_AddSubBlock_CheckArguments(MatlabArgs* args) +{ + // argument 1 : [int] handle + // argument 2 : [string] coordinate, e.g. 'C1Z23T4' + // argument 3 : [array of 4 numbers] logical position and size of the subblock + // argument 4 : [int or string] Pixeltype + // argument 5 : [array] data + // argument 6 : [struct] optional information (e.g. M-index or metadata-xml) + if (args->nrhs < 6) + { + throw invalid_argument("not enough arguments"); + } + + if (!CArgsUtils::IsNumericArrayOfMinSize(args->prhs[1], 1, args->app_functions)) + { + throw invalid_argument("1st argument must be an integer"); + } + + //if (!MexApi::GetInstance().MxIsChar(args->prhs[2])) + if (args->app_functions->pfn_IsChar(args->prhs[2])) + { + throw invalid_argument("2nd argument must be a string"); + } + + if (!CArgsUtils::IsNumericArrayOfMinSize(args->prhs[3], 4, args->app_functions)) + { + throw invalid_argument("3nd argument must be a ROI"); + } + + //if (!CArgsUtils::IsNumericArrayOfMinSize(args->prhs[4], 1, args->app_functions) && !MexApi::GetInstance().MxIsChar(args->prhs[4])) + if (!CArgsUtils::IsNumericArrayOfMinSize(args->prhs[4], 1, args->app_functions) && !args->app_functions->pfn_IsChar(args->prhs[4])) + { + throw invalid_argument("4th argument must be an integer or a string"); + } + + CArgsUtils::ArrayInfo array_info; + if (!CArgsUtils::TryGetArrayInfo(args->prhs[5], &array_info, args->app_functions)) + { + throw invalid_argument("5th argument must be an array"); + } + + if (array_info.number_of_dimensions != 2 && array_info.number_of_dimensions != 3) + { + throw invalid_argument("5th argument must be a 2D array or a 3D array"); + } + + if (array_info.number_of_dimensions==3 && array_info.dimensions[2] != 3) + { + throw invalid_argument("If the 5th argument is a 3D array, the 3rd dimension must be 3"); + } + + if (args->nrhs >= 7) + { + if (!CArgsUtils::IsStructure(args->prhs[6], args->app_functions)) + { + throw invalid_argument("6th argument must be a structure"); + } + } +} + +void MexFunction_AddSubBlock_Execute(MatlabArgs* args) +{ + int id; + bool b = CArgsUtils::TryGetInt32(args->prhs[1], &id, args->app_functions); + if (!b) + { + throw invalid_argument("1st argument must be an integer"); + } + + // get the coordinate of the subblock + libCZI::CDimCoordinate coord; + b = CArgsUtils::TryGetDimCoordinate(args->prhs[2], &coord, args->app_functions); + if (!b) + { + throw invalid_argument("2nd argument must be a string defining the coordinate"); + } + + // get the logical position/size + libCZI::IntRect rect; + b = CArgsUtils::TryGetIntRect(args->prhs[3], &rect, args->app_functions); + if (!b) + { + throw invalid_argument("3rd argument must be an array of 4 numbers"); + } + + // determine the pixel type for the subblock + libCZI::PixelType pixel_type; + b = CArgsUtils::TryGetPixelType(args->prhs[4], &pixel_type, args->app_functions); + if (!b) + { + throw invalid_argument("4th argument must be an integer or a string identifying a valid pixel type"); + } + + CArgsUtils::ArrayInfo array_info; + b = CArgsUtils::TryGetArrayInfo(args->prhs[5], &array_info, args->app_functions); + if (!b) + { + throw invalid_argument("5th argument must be an array"); + } + + std::optional m_index; + string metadata_xml; + libCZI::Utils::CompressionOption compression_option = make_pair(libCZI::CompressionMode::UnCompressed, nullptr); + if (args->nrhs >= 7) + { + int i; + if (CArgsUtils::TryGetIntValueOfField(args->prhs[6], "M", &i, args->app_functions)) + { + m_index = i; + } + + CArgsUtils::TryGetStringValueOfField(args->prhs[6], "metadata_xml", &metadata_xml, args->app_functions); + + string compression_options_text; + if (CArgsUtils::TryGetStringValueOfField(args->prhs[6], "compression", &compression_options_text, args->app_functions)) + { + compression_option = libCZI::Utils::ParseCompressionOptions(compression_options_text); + } + } + + if (array_info.dimensions[1] > (numeric_limits::max)() || array_info.dimensions[0] > (numeric_limits::max)()) + { + throw invalid_argument("Array dimensions are too large"); + } + + std::shared_ptr writer = ::Utils::GetWriterOrThrow(id); + libCZI::AddSubBlockInfoBase add_sub_block_info_base; + add_sub_block_info_base.Clear(); + add_sub_block_info_base.coordinate = coord; + add_sub_block_info_base.x = rect.x; + add_sub_block_info_base.y = rect.y; + add_sub_block_info_base.logicalWidth = rect.w; + add_sub_block_info_base.logicalHeight = rect.h; + add_sub_block_info_base.physicalWidth = static_cast(array_info.dimensions[1]); + add_sub_block_info_base.physicalHeight = static_cast(array_info.dimensions[0]); + add_sub_block_info_base.PixelType = pixel_type; + add_sub_block_info_base.mIndex = m_index.value_or(0); + add_sub_block_info_base.mIndexValid = m_index.has_value(); + + auto bitmap_data = Utils::ConvertToBitmapData(array_info, pixel_type); + writer->AddSubBlock(add_sub_block_info_base, bitmap_data, metadata_xml, compression_option); +} diff --git a/lib/src/functions/func_addsubblock.h b/lib/src/functions/func_addsubblock.h new file mode 100644 index 0000000..20200c7 --- /dev/null +++ b/lib/src/functions/func_addsubblock.h @@ -0,0 +1,6 @@ +#pragma once + +#include "../mexFunctions.h" + +void MexFunction_AddSubBlock_CheckArguments(MatlabArgs* args); +void MexFunction_AddSubBlock_Execute(MatlabArgs* args); diff --git a/lib/src/functions/func_closecziwriter.cpp b/lib/src/functions/func_closecziwriter.cpp new file mode 100644 index 0000000..622dd5a --- /dev/null +++ b/lib/src/functions/func_closecziwriter.cpp @@ -0,0 +1,48 @@ +#include "func_open.h" +//#include "libraryInfo.h" +//#include +#include + +#include "../implementation/CziWriterManager.h" +#include "../implementation/dbgprint.h" +//#include "mexapi.h" +#include "../implementation/utils.h" + +using namespace std; + + +void MexFunction_CloseCziWriter_CheckArguments(MatlabArgs* args) +{ + // argument 1 : [int] handle + if (args->nrhs < 2) + { + throw invalid_argument("not enough arguments"); + } + + if (!CArgsUtils::IsNumericArrayOfMinSize(args->prhs[1], 1, args->app_functions)) + { + throw invalid_argument("1st argument must be an integer"); + } +} + +void MexFunction_CloseCziWriter_Execute(MatlabArgs* args) +{ + int id; + bool b = CArgsUtils::TryGetInt32(args->prhs[1], &id, args->app_functions); + if (!b) + { + throw invalid_argument("1st argument must be an integer"); + } + + std::shared_ptr writer = ::Utils::GetWriterOrThrow(id); + writer->Close(); + writer.reset(); + + VDBGPRINT((CDbg::Level::Trace, "MexFunction_CloseCziWriter_Execute: trying to remove instance with id=%i.", id)); + b = CziWriterManager::GetInstance().RemoveInstance(id); + if (!b) + { + VDBGPRINT((CDbg::Level::Trace, "MexFunction_CloseCziWriter_Execute: removing instance with id=%i failed.", id)); + throw invalid_argument("invalid handle specified"); + } +} diff --git a/lib/src/functions/func_closecziwriter.h b/lib/src/functions/func_closecziwriter.h new file mode 100644 index 0000000..80fad29 --- /dev/null +++ b/lib/src/functions/func_closecziwriter.h @@ -0,0 +1,6 @@ +#pragma once + +#include "../mexFunctions.h" + +void MexFunction_CloseCziWriter_CheckArguments(MatlabArgs* args); +void MexFunction_CloseCziWriter_Execute(MatlabArgs* args); diff --git a/lib/src/functions/func_createcziwriter.cpp b/lib/src/functions/func_createcziwriter.cpp new file mode 100644 index 0000000..0901a6c --- /dev/null +++ b/lib/src/functions/func_createcziwriter.cpp @@ -0,0 +1,70 @@ +#include "func_open.h" +//#include "libraryInfo.h" +#include "../implementation/CziWriterManager.h" +#include +#include + +#include "../implementation/CziReaderManager.h" +#include "../implementation/dbgprint.h" +#include "../implementation/utils.h" + +using namespace std; + + +void MexFunction_CreateCziWriter_CheckArguments(MatlabArgs* args) +{ + // 2nd argument : [string] filename + // 3rd argument : [string] -optional- 'x' or 'overwrite' + if (args->nrhs < 2) + { + throw invalid_argument("not enough arguments"); + } + + //if (!MexApi::GetInstance().MxIsChar(args->prhs[1], args->app_functions)) + if (args->app_functions->pfn_IsChar(args->prhs[1])) + { + throw invalid_argument("Expecting a string as 2nd argument"); + } + + if (args->nrhs >= 2) + { + //if (!MexApi::GetInstance().MxIsChar(args->prhs[1], args->app_functions)) + if (args->app_functions->pfn_IsChar(args->prhs[2])) + { + throw invalid_argument("Expecting a string as 3rd argument"); + } + } +} + +void MexFunction_CreateCziWriter_Execute(MatlabArgs* args) +{ + //const auto filename = MexApi::GetInstance().UpMxArrayToMatlabAllocatedUtf8String(args->prhs[1]); + const auto filename = CArgsUtils::GetAsUtf8String(args->prhs[1], args->app_functions); + + bool overwrite_existing_file = false; + if (args->nrhs >= 2) + { + //const auto option = MexApi::GetInstance().UpMxArrayToMatlabAllocatedUtf8String(args->prhs[2]); + const auto option = CArgsUtils::GetAsUtf8String(args->prhs[2], args->app_functions); + if (option == "x" || option == "overwrite") + { + overwrite_existing_file = true; + } + } + + int id = CziWriterManager::GetInstance().CreateNewInstance(); + auto reader = CziWriterManager::GetInstance().GetInstance(id); + try + { + VDBGPRINT((CDbg::Level::Trace, "MexFunction_CreateCziWriter_Execute: attempting to create file \"%s\".", filename.c_str())); + reader->Create(filename, overwrite_existing_file); + } + catch (exception& excp) + { + VDBGPRINT((CDbg::Level::Warn, "MexFunction_CreateCziWriter_Execute: Open failed -> %s.", excp.what())); + CziReaderManager::GetInstance().RemoveInstance(id); + throw; + } + + args->plhs[0] = MexUtils::Int32To1x1Matrix(id, args->app_functions); +} diff --git a/lib/src/functions/func_createcziwriter.h b/lib/src/functions/func_createcziwriter.h new file mode 100644 index 0000000..042ad8a --- /dev/null +++ b/lib/src/functions/func_createcziwriter.h @@ -0,0 +1,6 @@ +#pragma once + +#include "../mexFunctions.h" + +void MexFunction_CreateCziWriter_CheckArguments(MatlabArgs* args); +void MexFunction_CreateCziWriter_Execute(MatlabArgs* args); diff --git a/lib/src/mexFunctions.cpp b/lib/src/mexFunctions.cpp index 5aced23..5503bad 100644 --- a/lib/src/mexFunctions.cpp +++ b/lib/src/mexFunctions.cpp @@ -12,8 +12,10 @@ #include "functions/func_close.h" #include "functions/func_getdefaultdisplaysettings.h" #include "functions/func_getsubblock.h" +#include "functions/func_createcziwriter.h" +#include "functions/func_addsubblock.h" +#include "functions/func_closecziwriter.h" /* -#include "src/func_createcziwriter.h" #include "src/func_addsubblock.h" #include "src/func_closecziwriter.h" */ @@ -35,11 +37,10 @@ {u8"GetBitmapFromSubBlock", {MexFunction_GetBitmapFromSubBlock_CheckArguments,MexFunction_GetBitmapFromSubBlock_Execute}}, {u8"GetMetadataFromSubBlock", {MexFunction_GetMetadataFromSubBlock_CheckArguments,MexFunction_GetMetadataFromSubBlock_Execute}}, {u8"ReleaseSubBlock", {MexFunction_ReleaseSubBlock_CheckArguments,MexFunction_ReleaseSubBlock_Execute}}, - /* {u8"CreateCziWriter", {MexFunction_CreateCziWriter_CheckArguments, MexFunction_CreateCziWriter_Execute}}, {u8"AddSubBlock", {MexFunction_AddSubBlock_CheckArguments, MexFunction_AddSubBlock_Execute}}, {u8"CloseCziWriter", {MexFunction_CloseCziWriter_CheckArguments, MexFunction_CloseCziWriter_Execute}}, - */ + /* */ }; /*static*/CMexFunctions CMexFunctions::instance;