use std::io::{Result, Error, ErrorKind, Read, Seek, SeekFrom};
use std::path::Path;
use std::fs::File;
use num::FromPrimitive;
use byteorder::{ReadBytesExt, ByteOrder, BigEndian, LittleEndian};
use lowlevel::{TIFFByteOrder, TIFFTag, BYTE, SBYTE, SHORT, SSHORT, LONG, SLONG, FLOAT,
TagType, TagValue, tag_size};
use tiff::{TIFF, IFD, IFDEntry, decode_tag, decode_tag_type};
pub trait SeekableReader: Seek + Read {}
impl<T: Seek + Read> SeekableReader for T {}
pub struct TIFFReader;
impl TIFFReader {
pub fn load(&self, filename: &str) -> Result<Box<TIFF>> {
let filepath = Path::new(filename);
let mut reader = File::open(&filepath)?;
self.read(&mut reader)
}
pub fn read(&self, reader: &mut SeekableReader) -> Result<Box<TIFF>> {
match self.read_byte_order(reader)? {
TIFFByteOrder::LittleEndian => self.read_tiff::<LittleEndian>(reader),
TIFFByteOrder::BigEndian => self.read_tiff::<BigEndian>(reader),
}
}
pub fn read_byte_order(&self, reader: &mut SeekableReader) -> Result<TIFFByteOrder> {
match TIFFByteOrder::from_u16(reader.read_u16::<LittleEndian>()?) {
Some(TIFFByteOrder::LittleEndian) => Ok(TIFFByteOrder::LittleEndian),
Some(TIFFByteOrder::BigEndian) => Ok(TIFFByteOrder::BigEndian),
None => Err(Error::new(ErrorKind::Other, format!("Invalid byte order in header."))),
}
}
fn read_tiff<T: ByteOrder>(&self, reader: &mut SeekableReader) -> Result<Box<TIFF>> {
self.read_magic::<T>(reader)?;
let ifd_offset = self.read_ifd_offset::<T>(reader)?;
let ifd = self.read_IFD::<T>(reader, ifd_offset)?;
let image_data = self.read_image_data::<T>(reader, &ifd)?;
Ok(Box::new(TIFF {
ifds: vec![ifd],
image_data,
}))
}
fn read_magic<T: ByteOrder>(&self, reader: &mut SeekableReader) -> Result<()> {
match reader.read_u16::<T>()? {
42 => Ok(()),
_ => Err(Error::new(ErrorKind::Other, "Invalid magic number in header")),
}
}
pub fn read_ifd_offset<T: ByteOrder>(&self, reader: &mut SeekableReader) -> Result<u32> {
let ifd_offset_field = reader.read_u32::<T>()?;
Ok(ifd_offset_field)
}
#[allow(non_snake_case)]
fn read_IFD<T: ByteOrder>(&self, reader: &mut SeekableReader, ifd_offset: u32) -> Result<IFD> {
reader.seek(SeekFrom::Start(ifd_offset as u64))?;
let entry_count = reader.read_u16::<T>()?;
let mut ifd = IFD { count: entry_count, entries: Vec::with_capacity(entry_count as usize) };
for entry_number in 0..entry_count as usize {
let entry = self.read_tag::<T>(ifd_offset as u64 + 2, entry_number, reader);
match entry {
Ok(e) => ifd.entries.push(e),
Err(err) => println!("Invalid tag at index {}: {}", entry_number, err),
}
}
Ok(ifd)
}
fn read_n(&self, reader: &mut SeekableReader, bytes_to_read: u64) -> Vec<u8> {
let mut buf = Vec::with_capacity(bytes_to_read as usize);
let mut chunk = reader.take(bytes_to_read);
let status = chunk.read_to_end(&mut buf);
match status {
Ok(n) => assert_eq!(bytes_to_read as usize, n),
_ => panic!("Didn't read enough"),
}
buf
}
fn vec_to_tag_value<Endian: ByteOrder>(&self, vec: Vec<u8>, tpe: &TagType) -> TagValue {
let len = vec.len();
match tpe {
&TagType::ByteTag => TagValue::ByteValue(vec[0]),
&TagType::ASCIITag => TagValue::AsciiValue(String::from_utf8_lossy(&vec).to_string()),
&TagType::ShortTag => TagValue::ShortValue(Endian::read_u16(&vec[..])),
&TagType::LongTag => TagValue::LongValue(Endian::read_u32(&vec[..])),
&TagType::RationalTag => TagValue::RationalValue((Endian::read_u32(&vec[..(len / 2)]),
Endian::read_u32(&vec[(len / 2)..]))),
&TagType::SignedByteTag => TagValue::SignedByteValue(vec[0] as i8),
&TagType::SignedShortTag => TagValue::SignedShortValue(Endian::read_i16(&vec[..])),
&TagType::SignedLongTag => TagValue::SignedLongValue(Endian::read_i32(&vec[..])),
&TagType::SignedRationalTag => TagValue::SignedRationalValue((Endian::read_i32(&vec[..(len / 2)]),
Endian::read_i32(&vec[(len / 2)..]))),
&TagType::FloatTag => TagValue::FloatValue(Endian::read_f32(&vec[..])),
&TagType::DoubleTag => TagValue::DoubleValue(Endian::read_f64(&vec[..])),
&TagType::UndefinedTag => TagValue::ByteValue(0),
_ => panic!("Tag not found!"),
}
}
fn vec_to_value<Endian: ByteOrder>(&self, vec: Vec<u8>) -> usize {
let len = vec.len();
match len {
0 => 0 as usize,
1 => vec[0] as usize,
2 => Endian::read_u16(&vec[..]) as usize,
4 => Endian::read_u32(&vec[..]) as usize,
8 => Endian::read_u64(&vec[..]) as usize,
_ => panic!("Vector has wrong number of elements!"),
}
}
fn read_tag<Endian: ByteOrder>(&self, ifd_offset: u64, entry_number: usize,
reader: &mut SeekableReader) -> Result<IFDEntry> {
reader.seek(SeekFrom::Start(ifd_offset + 12 * entry_number as u64))?;
let tag_value = reader.read_u16::<Endian>()?;
let tpe_value = reader.read_u16::<Endian>()?;
let count_value = reader.read_u32::<Endian>()?;
let value_offset_value = reader.read_u32::<Endian>()?;
let tag_msg = format!("Invalid tag {:04X}", tag_value);
let tag = decode_tag(tag_value).ok_or(Error::new(ErrorKind::InvalidData, tag_msg))?;
let tpe_msg = format!("Invalid tag type {:04X}", tpe_value);
let tpe = decode_tag_type(tpe_value).expect(&tpe_msg);
let value_size = tag_size(&tpe);
let tot_size = count_value * value_size;
let mut values = Vec::with_capacity(count_value as usize);
if tot_size <= 4 {
reader.seek(SeekFrom::Start(ifd_offset + 12 * entry_number as u64 + 8))?;
for _ in 0..count_value as usize {
let value = self.read_n(reader, value_size as u64);
values.push(self.vec_to_tag_value::<Endian>(value, &tpe));
}
} else {
reader.seek(SeekFrom::Start(value_offset_value as u64))?;
for _ in 0..count_value as usize {
let value = self.read_n(reader, value_size as u64);
values.push(self.vec_to_tag_value::<Endian>(value, &tpe));
}
}
let ifd_entry = IFDEntry {
tag,
tpe,
count: count_value,
value_offset: value_offset_value,
value: values,
};
Ok(ifd_entry)
}
fn read_image_data<Endian: ByteOrder>(&self, reader: &mut SeekableReader,
ifd: &IFD) -> Result<Vec<Vec<Vec<usize>>>> {
let image_length = ifd.entries.iter().find(|&e| e.tag == TIFFTag::ImageLengthTag)
.ok_or(Error::new(ErrorKind::InvalidData, "Image length not found."))?;
let image_width = ifd.entries.iter().find(|&e| e.tag == TIFFTag::ImageWidthTag)
.ok_or(Error::new(ErrorKind::InvalidData, "Image width not found."))?;
let image_depth = ifd.entries.iter().find(|&e| e.tag == TIFFTag::BitsPerSampleTag)
.ok_or(Error::new(ErrorKind::InvalidData, "Image depth not found."))?;
let rows_per_strip = ifd.entries.iter().find(|&e| e.tag == TIFFTag::RowsPerStripTag)
.ok_or(Error::new(ErrorKind::InvalidData, "Rows per strip not found."))?;
let strip_offsets = ifd.entries.iter().find(|&e| e.tag == TIFFTag::StripOffsetsTag)
.ok_or(Error::new(ErrorKind::InvalidData, "Strip offsets not found."))?;
let strip_byte_counts = ifd.entries.iter().find(|&e| e.tag == TIFFTag::StripByteCountsTag)
.ok_or(Error::new(ErrorKind::InvalidData, "Strip byte counts not found."))?;
let image_length = match image_length.value[0] {
TagValue::ShortValue(v) => v,
_ => 0 as u16,
};
let image_width = match image_width.value[0] {
TagValue::ShortValue(v) => v,
_ => 0 as u16,
};
let image_depth = match image_depth.value[0] {
TagValue::ShortValue(v) => v / 8,
_ => 0 as u16,
};
let mut img: Vec<Vec<Vec<usize>>> = Vec::with_capacity(image_length as usize);
for i in 0..image_length {
&img.push(Vec::with_capacity(image_width as usize));
for j in 0..image_width {
&img[i as usize].push(vec![0; 1]); }
}
let rows_per_strip = match rows_per_strip.value[0] {
TagValue::ShortValue(v) => v,
_ => 0 as u16,
};
let mut offsets: Vec<u32> = Vec::with_capacity(strip_offsets.value.len());
for v in &strip_offsets.value {
match v {
TagValue::LongValue(v) => offsets.push(*v),
_ => (),
};
}
let mut byte_counts: Vec<u32> = Vec::with_capacity(strip_byte_counts.value.len());
for v in &strip_byte_counts.value {
match v {
TagValue::LongValue(v) => byte_counts.push(*v),
_ => (),
};
}
let mut curr_x = 0;
let mut curr_y = 0;
let mut curr_z = 0;
for (offset, byte_count) in offsets.iter().zip(byte_counts.iter()) {
reader.seek(SeekFrom::Start(*offset as u64))?;
for i in 0..(*byte_count / image_depth as u32) {
let v = self.read_n(reader, image_depth as u64);
img[curr_x][curr_y][curr_z] = self.vec_to_value::<Endian>(v);
curr_z += 1;
if curr_z >= img[curr_x][curr_y].len() {
curr_z = 0;
curr_y += 1;
}
if curr_y >= img[curr_x].len() as usize {
curr_y = 0;
curr_x += 1;
}
}
}
Ok(img)
}
}