#![allow(dead_code)]
use std::fs::OpenOptions;
use std::path::Path;
use std::mem;
use std::ops;
use anyhow::Error;
use log::{debug, info};
use crate::taggroup_entries::{Key, Tag, TagGroup};
use crate::dmtypes::{SORTED, OPEN};
use crate::dmreader::DMImageReader;
use crate::dmwriter::{DMImageWriter, DMImageWriteByVersion};
mod dmreader;
mod dmwriter;
mod dmtypes;
mod taggroup_entries;
mod create_tgs;
#[cfg(test)]
mod tests;
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, Error>;
#[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 {
Tag::ULong(sizex) => sizex as usize,
_ => 0usize,
}
}
#[inline]
pub fn sizey(&self) -> usize {
match self.sizey {
Tag::ULong(sizey) => sizey as usize,
_ => 0usize,
}
}
#[inline]
pub fn sizez(&self) -> usize {
match self.sizez {
Tag::ULong(sizey) => sizey as usize,
_ => 0usize,
}
}
pub fn shape(&self) -> Vec<usize> {
let mut shape: Vec<usize> = Vec::new();
match self.sizex {
Tag::ULong(sizex) => shape.push(sizex as usize),
_ => return shape,
}
match self.sizey {
Tag::ULong(sizey) => shape.push(sizey as usize),
_ => return shape,
}
match self.sizez {
Tag::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 {
Tag::ArrayFloat(ref array) => array,
_ => panic!("Inconsistent data, exiting..."),
}
}
#[inline]
pub fn data_mut(&mut self) -> &mut Vec<f32> {
match self.data {
Tag::ArrayFloat(ref mut array) => array,
_ => panic!("Inconsistent data, exiting..."),
}
}
pub fn new(shape: &[usize]) -> DMImage {
info!("Called dm3io::DMImage::new()");
let mut image = DMImage {
path: None,
root: TagGroup::new(SORTED, !OPEN),
data: Tag::Empty,
sizex: Tag::Empty,
sizey: Tag::Empty,
sizez: Tag::Empty,
version: 3usize,
tg_size: 0usize,
bigendian: false,
};
image.root.insert(
Key::from_str("ApplicationBounds"),
Tag::Struct(vec![Tag::Long(0), Tag::Long(0), Tag::Long(944), Tag::Long(1524)]),
);
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"),
Tag::TagGroupEntry(dt),
);
image.root.insert(
Key::from_str("HasWindowPosition"),
Tag::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"),
Tag::Boolean(false),
);
image.root.insert(
Key::from_str("LayoutType"),
Tag::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 {
Tag::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(&Key::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(&Key::Index(1))
.unwrap()
.get_mut("ImageData")
.unwrap()
.get_mut("Dimensions")
.unwrap()
.get_tag_mut(&Key::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(&Key::Index(1))
.unwrap()
.get_mut("ImageData")
.unwrap()
.get_mut("Dimensions")
.unwrap()
.get_tag_mut(&Key::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(&Key::Index(1))
.unwrap()
.get_mut("ImageData")
.unwrap()
.get_mut("Dimensions")
.unwrap()
.get_tag_mut(&Key::Index(2))
{
mem::swap(&mut self.sizez, tg_sizez);
};
}
}