Skip to content

Repository files navigation

csif: Andor SIF Parser in C

A high-performance C library for reading Andor Technology SIF (Multi-Channel File) format files. Provides efficient access to scientific image and spectral data from Andor cameras and spectrographs.

Node.js integration is supported now.

Features

  • 🚀 High Performance: Pure C implementation for fast data loading
  • 📊 Complete Data Access: Read image data, calibration coefficients, and metadata
  • 🔧 Flexible Output Control: Configurable verbosity levels for different use cases
  • 📈 Calibration Support: Extracts and processes calibration data for accurate measurements
  • 🌐 Node.js Integration: High-performance Node.js addon for JavaScript applications
  • 📦 Multiple Output Formats: JSON output for web applications and data analysis

Project Structure

$ tree . -L 3
.
├── build
│ ├── bin
│ │ ├── debug_detail_sif # Independent debug tool
│ │ ├── debug_sif # Dependent debug tool 
│ │ └── read_sif # Main example executable
│ ├── lib
│ │ ├── libsifparser.a # Static library
│ │ └── libsifparser.so*# Shared library
│ └── Release
│ └── sifaddon.node # Node.js addon
├── include
│ ├── sif_parser.h # Main parsing library
│ ├── sif_utils.h # Utility functions
│ └── sif_json.h # JSON output functions
└── src
├── sif_parser.c # Core parsing implementation
├── sif_utils.c # Utility implementations
├── sif_json.c # JSON output implementation
├── binding.cc # Node.js addon binding
└── main.c # Example usage

Quick Start

Building the Library

C Library (CMake)

# Clone and build
git clone <repository-url>cd csif
mkdir build &&cd build
cmake ..
make -j4

Node.js Addon (npm)

# Build Node.js addon
npm install
npm run build
# Or manually with node-gyp
npx node-gyp configure
npx node-gyp build

Basic Usage

#include"sif_parser.h"intmain() {
SifFilesif_file;
// Open and parse SIF fileif (sif_open_file("data.sif", &sif_file) ==0) {
// Access image datafloat*frame_data=sif_get_frame_data(&sif_file, 0);
// Get calibration dataintcalib_size;
double*calibration=retrieve_calibration(&sif_file.info, &calib_size);
// Clean upsif_close(&sif_file);
}
return0;
}

Command Line Tools

# Basic file reading
./bin/read_sif /path/to/your/file.sif
# Quiet mode (only essential output)
./bin/read_sif /path/to/file.sif -q
# Verbose mode (detailed parsing info)
./bin/read_sif /path/to/file.sif -v
# Debug mode (all internal information)
./bin/read_sif /path/to/file.sif -d

Output Levels

LevelDescriptionUse Case
SIF_SILENT (0)No output except errorsBatch processing
SIF_QUIET (1)Essential results onlyIntegration
SIF_NORMAL (2)Basic progress informationDefault
SIF_VERBOSE (3)Detailed parsing processDebugging
SIF_DEBUG (4)All internal informationDevelopment

API Overview

Core Functions

// File operationsintsif_open_file(constchar*filename, SifFile*sif_file);
intsif_open(FILE*fp, SifFile*sif_file);
voidsif_close(SifFile*sif_file);
// Data accessfloat*sif_get_frame_data(SifFile*sif_file, intframe_index);
intsif_load_all_frames(SifFile*sif_file, intbyte_swap);
// Calibrationdouble*retrieve_calibration(SifInfo*info, int*calibration_size);
// Output controlvoidsif_set_verbose_level(SifVerboseLevellevel);

Key Data Structures

typedefstruct {
chardetector_type[64];
intnumber_of_frames;
intimage_width, image_height;
floatexposure_time;
doublecalibration_coefficients[MAX_CALIBRATION_COEFFS];
intcalibration_coeff_count;
// ... more fields
} SifInfo;
typedefstruct {
SifInfoinfo;
SifTile*tiles;
inttile_count;
FILE*file_ptr;
} SifFile;

Examples

Reading Image Data

SifFilesif_file;
if (sif_open_file("spectrum.sif", &sif_file) ==0) {
printf("Image size: %dx%d, Frames: %d\n", sif_file.info.image_width, sif_file.info.image_height,
sif_file.info.number_of_frames);
// Load all framesif (sif_load_all_frames(&sif_file, 0) ==0) {
float*frame0=sif_get_frame_data(&sif_file, 0);
// Process frame datafor (inti=0; i<10; i++) {
printf("Pixel %d: %.1f\n", i, frame0[i]);
}
}
sif_close(&sif_file);
}

JSON Output (C)

SifFilesif_file;
if (sif_open_file("spectrum.sif", &sif_file) ==0) {
JsonOutputOptionsopts= {
.pretty_print=1,
.include_metadata=1,
.include_calibration=1,
.include_raw_data=1
};
char*json_str=sif_file_to_json(&sif_file, opts);
if (json_str) {
printf("JSON Output:\n%s\n", json_str);
free(json_str);
}
sif_close(&sif_file);
}

Node.js Integration

constsifParser=require('./build/Release/sifaddon.node');classSpectrumAnalyzer{staticparseFile(filename){try{constjsonString=sifParser.sifFileToJson(filename);constdata=JSON.parse(jsonString);return{intensities: data.data,wavelengths: this.calculateWavelengths(data),metadata: data.metadata,calibration: data.calibration};}catch(error){thrownewError(`Failed to parse SIF file: ${error.message}`);}}staticcalculateWavelengths(data){if(data.calibration&&data.calibration.coefficients){constcoeffs=data.calibration.coefficients;returndata.data.map((_,i)=>{// Polynomial calibration: λ = c0 + c1*x + c2*x² + c3*x³constx=i;returncoeffs[0]+coeffs[1]*x+coeffs[2]*x*x+coeffs[3]*x*x*x;});}returnnull;}}// Usageconstspectrum=SpectrumAnalyzer.parseFile('spectrum.sif');console.log('Peak intensity:',Math.max(...spectrum.intensities));console.log('Data points:',spectrum.intensities.length);

Working with Calibration Data

intcalib_size;
double*calibration=retrieve_calibration(&sif_file.info, &calib_size);
if (calibration) {
printf("Calibration coefficients: %d\n", sif_file.info.calibration_coeff_count);
if (sif_file.info.has_frame_calibrations) {
printf("Frame-specific calibration available\n");
} else {
printf("Global calibration data:\n");
for (inti=0; i<5&&i<calib_size; i++) {
printf(" [%d] = %f\n", i, calibration[i]);
}
}
free(calibration);
}

Javascript Integration by Node Addon

Compiling the c code to a node addon will enable JS applications call c sif parsing with intrinsic C performance, but some details need to be considered

Here, I had attempted to integrate C sif parser into a web/desktop application by several methods:

  • children process to output JSON
  • node addon to process data
    • binary Arraybuffer to output JSON (let sifParser.js to parse JSON again)
    • binary Arraybuffer to TypedArray (this type conversion operation is resource-intensive)
    • binary Arraybuffer shared to JS

The last approach will be memory efficient and reduce resource expenses in JS.

Memeory Mapping

For example, a sif of 2500 frames, whose image sensor size is of 1 x 1240, will have 2500 x 1240 = 2560,000 data point. The light intensity, originally a 16-bit integer, is stored as a floating-point value here in sif format though it is stupid not efficient in memory arrangement.

In binding.cc

// crate binary data uinsg Float32Arraysize_t buffer_size = total_data_points * sizeof(float); //every data point occupies a float
Napi::ArrayBuffer array_buffer = Napi::ArrayBuffer::New(env, buffer_size); //initialize arraybuffer of a continuous memmory of buffer_size in size in JS with Napifloat* buffer_data = static_cast<float*>(array_buffer.Data()); // claim a pointer pointing towards the initial position of array_buffer (array_buffer.Data() return void* so it needs static_cast to float pointer)// direct copymemcpy(buffer_data, sif_file.frame_data, buffer_size);
// create Float32Array
Napi::TypedArray binary_data = Napi::TypedArrayOf<float>::New(env, total_data_points, array_buffer, 0, napi_float32_array);
...
ArrayBuffer (10,240,000 bytes = 2,560,000 × 4)
┌──────────────────────────────────────────────────────────────────────┐
│ bytes 0-3 │ bytes 4-7 │ bytes 8-11 │ ... │ bytes 10239996-10239999 │
│ float[0] │ float[1] │ float[2] │ ... │ float[2559999] │
└──────────────────────────────────────────────────────────────────────┘
↑ ↑ ↑ ↑
Float32Array view (2,560,000 elements)
┌──────────────┬──────────────┬──────────────┬───┬─────────────────────┐
│ element[0] │ element[1] │ element[2] │...│ element[2559999] │
└──────────────┴──────────────┴──────────────┴───┴─────────────────────┘

so this can let JS process the spectrum data from the memory read/parsed by C.

Compile with N-API

Remember to have node-gyp tool

sudo npm install -g node-gyp

and include napi header file in the binding.cc,

#if there is 'build' by CMakeLists
mv build build_cmake_backup
mkdir build
npx node-gyp configure
npx node-gyp build

finally, your would see a addon appears under the build/Release

If anything changed, then do

rm -rf build
npx node-gyp clean
npx node-gyp configure
npx node-gyp build

Load the node addon

First, let your electron app or web app to load this node addon correctly.

Just follow the example of test_complete.jsor the example in the previous section

Have fun!

Debug Tools

debug_detail_sif

  • Independent debugging tool
  • Direct file analysis without library dependencies
  • Raw file structure examination

debug_sif

  • Library-dependent debug tool
  • Tests parsing functionality
  • Internal state inspection

Installation

System-wide Installation

cd build
sudo make install

Using in Your Project

CMake Integration

# CMakeLists.txtfind_library(SIFPARSER_LIBsifparser)
target_link_libraries(your_target${SIFPARSER_LIB})

Node.js Integration

# Install from local path
npm install /path/to/csif
# Or link for developmentcd /path/to/csif
npm link
cd /path/to/your-project
npm link sif-parser

Performance Comparison

MethodPerformanceUse Case
Node.js Addon🚀 HighestElectron apps, web services
C Library🚀 HighNative applications, CLI tools
CLI + Subprocess🐢 LowerLegacy integration
  • ✅ Andor SIF format versions including 65567, 65540
  • ✅ Multi-frame data
  • ✅ Calibration data extraction
  • ✅ Subimage and binning information
  • ✅ Timestamp data
  • ✅ User text metadata
  • ✅ JSON output for web applications

License

This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.

Contributing

Fork the repository

Create a feature branch (git checkout -b feature/amazing-feature)

Commit your changes (git commit -m 'Add amazing feature')

Push to the branch (git push origin feature/amazing-feature)

Open a Pull Request

Development

Building for Development

# C library development
mkdir build &&cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
# Node.js addon development
npm run clean && npm run build
# Testing
npm test
./bin/read_sif test_data/example.sif

Project Architecture

  • Core Parser (sif_parser.c): Low-level SIF file parsing

  • JSON Output (sif_json.c): Structured data serialization

  • Node.js Binding (binding.cc): V8/N-API integration

  • CLI Tools: Example applications and debugging utilities

Citation

If you use this library in your research, please cite:

@software{csif_parser,
title = {csif: Andor SIF Parser in C},
author = {Tim},
year = {2025},
url = {https://github.com/mithgil/csif}
}

Support

For bug reports and feature requests, please open an issue on GitHub.


csif - Efficient Andor SIF file parsing in pure C.

About

A high-performance C library for reading Andor Technology SIF (Multi-Channel File) format files. Provides efficient access to scientific image and spectral data from Andor cameras and spectrographs. csif parser can be implemented in a node.js app.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages