#![allow(dead_code)]
extern crate byteorder;
#[macro_use]
extern crate log;
mod dmreader;
mod dmwriter;
mod dmtypes;
mod taggroup_entries;
mod create_tgs;
#[cfg(test)]
mod tests;
use std::fs::OpenOptions;
use std::path::Path;
use std::mem;
use std::ops;
use taggroup_entries::{Key, Tag, TagGroup};
use taggroup_entries::Key::*;
use taggroup_entries::Tag::*;
use dmtypes::{SORTED, OPEN};
use dmreader::DMImageReader;
use dmwriter::{DMImageWriter, DMImageWriteByVersion};
pub type DM3Reader = dmtypes::DM3Reader;
pub type DM4Reader = dmtypes::DM4Reader;
pub type DM3Writer = dmtypes::DM3Writer;
pub type DM4Writer = dmtypes::DM4Writer;
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
#[derive(Debug, Default)]
pub struct DMImage {
path: Option<String>,
root: TagGroup,
data: Tag,
sizex: Tag,
sizey: Tag,
sizez: Tag,
version: usize,
tg_size: usize,
bigendian: bool,
}
impl ops::Index<[usize; 3]> for DMImage {
type Output = f32;
fn index(&self, index: [usize; 3]) -> &f32 {
let z_offset = index[2] * self.sizex() * self.sizey();
let y_offset = index[1] * self.sizex();
let x_offset = index[0];
&self.data()[z_offset + y_offset + x_offset]
}
}
impl ops::IndexMut<[usize; 3]> for DMImage {
fn index_mut(&mut self, index: [usize; 3]) -> &mut f32 {
let z_offset = index[2] * self.sizex() * self.sizey();
let y_offset = index[1] * self.sizex();
let x_offset = index[0];
&mut self.data_mut()[z_offset + y_offset + x_offset]
}
}
impl ops::Index<[usize; 2]> for DMImage {
type Output = f32;
fn index(&self, index: [usize; 2]) -> &f32 {
let y_offset = index[1] * self.sizex();
let x_offset = index[0];
&self.data()[y_offset + x_offset]
}
}
impl ops::IndexMut<[usize; 2]> for DMImage {
fn index_mut(&mut self, index: [usize; 2]) -> &mut f32 {
let y_offset = index[1] * self.sizex();
let x_offset = index[0];
&mut self.data_mut()[y_offset + x_offset]
}
}
impl DMImage {
pub fn ind(&self, x: usize, y: usize, z: usize) -> &f32 {
let z_offset = z * self.sizex() * self.sizey();
let y_offset = y * self.sizex();
let x_offset = x;
&self.data()[z_offset + y_offset + x_offset]
}
#[inline]
pub fn sizex(&self) -> usize {
match self.sizex {
ULong(sizex) => sizex as usize,
_ => 0usize,
}
}
#[inline]
pub fn sizey(&self) -> usize {
match self.sizey {
ULong(sizey) => sizey as usize,
_ => 0usize,
}
}
#[inline]
pub fn sizez(&self) -> usize {
match self.sizez {
ULong(sizey) => sizey as usize,
_ => 0usize,
}
}
pub fn shape(&self) -> Vec<usize> {
let mut shape: Vec<usize> = Vec::new();
match self.sizex {
ULong(sizex) => shape.push(sizex as usize),
_ => return shape,
}
match self.sizey {
ULong(sizey) => shape.push(sizey as usize),
_ => return shape,
}
match self.sizez {
ULong(sizez) => shape.push(sizez as usize),
_ => return shape,
}
shape
}
#[inline]
pub fn is_bigendian(&self) -> bool {
self.bigendian
}
#[inline]
pub fn data(&self) -> &Vec<f32> {
match self.data {
ArrayFloat(ref array) => array,
_ => panic!("Inconsistent data, exiting..."),
}
}
#[inline]
pub fn data_mut(&mut self) -> &mut Vec<f32> {
match self.data {
ArrayFloat(ref mut array) => array,
_ => panic!("Inconsistent data, exiting..."),
}
}
pub unsafe fn replace_data_with(&mut self, new_data: Vec<f32>, shape: &[usize]) -> Result<()> {
match self.data {
ArrayFloat(ref mut array) => {
mem::replace(array, new_data);
}
_ => {
return Err(From::from(
"Error while replacing the image data, operation not performed...",
))
}
}
self.swap_data();
for (dim_ind, &size) in shape.iter().enumerate() {
match *self.root
.get_mut("ImageList").unwrap()
.get_tag_mut(&Key::Index(1)).unwrap()
.get_mut("ImageData").unwrap()
.get_mut("Dimensions").unwrap() {
TagGroupEntry(ref mut tg) => {
let _ = tg.insert(Index(dim_ind), ULong(size as u32));
}
_ => return Err(From::from("Unexpected tag type for 'Dimensions'")),
}
}
self.swap_data();
Ok(())
}
pub fn new(shape: &[usize]) -> DMImage {
info!("Called dm3io::DMImage::new()");
let mut image = DMImage {
path: None,
root: TagGroup::new(SORTED, !OPEN),
data: Empty,
sizex: Empty,
sizey: Empty,
sizez: Empty,
version: 3usize,
tg_size: 0usize,
bigendian: false,
};
let app_bounds = Struct(vec![Long(0), Long(0), Long(944), Long(1524)]);
image.root.insert(
Key::from_str("ApplicationBounds"),
app_bounds,
);
image.root.insert(
Key::from_str("DocumentObjectList"),
create_tgs::document_object_list(),
);
let dt = TagGroup::new(SORTED, !OPEN);
image.root.insert(
Key::from_str("DocumentTags"),
TagGroupEntry(dt),
);
image.root.insert(
Key::from_str("HasWindowPosition"),
Boolean(false),
);
image.root.insert(
Key::from_str("Image Behavior"),
create_tgs::image_behavior(),
);
let image_type = 2u32;
image.root.insert(
Key::from_str("ImageList"),
create_tgs::image_list(shape, image_type),
);
image.root.insert(
Key::from_str("ImageSourceList"),
create_tgs::image_source_list(),
);
image.root.insert(
Key::from_str("InImageMode"),
Boolean(false),
);
image.root.insert(
Key::from_str("LayoutType"),
ArrayUShort(vec![85, 110, 107, 110, 111, 119, 110]),
);
image.root.insert(
Key::from_str("Thumbnails"),
create_tgs::thumbnails(),
);
image.swap_data();
image
}
pub fn open(filepath: &str) -> Result<DMImage> {
debug!("DMImage::open({})", filepath);
let path = Path::new(filepath);
let file = OpenOptions::new().read(true).open(path)?;
let mut reader = DMImageReader::new(file)?;
let mut image = reader.parse()?;
image.swap_data();
Ok(image)
}
pub fn save_as<R: DMImageWriteByVersion>(&mut self, filepath: &str) -> Result<()> {
debug!("DMImage::save_as({})", filepath);
let path = Path::new(filepath);
let mut options = OpenOptions::new();
let file = options.create(true).write(true).truncate(true).open(path)?;
self.swap_data();
{
let mut writer = DMImageWriter::from(self);
writer.write_to_file::<R>(file)?;
}
self.swap_data();
Ok(())
}
pub fn get_min(&self) -> f32 {
let mut min = self.data()[0];
for val in self.data() {
if *val < min {
min = *val
}
}
min
}
pub fn get_max(&self) -> f32 {
let mut max = self.data()[0];
for val in self.data() {
if *val > max {
max = *val
}
}
max
}
pub fn to_raw_rgb(&self) -> Vec<u8> {
match self.data {
ArrayFloat(_) => {
const RGB_BITS: usize = 3;
const DEPTH: f32 = 255.0;
let mut buf = Vec::with_capacity(self.sizex()*self.sizey()*RGB_BITS);
let min_val = self.get_min();
let max_val = self.get_max();
let slot = if (max_val - min_val).abs() < std::f32::EPSILON {
(max_val - min_val) / DEPTH
} else {
1f32
};
for val in self.data() {
let temp = (val - min_val) / slot;
let grayvalue = temp.trunc() as u8;
buf.push(grayvalue);
buf.push(grayvalue);
buf.push(grayvalue);
}
buf
},
_ => panic!("Inconsistent data in `DMImage::to_raw_data()`"),
}
}
fn swap_data(&mut self) {
match self.root
.get_mut("ImageList")
.unwrap()
.get_tag_mut(&Index(1))
.unwrap()
.get_mut("ImageData")
.unwrap()
.get_mut("Data") {
Some(ref mut tg_data) => mem::swap(&mut self.data, tg_data),
None => panic!("Inconsistent data, exiting..."),
}
if let Some(ref mut tg_sizex) =
self.root
.get_mut("ImageList")
.unwrap()
.get_tag_mut(&Index(1))
.unwrap()
.get_mut("ImageData")
.unwrap()
.get_mut("Dimensions")
.unwrap()
.get_tag_mut(&Index(0))
{
mem::swap(&mut self.sizex, tg_sizex);
};
if let Some(ref mut tg_sizey) =
self.root
.get_mut("ImageList")
.unwrap()
.get_tag_mut(&Index(1))
.unwrap()
.get_mut("ImageData")
.unwrap()
.get_mut("Dimensions")
.unwrap()
.get_tag_mut(&Index(1))
{
mem::swap(&mut self.sizey, tg_sizey);
}
if let Some(ref mut tg_sizez) =
self.root
.get_mut("ImageList")
.unwrap()
.get_tag_mut(&Index(1))
.unwrap()
.get_mut("ImageData")
.unwrap()
.get_mut("Dimensions")
.unwrap()
.get_tag_mut(&Index(2))
{
mem::swap(&mut self.sizez, tg_sizez);
};
}
}