Skip to content
Snippets Groups Projects
czi_file.cpp 11.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • theazgra's avatar
    theazgra committed
    #include "czi_file.h"
    
    
    bool CziFile::is_master_file() const
    
    theazgra's avatar
    theazgra committed
    {
    
        return ((header.filePart == 0) && (header.fileGuid == header.masterFileGuid));
    
    theazgra's avatar
    theazgra committed
    }
    
    
    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);
    
    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);
    
    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);
    
    const char *CziFile::dimension_type_str(const Dimension &d) const
    
    {
        switch (d)
        {
        case Dimension::X:
    
        case Dimension::Y:
    
        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:
    
        case Dimension::I:
    
            return "I (illumination)";
    
        case Dimension::B:
    
            return "B (block index)";
    
        case Dimension::M:
    
        case Dimension::H:
    
        case Dimension::V:
    
            always_assert("Bad dimension type." && false);
    
    const char *CziFile::dimension_char(const Dimension &d) const
    
    theazgra's avatar
    theazgra committed
    {
    
    theazgra's avatar
    theazgra committed
        switch (d)
        {
        case Dimension::X:
    
    theazgra's avatar
    theazgra committed
        case Dimension::Y:
    
    theazgra's avatar
    theazgra committed
        case Dimension::C:
    
    theazgra's avatar
    theazgra committed
        case Dimension::Z:
    
    theazgra's avatar
    theazgra committed
        case Dimension::T:
    
    theazgra's avatar
    theazgra committed
        case Dimension::R:
    
    theazgra's avatar
    theazgra committed
        case Dimension::S:
    
    theazgra's avatar
    theazgra committed
        case Dimension::I:
    
    theazgra's avatar
    theazgra committed
        case Dimension::B:
    
    theazgra's avatar
    theazgra committed
        case Dimension::M:
    
    theazgra's avatar
    theazgra committed
        case Dimension::H:
    
    theazgra's avatar
    theazgra committed
        case Dimension::V:
    
    theazgra's avatar
    theazgra committed
            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
    
    theazgra's avatar
    theazgra committed
    {
    
        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();
    
    theazgra's avatar
    theazgra committed
    }
    
    void CziFile::report_verbose() const
    {
    
    theazgra's avatar
    theazgra committed
        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++)
        {
    
    theazgra's avatar
    theazgra committed
            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),
    
    theazgra's avatar
    theazgra committed
                   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);
            // }
    
    theazgra's avatar
    theazgra committed
            // 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;
    }
    
    
    theazgra's avatar
    theazgra committed
    void CziFile::report() const
    
    {
        printf("Loaded CZI FILE: %s\n", fileName.c_str());
    
    
    theazgra's avatar
    theazgra committed
        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);
    
    theazgra's avatar
    theazgra committed
        printf("%-25s %15i\n", "AttachmentCount", attachmentDirectory.entryCount);
    
    
    theazgra's avatar
    theazgra committed
        if (subBlockDirectory.entryCount > 0)
    
    theazgra's avatar
    theazgra committed
            {
                std::map<PixelType, int> pixelTypeMap;
                std::map<CompressionType, int> compressionMap;
                std::map<std::string, int> dimensionMap;
    
    theazgra's avatar
    theazgra committed
                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));
        }
    
    theazgra's avatar
    theazgra committed
    
        printf("==================================\n");
    
    theazgra's avatar
    theazgra committed
    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";
    
    
    theazgra's avatar
    theazgra committed
            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());
    
    theazgra's avatar
    theazgra committed
    
    
            printf("Wrote %s\n", binaryFileName.c_str());
        }
    }