rustiff 0.1.2

TIFF decoding/encoding library in Rust.
Documentation

use error::{
    DecodeError,
    DecodeErrorKind,
    DecodeResult,
};
use byte::{
    Endian,
    EndianReadExt,
    ReadExt,
    SeekExt,
    LZWReader,
};
use ifd::{
    IFD,
    Entry,
    DataType,
};
use tag::{
    self,
    TagType,
    AnyTag,
};
use std::io::{
    Read,
    Seek,
};
use image::{
    BitsPerSample,
    Image,
    ImageData,
    ImageHeader,
    Compression,
    PhotometricInterpretation,
};

macro_rules! read_byte {
    ($method:ident, $method2:ident, $typestr:ident, $t:ty) => {
        #[inline]
        fn $method(&mut self, ifd: &IFD, header: &ImageHeader, buffer_size: usize) -> DecodeResult<ImageData> {
            let interpretation = header.photometric_interpretation();
            let compression = header.compression();
            let offsets = self.get_value(ifd, tag::StripOffsets)?;
            let strip_byte_counts = self.get_value(ifd, tag::StripByteCounts)?;
            let endian = self.endian;
            
            let mut buffer: Vec<$t> = vec![0; buffer_size];
            let mut read_size = 0;
            for (offset, byte_count) in offsets.into_iter().zip(strip_byte_counts.into_iter()) {
                let offset = offset as usize;
                let byte_count = byte_count as usize;
                
                self.reader.goto(offset as u64)?;

                read_size += match compression {
                    Compression::No => $method2(
                        interpretation,
                        read_size,
                        buffer_size,
                        endian,
                        (&mut self.reader, byte_count),
                        &mut buffer[read_size..])?,

                    Compression::LZW => $method2(
                        interpretation,
                        read_size,
                        buffer_size,
                        endian,
                        LZWReader::new(&mut self.reader, byte_count)?,
                        &mut buffer[read_size..])?,
                };
            }
            buffer.shrink_to_fit();

            Ok(ImageData::$typestr(buffer))
        }
    }
}

#[derive(Debug)]
pub struct Decoder<R> {
    reader: R,
    endian: Endian,
    start: u32,
    next: u32,
}

impl<R> Decoder<R> where R: Read + Seek {
    pub fn new(mut reader: R) -> DecodeResult<Decoder<R>> {
        let mut byte_order = [0u8; 2];
        if let Err(_) = reader.read_exact(&mut byte_order) {
            return Err(DecodeError::from(DecodeErrorKind::NoByteOrder));
        }
        let endian = match &byte_order {
            b"II" => Endian::Little,
            b"MM" => Endian::Big,
            _ => return Err(DecodeError::from(DecodeErrorKind::NoByteOrder)),
        };

        match reader.read_u16(endian) {
            Ok(x) if x == 42 => {},
            _ => return Err(DecodeError::from(DecodeErrorKind::NoVersion))
        }
        let start = match reader.read_u32(endian) {
            Ok(x) => x,
            Err(_) => return Err(DecodeError::from(DecodeErrorKind::NoIFDAddress))
        };
        let decoder = Decoder {
            start: start,
            next: start,
            reader: reader,
            endian: endian,
        };

        Ok(decoder)
    }

    pub fn ifds(&mut self) -> Vec<IFD> {
        self.collect::<Vec<_>>()
    }

    pub fn ifd(&mut self) -> DecodeResult<IFD> {
        let start = self.start;
        let (ifd, _) = self.read_ifd(start)?;
        Ok(ifd)
    }

    pub fn endian(&self) -> Endian {
        self.endian
    }

    fn get_entry<'a, T: TagType>(&mut self, ifd: &'a IFD, tag: T) -> DecodeResult<&'a Entry> {
        ifd.get(tag).ok_or(DecodeError::from(DecodeErrorKind::CannotFindTheTag{ tag: AnyTag::from(tag) }))
    }
    
    pub fn get_value<T: TagType>(&mut self, ifd: &IFD, tag: T) -> DecodeResult<T::Value> {
        let entry = self.get_entry(ifd, tag)?;
        tag.decode(&mut self.reader, entry.offset(), self.endian, entry.datatype(), entry.count() as usize)
    }

    fn read_ifd(&mut self, from: u32) -> DecodeResult<(IFD, u32)>  {
        self.reader.goto(from as u64)?;

        let mut ifd = IFD::new();
        for _ in 0..self.reader.read_u16(self.endian)? {
            let (tag, entry) = self.read_entry()?;
            ifd.insert_anytag(tag, entry);
        }

        let next = self.reader.read_u32(self.endian)?;

        Ok((ifd, next))
    }
    
    fn read_entry(&mut self) -> DecodeResult<(AnyTag, Entry)> {
        let tag = AnyTag::from(self.reader.read_u16(self.endian)?);
        let datatype = DataType::from(self.reader.read_u16(self.endian)?);
        let count = self.reader.read_u32(self.endian)?;
        let offset = self.reader.read_4byte()?;
        let entry = Entry::new(datatype, count, offset);

        Ok((tag, entry))
    }

    pub fn header_with(&mut self, ifd: &IFD) -> DecodeResult<ImageHeader> {
        let width = self.get_value(ifd, tag::ImageWidth)?;
        let height = self.get_value(ifd, tag::ImageLength)?;
        let compression = Compression::from_u16(self.get_value(ifd, tag::Compression)?)?;
        let interpretation = PhotometricInterpretation::from_u16(self.get_value(ifd, tag::PhotometricInterpretation)?)?;
        let bits_per_sample = BitsPerSample::new(self.get_value(ifd, tag::BitsPerSample)?)?;
        let header = ImageHeader::new(width, height, compression, interpretation, bits_per_sample)?;
        
        Ok(header)
    }
    
    pub fn header(&mut self) -> DecodeResult<ImageHeader> {
        let ifd = self.ifd()?;

        self.header_with(&ifd)
    }
    
    read_byte!(read_byte_u8, read_byte_detail_u8, U8, u8);
    read_byte!(read_byte_u16, read_byte_detail_u16, U16, u16);

    pub fn image_with(&mut self, ifd: &IFD) -> DecodeResult<Image> {
        let header = self.header_with(ifd)?;
        let width = header.width() as usize;
        let height = header.height() as usize;
        let bits_per_sample = header.bits_per_sample();
        let buffer_size = width * height * header.bits_per_sample().len();
        let data = match bits_per_sample {
            BitsPerSample::U8_1 | BitsPerSample::U8_3 | BitsPerSample::U8_4 => self.read_byte_u8(ifd, &header, buffer_size)?,
            BitsPerSample::U16_1 | BitsPerSample::U16_3 | BitsPerSample::U16_4 => self.read_byte_u16(ifd, &header, buffer_size)?,
        };
        
        Ok(Image::new(header, data))
    }
    
    pub fn image(&mut self) -> DecodeResult<Image> {
        let ifd = self.ifd()?;
        self.image_with(&ifd)
    }
} 

impl<R> Iterator for Decoder<R> where R: Read + Seek {
    type Item = IFD;

    fn next(&mut self) -> Option<IFD> {
        let next = self.next;
        if let Some((ifd, next)) = self.read_ifd(next).ok() {
            self.next = next;

            Some(ifd)
        } else {
            None
        }
    }
}

fn read_byte_detail_u16<S>(
    interpretation: PhotometricInterpretation,
    read_size: usize,
    buffer_size: usize,
    endian: Endian,
    reader_and_size: (S, usize),
    buffer: &mut [u16]) -> DecodeResult<usize> where S: Read
{
    let mut reader = reader_and_size.0;
    let compressed_size = reader_and_size.1;

    if read_size + compressed_size > buffer_size {
        return Err(DecodeError::from(DecodeErrorKind::IncorrectBufferSize { calc: buffer_size, sum: read_size + compressed_size }));
    }
    
    for data in buffer[..compressed_size/2].iter_mut() {
        *data = if interpretation == PhotometricInterpretation::BlackIsZero {
            u16::max_value() - reader.read_u16(endian)?
        } else {
            reader.read_u16(endian)?
        };
    }

    Ok(compressed_size/2)
}

fn read_byte_detail_u8<S>(
    interpretation: PhotometricInterpretation, 
    read_size: usize,
    buffer_size: usize,
    _endian: Endian,
    reader_and_size: (S, usize),
    buffer: &mut [u8]) -> DecodeResult<usize> where S: Read,
{
    let mut reader = reader_and_size.0;
    let compressed_size = reader_and_size.1;
    if read_size + compressed_size > buffer_size {
        return Err(DecodeError::from(DecodeErrorKind::IncorrectBufferSize { calc: buffer_size, sum: read_size + compressed_size }));
    }
    let res = reader.read(&mut buffer[..compressed_size])?;
    if interpretation == PhotometricInterpretation::BlackIsZero {
        for data in buffer[..compressed_size].iter_mut() {
            *data = u8::max_value() - *data;
        }
    }
    Ok(res)
}