czi_file.cpp 11.84 KiB
#include "czi_file.h"
bool CziFile::is_master_file() const
{
return ((header.filePart == 0) && (header.fileGuid == header.masterFileGuid));
}
void CziFile::print_segment_header(const SegmentHeader &segmentHeader) const
{
printf("---------SegmentHeader---------\n");
printf("%-25s %15s\n", "SID", segmentHeader.sId.c_str());
printf("%-25s %15li\n", "AllocatedSize", segmentHeader.allocatedSize);
printf("%-25s %15li\n", "UsedSize", segmentHeader.usedSize);
printf("-------------------------------\n");
}
const char *CziFile::pixel_type_str(const PixelType px) const
{
switch (px)
{
case PixelType::Gray8:
return "Gray8";
case PixelType::Gray16:
return "Gray16";
case PixelType::Gray32Float:
return "Gray32Float";
case PixelType::Bgr24:
return "Bgr24";
case PixelType::Bgr48:
return "Bgr48";
case PixelType::Bgr96Float:
return "Bgr96Float";
case PixelType::Bgra32:
return "Bgra32";
case PixelType::Gray64ComplexFloat:
return "Gray64ComplexFloat";
case PixelType::Bgr192ComplexFloat:
return "Bgr192ComplexFloat";
case PixelType::Gray32:
return "Gray32";
case PixelType::Gray64:
return "Gray64";
default:
always_assert("Bad pixel type." && false);
break;
}
return nullptr;
}
const char *CziFile::pyramid_type_str(const PyramidType pt) const
{
switch (pt)
{
case PyramidType::None:
return "None";
case PyramidType::SingleSubBlock:
return "SingleSubBlock";
case PyramidType::MultiSubBlock:
return "MultiSubBlock";
break;
default:
{
always_assert("Bad pyramid type." && false);
break;
}
}
return nullptr;
}
const char *CziFile::compression_type_str(const CompressionType ct) const
{
switch (ct)
{
case CompressionType::Uncompressed:
return "Uncompressed";
case CompressionType::LZW:
return "LZW";
case CompressionType::JpgFile:
return "JpgFile";
case CompressionType::JpegXrFile:
return "JpegXrFile";
case CompressionType::Camera:
return "Camera";
case CompressionType::System:
return "System";
break;
default:
{
always_assert("Bad compression type." && false);
break;
}
}
return nullptr;
}
const char *CziFile::dimension_type_str(const Dimension &d) const
{
switch (d)
{
case Dimension::X:
return "X (width)";
case Dimension::Y:
return "Y (height)";
case Dimension::C:
return "C (channels)";
case Dimension::Z:
return "Z (Z-slices)";
case Dimension::T:
return "T (timestamps)";
case Dimension::R:
return "R (rotation)";
case Dimension::S:
return "S (scene)";
case Dimension::I:
return "I (illumination)";
case Dimension::B:
return "B (block index)";
case Dimension::M:
return "M (mosaic)";
case Dimension::H:
return "H (phase)";
case Dimension::V:
return "V (views)";
break;
default:
{
always_assert("Bad dimension type." && false);
break;
}
}
return nullptr;
}
const char *CziFile::dimension_char(const Dimension &d) const
{
std::string result;
switch (d)
{
case Dimension::X:
result = "X";
break;
case Dimension::Y:
result = "Y";
break;
case Dimension::C:
result = "C";
break;
case Dimension::Z:
result = "Z";
break;
case Dimension::T:
result = "T";
break;
case Dimension::R:
result = "R";
break;
case Dimension::S:
result = "S";
break;
case Dimension::I:
result = "I";
break;
case Dimension::B:
result = "B";
break;
case Dimension::M:
result = "M";
break;
case Dimension::H:
result = "H";
break;
case Dimension::V:
result = "V";
break;
default:
{
always_assert("Bad dimension type." && false);
break;
}
}
return result.c_str();
}
const char *CziFile::dimension_stack_str(const std::vector<DimensionEntryDV1> &dims, bool includeSize) const
{
std::string result;
for (const DimensionEntryDV1 &entry : dims)
{
result.append(dimension_char(entry.dimension) + (includeSize ? ("(" + std::to_string(entry.size) + ")-") : ""));
}
return (includeSize ? result.substr(0, result.length() - 1) : result).c_str();
}
void CziFile::report_verbose() const
{
report();
printf("==========SubBlock directory==========\n");
print_segment_header(subBlockDirectory.header);
printf("%-25s %15i\n", "EntryCount", subBlockDirectory.entryCount);
for (size_t entry = 0; entry < subBlockDirectory.entryCount; entry++)
{
printf("SubBlockId: %i\tPixelType: %s\tCompression: %s\tDimensionStack: %s\tPyramidType: %s\n",
(int)entry,
pixel_type_str(subBlockDirectory.entries[entry].pixelType),
compression_type_str(subBlockDirectory.entries[entry].compression),
dimension_stack_str(subBlockDirectory.entries[entry].dimensions, true),
pyramid_type_str(subBlockDirectory.entries[entry].pyramidType));
// printf("-------SubBlock directory entry %i-------\n", (int)entry);
// printf("%-25s %15s\n", "PixelType", pixel_type_str(subBlockDirectory.entries[entry].pixelType));
// printf("%-25s %15li\n", "FilePosition", subBlockDirectory.entries[entry].filePosition);
// printf("%-25s %15i\n", "FilePart", subBlockDirectory.entries[entry].filePart);
// printf("%-25s %15s\n", "Compression", compression_type_str(subBlockDirectory.entries[entry].compression));
// printf("%-25s %15s\n", "PyramidType", pyramid_type_str(subBlockDirectory.entries[entry].pyramidType));
// printf("%-25s %15i\n", "DimensionCount", subBlockDirectory.entries[entry].dimensionCount);
// for (size_t dim = 0; dim < subBlockDirectory.entries[entry].dimensionCount; dim++)
// {
// printf("-------SubBlock %i dimension %i-------\n", (int)entry, (int)dim);
// printf("%-25s %15s\n", "Dimension", dimension_type_str(subBlockDirectory.entries[entry].dimensions[dim].dimension));
// printf("%-25s %15i\n", "Start", subBlockDirectory.entries[entry].dimensions[dim].start);
// printf("%-25s %15i\n", "Size", subBlockDirectory.entries[entry].dimensions[dim].size);
// printf("%-25s %15i\n", "StoredSize", subBlockDirectory.entries[entry].dimensions[dim].storedSize);
// }
// printf("-----------------------------------------\n");
}
printf("======================================\n");
}
std::string byte_array_str(const std::vector<byte> &bytes)
{
std::string result = "";
for (size_t i = 0; i < bytes.size(); i++)
{
result.append(std::to_string(bytes[i]));
if (i % 4 == 0 && i != bytes.size() - 1)
result.append("-");
}
return result;
}
void CziFile::report() const
{
printf("Loaded CZI FILE: %s\n", fileName.c_str());
printf("==========Summary report==========\n");
print_segment_header(header.header);
printf("%-25s %13i.%i\n", "FileVersion", header.fileVersion.major, header.fileVersion.minor);
printf("%-25s %15i\n", "FilePart", header.filePart);
printf("%-25s %30s\n", "MasterGUID", byte_array_str(header.masterFileGuid).c_str());
printf("%-25s %30s\n", "FileGUID", byte_array_str(header.masterFileGuid).c_str());
//TODO: Replace with GUID print.
printf("%-25s %15i\n", "GUIDs are matching", are_same_vectors(header.masterFileGuid, header.fileGuid));
printf("%-25s %15i\n", "UpdatePending", header.updatePending);
printf("%-25s %15li\n", "SubblockDirPosition", header.subBlockDirectoryPosition);
printf("%-25s %15li\n", "MetadataPosition", header.metadataPosition);
printf("%-25s %15li\n", "AttachmentDirPosition", header.attachmentDirectoryPosition);
printf("%-25s %15i\n", "SubBlockCount", subBlockDirectory.entryCount);
printf("%-25s %15i\n", "AttachmentCount", attachmentDirectory.entryCount);
if (subBlockDirectory.entryCount > 0)
{
{
std::map<PixelType, int> pixelTypeMap;
std::map<CompressionType, int> compressionMap;
std::map<std::string, int> dimensionMap;
for (size_t sbId = 0; sbId < subBlockDirectory.entryCount; sbId++)
{
const DirectoryEntryDV entry = subBlockDirectory.entries[sbId];
if (pixelTypeMap.count(entry.pixelType))
pixelTypeMap[entry.pixelType]++;
else
pixelTypeMap.emplace(std::make_pair(entry.pixelType, 1));
if (compressionMap.count(entry.compression))
compressionMap[entry.compression]++;
else
compressionMap.emplace(std::make_pair(entry.compression, 1));
std::string dimStackStr = dimension_stack_str(entry.dimensions, false);
if (dimensionMap.count(dimStackStr))
dimensionMap[dimStackStr]++;
else
dimensionMap.emplace(std::make_pair(dimStackStr, 1));
}
printf("Pixel type distribution:\n");
for (auto &&ptPair : pixelTypeMap)
{
printf("\t%s %ix\n", pixel_type_str(ptPair.first), ptPair.second);
}
printf("Compression type distribution:\n");
for (auto &&ctPair : compressionMap)
{
printf("\t%s %ix\n", compression_type_str(ctPair.first), ctPair.second);
}
printf("Dimension stack distribution:\n");
for (auto &&dimPair : dimensionMap)
{
printf("\t%s %ix\n", dimPair.first.c_str(), dimPair.second);
}
}
//printf("%-25s %15i\n", "DimensionCount", subBlockDirectory.entries[0].dimensionCount);
//printf("%-25s %15s\n", "PixelType", pixel_type_str(subBlockDirectory.entries[0].pixelType));
}
printf("==================================\n");
}
std::vector<byte> CziFile::get_image_data(const int subblockId)
{
always_assert((uint)subblockId < subBlockDirectory.entries.size());
auto entry = subBlockDirectory.entries[subblockId];
always_assert(entry.width > 0 && entry.height > 0);
BinaryFileStream cziStream(fileName);
return cziStream.move_and_consume_bytes(entry.subBlock.dataLocation, entry.subBlock.dataSize);
}
void CziFile::extract_images(const std::string &baseName) const
{
BinaryFileStream cziStream(fileName);
int imageIndex = 0;
for (const DirectoryEntryDV &entry : subBlockDirectory.entries)
{
always_assert(entry.width > 0 && entry.height > 0);
auto imageBytes = cziStream.move_and_consume_bytes(entry.subBlock.dataLocation, entry.subBlock.dataSize);
std::string imageFileName = baseName + std::to_string(imageIndex++) + ".pnm";
create_image_file(imageFileName.c_str(), imageBytes, entry.pixelType, entry.width, entry.height);
}
}
void CziFile::dump_image_data(const std::string &baseName) const
{
BinaryFileStream cziStream(fileName);
int imageIndex = 0;
for (const DirectoryEntryDV &entry : subBlockDirectory.entries)
{
always_assert(entry.width > 0 && entry.height > 0);
std::string binaryFileName = baseName + std::to_string(imageIndex++) + ".bin";
auto imageBytes = cziStream.move_and_consume_bytes(entry.subBlock.dataLocation, entry.subBlock.dataSize);
std::ofstream binaryStream(binaryFileName, std::ios::binary | std::ios::out);
always_assert(binaryStream.is_open());
binaryStream.write(reinterpret_cast<const char *>(imageBytes.data()), imageBytes.size());
printf("Wrote %s\n", binaryFileName.c_str());
}
}