From 2b58e067120c06290ebd93085c6bf1bf5311cda1 Mon Sep 17 00:00:00 2001 From: ptahmose Date: Fri, 4 Oct 2024 23:12:55 +0200 Subject: [PATCH 1/2] Update RapidJSON integration and improve type safety Increment patch version in CMakeLists.txt. Add src/include_rapidjson.h to mexoctaveSourceFiles. Centralize RapidJSON includes in include_rapidjson.h. Update RapidJSON commit hash in rapidJSON.cmake. Ensure type consistency with std::uint32_t casts in CziWriter.cpp. Simplify exception handling in argsutils.cpp, func_getsubblockbitmap.cpp, and func_open.cpp. Add array dimension checks and casts in func_addsubblock.cpp and utils.cpp. Add platform-specific UTF-8 to wide string conversion in utils.cpp. --- CMakeLists.txt | 2 +- MEXlibCZI/CMakeLists.txt | 1 + MEXlibCZI/src/CziReader.cpp | 980 +++++++++++------------ MEXlibCZI/src/CziUtilities.cpp | 3 +- MEXlibCZI/src/CziUtilities.h | 3 +- MEXlibCZI/src/CziWriter.cpp | 6 +- MEXlibCZI/src/argsutils.cpp | 4 +- MEXlibCZI/src/func_addsubblock.cpp | 11 +- MEXlibCZI/src/func_getsubblockbitmap.cpp | 5 +- MEXlibCZI/src/func_open.cpp | 5 +- MEXlibCZI/src/include_rapidjson.h | 6 + MEXlibCZI/src/utils.cpp | 30 +- modules/rapidJSON.cmake | 2 +- 13 files changed, 550 insertions(+), 508 deletions(-) create mode 100644 MEXlibCZI/src/include_rapidjson.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b13c275..0b918c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required (VERSION 3.11) set(MEXCZI_MAJOR 0) set(MEXCZI_MINOR 2) -set(MEXCZI_PATCH 0) +set(MEXCZI_PATCH 1) set(MEXCZI_EXT "alpha") if(WIN32) diff --git a/MEXlibCZI/CMakeLists.txt b/MEXlibCZI/CMakeLists.txt index 7181eba..9c8a096 100644 --- a/MEXlibCZI/CMakeLists.txt +++ b/MEXlibCZI/CMakeLists.txt @@ -74,6 +74,7 @@ set(mexoctaveSourceFiles "src/func_addsubblock.cpp" "src/func_closecziwriter.h" "src/func_closecziwriter.cpp" + "src/include_rapidjson.h" ) add_library (MEXlibCZI SHARED diff --git a/MEXlibCZI/src/CziReader.cpp b/MEXlibCZI/src/CziReader.cpp index 5ff0c97..f41a790 100644 --- a/MEXlibCZI/src/CziReader.cpp +++ b/MEXlibCZI/src/CziReader.cpp @@ -12,170 +12,168 @@ using namespace libCZI; void CziReader::Open(const std::string& utf8_filename) { - std::wstring_convert, wchar_t> wcsconv; - std::wstring wstr = wcsconv.from_bytes(utf8_filename); - auto stream = libCZI::CreateStreamFromFile(wstr.c_str()); - this->reader->Open(stream); + wstring wstr = ::Utils::convertUtf8ToWchar_t(utf8_filename); + auto stream = libCZI::CreateStreamFromFile(wstr.c_str()); + this->reader->Open(stream); } std::array CziReader::GetScaling() { - const libCZI::ScalingInfo& scaling = this->GetScalingInfoFromCzi(); - return std::array - { - scaling.IsScaleXValid() ? scaling.scaleX : -1, - scaling.IsScaleYValid() ? scaling.scaleY : -1, - scaling.IsScaleZValid() ? scaling.scaleZ : -1 - }; + const libCZI::ScalingInfo& scaling = this->GetScalingInfoFromCzi(); + return std::array + { + scaling.IsScaleXValid() ? scaling.scaleX : -1, + scaling.IsScaleYValid() ? scaling.scaleY : -1, + scaling.IsScaleZValid() ? scaling.scaleZ : -1 + }; } MexArray* CziReader::GetScalingAsMatlabStruct() { - static const char* fieldNames[] = { "scaleX", "scaleY", "scaleZ" }; + static const char* fieldNames[] = { "scaleX", "scaleY", "scaleZ" }; - static const mwSize dims[2] = { 1, 1 }; - auto mexApi = MexApi::GetInstance(); - auto* s = mexApi.MxCreateStructArray( - 2, - dims, - sizeof(fieldNames) / sizeof(fieldNames[0]), - fieldNames); - const libCZI::ScalingInfo& scaling = this->GetScalingInfoFromCzi(); - mexApi.MxSetFieldByNumber(s, 0, 0, MexUtils::DoubleTo1x1Matrix(scaling.IsScaleXValid() ? scaling.scaleX : numeric_limits::quiet_NaN())); - mexApi.MxSetFieldByNumber(s, 0, 1, MexUtils::DoubleTo1x1Matrix(scaling.IsScaleYValid() ? scaling.scaleY : numeric_limits::quiet_NaN())); - mexApi.MxSetFieldByNumber(s, 0, 2, MexUtils::DoubleTo1x1Matrix(scaling.IsScaleZValid() ? scaling.scaleZ : numeric_limits::quiet_NaN())); - return s; + static const mwSize dims[2] = { 1, 1 }; + auto mexApi = MexApi::GetInstance(); + auto* s = mexApi.MxCreateStructArray( + 2, + dims, + sizeof(fieldNames) / sizeof(fieldNames[0]), + fieldNames); + const libCZI::ScalingInfo& scaling = this->GetScalingInfoFromCzi(); + mexApi.MxSetFieldByNumber(s, 0, 0, MexUtils::DoubleTo1x1Matrix(scaling.IsScaleXValid() ? scaling.scaleX : numeric_limits::quiet_NaN())); + mexApi.MxSetFieldByNumber(s, 0, 1, MexUtils::DoubleTo1x1Matrix(scaling.IsScaleYValid() ? scaling.scaleY : numeric_limits::quiet_NaN())); + mexApi.MxSetFieldByNumber(s, 0, 2, MexUtils::DoubleTo1x1Matrix(scaling.IsScaleZValid() ? scaling.scaleZ : numeric_limits::quiet_NaN())); + return s; } const libCZI::ScalingInfo& CziReader::GetScalingInfoFromCzi() { - this->InitializeInfoFromCzi(); - return this->scalingInfoFromCzi; + this->InitializeInfoFromCzi(); + return this->scalingInfoFromCzi; } void CziReader::InitializeInfoFromCzi() { - std::call_once( - this->flagInfoFromCziMetadata, - [this]() - { - auto mds = this->reader->ReadMetadataSegment(); - auto md = mds->CreateMetaFromMetadataSegment(); - const auto docInfo = md->GetDocumentInfo(); - this->displaySettingsFromCzi = docInfo->GetDisplaySettings(); - this->scalingInfoFromCzi = docInfo->GetScalingInfoEx(); - }); + std::call_once( + this->flagInfoFromCziMetadata, + [this]() + { + auto mds = this->reader->ReadMetadataSegment(); + auto md = mds->CreateMetaFromMetadataSegment(); + const auto docInfo = md->GetDocumentInfo(); + this->displaySettingsFromCzi = docInfo->GetDisplaySettings(); + this->scalingInfoFromCzi = docInfo->GetScalingInfoEx(); + }); } MexArray* CziReader::GetInfo() { - auto statistics = this->reader->GetStatistics(); + auto statistics = this->reader->GetStatistics(); - static const char* fieldNames[] = { "subblockcount", "boundingBox", "boundingBoxLayer0", "dimBounds", "sceneBoundingBoxes", "minMindex", "maxMindex" }; + static const char* fieldNames[] = { "subblockcount", "boundingBox", "boundingBoxLayer0", "dimBounds", "sceneBoundingBoxes", "minMindex", "maxMindex" }; - auto mexApi = MexApi::GetInstance(); - auto s = mexApi.MxCreateStructArray( - 2, - MexUtils::Dims_1_by_1, - (sizeof(fieldNames) / sizeof(fieldNames[0])) - (statistics.IsMIndexValid() ? 0 : 2), - fieldNames); + auto mexApi = MexApi::GetInstance(); + auto s = mexApi.MxCreateStructArray( + 2, + MexUtils::Dims_1_by_1, + (sizeof(fieldNames) / sizeof(fieldNames[0])) - (statistics.IsMIndexValid() ? 0 : 2), + fieldNames); - mexApi.MxSetFieldByNumber(s, 0, 0, MexUtils::Int32To1x1Matrix(statistics.subBlockCount)); - mexApi.MxSetFieldByNumber(s, 0, 1, CziReader::ConvertToMatlabStruct(statistics.boundingBox)); - mexApi.MxSetFieldByNumber(s, 0, 2, CziReader::ConvertToMatlabStruct(statistics.boundingBoxLayer0Only)); - mexApi.MxSetFieldByNumber(s, 0, 3, CziReader::ConvertToMatlabStruct(&statistics.dimBounds)); - mexApi.MxSetFieldByNumber(s, 0, 4, CziReader::ConvertToMatlabStruct(statistics.sceneBoundingBoxes)); + mexApi.MxSetFieldByNumber(s, 0, 0, MexUtils::Int32To1x1Matrix(statistics.subBlockCount)); + mexApi.MxSetFieldByNumber(s, 0, 1, CziReader::ConvertToMatlabStruct(statistics.boundingBox)); + mexApi.MxSetFieldByNumber(s, 0, 2, CziReader::ConvertToMatlabStruct(statistics.boundingBoxLayer0Only)); + mexApi.MxSetFieldByNumber(s, 0, 3, CziReader::ConvertToMatlabStruct(&statistics.dimBounds)); + mexApi.MxSetFieldByNumber(s, 0, 4, CziReader::ConvertToMatlabStruct(statistics.sceneBoundingBoxes)); - if (statistics.IsMIndexValid()) - { - mexApi.MxSetFieldByNumber(s, 0, 5, MexUtils::Int32To1x1Matrix(statistics.minMindex)); - mexApi.MxSetFieldByNumber(s, 0, 6, MexUtils::Int32To1x1Matrix(statistics.maxMindex)); - } + if (statistics.IsMIndexValid()) + { + mexApi.MxSetFieldByNumber(s, 0, 5, MexUtils::Int32To1x1Matrix(statistics.minMindex)); + mexApi.MxSetFieldByNumber(s, 0, 6, MexUtils::Int32To1x1Matrix(statistics.maxMindex)); + } - return s; + return s; } std::string CziReader::GetMetadataXml() { - auto mds = this->reader->ReadMetadataSegment(); - auto m = mds->CreateMetaFromMetadataSegment(); - if (!m->IsXmlValid()) - { - throw runtime_error("Metadata-XML found to be invalid."); - } + auto mds = this->reader->ReadMetadataSegment(); + auto m = mds->CreateMetaFromMetadataSegment(); + if (!m->IsXmlValid()) + { + throw runtime_error("Metadata-XML found to be invalid."); + } - return m->GetXml(); + return m->GetXml(); } MexArray* CziReader::GetMetadataXmlAsMxArray() { - auto s = MexApi::GetInstance().MxCreateString(this->GetMetadataXml().c_str()); - return s; + auto s = MexApi::GetInstance().MxCreateString(this->GetMetadataXml().c_str()); + return s; } MexArray* CziReader::GetDefaultDisplaySettingsAsMxArray() { - const auto displaySettings = this->GetDisplaySettingsFromCzi(); - return this->ConvertToMatlabStruct(*displaySettingsFromCzi); + const auto displaySettings = this->GetDisplaySettingsFromCzi(); + return CziReader::ConvertToMatlabStruct(*displaySettings); } MexArray* CziReader::GetSubBlockImage(int sbBlkNo) { - auto sbBlk = this->reader->ReadSubBlock(sbBlkNo); - if (!sbBlk) - { - std::stringstream ss; - ss << "SubBlock for id=" << sbBlkNo << " was not found."; - throw invalid_argument(ss.str()); - } + auto sbBlk = this->reader->ReadSubBlock(sbBlkNo); + if (!sbBlk) + { + std::stringstream ss; + ss << "SubBlock for id=" << sbBlkNo << " was not found."; + throw invalid_argument(ss.str()); + } - auto bm = sbBlk->CreateBitmap(); - return ConvertToMxArray(bm.get()); + auto bm = sbBlk->CreateBitmap(); + return ConvertToMxArray(bm.get()); } MexArray* CziReader::GetMultiChannelScalingTileComposite(const libCZI::IntRect& roi, const libCZI::IDimCoordinate* planeCoordinate, float zoom, const char* displaySettingsJson) { - if (displaySettingsJson == nullptr || *displaySettingsJson == '\0') - { - return CziReader::GetMultiChannelScalingTileComposite(roi, planeCoordinate, zoom, this->GetDisplaySettingsFromCzi().get()); - } - - ChannelDisplaySettingsInfo dsinfo = CziUtilities::ParseDisplaySettings(displaySettingsJson); + if (displaySettingsJson == nullptr || *displaySettingsJson == '\0') + { + return CziReader::GetMultiChannelScalingTileComposite(roi, planeCoordinate, zoom, this->GetDisplaySettingsFromCzi().get()); + } - if (dsinfo.isToBeMerged == true) - { - const auto displaySettingsFromCzi = this->GetDisplaySettingsFromCzi(); - const auto combinedDisplaySettings = CziUtilities::CombineDisplaySettings(displaySettingsFromCzi.get(), dsinfo.displaySettings); + ChannelDisplaySettingsInfo dsinfo = CziUtilities::ParseDisplaySettings(displaySettingsJson); - return CziReader::GetMultiChannelScalingTileComposite(roi, planeCoordinate, zoom, combinedDisplaySettings.get()); - } - else - { - const auto resultingDisplaySettings = CziUtilities::ConvertToDisplaySettings(dsinfo.displaySettings); + if (dsinfo.isToBeMerged == true) + { + const auto displaySettingsFromCzi = this->GetDisplaySettingsFromCzi(); + const auto combinedDisplaySettings = CziUtilities::CombineDisplaySettings(displaySettingsFromCzi.get(), dsinfo.displaySettings); - return CziReader::GetMultiChannelScalingTileComposite(roi, planeCoordinate, zoom, resultingDisplaySettings.get()); - } + return CziReader::GetMultiChannelScalingTileComposite(roi, planeCoordinate, zoom, combinedDisplaySettings.get()); + } + else + { + const auto resultingDisplaySettings = CziUtilities::ConvertToDisplaySettings(dsinfo.displaySettings); + return CziReader::GetMultiChannelScalingTileComposite(roi, planeCoordinate, zoom, resultingDisplaySettings.get()); + } } MexArray* CziReader::GetMultiChannelScalingTileComposite(const libCZI::IntRect& roi, const libCZI::IDimCoordinate* planeCoordinate, float zoom, const libCZI::IDisplaySettings* displaySettings) { - std::vector activeChannels = libCZI::CDisplaySettingsHelper::GetActiveChannels(displaySettings); + std::vector activeChannels = libCZI::CDisplaySettingsHelper::GetActiveChannels(displaySettings); - // we need to deal with the pathological case that all channels are disabled - if (activeChannels.empty()) - { - return CziReader::GetMultiChannelScalingTileCompositeAllChannelsDisabled(roi, zoom); - } + // we need to deal with the pathological case that all channels are disabled + if (activeChannels.empty()) + { + return CziReader::GetMultiChannelScalingTileCompositeAllChannelsDisabled(roi, zoom); + } IntSize sizeResult; - std::vector> channelBitmaps = CziUtilities::GetBitmapsFromSpecifiedChannels( + std::vector> channelBitmaps = CziUtilities::GetBitmapsFromSpecifiedChannels( this->reader.get(), planeCoordinate, roi, zoom, [&](int idx, int& chNo)-> bool { - if (idx < (int)activeChannels.size()) + if (idx < static_cast(activeChannels.size())) { chNo = activeChannels.at(idx); return true; @@ -185,493 +183,493 @@ MexArray* CziReader::GetMultiChannelScalingTileComposite(const libCZI::IntRect& }, &sizeResult); - libCZI::CDisplaySettingsHelper dsplHlp; - dsplHlp.Initialize(displaySettings, [&](int chIndx)->libCZI::PixelType - { - const auto idx = std::distance(activeChannels.cbegin(), std::find(activeChannels.cbegin(), activeChannels.cend(), chIndx)); - return channelBitmaps[idx]->GetPixelType(); - }); - - std::vector vecBm; vecBm.reserve(channelBitmaps.size()); - for (int i = 0; i < channelBitmaps.size(); ++i) - { - vecBm.emplace_back(channelBitmaps[i].get()); - } - - auto bitmap = Compositors::ComposeMultiChannel_Bgr24( - (int)channelBitmaps.size(), + libCZI::CDisplaySettingsHelper dsplHlp; + dsplHlp.Initialize(displaySettings, [&](int chIndx)->libCZI::PixelType + { + const auto idx = std::distance(activeChannels.cbegin(), std::find(activeChannels.cbegin(), activeChannels.cend(), chIndx)); + return channelBitmaps[idx]->GetPixelType(); + }); + + std::vector vecBm; vecBm.reserve(channelBitmaps.size()); + for (int i = 0; i < channelBitmaps.size(); ++i) + { + vecBm.emplace_back(channelBitmaps[i].get()); + } + + auto bitmap = Compositors::ComposeMultiChannel_Bgr24( + (int)channelBitmaps.size(), vecBm.data(), - dsplHlp.GetChannelInfosArray()); + dsplHlp.GetChannelInfosArray()); - mwSize dims[3] = { bitmap->GetHeight(), bitmap->GetWidth(), 3 }; - auto mexApi = MexApi::GetInstance(); - //auto* arr = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); - auto* arr = mexApi.MxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); - CziReader::CopyTransposeInterleavedToPlanarBgr24( - bitmap.get(), - mexApi.MxGetData(arr), - static_cast(bitmap->GetHeight()), - static_cast(bitmap->GetWidth()) * static_cast(bitmap->GetHeight())); - return arr; + mwSize dims[3] = { bitmap->GetHeight(), bitmap->GetWidth(), 3 }; + auto mexApi = MexApi::GetInstance(); + //auto* arr = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); + auto* arr = mexApi.MxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); + CziReader::CopyTransposeInterleavedToPlanarBgr24( + bitmap.get(), + mexApi.MxGetData(arr), + static_cast(bitmap->GetHeight()), + static_cast(bitmap->GetWidth()) * static_cast(bitmap->GetHeight())); + return arr; } MexArray* CziReader::GetMultiChannelScalingTileCompositeAllChannelsDisabled(const libCZI::IntRect& roi, float zoom) { - auto accessor = reader->CreateSingleChannelScalingTileAccessor(); - const auto sizeResult = accessor->CalcSize(roi, zoom); - RgbFloatColor color{ 0,0,0 }; + auto accessor = reader->CreateSingleChannelScalingTileAccessor(); + const auto sizeResult = accessor->CalcSize(roi, zoom); + RgbFloatColor color{ 0,0,0 }; - mwSize dims[3] = { sizeResult.h, sizeResult.w, 3 }; - //auto* arr = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); - auto* arr = MexApi::GetInstance().MxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); - return arr; + mwSize dims[3] = { sizeResult.h, sizeResult.w, 3 }; + //auto* arr = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); + auto* arr = MexApi::GetInstance().MxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); + return arr; } MexArray* CziReader::GetSingleChannelScalingTileComposite(const libCZI::IntRect& roi, const libCZI::IDimCoordinate* planeCoordinate, float zoom) { - const RgbFloatColor backgndCol{ 0,0,0 }; - return this->GetSingleChannelScalingTileComposite(roi, planeCoordinate, zoom, backgndCol); + const RgbFloatColor backgndCol{ 0,0,0 }; + return this->GetSingleChannelScalingTileComposite(roi, planeCoordinate, zoom, backgndCol); } MexArray* CziReader::GetSingleChannelScalingTileComposite(const libCZI::IntRect& roi, const libCZI::IDimCoordinate* planeCoordinate, float zoom, const libCZI::RgbFloatColor& backgroundColor) { - auto scsta = this->reader->CreateSingleChannelScalingTileAccessor(); - libCZI::IntSize size = scsta->CalcSize(roi, zoom); + auto scsta = this->reader->CreateSingleChannelScalingTileAccessor(); + libCZI::IntSize size = scsta->CalcSize(roi, zoom); - int c = (numeric_limits::min)(); - planeCoordinate->TryGetPosition(libCZI::DimensionIndex::C, &c); + int c = (numeric_limits::min)(); + planeCoordinate->TryGetPosition(libCZI::DimensionIndex::C, &c); - // the idea is: for the cornerstone-case where we do not have a C-index, the call to "TryGetSubBlockInfoOfArbitrarySubBlockInChannel" - // will ignore the specified index _if_ there are no C-indices at all - libCZI::PixelType pixeltype = libCZI::Utils::TryDeterminePixelTypeForChannel(this->reader.get(), c); + // the idea is: for the cornerstone-case where we do not have a C-index, the call to "TryGetSubBlockInfoOfArbitrarySubBlockInChannel" + // will ignore the specified index _if_ there are no C-indices at all + libCZI::PixelType pixeltype = libCZI::Utils::TryDeterminePixelTypeForChannel(this->reader.get(), c); - // however - if we get here with an invalid pixeltype, then we need to give up - if (pixeltype == PixelType::Invalid) - { - throw invalid_argument("Unable to determine pixeltype."); - } + // however - if we get here with an invalid pixeltype, then we need to give up + if (pixeltype == PixelType::Invalid) + { + throw invalid_argument("Unable to determine pixeltype."); + } - ISingleChannelScalingTileAccessor::Options accessorGetOptions; - accessorGetOptions.Clear(); - accessorGetOptions.backGroundColor = backgroundColor; - auto bitmap = scsta->Get(pixeltype, roi, planeCoordinate, zoom, &accessorGetOptions); + ISingleChannelScalingTileAccessor::Options accessorGetOptions; + accessorGetOptions.Clear(); + accessorGetOptions.backGroundColor = backgroundColor; + auto bitmap = scsta->Get(pixeltype, roi, planeCoordinate, zoom, &accessorGetOptions); - auto* mxarray = ConvertToMxArray(bitmap.get()); - return mxarray; + auto* mxarray = ConvertToMxArray(bitmap.get()); + return mxarray; } std::shared_ptr CziReader::GetDisplaySettingsFromCzi() { - this->InitializeInfoFromCzi(); - return this->displaySettingsFromCzi; + this->InitializeInfoFromCzi(); + return this->displaySettingsFromCzi; } /*static*/MexArray* CziReader::ConvertToMxArray(libCZI::IBitmapData* bitmapData) { - auto mexApi = MexApi::GetInstance(); - switch (bitmapData->GetPixelType()) - { - case PixelType::Gray8: - { - auto* arr = mexApi.MxCreateNumericMatrix(bitmapData->GetHeight(), bitmapData->GetWidth(), mxUINT8_CLASS, mxREAL); - CziReader::CopyTransposeGray8(bitmapData, mexApi.MxGetData(arr), 1 * static_cast(bitmapData->GetHeight())); - return arr; - } - case PixelType::Gray16: - { - auto* arr = mexApi.MxCreateNumericMatrix(bitmapData->GetHeight(), bitmapData->GetWidth(), mxUINT16_CLASS, mxREAL); - CziReader::CopyTransposeGray16(bitmapData, mexApi.MxGetData(arr), 2 * static_cast(bitmapData->GetHeight())); - return arr; - } - case PixelType::Bgr24: - { - size_t dims[3] = { bitmapData->GetHeight(), bitmapData->GetWidth(), 3 }; - auto* arr = mexApi.MxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); - CziReader::CopyTransposeInterleavedToPlanarBgr24( - bitmapData, - mexApi.MxGetData(arr), - static_cast(bitmapData->GetHeight()), - static_cast(bitmapData->GetWidth()) * static_cast(bitmapData->GetHeight())); - return arr; - } - case PixelType::Bgr48: - { - size_t dims[3] = { bitmapData->GetHeight(), bitmapData->GetWidth() ,3 }; - auto* arr = mexApi.MxCreateNumericArray(3, dims, mxUINT16_CLASS, mxREAL); - CziReader::CopyTransposeInterleavedToPlanarBgr48( - bitmapData, - mexApi.MxGetData(arr), - static_cast(bitmapData->GetHeight()) * 2, - static_cast(bitmapData->GetWidth()) * static_cast(bitmapData->GetHeight()) * 2); - return arr; - } - case PixelType::Gray32Float: - { - auto* arr = mexApi.MxCreateNumericMatrix(bitmapData->GetHeight(), bitmapData->GetWidth(), mxSINGLE_CLASS, mxREAL); - CziReader::CopyTransposeGrayFloat(bitmapData, mexApi.MxGetData(arr), 4 * static_cast(bitmapData->GetHeight())); - return arr; - } - default: - throw std::invalid_argument("unsupported pixeltype"); - } + auto mexApi = MexApi::GetInstance(); + switch (bitmapData->GetPixelType()) + { + case PixelType::Gray8: + { + auto* arr = mexApi.MxCreateNumericMatrix(bitmapData->GetHeight(), bitmapData->GetWidth(), mxUINT8_CLASS, mxREAL); + CziReader::CopyTransposeGray8(bitmapData, mexApi.MxGetData(arr), 1 * static_cast(bitmapData->GetHeight())); + return arr; + } + case PixelType::Gray16: + { + auto* arr = mexApi.MxCreateNumericMatrix(bitmapData->GetHeight(), bitmapData->GetWidth(), mxUINT16_CLASS, mxREAL); + CziReader::CopyTransposeGray16(bitmapData, mexApi.MxGetData(arr), 2 * static_cast(bitmapData->GetHeight())); + return arr; + } + case PixelType::Bgr24: + { + size_t dims[3] = { bitmapData->GetHeight(), bitmapData->GetWidth(), 3 }; + auto* arr = mexApi.MxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); + CziReader::CopyTransposeInterleavedToPlanarBgr24( + bitmapData, + mexApi.MxGetData(arr), + static_cast(bitmapData->GetHeight()), + static_cast(bitmapData->GetWidth()) * static_cast(bitmapData->GetHeight())); + return arr; + } + case PixelType::Bgr48: + { + size_t dims[3] = { bitmapData->GetHeight(), bitmapData->GetWidth() ,3 }; + auto* arr = mexApi.MxCreateNumericArray(3, dims, mxUINT16_CLASS, mxREAL); + CziReader::CopyTransposeInterleavedToPlanarBgr48( + bitmapData, + mexApi.MxGetData(arr), + static_cast(bitmapData->GetHeight()) * 2, + static_cast(bitmapData->GetWidth()) * static_cast(bitmapData->GetHeight()) * 2); + return arr; + } + case PixelType::Gray32Float: + { + auto* arr = mexApi.MxCreateNumericMatrix(bitmapData->GetHeight(), bitmapData->GetWidth(), mxSINGLE_CLASS, mxREAL); + CziReader::CopyTransposeGrayFloat(bitmapData, mexApi.MxGetData(arr), 4 * static_cast(bitmapData->GetHeight())); + return arr; + } + default: + throw std::invalid_argument("unsupported pixeltype"); + } } /*static*/void CziReader::CopyTransposeGray8(libCZI::IBitmapData* bitmapData, void* pDst, size_t lineLength) { - auto height = bitmapData->GetHeight(); - auto width = bitmapData->GetWidth(); - ScopedBitmapLocker lckBm{ bitmapData }; - for (decltype(height) y = 0; y < height; ++y) - { - const uint8_t* ptrSrc = static_cast(lckBm.ptrDataRoi) + y * static_cast(lckBm.stride); - uint8_t* ptrDst = static_cast(pDst) + y; - for (decltype(width) x = 0; x < width; ++x) - { - *ptrDst = *ptrSrc++; - ptrDst += lineLength; - } - } -} + auto height = bitmapData->GetHeight(); + auto width = bitmapData->GetWidth(); + ScopedBitmapLocker lckBm{ bitmapData }; + for (decltype(height) y = 0; y < height; ++y) + { + const uint8_t* ptrSrc = static_cast(lckBm.ptrDataRoi) + y * static_cast(lckBm.stride); + uint8_t* ptrDst = static_cast(pDst) + y; + for (decltype(width) x = 0; x < width; ++x) + { + *ptrDst = *ptrSrc++; + ptrDst += lineLength; + } + } +} /*static*/void CziReader::CopyTransposeGray16(libCZI::IBitmapData* bitmapData, void* pDst, size_t lineLength) { - auto height = bitmapData->GetHeight(); - auto width = bitmapData->GetWidth(); - ScopedBitmapLocker lckBm{ bitmapData }; - for (decltype(height) y = 0; y < height; ++y) - { - const uint16_t* ptrSrc = reinterpret_cast(static_cast(lckBm.ptrDataRoi) + y * static_cast(lckBm.stride)); - uint16_t* ptrDst = reinterpret_cast(static_cast(pDst) + static_cast(y) * 2); - for (decltype(width) x = 0; x < width; ++x) - { - *ptrDst = *ptrSrc++; - ptrDst = reinterpret_cast(reinterpret_cast(ptrDst) + lineLength); - } - } + auto height = bitmapData->GetHeight(); + auto width = bitmapData->GetWidth(); + ScopedBitmapLocker lckBm{ bitmapData }; + for (decltype(height) y = 0; y < height; ++y) + { + const uint16_t* ptrSrc = reinterpret_cast(static_cast(lckBm.ptrDataRoi) + y * static_cast(lckBm.stride)); + uint16_t* ptrDst = reinterpret_cast(static_cast(pDst) + static_cast(y) * 2); + for (decltype(width) x = 0; x < width; ++x) + { + *ptrDst = *ptrSrc++; + ptrDst = reinterpret_cast(reinterpret_cast(ptrDst) + lineLength); + } + } } /*static*/void CziReader::CopyTransposeGrayFloat(libCZI::IBitmapData* bitmapData, void* pDst, size_t lineLength) { - auto height = bitmapData->GetHeight(); - auto width = bitmapData->GetWidth(); - ScopedBitmapLocker lckBm{ bitmapData }; - for (decltype(height) y = 0; y < height; ++y) - { - const float* ptrSrc = reinterpret_cast(static_cast(lckBm.ptrDataRoi) + y * static_cast(lckBm.stride)); - float* ptrDst = reinterpret_cast(static_cast(pDst) + static_cast(y) * 4); - for (decltype(width) x = 0; x < width; ++x) - { - *ptrDst = *ptrSrc++; - ptrDst = reinterpret_cast(reinterpret_cast(ptrDst) + lineLength); - } - } + auto height = bitmapData->GetHeight(); + auto width = bitmapData->GetWidth(); + ScopedBitmapLocker lckBm{ bitmapData }; + for (decltype(height) y = 0; y < height; ++y) + { + const float* ptrSrc = reinterpret_cast(static_cast(lckBm.ptrDataRoi) + y * static_cast(lckBm.stride)); + float* ptrDst = reinterpret_cast(static_cast(pDst) + static_cast(y) * 4); + for (decltype(width) x = 0; x < width; ++x) + { + *ptrDst = *ptrSrc++; + ptrDst = reinterpret_cast(reinterpret_cast(ptrDst) + lineLength); + } + } } /*static*/void CziReader::CopyTransposeInterleavedToPlanarBgr24(libCZI::IBitmapData* bitmapData, void* pDst, size_t lineStride, size_t planeStride) { - auto height = bitmapData->GetHeight(); - auto width = bitmapData->GetWidth(); - ScopedBitmapLocker lckBm{ bitmapData }; - for (decltype(height) y = 0; y < height; ++y) - { - const uint8_t* ptrSrc = static_cast(lckBm.ptrDataRoi) + y * static_cast(lckBm.stride); - uint8_t* ptrDst = static_cast(pDst) + y; - for (decltype(width) x = 0; x < width; ++x) - { - const uint8_t b = *ptrSrc++; - const uint8_t g = *ptrSrc++; - const uint8_t r = *ptrSrc++; - - *ptrDst = r; - *(ptrDst + planeStride) = g; - *(ptrDst + 2 * planeStride) = b; - ptrDst += lineStride; - } - } + auto height = bitmapData->GetHeight(); + auto width = bitmapData->GetWidth(); + ScopedBitmapLocker lckBm{ bitmapData }; + for (decltype(height) y = 0; y < height; ++y) + { + const uint8_t* ptrSrc = static_cast(lckBm.ptrDataRoi) + y * static_cast(lckBm.stride); + uint8_t* ptrDst = static_cast(pDst) + y; + for (decltype(width) x = 0; x < width; ++x) + { + const uint8_t b = *ptrSrc++; + const uint8_t g = *ptrSrc++; + const uint8_t r = *ptrSrc++; + + *ptrDst = r; + *(ptrDst + planeStride) = g; + *(ptrDst + 2 * planeStride) = b; + ptrDst += lineStride; + } + } } /*static*/void CziReader::CopyTransposeInterleavedToPlanarBgr48(libCZI::IBitmapData* bitmapData, void* pDst, size_t lineStride, size_t planeStride) { - auto height = bitmapData->GetHeight(); - auto width = bitmapData->GetWidth(); - ScopedBitmapLocker lckBm{ bitmapData }; - for (decltype(height) y = 0; y < height; ++y) - { - const uint16_t* ptrSrc = reinterpret_cast(static_cast(lckBm.ptrDataRoi) + y * static_cast(lckBm.stride)); - uint16_t* ptrDst = reinterpret_cast(static_cast(pDst) + y * static_cast(2)); - for (decltype(width) x = 0; x < width; ++x) - { - const uint16_t b = *ptrSrc++; - const uint16_t g = *ptrSrc++; - const uint16_t r = *ptrSrc++; - - *ptrDst = r; - *reinterpret_cast(reinterpret_cast(ptrDst) + planeStride) = g; - *reinterpret_cast(reinterpret_cast(ptrDst) + 2 * planeStride) = b; - ptrDst = reinterpret_cast(reinterpret_cast(ptrDst) + lineStride); - } - } + auto height = bitmapData->GetHeight(); + auto width = bitmapData->GetWidth(); + ScopedBitmapLocker lckBm{ bitmapData }; + for (decltype(height) y = 0; y < height; ++y) + { + const uint16_t* ptrSrc = reinterpret_cast(static_cast(lckBm.ptrDataRoi) + y * static_cast(lckBm.stride)); + uint16_t* ptrDst = reinterpret_cast(static_cast(pDst) + y * static_cast(2)); + for (decltype(width) x = 0; x < width; ++x) + { + const uint16_t b = *ptrSrc++; + const uint16_t g = *ptrSrc++; + const uint16_t r = *ptrSrc++; + + *ptrDst = r; + *reinterpret_cast(reinterpret_cast(ptrDst) + planeStride) = g; + *reinterpret_cast(reinterpret_cast(ptrDst) + 2 * planeStride) = b; + ptrDst = reinterpret_cast(reinterpret_cast(ptrDst) + lineStride); + } + } } /*static*/MexArray* CziReader::ConvertToMatlabStruct(const libCZI::IDimBounds* bounds) { - vector dimensions; - for (auto i = (std::underlying_type::type)(libCZI::DimensionIndex::MinDim); i <= (std::underlying_type::type)(libCZI::DimensionIndex::MaxDim); ++i) - { - auto d = static_cast(i); - if (bounds->IsValid(d)) - { - char dimStr[2] = { libCZI::Utils::DimensionToChar(d) ,'\0' }; - dimensions.emplace_back(dimStr); - } - } - - vector fieldNames; - fieldNames.reserve(dimensions.size()); - for (const auto& i : dimensions) - { - fieldNames.emplace_back(i.c_str()); - } - - size_t dims[2] = { 1, 1 }; - auto mexApi = MexApi::GetInstance(); - auto* s = mexApi.MxCreateStructArray(2, dims, (int)fieldNames.size(), &fieldNames[0]); - - for (int i = 0; i < dimensions.size(); ++i) - { - int startIndex, size; - bounds->TryGetInterval(libCZI::Utils::CharToDimension(dimensions[i][0]), &startIndex, &size); - auto* no = mexApi.MxCreateNumericMatrix(1, 2, mxINT32_CLASS, mxREAL); - int* ptr = mexApi.MxGetInt32s(no); - *ptr = startIndex; - *(ptr + 1) = size; - mexApi.MxSetFieldByNumber(s, 0, i, no); - } - - return s; + vector dimensions; + for (auto i = (std::underlying_type::type)(libCZI::DimensionIndex::MinDim); i <= (std::underlying_type::type)(libCZI::DimensionIndex::MaxDim); ++i) + { + auto d = static_cast(i); + if (bounds->IsValid(d)) + { + char dimStr[2] = { libCZI::Utils::DimensionToChar(d) ,'\0' }; + dimensions.emplace_back(dimStr); + } + } + + vector fieldNames; + fieldNames.reserve(dimensions.size()); + for (const auto& i : dimensions) + { + fieldNames.emplace_back(i.c_str()); + } + + size_t dims[2] = { 1, 1 }; + auto mexApi = MexApi::GetInstance(); + auto* s = mexApi.MxCreateStructArray(2, dims, (int)fieldNames.size(), &fieldNames[0]); + + for (int i = 0; i < dimensions.size(); ++i) + { + int startIndex, size; + bounds->TryGetInterval(libCZI::Utils::CharToDimension(dimensions[i][0]), &startIndex, &size); + auto* no = mexApi.MxCreateNumericMatrix(1, 2, mxINT32_CLASS, mxREAL); + int* ptr = mexApi.MxGetInt32s(no); + *ptr = startIndex; + *(ptr + 1) = size; + mexApi.MxSetFieldByNumber(s, 0, i, no); + } + + return s; } /*static*/MexArray* CziReader::ConvertToMatlabStruct(const std::map& boundingBoxMap) { - static const char* fieldNames[] = { "sceneIndex", "boundingBox", "boundingBoxLayer0" }; - size_t dims[2] = { 1, boundingBoxMap.size() }; - auto mexApi = MexApi::GetInstance(); - auto* s = mexApi.MxCreateStructArray(2, dims, sizeof(fieldNames) / sizeof(fieldNames[0]), fieldNames); + static const char* fieldNames[] = { "sceneIndex", "boundingBox", "boundingBoxLayer0" }; + size_t dims[2] = { 1, boundingBoxMap.size() }; + auto mexApi = MexApi::GetInstance(); + auto* s = mexApi.MxCreateStructArray(2, dims, sizeof(fieldNames) / sizeof(fieldNames[0]), fieldNames); - int i = 0; - for (auto it = boundingBoxMap.cbegin(); it != boundingBoxMap.cend(); ++it) - { - mexApi.MxSetFieldByNumber(s, i, 0, MexUtils::Int32To1x1Matrix(it->first)); - mexApi.MxSetFieldByNumber(s, i, 1, CziReader::ConvertToMatlabStruct(it->second.boundingBox)); - mexApi.MxSetFieldByNumber(s, i, 2, CziReader::ConvertToMatlabStruct(it->second.boundingBoxLayer0)); - ++i; - } + int i = 0; + for (auto it = boundingBoxMap.cbegin(); it != boundingBoxMap.cend(); ++it) + { + mexApi.MxSetFieldByNumber(s, i, 0, MexUtils::Int32To1x1Matrix(it->first)); + mexApi.MxSetFieldByNumber(s, i, 1, CziReader::ConvertToMatlabStruct(it->second.boundingBox)); + mexApi.MxSetFieldByNumber(s, i, 2, CziReader::ConvertToMatlabStruct(it->second.boundingBoxLayer0)); + ++i; + } - return s; + return s; } /*static*/ MexArray* CziReader::ConvertToMatlabStruct(const libCZI::IntRect& rect) { - auto mexApi = MexApi::GetInstance(); - auto* m = mexApi.MxCreateNumericMatrix(1, 4, mxINT32_CLASS, mxREAL); - int* ptr = mexApi.MxGetInt32s(m); - ptr[0] = rect.x; - ptr[1] = rect.y; - ptr[2] = rect.w; - ptr[3] = rect.h; - return m; + auto mexApi = MexApi::GetInstance(); + auto* m = mexApi.MxCreateNumericMatrix(1, 4, mxINT32_CLASS, mxREAL); + int* ptr = mexApi.MxGetInt32s(m); + ptr[0] = rect.x; + ptr[1] = rect.y; + ptr[2] = rect.w; + ptr[3] = rect.h; + return m; } /*static*/ MexArray* CziReader::ConvertToMatlabStruct(const libCZI::IntSize& size) { - auto mexApi = MexApi::GetInstance(); - auto* m = mexApi.MxCreateNumericMatrix(1, 2, mxINT32_CLASS, mxREAL); - int* ptr = mexApi.MxGetInt32s(m); - ptr[0] = size.w; - ptr[1] = size.h; - return m; + auto mexApi = MexApi::GetInstance(); + auto* m = mexApi.MxCreateNumericMatrix(1, 2, mxINT32_CLASS, mxREAL); + int* ptr = mexApi.MxGetInt32s(m); + ptr[0] = size.w; + ptr[1] = size.h; + return m; } /*static*/ MexArray* CziReader::ConvertToMatlabStruct(const libCZI::IDisplaySettings& ds) { - static const char* tintingModesNone = "none"; - static const char* tintingModesColor = "color"; - - static const char* gradationcurveLinear = "linear"; - static const char* gradationcurveGamma = "gamma"; - static const char* gradationcurveSpline = "spline"; - - static const char* fieldNames[] = { - "channelIndex", - "isEnabled", - "weight", - "tintingmode", - "tintingcolor", - "blackwhitepoint", - "gradationcurvemode", - "gamma", - "splinectrlpts" }; - vector chIndices; - ds.EnumChannels( - [&](int idx) -> bool - { - chIndices.emplace_back(idx); - return true; - } - ); - - size_t dims[2] = { 1, chIndices.size() }; - auto mexApi = MexApi::GetInstance(); - auto* s = mexApi.MxCreateStructArray(2, dims, sizeof(fieldNames) / sizeof(fieldNames[0]), fieldNames); - size_t i = 0; - for (auto it : chIndices) - { - auto chDs = ds.GetChannelDisplaySettings(it); - mexApi.MxSetFieldByNumber(s, i, 0, MexUtils::Int32To1x1Matrix(it)); - mexApi.MxSetFieldByNumber(s, i, 1, MexUtils::BooleanTo1x1Matrix(chDs->GetIsEnabled())); - mexApi.MxSetFieldByNumber(s, i, 2, MexUtils::DoubleTo1x1Matrix(chDs->GetWeight())); - - Rgb8Color tintingColor; - if (chDs->TryGetTintingColorRgb8(&tintingColor)) - { - mexApi.MxSetFieldByNumber(s, i, 3, mexApi.MxCreateString(tintingModesColor)); - auto* m = MexApi::GetInstance().MxCreateNumericMatrix(3, 1, mxUINT8_CLASS, mxREAL); - auto* ptr = MexApi::GetInstance().MxGetUint8s(m); - ptr[0] = tintingColor.r; - ptr[1] = tintingColor.g; - ptr[2] = tintingColor.b; - mexApi.MxSetFieldByNumber(s, i, 4, m); - } - /*else if TODO -> Lookup-Table */ - else - { - mexApi.MxSetFieldByNumber(s, i, 3, mexApi.MxCreateString(tintingModesNone)); - } - - float blackPoint, whitePoint; - chDs->GetBlackWhitePoint(&blackPoint, &whitePoint); - mexApi.MxSetFieldByNumber(s, i, 5, MexUtils::DoublesAsNx1Matrix(2, static_cast(blackPoint), static_cast(whitePoint))); - - switch (chDs->GetGradationCurveMode()) - { - case IDisplaySettings::GradationCurveMode::Linear: - mexApi.MxSetFieldByNumber(s, i, 6, mexApi.MxCreateString(gradationcurveLinear)); - break; - case IDisplaySettings::GradationCurveMode::Gamma: - mexApi.MxSetFieldByNumber(s, i, 6, mexApi.MxCreateString(gradationcurveGamma)); - float gamma; - chDs->TryGetGamma(&gamma); - mexApi.MxSetFieldByNumber(s, i, 7, MexUtils::DoubleTo1x1Matrix(gamma)); - break; - case IDisplaySettings::GradationCurveMode::Spline: - mexApi.MxSetFieldByNumber(s, i, 6, mexApi.MxCreateString(gradationcurveSpline)); - vector splineCtrlPts; - chDs->TryGetSplineControlPoints(&splineCtrlPts); - auto* m = MexApi::GetInstance().MxCreateNumericMatrix(splineCtrlPts.size(), 2, mxDOUBLE_CLASS, mxREAL); - auto* ptrDbls = MexApi::GetInstance().MxGetDoubles(m); - for (const auto& splineCtrlPt : splineCtrlPts) - { - *ptrDbls++ = splineCtrlPt.x; - *ptrDbls++ = splineCtrlPt.y; - } - - mexApi.MxSetFieldByNumber(s, i, 8, m); - } - - ++i; - } - - return s; + static const char* tintingModesNone = "none"; + static const char* tintingModesColor = "color"; + + static const char* gradationcurveLinear = "linear"; + static const char* gradationcurveGamma = "gamma"; + static const char* gradationcurveSpline = "spline"; + + static const char* fieldNames[] = { + "channelIndex", + "isEnabled", + "weight", + "tintingmode", + "tintingcolor", + "blackwhitepoint", + "gradationcurvemode", + "gamma", + "splinectrlpts" }; + vector chIndices; + ds.EnumChannels( + [&](int idx) -> bool + { + chIndices.emplace_back(idx); + return true; + } + ); + + size_t dims[2] = { 1, chIndices.size() }; + auto mexApi = MexApi::GetInstance(); + auto* s = mexApi.MxCreateStructArray(2, dims, sizeof(fieldNames) / sizeof(fieldNames[0]), fieldNames); + size_t i = 0; + for (auto it : chIndices) + { + auto chDs = ds.GetChannelDisplaySettings(it); + mexApi.MxSetFieldByNumber(s, i, 0, MexUtils::Int32To1x1Matrix(it)); + mexApi.MxSetFieldByNumber(s, i, 1, MexUtils::BooleanTo1x1Matrix(chDs->GetIsEnabled())); + mexApi.MxSetFieldByNumber(s, i, 2, MexUtils::DoubleTo1x1Matrix(chDs->GetWeight())); + + Rgb8Color tintingColor; + if (chDs->TryGetTintingColorRgb8(&tintingColor)) + { + mexApi.MxSetFieldByNumber(s, i, 3, mexApi.MxCreateString(tintingModesColor)); + auto* m = MexApi::GetInstance().MxCreateNumericMatrix(3, 1, mxUINT8_CLASS, mxREAL); + auto* ptr = MexApi::GetInstance().MxGetUint8s(m); + ptr[0] = tintingColor.r; + ptr[1] = tintingColor.g; + ptr[2] = tintingColor.b; + mexApi.MxSetFieldByNumber(s, i, 4, m); + } + /*else if TODO -> Lookup-Table */ + else + { + mexApi.MxSetFieldByNumber(s, i, 3, mexApi.MxCreateString(tintingModesNone)); + } + + float blackPoint, whitePoint; + chDs->GetBlackWhitePoint(&blackPoint, &whitePoint); + mexApi.MxSetFieldByNumber(s, i, 5, MexUtils::DoublesAsNx1Matrix(2, static_cast(blackPoint), static_cast(whitePoint))); + + switch (chDs->GetGradationCurveMode()) + { + case IDisplaySettings::GradationCurveMode::Linear: + mexApi.MxSetFieldByNumber(s, i, 6, mexApi.MxCreateString(gradationcurveLinear)); + break; + case IDisplaySettings::GradationCurveMode::Gamma: + mexApi.MxSetFieldByNumber(s, i, 6, mexApi.MxCreateString(gradationcurveGamma)); + float gamma; + chDs->TryGetGamma(&gamma); + mexApi.MxSetFieldByNumber(s, i, 7, MexUtils::DoubleTo1x1Matrix(gamma)); + break; + case IDisplaySettings::GradationCurveMode::Spline: + mexApi.MxSetFieldByNumber(s, i, 6, mexApi.MxCreateString(gradationcurveSpline)); + vector splineCtrlPts; + chDs->TryGetSplineControlPoints(&splineCtrlPts); + auto* m = MexApi::GetInstance().MxCreateNumericMatrix(splineCtrlPts.size(), 2, mxDOUBLE_CLASS, mxREAL); + auto* ptrDbls = MexApi::GetInstance().MxGetDoubles(m); + for (const auto& splineCtrlPt : splineCtrlPts) + { + *ptrDbls++ = splineCtrlPt.x; + *ptrDbls++ = splineCtrlPt.y; + } + + mexApi.MxSetFieldByNumber(s, i, 8, m); + } + + ++i; + } + + return s; } MexArray* CziReader::ReadSubBlock(int no) { - auto sbBlk = this->reader->ReadSubBlock(no); - if (!sbBlk) - { - std::stringstream ss; - ss << "SubBlock for id=" << no << " was not found."; - throw invalid_argument(ss.str()); - } + auto sbBlk = this->reader->ReadSubBlock(no); + if (!sbBlk) + { + std::stringstream ss; + ss << "SubBlock for id=" << no << " was not found."; + throw invalid_argument(ss.str()); + } - int32_t h = this->sbBlkStore.AddSubBlock(sbBlk); - return MexUtils::Int32To1x1Matrix(h); + int32_t h = this->sbBlkStore.AddSubBlock(sbBlk); + return MexUtils::Int32To1x1Matrix(h); } MexArray* CziReader::GetInfoFromSubBlock(int subBlkHandle) { - auto sbBlk = this->sbBlkStore.GetForHandle(subBlkHandle); - if (!sbBlk) - { - std::stringstream ss; - ss << "SubBlock for handle=" << subBlkHandle << " is not present."; - throw invalid_argument(ss.str()); - } + auto sbBlk = this->sbBlkStore.GetForHandle(subBlkHandle); + if (!sbBlk) + { + std::stringstream ss; + ss << "SubBlock for handle=" << subBlkHandle << " is not present."; + throw invalid_argument(ss.str()); + } - const auto& sbInfo = sbBlk->GetSubBlockInfo(); - return CziReader::ConvertToMatlabStruct(sbInfo); + const auto& sbInfo = sbBlk->GetSubBlockInfo(); + return CziReader::ConvertToMatlabStruct(sbInfo); } MexArray* CziReader::GetMetadataFromSubBlock(int subBlkHandle) { - auto sbBlk = this->sbBlkStore.GetForHandle(subBlkHandle); - if (!sbBlk) - { - std::stringstream ss; - ss << "SubBlock for handle=" << subBlkHandle << " is not present."; - throw invalid_argument(ss.str()); - } + auto sbBlk = this->sbBlkStore.GetForHandle(subBlkHandle); + if (!sbBlk) + { + std::stringstream ss; + ss << "SubBlock for handle=" << subBlkHandle << " is not present."; + throw invalid_argument(ss.str()); + } - auto mexApi = MexApi::GetInstance(); - size_t sizeData; - auto ptrData = sbBlk->GetRawData(ISubBlock::MemBlkType::Metadata, &sizeData); - if (!ptrData) - { - return mexApi.MxCreateString(""); - } + auto mexApi = MexApi::GetInstance(); + size_t sizeData; + auto ptrData = sbBlk->GetRawData(ISubBlock::MemBlkType::Metadata, &sizeData); + if (!ptrData) + { + return mexApi.MxCreateString(""); + } - string metadataXml(static_cast(ptrData.get()), sizeData); - return mexApi.MxCreateString(metadataXml.c_str()); + string metadataXml(static_cast(ptrData.get()), sizeData); + return mexApi.MxCreateString(metadataXml.c_str()); } MexArray* CziReader::GetBitmapFromSubBlock(int subBlkHandle) { - auto sbBlk = this->sbBlkStore.GetForHandle(subBlkHandle); - if (!sbBlk) - { - std::stringstream ss; - ss << "SubBlock for handle=" << subBlkHandle << " is not present."; - throw invalid_argument(ss.str()); - } + auto sbBlk = this->sbBlkStore.GetForHandle(subBlkHandle); + if (!sbBlk) + { + std::stringstream ss; + ss << "SubBlock for handle=" << subBlkHandle << " is not present."; + throw invalid_argument(ss.str()); + } - auto bm = sbBlk->CreateBitmap(); - return ConvertToMxArray(bm.get()); + auto bm = sbBlk->CreateBitmap(); + return ConvertToMxArray(bm.get()); } bool CziReader::ReleaseSubBlock(int subBlkHandle) { - return this->sbBlkStore.RemoveSubBlock(subBlkHandle); + return this->sbBlkStore.RemoveSubBlock(subBlkHandle); } /*static*/MexArray* CziReader::ConvertToMatlabStruct(const libCZI::SubBlockInfo& sbBlkInfo) { - auto mexApi = MexApi::GetInstance(); - array fieldNames = { "Mode", "Pixeltype", "Coordinate", "LogicalRect", "PhysicalSize", "MIndex", "Zoom"}; - auto s = mexApi.MxCreateStructArray( - 2, - MexUtils::Dims_1_by_1, - static_cast(fieldNames.size()), - fieldNames.data()); - mexApi.MxSetFieldByNumber(s, 0, 0, mexApi.MxCreateString(libCZI::Utils::CompressionModeToInformalString(sbBlkInfo.GetCompressionMode()))); - mexApi.MxSetFieldByNumber(s, 0, 1, mexApi.MxCreateString(libCZI::Utils::PixelTypeToInformalString(sbBlkInfo.pixelType))); - mexApi.MxSetFieldByNumber(s, 0, 2, mexApi.MxCreateString(libCZI::Utils::DimCoordinateToString(&sbBlkInfo.coordinate).c_str())); - mexApi.MxSetFieldByNumber(s, 0, 3, CziReader::ConvertToMatlabStruct(sbBlkInfo.logicalRect)); - mexApi.MxSetFieldByNumber(s, 0, 4, CziReader::ConvertToMatlabStruct(sbBlkInfo.physicalSize)); - if (sbBlkInfo.mIndex != std::numeric_limits::max() && sbBlkInfo.mIndex != std::numeric_limits::min()) - { - mexApi.MxSetFieldByNumber(s, 0, 5, MexUtils::Int32To1x1Matrix(sbBlkInfo.mIndex)); - } - - mexApi.MxSetFieldByNumber(s, 0, 6, MexUtils::DoubleTo1x1Matrix(sbBlkInfo.GetZoom())); - return s; + auto mexApi = MexApi::GetInstance(); + array fieldNames = { "Mode", "Pixeltype", "Coordinate", "LogicalRect", "PhysicalSize", "MIndex", "Zoom" }; + auto s = mexApi.MxCreateStructArray( + 2, + MexUtils::Dims_1_by_1, + static_cast(fieldNames.size()), + fieldNames.data()); + mexApi.MxSetFieldByNumber(s, 0, 0, mexApi.MxCreateString(libCZI::Utils::CompressionModeToInformalString(sbBlkInfo.GetCompressionMode()))); + mexApi.MxSetFieldByNumber(s, 0, 1, mexApi.MxCreateString(libCZI::Utils::PixelTypeToInformalString(sbBlkInfo.pixelType))); + mexApi.MxSetFieldByNumber(s, 0, 2, mexApi.MxCreateString(libCZI::Utils::DimCoordinateToString(&sbBlkInfo.coordinate).c_str())); + mexApi.MxSetFieldByNumber(s, 0, 3, CziReader::ConvertToMatlabStruct(sbBlkInfo.logicalRect)); + mexApi.MxSetFieldByNumber(s, 0, 4, CziReader::ConvertToMatlabStruct(sbBlkInfo.physicalSize)); + if (sbBlkInfo.mIndex != std::numeric_limits::max() && sbBlkInfo.mIndex != std::numeric_limits::min()) + { + mexApi.MxSetFieldByNumber(s, 0, 5, MexUtils::Int32To1x1Matrix(sbBlkInfo.mIndex)); + } + + mexApi.MxSetFieldByNumber(s, 0, 6, MexUtils::DoubleTo1x1Matrix(sbBlkInfo.GetZoom())); + return s; } diff --git a/MEXlibCZI/src/CziUtilities.cpp b/MEXlibCZI/src/CziUtilities.cpp index 7449d61..e737393 100644 --- a/MEXlibCZI/src/CziUtilities.cpp +++ b/MEXlibCZI/src/CziUtilities.cpp @@ -1,5 +1,6 @@ #include "CziUtilities.h" -#include +//#include +#include "include_rapidjson.h" #include "utils.h" using namespace libCZI; diff --git a/MEXlibCZI/src/CziUtilities.h b/MEXlibCZI/src/CziUtilities.h index 89f2225..4d5ef51 100644 --- a/MEXlibCZI/src/CziUtilities.h +++ b/MEXlibCZI/src/CziUtilities.h @@ -2,7 +2,8 @@ #include #include -#include +//#include +#include "include_rapidjson.h" struct ChannelDisplaySettingsValidity { diff --git a/MEXlibCZI/src/CziWriter.cpp b/MEXlibCZI/src/CziWriter.cpp index 3a6dcd7..3b96372 100644 --- a/MEXlibCZI/src/CziWriter.cpp +++ b/MEXlibCZI/src/CziWriter.cpp @@ -66,7 +66,7 @@ void CziWriter::AddSubBlockUncompressed( if (!subblock_metadata_xml.empty()) { add_sub_block_info_strided_bitmap.ptrSbBlkMetadata = subblock_metadata_xml.c_str(); - add_sub_block_info_strided_bitmap.sbBlkMetadataSize = subblock_metadata_xml.size(); + add_sub_block_info_strided_bitmap.sbBlkMetadataSize = static_cast(subblock_metadata_xml.size()); } libCZI::ScopedBitmapLockerSP bitmap_locker(bitmap_data); @@ -139,12 +139,12 @@ void CziWriter::AddSubBlockCompressed( addInfo.physicalHeight = add_sub_block_info_base.physicalHeight; addInfo.PixelType = add_sub_block_info_base.PixelType; addInfo.ptrData = compressed_data->GetPtr(); - addInfo.dataSize = compressed_data->GetSizeOfData(); + addInfo.dataSize = static_cast(compressed_data->GetSizeOfData()); if (!subblock_metadata_xml.empty()) { addInfo.ptrSbBlkMetadata = subblock_metadata_xml.c_str(); - addInfo.sbBlkMetadataSize = subblock_metadata_xml.size(); + addInfo.sbBlkMetadataSize = static_cast(subblock_metadata_xml.size()); } addInfo.SetCompressionMode(compression_mode); diff --git a/MEXlibCZI/src/argsutils.cpp b/MEXlibCZI/src/argsutils.cpp index b333c8c..aec7d4f 100644 --- a/MEXlibCZI/src/argsutils.cpp +++ b/MEXlibCZI/src/argsutils.cpp @@ -398,11 +398,11 @@ using namespace libCZI; { planeCoordinate = CDimCoordinate::Parse(argStr.c_str()); } - catch (libCZI::LibCZIStringParseException& libExcp) + catch (libCZI::LibCZIStringParseException&) { return false; } - catch (exception& excp) + catch (exception&) { return false; } diff --git a/MEXlibCZI/src/func_addsubblock.cpp b/MEXlibCZI/src/func_addsubblock.cpp index 73fd788..5af279f 100644 --- a/MEXlibCZI/src/func_addsubblock.cpp +++ b/MEXlibCZI/src/func_addsubblock.cpp @@ -1,7 +1,7 @@ #include "func_open.h" #include "libraryInfo.h" #include "CziWriterManager.h" -#include +#include #include #include @@ -131,6 +131,11 @@ void MexFunction_AddSubBlock_Execute(MatlabArgs* args) } } + 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(); @@ -139,8 +144,8 @@ void MexFunction_AddSubBlock_Execute(MatlabArgs* args) 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 = array_info.dimensions[1]; - add_sub_block_info_base.physicalHeight = array_info.dimensions[0]; + 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(); diff --git a/MEXlibCZI/src/func_getsubblockbitmap.cpp b/MEXlibCZI/src/func_getsubblockbitmap.cpp index e39c93b..325148e 100644 --- a/MEXlibCZI/src/func_getsubblockbitmap.cpp +++ b/MEXlibCZI/src/func_getsubblockbitmap.cpp @@ -52,9 +52,10 @@ void MexFunction_GetSubBlockBitmap_Execute(MatlabArgs* args) auto* out = reader->GetSubBlockImage(blkNo); args->plhs[0] = out; } - catch (exception& excp) + catch (exception& exception) { - VDBGPRINT((CDbg::Level::Warn, "MexFunction_GetSubBlockBitmap_Execute: GetSubBlockImage failed -> %s.", excp.what())); + (void)exception; // suppress "unreferenced local variable" warning + VDBGPRINT((CDbg::Level::Warn, "MexFunction_GetSubBlockBitmap_Execute: GetSubBlockImage failed -> %s.", exception.what())); throw; } } \ No newline at end of file diff --git a/MEXlibCZI/src/func_open.cpp b/MEXlibCZI/src/func_open.cpp index 2b2567c..3e600cf 100644 --- a/MEXlibCZI/src/func_open.cpp +++ b/MEXlibCZI/src/func_open.cpp @@ -34,9 +34,10 @@ void MexFunction_Open_Execute(MatlabArgs* args) VDBGPRINT((CDbg::Level::Trace, "MexFunction_Open_Execute: attempt to open file \"%s\".", filename.get())); reader->Open(filename.get()); } - catch (exception& excp) + catch (exception& exception) { - VDBGPRINT((CDbg::Level::Warn, "MexFunction_Open_Execute: Open failed -> %s.", excp.what())); + (void)exception; // suppress "unreferenced local variable" warning + VDBGPRINT((CDbg::Level::Warn, "MexFunction_Open_Execute: Open failed -> %s.", exception.what())); CziReaderManager::GetInstance().RemoveInstance(id); throw; } diff --git a/MEXlibCZI/src/include_rapidjson.h b/MEXlibCZI/src/include_rapidjson.h new file mode 100644 index 0000000..40b45ef --- /dev/null +++ b/MEXlibCZI/src/include_rapidjson.h @@ -0,0 +1,6 @@ +#pragma once + +#define RAPIDJSON_HAS_STDSTRING 1 + +#include "rapidjson/rapidjson.h" +#include "rapidjson/document.h" \ No newline at end of file diff --git a/MEXlibCZI/src/utils.cpp b/MEXlibCZI/src/utils.cpp index 872507c..fc42c65 100644 --- a/MEXlibCZI/src/utils.cpp +++ b/MEXlibCZI/src/utils.cpp @@ -1,11 +1,15 @@ #include "utils.h" #include #include +#include #include #include "CziReaderManager.h" #include "CziWriterManager.h" #include "mexapi.h" #include "dbgprint.h" +#if _WIN32 +#include +#endif using namespace std; @@ -58,9 +62,28 @@ using namespace std; /*static*/std::wstring Utils::convertUtf8ToWchar_t(const char* sz) { +#if _WIN32 + // Get the size of the wide char string we need. + int len = MultiByteToWideChar(CP_UTF8, 0, sz, -1, nullptr, 0); + if (len == 0) + { + return L""; + } + + // Create a wstring to hold the result. + std::wstring conv(len, 0); + + // Perform the actual conversion. + MultiByteToWideChar(CP_UTF8, 0, sz, -1, conv.data(), len); + + // Remove the extra null terminator added by MultiByteToWideChar + conv.resize(len - 1); + return conv; +#else std::wstring_convert> utf8conv; std::wstring conv = utf8conv.from_bytes(sz); return conv; +#endif } /*static*/std::shared_ptr Utils::GetReaderOrThrow(int id) @@ -191,6 +214,11 @@ class Converters throw invalid_argument("array must be at most 3-dimensional"); } + if (array_info.dimensions[1] > (numeric_limits::max)() || array_info.dimensions[0] > (numeric_limits::max)()) + { + throw invalid_argument("array dimensions are too large"); + } + static constexpr struct ConversionInfo { mxClassID mx_class; @@ -210,7 +238,7 @@ class Converters { if (conversionInfo.mx_class == array_info.class_id && conversionInfo.has_3rd_dimension == has_3rd_dimension) { - auto bitmapData = make_shared(pixel_type, array_info.dimensions[1], array_info.dimensions[0]); + auto bitmapData = make_shared(pixel_type, static_cast(array_info.dimensions[1]), static_cast(array_info.dimensions[0])); conversionInfo.conversion_function(array_info, bitmapData.get()); return bitmapData; } diff --git a/modules/rapidJSON.cmake b/modules/rapidJSON.cmake index bebbe22..fbe1298 100644 --- a/modules/rapidJSON.cmake +++ b/modules/rapidJSON.cmake @@ -5,7 +5,7 @@ ExternalProject_Add( rapidjson PREFIX "vendor/rapidjson" GIT_REPOSITORY "https://github.com/Tencent/rapidjson.git" - GIT_TAG f54b0e47a08782a6131cc3d60f94d038fa6e0a51 + GIT_TAG 815e6e7e7e14be44a6c15d9aefed232ff064cad0 TIMEOUT 10 CMAKE_ARGS -DRAPIDJSON_BUILD_TESTS=OFF From 8d0fc078d7eb5b1cc2334fe30d2def3fbf9a50f0 Mon Sep 17 00:00:00 2001 From: ptahmose Date: Fri, 4 Oct 2024 23:15:37 +0200 Subject: [PATCH 2/2] Remove unused rapidjson includes; add #pragma once Removed unnecessary #include directives for rapidjson in CziUtilities.cpp and CziUtilities.h to clean up the code. Added #pragma once to CziUtilities.h to prevent multiple inclusions and improve compilation efficiency. --- MEXlibCZI/src/CziUtilities.cpp | 1 - MEXlibCZI/src/CziUtilities.h | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MEXlibCZI/src/CziUtilities.cpp b/MEXlibCZI/src/CziUtilities.cpp index e737393..6c832de 100644 --- a/MEXlibCZI/src/CziUtilities.cpp +++ b/MEXlibCZI/src/CziUtilities.cpp @@ -1,5 +1,4 @@ #include "CziUtilities.h" -//#include #include "include_rapidjson.h" #include "utils.h" diff --git a/MEXlibCZI/src/CziUtilities.h b/MEXlibCZI/src/CziUtilities.h index 4d5ef51..b1e6826 100644 --- a/MEXlibCZI/src/CziUtilities.h +++ b/MEXlibCZI/src/CziUtilities.h @@ -1,8 +1,9 @@ +#pragma once + #include "inc_libczi.h" #include #include -//#include #include "include_rapidjson.h" struct ChannelDisplaySettingsValidity