- update README
- fix tests - crt-static in build.rs
This commit is contained in:
@@ -1,9 +1,219 @@
|
||||
# libCZIrw-sys
|
||||
|
||||
Crate linking to [libCZIAPI](https://github.com/ZEISS/libczi).
|
||||
This crate attempts to provide save wrappers to objects and functions in libCZIAPI.
|
||||
Direct often unsafe access using pointer is available through the sys module.
|
||||
Crate linking to [libCZIAPI](https://github.com/ZEISS/libczi). This crate attempts to provide safe wrappers to objects
|
||||
and functions in libCZIAPI. Direct often unsafe access using pointer is available through the `sys` module.
|
||||
|
||||
By default, libCZIAPI will be statically linked. The feature 'dynamic' will switch it to dynamic linking.
|
||||
By default, libCZIAPI will be statically linked. The feature `dynamic` will switch it to dynamic linking.
|
||||
|
||||
This code is licensed with an MIT or APACHE 2 license, but Zeiss' libCZI which is included as a submodule has a LGPL license.
|
||||
This code is licensed with an MIT or APACHE 2 license, but Zeiss' libCZI which is included as a submodule has a LGPL
|
||||
license.
|
||||
|
||||
### Reading a CZI file
|
||||
|
||||
The typical pattern is: create a reader, open it with an input stream, and query statistics or sub-blocks:
|
||||
|
||||
```rust
|
||||
use libczirw_sys::{CziReader, Dimension, InputStream, ReaderOpenInfo};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// create the reader and a stream for the file
|
||||
let czi = CziReader::create()?;
|
||||
let stream = InputStream::create_from_file_utf8("path/to/file.czi")?;
|
||||
czi.open(ReaderOpenInfo::new(&stream))?;
|
||||
|
||||
// get the (simple) statistics about the sub-blocks
|
||||
let statistics = czi.get_statistics_simple()?;
|
||||
println!("number of sub-blocks: {}", statistics.get_sub_block_count());
|
||||
|
||||
// iterate over the dimensions that are present (Z, C, T, ...)
|
||||
let dim_bounds = statistics.get_dim_bounds();
|
||||
let dimensions = Dimension::vec_from_bitflags(dim_bounds.get_dimensions_valid());
|
||||
for (i, dim) in dimensions.iter().enumerate() {
|
||||
println!("{:?}: {}", dim, dim_bounds.get_size()[i]);
|
||||
}
|
||||
|
||||
// the bounding box of all sub-blocks
|
||||
let bbox = statistics.get_bounding_box();
|
||||
println!(
|
||||
"overall extent: {} x {} (offset {}, {})",
|
||||
bbox.get_w(),
|
||||
bbox.get_h(),
|
||||
bbox.get_x(),
|
||||
bbox.get_y()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### Reading pixel data
|
||||
|
||||
Each sub-block can be decoded into a bitmap. Locking the bitmap gives access to the raw pixels:
|
||||
|
||||
```rust
|
||||
use libczirw_sys::{CziReader, InputStream, ReaderOpenInfo};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let czi = CziReader::create()?;
|
||||
let stream = InputStream::create_from_file_utf8("path/to/file.czi")?;
|
||||
czi.open(ReaderOpenInfo::new(&stream))?;
|
||||
|
||||
// read the first sub-block and turn it into a bitmap
|
||||
let sub_block = czi.read_sub_block(0)?;
|
||||
let bitmap = sub_block.create_bitmap()?;
|
||||
let info = bitmap.get_info()?;
|
||||
println!(
|
||||
"width: {}, height: {}, pixel type: {:?}",
|
||||
info.get_width(),
|
||||
info.get_height(),
|
||||
info.get_pixel_type()?
|
||||
);
|
||||
|
||||
// locking gives access to the raw pixel data
|
||||
let locked = bitmap.lock()?;
|
||||
let stride = locked.lock_info.get_stride();
|
||||
let pixels = locked.lock_info.get_data_roi(); // copies the pixel bytes
|
||||
|
||||
// the bitmap is automatically unlocked when `locked` goes out of scope
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### Reading the metadata
|
||||
|
||||
CZI files store metadata as an XML document, which can be retrieved as a string:
|
||||
|
||||
```rust
|
||||
use libczirw_sys::{CziReader, InputStream, ReaderOpenInfo};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let czi = CziReader::create()?;
|
||||
let stream = InputStream::create_from_file_utf8("path/to/file.czi")?;
|
||||
czi.open(ReaderOpenInfo::new(&stream))?;
|
||||
|
||||
let metadata_segment = czi.get_metadata_segment()?;
|
||||
let xml = metadata_segment.get_metadata_as_xml()?;
|
||||
let xml: String = (&xml).try_into()?;
|
||||
println!("{}", xml);
|
||||
|
||||
// document-level information (title, user, creation date, ...) as JSON
|
||||
let doc_info = metadata_segment.get_czi_document_info()?;
|
||||
let general_info = doc_info.get_general_document_info()?;
|
||||
println!("{}", general_info);
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### Reading attachments
|
||||
|
||||
Attachments hold additional data (e.g. microscope setup or experiment info) and are decoded based on their content type:
|
||||
|
||||
```rust
|
||||
use libczirw_sys::{AttachmentData, CziReader, InputStream, ReaderOpenInfo};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let czi = CziReader::create()?;
|
||||
let stream = InputStream::create_from_file_utf8("path/to/file.czi")?;
|
||||
czi.open(ReaderOpenInfo::new(&stream))?;
|
||||
|
||||
for index in 0..czi.get_attachment_count()? {
|
||||
let info = czi.get_attachment_info_from_directory(index)?;
|
||||
println!(
|
||||
"attachment '{}' of type {}",
|
||||
info.get_name()?,
|
||||
info.get_content_file_type()?
|
||||
);
|
||||
|
||||
let attachment = czi.read_attachment(index)?;
|
||||
match attachment.get_data()? {
|
||||
AttachmentData::Float(values) => println!(" floats: {:?}", values),
|
||||
AttachmentData::Xml(xml) => println!(" xml: {}", &xml[..xml.len().min(100)]),
|
||||
AttachmentData::Unknown(bytes) => println!(" raw bytes: {}", bytes.len()),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### Writing a CZI file
|
||||
|
||||
Create a writer, add sub-blocks and metadata, and close the file to finalize it:
|
||||
|
||||
```rust
|
||||
use libczirw_sys::{
|
||||
AddSubBlockInfo, Coordinate, CziWriter, OutputStream, PixelType, WriteMetadataInfo,
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let writer = CziWriter::create(r#"{"allow_duplicate_subblocks": true}"#)?;
|
||||
let stream = OutputStream::create_for_file_utf8("output.czi", true)?;
|
||||
writer.init(&stream, r#"{"minimum_m_index": 0, "maximum_m_index": 0}"#)?;
|
||||
|
||||
// a single gray-8-bit sub-block of 100 x 100 pixels
|
||||
let width = 100;
|
||||
let height = 100;
|
||||
let pixels: Vec<u8> = (0..(width * height)).map(|i| i as u8).collect();
|
||||
|
||||
// bit 0 => dimension Z is valid (Z is the first dimension, value 1);
|
||||
// the Z coordinate of this sub-block is 0
|
||||
let coordinate = Coordinate::new(1 << 0, [0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
let sub_block = AddSubBlockInfo::new(
|
||||
coordinate,
|
||||
0, // m_index_valid
|
||||
0, // m_index
|
||||
0, // x
|
||||
0, // y
|
||||
width, // logical width
|
||||
height, // logical height
|
||||
width, // physical width
|
||||
height, // physical height
|
||||
PixelType::Gray8,
|
||||
0, // compression mode (none)
|
||||
&pixels, // raw pixel data
|
||||
b"", // sub-block metadata
|
||||
b"", // attachment data
|
||||
);
|
||||
writer.add_sub_block(sub_block)?;
|
||||
|
||||
let xml_metadata = br#"<?xml version="1.0" encoding="utf-8"?>
|
||||
<ImageDocument>
|
||||
<Metadata>
|
||||
<Information>
|
||||
<Title>My document</Title>
|
||||
</Information>
|
||||
</Metadata>
|
||||
</ImageDocument>"#;
|
||||
writer.write_metadata(WriteMetadataInfo::new(xml_metadata))?;
|
||||
|
||||
// finalize the file - required to produce a valid CZI
|
||||
writer.close()?;
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### Version and build information
|
||||
|
||||
```rust
|
||||
use libczirw_sys::{LibCZIBuildInformation, LibCZIVersionInfo};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let version = LibCZIVersionInfo::get_lib_czi_version_info()?;
|
||||
println!(
|
||||
"libCZI version {}.{}.{}",
|
||||
version.get_major(),
|
||||
version.get_minor(),
|
||||
version.get_patch()
|
||||
);
|
||||
|
||||
let build_info = LibCZIBuildInformation::get()?;
|
||||
println!("compiler: {}", build_info.get_compiler_information());
|
||||
println!("repository: {}", build_info.get_repository_url());
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## Error handling
|
||||
|
||||
All fallible operations return a `Result` with the crate's `Error` type, which maps libCZIAPI error codes onto
|
||||
descriptive variants (see `src/error.rs`). The `?` operator can be used directly; conversions from UTF-8 and
|
||||
null-termination errors are provided via `From` implementations on the error type.
|
||||
|
||||
Reference in New Issue
Block a user