Skip to content

Commit

Permalink
Update CMake, refactor CziReader/Writer, add validation
Browse files Browse the repository at this point in the history
Removed `src/func_readsubblock.h` and `src/func_readsubblock.cpp` from `CMakeLists.txt`.
Updated C++ standard from C++11 to C++17 in `CMakeLists.txt`.
Replaced raw pointers with `std::vector::data()` in `CziReader::GetMultiChannelScalingTileComposite`.
Replaced C-style casts with `static_cast` and `reinterpret_cast` in `CziReader::GetDisplaySettingsFromCzi`.
Removed redundant `#include <locale>` from `CziWriter.cpp`.
Added `subblock_metadata_xml` parameter to `CziWriter::AddSubBlock` and updated its implementation.
Removed commented-out code and unused includes from `CziWriter.h`.
Added `CArgsUtils::IsStructure`, `CArgsUtils::TryGetIntValueOfField`, and `CArgsUtils::TryGetStringValueOfField` methods in `argsutils.cpp` and `argsutils.h`.
Added validation for the 5th argument in `MexFunction_AddSubBlock_CheckArguments` to ensure it is a 2D or 3D array.
Added validation for the 6th argument in `MexFunction_AddSubBlock_CheckArguments` to ensure it is a structure.
Added handling for optional `m_index` and `metadata_xml` in `MexFunction_AddSubBlock_Execute`.
Removed `func_readsubblock.h`.
Added `MexApi::MxIsStruct` and `MexApi::MxGetField` methods in `mexapi.cpp` and `mexapi.h`.
Updated `notes.txt` to include examples of using the new `metadata_xml` parameter in `MEXlibCZI`.
  • Loading branch information
ptahmose committed Oct 3, 2024
1 parent 17c6c77 commit 6292fd9
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 86 deletions.
4 changes: 1 addition & 3 deletions MEXlibCZI/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ set(mexoctaveSourceFiles
"src/dbgprint.cpp"
"src/func_getdefaultdisplaysettings.cpp"
"src/func_getdefaultdisplaysettings.h"
"src/func_readsubblock.h"
"src/func_readsubblock.cpp"
"src/CziReaderSbBlkStore.h"
"src/CziReaderSbBlkStore.cpp"
"src/func_getsubblock.h"
Expand All @@ -81,7 +79,7 @@ set(mexoctaveSourceFiles
add_library (MEXlibCZI SHARED
${mexoctaveSourceFiles})

set_target_properties(MEXlibCZI PROPERTIES CXX_STANDARD 11)
set_target_properties(MEXlibCZI PROPERTIES CXX_STANDARD 17)

target_include_directories(MEXlibCZI PRIVATE ${Matlab_INCLUDE_DIRS} ${RAPIDJSON_INCLUDE_DIR})

Expand Down
34 changes: 17 additions & 17 deletions MEXlibCZI/src/CziReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ MexArray* CziReader::GetMultiChannelScalingTileComposite(const libCZI::IntRect&

auto bitmap = Compositors::ComposeMultiChannel_Bgr24(
(int)channelBitmaps.size(),
&vecBm[0],
vecBm.data(),
dsplHlp.GetChannelInfosArray());

mwSize dims[3] = { bitmap->GetHeight(), bitmap->GetWidth(), 3 };
Expand Down Expand Up @@ -323,8 +323,8 @@ std::shared_ptr<libCZI::IDisplaySettings> CziReader::GetDisplaySettingsFromCzi()
ScopedBitmapLocker<IBitmapData*> lckBm{ bitmapData };
for (decltype(height) y = 0; y < height; ++y)
{
const uint8_t* ptrSrc = ((const uint8_t*)lckBm.ptrDataRoi) + y * (size_t)lckBm.stride;
uint8_t* ptrDst = ((uint8_t*)pDst) + y;
const uint8_t* ptrSrc = static_cast<const uint8_t*>(lckBm.ptrDataRoi) + y * static_cast<size_t>(lckBm.stride);
uint8_t* ptrDst = static_cast<uint8_t*>(pDst) + y;
for (decltype(width) x = 0; x < width; ++x)
{
*ptrDst = *ptrSrc++;
Expand All @@ -340,12 +340,12 @@ std::shared_ptr<libCZI::IDisplaySettings> CziReader::GetDisplaySettingsFromCzi()
ScopedBitmapLocker<IBitmapData*> lckBm{ bitmapData };
for (decltype(height) y = 0; y < height; ++y)
{
const uint16_t* ptrSrc = (const uint16_t*)(((const uint8_t*)lckBm.ptrDataRoi) + y * (size_t)lckBm.stride);
uint16_t* ptrDst = (uint16_t*)(((uint8_t*)pDst) + y * 2);
const uint16_t* ptrSrc = reinterpret_cast<const uint16_t*>(static_cast<const uint8_t*>(lckBm.ptrDataRoi) + y * static_cast<size_t>(lckBm.stride));
uint16_t* ptrDst = reinterpret_cast<uint16_t*>(static_cast<uint8_t*>(pDst) + static_cast<size_t>(y) * 2);
for (decltype(width) x = 0; x < width; ++x)
{
*ptrDst = *ptrSrc++;
ptrDst = (uint16_t*)(((uint8_t*)ptrDst) + lineLength);
ptrDst = reinterpret_cast<uint16_t*>(reinterpret_cast<uint8_t*>(ptrDst) + lineLength);
}
}
}
Expand All @@ -357,12 +357,12 @@ std::shared_ptr<libCZI::IDisplaySettings> CziReader::GetDisplaySettingsFromCzi()
ScopedBitmapLocker<IBitmapData*> lckBm{ bitmapData };
for (decltype(height) y = 0; y < height; ++y)
{
const float* ptrSrc = (const float*)(((const uint8_t*)lckBm.ptrDataRoi) + y * (size_t)lckBm.stride);
float* ptrDst = (float*)(((uint8_t*)pDst) + y * 4);
const float* ptrSrc = reinterpret_cast<const float*>(static_cast<const uint8_t*>(lckBm.ptrDataRoi) + y * static_cast<size_t>(lckBm.stride));
float* ptrDst = reinterpret_cast<float*>(static_cast<uint8_t*>(pDst) + static_cast<size_t>(y) * 4);
for (decltype(width) x = 0; x < width; ++x)
{
*ptrDst = *ptrSrc++;
ptrDst = (float*)(((uint8_t*)ptrDst) + lineLength);;
ptrDst = reinterpret_cast<float*>(reinterpret_cast<uint8_t*>(ptrDst) + lineLength);
}
}
}
Expand All @@ -374,8 +374,8 @@ std::shared_ptr<libCZI::IDisplaySettings> CziReader::GetDisplaySettingsFromCzi()
ScopedBitmapLocker<IBitmapData*> lckBm{ bitmapData };
for (decltype(height) y = 0; y < height; ++y)
{
const uint8_t* ptrSrc = ((const uint8_t*)lckBm.ptrDataRoi) + y * (size_t)lckBm.stride;
uint8_t* ptrDst = ((uint8_t*)pDst) + y;
const uint8_t* ptrSrc = static_cast<const uint8_t*>(lckBm.ptrDataRoi) + y * static_cast<size_t>(lckBm.stride);
uint8_t* ptrDst = static_cast<uint8_t*>(pDst) + y;
for (decltype(width) x = 0; x < width; ++x)
{
const uint8_t b = *ptrSrc++;
Expand All @@ -397,18 +397,18 @@ std::shared_ptr<libCZI::IDisplaySettings> CziReader::GetDisplaySettingsFromCzi()
ScopedBitmapLocker<IBitmapData*> lckBm{ bitmapData };
for (decltype(height) y = 0; y < height; ++y)
{
const uint16_t* ptrSrc = (const uint16_t*)(((const uint8_t*)lckBm.ptrDataRoi) + y * (size_t)lckBm.stride);
uint16_t* ptrDst = (uint16_t*)(((uint8_t*)pDst) + y * (size_t)2);
const uint16_t* ptrSrc = reinterpret_cast<const uint16_t*>(static_cast<const uint8_t*>(lckBm.ptrDataRoi) + y * static_cast<size_t>(lckBm.stride));
uint16_t* ptrDst = reinterpret_cast<uint16_t*>(static_cast<uint8_t*>(pDst) + y * static_cast<size_t>(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;
*((uint16_t*)(((uint8_t*)ptrDst) + planeStride)) = g;
*((uint16_t*)(((uint8_t*)ptrDst) + 2 * planeStride)) = b;
ptrDst = (uint16_t*)(((uint8_t*)ptrDst) + lineStride);
*reinterpret_cast<uint16_t*>(reinterpret_cast<uint8_t*>(ptrDst) + planeStride) = g;
*reinterpret_cast<uint16_t*>(reinterpret_cast<uint8_t*>(ptrDst) + 2 * planeStride) = b;
ptrDst = reinterpret_cast<uint16_t*>(reinterpret_cast<uint8_t*>(ptrDst) + lineStride);
}
}
}
Expand All @@ -418,7 +418,7 @@ std::shared_ptr<libCZI::IDisplaySettings> CziReader::GetDisplaySettingsFromCzi()
vector<string> dimensions;
for (auto i = (std::underlying_type<libCZI::DimensionIndex>::type)(libCZI::DimensionIndex::MinDim); i <= (std::underlying_type<libCZI::DimensionIndex>::type)(libCZI::DimensionIndex::MaxDim); ++i)
{
auto d = (libCZI::DimensionIndex)i;
auto d = static_cast<libCZI::DimensionIndex>(i);
if (bounds->IsValid(d))
{
char dimStr[2] = { libCZI::Utils::DimensionToChar(d) ,'\0' };
Expand Down
12 changes: 9 additions & 3 deletions MEXlibCZI/src/CziWriter.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "CziWriter.h"
#include "inc_libczi.h"
#include <locale>
#include "utils.h"

using namespace std;
Expand All @@ -19,9 +18,10 @@ void CziWriter::Create(const std::string& utf8_filename, bool overwrite_existing
this->writer->Create(output_stream, nullptr);
}

void CziWriter::AddSubBlock(const libCZI::AddSubBlockInfoBase& add_sub_block_info_base, const std::shared_ptr<libCZI::IBitmapData>& bitmap_data)
void CziWriter::AddSubBlock(const libCZI::AddSubBlockInfoBase& add_sub_block_info_base, const std::shared_ptr<libCZI::IBitmapData>& bitmap_data, const std::string& subblock_metadata_xml)
{
libCZI::AddSubBlockInfoStridedBitmap add_sub_block_info_strided_bitmap;
add_sub_block_info_strided_bitmap.Clear();
add_sub_block_info_strided_bitmap.coordinate = add_sub_block_info_base.coordinate;
add_sub_block_info_strided_bitmap.mIndexValid = add_sub_block_info_base.mIndexValid;
add_sub_block_info_strided_bitmap.mIndex = add_sub_block_info_base.mIndex;
Expand All @@ -35,6 +35,12 @@ void CziWriter::AddSubBlock(const libCZI::AddSubBlockInfoBase& add_sub_block_inf
add_sub_block_info_strided_bitmap.pyramid_type = add_sub_block_info_base.pyramid_type;
add_sub_block_info_strided_bitmap.compressionModeRaw = add_sub_block_info_base.compressionModeRaw;

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();
}

libCZI::ScopedBitmapLockerSP destination_locker(bitmap_data);
add_sub_block_info_strided_bitmap.ptrBitmap = destination_locker.ptrDataRoi;
add_sub_block_info_strided_bitmap.strideBitmap = destination_locker.stride;
Expand All @@ -53,4 +59,4 @@ void CziWriter::Close()
writerMdInfo.szMetadataSize = xml.size();
writer->SyncWriteMetadata(writerMdInfo);
this->writer->Close();
}
}
57 changes: 3 additions & 54 deletions MEXlibCZI/src/CziWriter.h
Original file line number Diff line number Diff line change
@@ -1,70 +1,19 @@
#pragma once

#include "inc_libczi.h"
#include <mutex>
#include <memory>
#include <array>
#include "mexapi.h"
#include <string>

class CziWriter
{
private:
std::shared_ptr<libCZI::ICziWriter> writer;

//std::once_flag flagInfoFromCziMetadata;

//std::shared_ptr<libCZI::IDisplaySettings> displaySettingsFromCzi;
//libCZI::ScalingInfoEx scalingInfoFromCzi;

public:
CziWriter() : writer(libCZI::CreateCZIWriter())
{}

void Create(const std::string& utf8_filename, bool overwrite_existing);

void AddSubBlock(const libCZI::AddSubBlockInfoBase& add_sub_block_info_base, const std::shared_ptr<libCZI::IBitmapData>& bitmap_data);
void AddSubBlock(const libCZI::AddSubBlockInfoBase& add_sub_block_info_base, const std::shared_ptr<libCZI::IBitmapData>& bitmap_data, const std::string& subblock_metadata_xml);
void Close();
/* MexArray* GetInfo();
std::string GetMetadataXml();
MexArray* GetMetadataXmlAsMxArray();
MexArray* GetDefaultDisplaySettingsAsMxArray();
MexArray* GetSubBlockImage(int sbBlkNo);
MexArray* GetMultiChannelScalingTileComposite(const libCZI::IntRect& roi, const libCZI::IDimCoordinate* planeCoordinate, float zoom, const char* displaySettingsJson);
MexArray* GetSingleChannelScalingTileComposite(const libCZI::IntRect& roi, const libCZI::IDimCoordinate* planeCoordinate, float zoom);
MexArray* GetSingleChannelScalingTileComposite(const libCZI::IntRect& roi, const libCZI::IDimCoordinate* planeCoordinate, float zoom, const libCZI::RgbFloatColor& backgroundColor);
std::array<double, 3> GetScaling();
MexArray* GetScalingAsMatlabStruct();
MexArray* ReadSubBlock(int no);
MexArray* GetInfoFromSubBlock(int subBlkHandle);
MexArray* GetMetadataFromSubBlock(int subBlkHandle);
MexArray* GetBitmapFromSubBlock(int subBlkHandle);
bool ReleaseSubBlock(int subBlkHandle)*/;
private:
/* static MexArray* ConvertToMatlabStruct(const libCZI::IDimBounds* bounds);
/// Initializes the members "displaySettingsFromCzi" and "scalingInfoFromCzi".
void InitializeInfoFromCzi();
std::shared_ptr<libCZI::IDisplaySettings> GetDisplaySettingsFromCzi();
const libCZI::ScalingInfo& GetScalingInfoFromCzi();
MexArray* GetMultiChannelScalingTileComposite(const libCZI::IntRect& roi, const libCZI::IDimCoordinate* planeCoordinate, float zoom, const libCZI::IDisplaySettings* displaySettings);
MexArray* GetMultiChannelScalingTileCompositeAllChannelsDisabled(const libCZI::IntRect& roi, float zoom);
static MexArray* ConvertToMxArray(libCZI::IBitmapData* bitmapData);
static MexArray* ConvertToMatlabStruct(const std::map<int, libCZI::BoundingBoxes>& boundingBoxMap);
static MexArray* ConvertToMatlabStruct(const libCZI::IntRect& rect);
static MexArray* ConvertToMatlabStruct(const libCZI::IntSize& size);
static MexArray* ConvertToMatlabStruct(const libCZI::IDisplaySettings& ds);
static MexArray* ConvertToMatlabStruct(const libCZI::SubBlockInfo& sbBlkInfo);
static void CopyTransposeGray8(libCZI::IBitmapData* bitmapData, void* pDst, size_t lineLength);
static void CopyTransposeGray16(libCZI::IBitmapData* bitmapData, void* pDst, size_t lineLength);
static void CopyTransposeGrayFloat(libCZI::IBitmapData* bitmapData, void* pDst, size_t lineLength);
static void CopyTransposeInterleavedToPlanarBgr24(libCZI::IBitmapData* bitmapData, void* pDst, size_t lineStride, size_t planeStride);
static void CopyTransposeInterleavedToPlanarBgr48(libCZI::IBitmapData* bitmapData, void* pDst, size_t lineStride, size_t planeStride);
*/
};
};
30 changes: 30 additions & 0 deletions MEXlibCZI/src/argsutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,12 @@ using namespace libCZI;
return numOfElements >= minElementCount;
}

/*static*/bool CArgsUtils::IsStructure(const MexArray* pArr)
{
auto mexApi = MexApi::GetInstance();
return mexApi.MxIsStruct(pArr);
}

/*static*/bool CArgsUtils::TryGetIntRect(const MexArray* pArr, libCZI::IntRect* rect)
{
IntRect r;
Expand Down Expand Up @@ -544,4 +550,28 @@ using namespace libCZI;
}

return false;
}

/*static*/bool CArgsUtils::TryGetIntValueOfField(const MexArray* argument, const char* field_name, std::int32_t* int_value)
{
auto mexApi = MexApi::GetInstance();
const auto field = mexApi.MxGetField(argument, field_name);
if (field == nullptr)
{
return false;
}

return CArgsUtils::TryGetInt32(field, int_value);
}

/*static*/bool CArgsUtils::TryGetStringValueOfField(const MexArray* argument, const char* field_name, std::string* str)
{
auto mexApi = MexApi::GetInstance();
const auto field = mexApi.MxGetField(argument, field_name);
if (field == nullptr)
{
return false;
}

return CArgsUtils::TryGetString(field, str);
}
5 changes: 5 additions & 0 deletions MEXlibCZI/src/argsutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class CArgsUtils
static bool TryGetSingle(const MexArray* pArr, size_t index, float* ptr);

static bool IsNumericArrayOfMinSize(const MexArray* pArr, size_t minElementCount);
static bool IsStructure(const MexArray* pArr);

static bool TryGetIntRect(const MexArray* pArr, libCZI::IntRect* rect);

Expand All @@ -43,4 +44,8 @@ class CArgsUtils
///
/// \returns True if it succeeds; false otherwise.
static bool TryGetPixelType(const MexArray* argument, libCZI::PixelType* pixel_type);

static bool TryGetIntValueOfField(const MexArray* argument, const char* field_name, std::int32_t* int_value);

static bool TryGetStringValueOfField(const MexArray* argument, const char* field_name, std::string* str);
};
45 changes: 43 additions & 2 deletions MEXlibCZI/src/func_addsubblock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "CziWriterManager.h"
#include <vector>
#include <memory>
#include <optional>

#include "argsutils.h"
#include "dbgprint.h"
Expand All @@ -19,6 +20,7 @@ void MexFunction_AddSubBlock_CheckArguments(MatlabArgs* args)
// 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");
Expand All @@ -43,6 +45,30 @@ void MexFunction_AddSubBlock_CheckArguments(MatlabArgs* args)
{
throw invalid_argument("4th argument must be an integer or a string");
}

CArgsUtils::ArrayInfo array_info;
if (!CArgsUtils::TryGetArrayInfo(args->prhs[5], &array_info))
{
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]))
{
throw invalid_argument("6th argument must be a structure");
}
}
}

void MexFunction_AddSubBlock_Execute(MatlabArgs* args)
Expand Down Expand Up @@ -85,8 +111,22 @@ void MexFunction_AddSubBlock_Execute(MatlabArgs* args)
throw invalid_argument("5th argument must be an array");
}

std::optional<int> m_index;
string metadata_xml;
if (args->nrhs >= 7)
{
int i;
if (CArgsUtils::TryGetIntValueOfField(args->prhs[6], "M", &i))
{
m_index = i;
}

CArgsUtils::TryGetStringValueOfField(args->prhs[6], "metadata_xml", &metadata_xml);
}

std::shared_ptr<CziWriter> 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;
Expand All @@ -95,9 +135,10 @@ void MexFunction_AddSubBlock_Execute(MatlabArgs* args)
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.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);

writer->AddSubBlock(add_sub_block_info_base, bitmap_data, metadata_xml);
}
Empty file.
6 changes: 0 additions & 6 deletions MEXlibCZI/src/func_readsubblock.h

This file was deleted.

Loading

0 comments on commit 6292fd9

Please sign in to comment.