Skip to content

Commit

Permalink
device adapter bug fixes and update to the latest API changes
Browse files Browse the repository at this point in the history
  • Loading branch information
nenada committed Dec 18, 2024
1 parent 48533ca commit 8d5e513
Show file tree
Hide file tree
Showing 9 changed files with 594 additions and 197 deletions.
10 changes: 10 additions & 0 deletions DeviceAdapters/go2scope/AcqZarrStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,11 @@ int AcqZarrStorage::GetCoordinate(const char* handle, int dimension, int coordin
return DEVICE_NOT_YET_IMPLEMENTED;
}

int AcqZarrStorage::GetImageCount(const char* handle, int& imgcount)
{
return DEVICE_NOT_YET_IMPLEMENTED;
}

bool AcqZarrStorage::IsOpen(const char* handle)
{
if (streamHandle.compare(handle) != 0)
Expand All @@ -515,6 +520,11 @@ bool AcqZarrStorage::IsOpen(const char* handle)
return true;
}

bool AcqZarrStorage::IsReadOnly(const char* handle)
{
return false;
}

int AcqZarrStorage::GetPath(const char* handle, char* path, int maxPathLength)
{
return 0;
Expand Down
4 changes: 3 additions & 1 deletion DeviceAdapters/go2scope/AcqZarrStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ class AcqZarrStorage : public CStorageBase<AcqZarrStorage>
int GetNumberOfDimensions(const char* handle, int& numDimensions);
int GetDimension(const char* handle, int dimension, char* name, int nameLength, char* meaning, int meaningLength);
int GetCoordinate(const char* handle, int dimension, int coordinate, char* name, int nameLength);
int GetImageCount(const char* handle, int& imgcnt);
bool IsOpen(const char* handle);
int GetPath(const char* handle, char* path, int maxPathLength);
bool IsReadOnly(const char* handle);
int GetPath(const char* handle, char* path, int maxPathLength);


// action interface
Expand Down
50 changes: 49 additions & 1 deletion DeviceAdapters/go2scope/CFileUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,52 @@ std::uint64_t readInt(const unsigned char* buff, std::uint8_t len) noexcept
ret |= xval;
}
return ret;
}
}

/**
* Split CSV line into tokens
* @param line CSV line
* @return Tokens list
*/
std::vector<std::string> splitLineCSV(const std::string& line) noexcept
{
std::vector<std::string> ret;
if(line.empty())
return ret;

std::string curr = "";
bool qopen = false;
int qcnt = 0;
for(char c : line)
{
bool endswithQ = curr.size() >= 1 && curr[curr.size() - 1] == '\"';
bool endswithS = curr.size() >= 1 && curr[curr.size() - 1] == ' ';
bool endswithEQ = curr.size() >= 2 && curr[curr.size() - 1] == '\"' && curr[curr.size() - 1] == '\\';
if(c == ',' && (!qopen || (qcnt % 2 == 0 && (endswithQ || endswithS) && !endswithEQ)))
{
if(curr.size() >= 2 && curr[0] == '\"' && curr[curr.size() - 1] == '\"')
curr = curr.substr(1, curr.size() - 2);
ret.push_back(curr);
curr = "";
qcnt = 0;
qopen = false;
}
else if(c == '"')
{
if(qcnt == 0)
qopen = true;
qcnt++;
//if(qcnt > 1 && qcnt % 2 == 1)
curr += "\"";
}
else
curr += c;
}
if(!curr.empty())
{
if(curr.size() >= 2 && curr[0] == '\"' && curr[curr.size() - 1] == '\"')
curr = curr.substr(1, curr.size() - 2);
ret.push_back(curr);
}
return ret;
}
185 changes: 184 additions & 1 deletion DeviceAdapters/go2scope/G2SBigTiffDataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <sstream>
#include <filesystem>
#include <cstring>
#include <fstream>
#include "G2SBigTiffDataset.h"
#ifdef _WIN32
#include <Windows.h>
Expand All @@ -40,6 +41,7 @@

#define G2SFOLDER_EXT ".g2s"
#define G2SFILE_EXT ".g2s.tif"
#define G2SAXISINFO_FILE "axisinfo.txt"

/**
* Class constructor
Expand Down Expand Up @@ -83,6 +85,7 @@ void G2SBigTiffDataset::create(const std::string& path, bool dio, bool fbig, std
directIo = dio;
writemode = true;
chunksize = chunksz;
bigTiff = fbig;

// Extract dataset name
std::filesystem::path basepath = std::filesystem::u8path(path);
Expand All @@ -109,7 +112,7 @@ void G2SBigTiffDataset::create(const std::string& path, bool dio, bool fbig, std
std::filesystem::create_directories(fp.parent_path(), ec);
if(ec.value() != 0)
throw std::runtime_error("Unable to create a file stream. Directory tree creation failed");
activechunk = std::make_shared<G2SBigTiffStream>(fp.u8string(), directIo);
activechunk = std::make_shared<G2SBigTiffStream>(fp.u8string(), directIo, bigTiff);
if(!activechunk)
throw std::runtime_error("Unable to create a file stream. Data chunk allocation failed");
activechunk->open(true);
Expand Down Expand Up @@ -199,6 +202,8 @@ void G2SBigTiffDataset::load(const std::string& path, bool dio)
activechunk->open(false);
activechunk->parse(datasetuid, shape, chunksize, metadata, bitdepth);
imgcounter += activechunk->getImageCount();
resetAxisInfo();
parseAxisInfo();

// Validate dataset parameters
if(activechunk->getChunkIndex() != 0)
Expand Down Expand Up @@ -241,6 +246,7 @@ void G2SBigTiffDataset::close() noexcept
{
if(writemode && datachunks.size() == 1 && datachunks[0]->isOpen())
datachunks[0]->appendMetadata(metadata);
writeAxisInfo();
for(const auto& fx : datachunks)
fx->close();
imgcounter = 0;
Expand All @@ -250,6 +256,7 @@ void G2SBigTiffDataset::close() noexcept
shape.clear();
datachunks.clear();
activechunk.reset();
axisinfo.clear();
}

/**
Expand Down Expand Up @@ -277,6 +284,11 @@ void G2SBigTiffDataset::setShape(const std::vector<std::uint32_t>& dims)
return;
}
shape = dims;

// Resize axis descriptors vector
resetAxisInfo();

// Write shape info
if(activechunk)
activechunk->writeShapeInfo(shape, chunksize);
}
Expand Down Expand Up @@ -306,6 +318,11 @@ void G2SBigTiffDataset::setShape(std::initializer_list<std::uint32_t> dims)
return;
}
shape = dims;

// Resize axis descriptors vector
resetAxisInfo();

// Write shape info
if(activechunk)
activechunk->writeShapeInfo(shape, chunksize);
}
Expand Down Expand Up @@ -389,6 +406,41 @@ void G2SBigTiffDataset::setUID(const std::string& val)
activechunk->writeDatasetUid(datasetuid);
}

/**
* Configure axis info
* If axis index is invalid this method will have no effect
* @param dim Axis index
* @param name Axis name
* @param desc Axis description
*/
void G2SBigTiffDataset::configureAxis(int dim, const std::string& name, const std::string& desc) noexcept
{
if(!writemode)
return;
if(dim < 0 || (std::size_t)dim >= axisinfo.size())
return;
axisinfo[dim].Name = name;
axisinfo[dim].Description = desc;
}

/**
* Configure axis coordinate info
* If axis / coordinate index is invalid this method will have no effect
* @param dim Axis index
* @param coord Axis coordinate index
* @param desc Coordinate description
*/
void G2SBigTiffDataset::configureCoordinate(int dim, int coord, const std::string& desc) noexcept
{
if(!writemode)
return;
if(dim < 0 || (std::size_t)dim >= axisinfo.size() - 2)
return;
if(coord < 0 || (std::size_t)coord >= axisinfo[dim].Coordinates.size())
return;
axisinfo[dim].Coordinates[coord] = desc;
}

/**
* Get dataset metadata
* If metadata is specified value will be returned from cache, otherwise it will be read from a file stream
Expand Down Expand Up @@ -512,6 +564,27 @@ std::vector<unsigned char> G2SBigTiffDataset::getImage(const std::vector<std::ui
return activechunk->getImage();
}

/**
* Check if image for the specified coordinates is already set
* @param coordinates Coordinates list
* @param numCoordinates Coordinates count
* @return Does image at the specified coordinates exists
*/
bool G2SBigTiffDataset::isCoordinateSet(int coordinates[], int numCoordinates) const noexcept
{
std::uint32_t imgind = 0;
for(int i = 0; i < numCoordinates; i++)
{
if(i >= shape.size() - 2)
break;
std::uint32_t sum = 1;
for(int j = i + 1; j < shape.size() - 2; j++)
sum *= shape[j];
imgind += sum * coordinates[i];
}
return imgind < imgcounter;
}

/**
* Change active data chunk
* This method is used only for reading data
Expand Down Expand Up @@ -709,3 +782,113 @@ void G2SBigTiffDataset::calcImageIndex(const std::vector<std::uint32_t>& coord,
}
imgind = ind;
}

/**
* Reset axis info structure
*/
void G2SBigTiffDataset::resetAxisInfo() noexcept
{
axisinfo.clear();
axisinfo.resize(shape.size());
for(std::size_t i = 0; i < shape.size() - 2; i++)
axisinfo[i].setSize((std::size_t)shape[i]);
}

/**
* Parse axis info
* Axis info is expected to be stored in a file: 'axisinfo.txt'
* @throws std::runtime_error
*/
void G2SBigTiffDataset::parseAxisInfo()
{
auto fpath = std::filesystem::u8path(dspath) / G2SAXISINFO_FILE;
if(!std::filesystem::exists(fpath) || axisinfo.empty())
return;

// Load file content
std::fstream fs(fpath.u8string(), std::ios::in);
if(!fs.is_open())
throw std::runtime_error("Unable to load axis info. Opening axis info file failed");

int ind = 0;
std::string line = "";
while(std::getline(fs, line))
{
if(line.empty())
continue;
if((std::size_t)ind >= axisinfo.size())
throw std::runtime_error("Unable to load axis info. Invalid axis info data");
std::vector<std::string> tokens = splitLineCSV(line);
if(tokens.size() < 3)
throw std::runtime_error("Unable to load axis info. Corrupted axis info, axis: " + std::to_string(ind));
std::uint32_t axisdim = 0;
try
{
axisdim = std::stoul(tokens[2]);
}
catch(std::exception& e)
{
throw std::runtime_error("Unable to load axis info. " + std::string(e.what()) + ", axis: " + std::to_string(ind));
}
if(axisinfo[ind].Coordinates.size() != axisdim || tokens.size() != (std::size_t)(3 + axisdim))
throw std::runtime_error("Unable to load axis info. Axis size missmatch, axis: " + std::to_string(ind));
axisinfo[ind].Name = tokens[0];
axisinfo[ind].Description = tokens[1];
for(std::uint32_t i = 0; i < axisdim; i++)
axisinfo[ind].Coordinates[i] = tokens[3 + i];
ind++;
}
}

/**
* Write axis info
* Axis info will be stored in a separate file: 'axisinfo.txt'
* If no axis info is defined file won't be created
* Axis info will be stored in plain text, CSV-like format
*/
void G2SBigTiffDataset::writeAxisInfo() const noexcept
{
// Check if axis info is set, and that we are in WRITE mode
if(axisinfo.empty() || !writemode)
return;

bool hasinfo = false;
for(const auto& dinf : axisinfo)
{
if(!dinf.Name.empty() || !dinf.Description.empty())
{
hasinfo = true;
break;
}
for(const auto& cinf : dinf.Coordinates)
{
if(!cinf.empty())
{
hasinfo = true;
break;
}
}
if(hasinfo)
break;
}

// If axis info is empty, but the file exists -> delete it before exiting
auto fpath = std::filesystem::u8path(dspath) / G2SAXISINFO_FILE;
if(!hasinfo)
{
return;
}

// Write data to a file
std::fstream fs(fpath.u8string(), std::ios::out | std::ios::trunc);
if(!fs.is_open())
return;
for(const auto& dinf : axisinfo)
{
fs << "\"" << dinf.Name << "\",\"" << dinf.Description << "\"," << dinf.Coordinates.size();
for(const auto& cinf : dinf.Coordinates)
fs << ",\"" << cinf << "\"";
fs << std::endl;
}
fs.close();
}
Loading

0 comments on commit 8d5e513

Please sign in to comment.