Fix some small problems

This commit is contained in:
Birk Tjelmeland committed 2019-02-20 23:08:40 +01:00
1 parent b0d7ac9cbf
commit addfaa5692
2 files changed
+118 -47

No files matched your search

+11 -9
View File
@@ -1,9 +1,11 @@
use crate::decoder::PhotometricInterpretation;
/// Trait for different colortypes that can be encoded.
pub trait ColorType {
/// The type of each sample of thes colortype
/// The type of each sample of this colortype
type Inner: super::TiffValue;
/// The value of the tiff tag `PhotometricInterpretation`
const TIFF_VALUE: u8;
const TIFF_VALUE: PhotometricInterpretation;
/// The value of the tiff tag `BitsPerSample`
fn bits_per_sample() -> Vec<u16>;
}
@@ -11,7 +13,7 @@ pub trait ColorType {
pub struct Gray8;
impl ColorType for Gray8 {
type Inner = u8;
const TIFF_VALUE: u8 = 1;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
fn bits_per_sample() -> Vec<u16> {
vec![8]
}
@@ -20,7 +22,7 @@ impl ColorType for Gray8 {
pub struct Gray16;
impl ColorType for Gray16 {
type Inner = u16;
const TIFF_VALUE: u8 = 1;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
fn bits_per_sample() -> Vec<u16> {
vec![16]
}
@@ -29,7 +31,7 @@ impl ColorType for Gray16 {
pub struct RGB8;
impl ColorType for RGB8 {
type Inner = u8;
const TIFF_VALUE: u8 = 2;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
fn bits_per_sample() -> Vec<u16> {
vec![8,8,8]
}
@@ -38,7 +40,7 @@ impl ColorType for RGB8 {
pub struct RGB16;
impl ColorType for RGB16 {
type Inner = u16;
const TIFF_VALUE: u8 = 2;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
fn bits_per_sample() -> Vec<u16> {
vec![16,16,16]
}
@@ -47,7 +49,7 @@ impl ColorType for RGB16 {
pub struct RGBA8;
impl ColorType for RGBA8 {
type Inner = u8;
const TIFF_VALUE: u8 = 2;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
fn bits_per_sample() -> Vec<u16> {
vec![8,8,8,8]
}
@@ -56,7 +58,7 @@ impl ColorType for RGBA8 {
pub struct RGBA16;
impl ColorType for RGBA16 {
type Inner = u16;
const TIFF_VALUE: u8 = 2;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
fn bits_per_sample() -> Vec<u16> {
vec![16,16,16,16]
}
@@ -65,7 +67,7 @@ impl ColorType for RGBA16 {
pub struct CMYK8;
impl ColorType for CMYK8 {
type Inner = u8;
const TIFF_VALUE: u8 = 5;
const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::CMYK;
fn bits_per_sample() -> Vec<u16> {
vec![8,8,8,8]
}
+107 -38
View File
@@ -2,7 +2,7 @@ use std::io::{Write, Seek};
use std::collections::BTreeMap;
use byteorder::{NativeEndian};
use crate::decoder::ifd::Tag;
use crate::decoder::ifd::{self, Tag};
use crate::error::{TiffResult, TiffFormatError, TiffError};
mod writer;
@@ -12,15 +12,23 @@ use self::writer::*;
use self::colortype::*;
/// Type to represent tiff values of type `RATIONAL`
#[derive(Clone)]
pub struct Rational {
pub n: u32,
pub d: u32,
}
/// Type to represent resolution units
pub enum ResolutionUnit {
None = 1,
Inch = 2,
Centimeter = 3,
}
/// Trait for types that can be encoded in a tiff file
pub trait TiffValue {
const BYTE_LEN: u32;
const FIELD_TYPE: u16;
const FIELD_TYPE: ifd::Type;
fn count(&self) -> u32;
fn bytes(&self) -> u32 {
self.count() * Self::BYTE_LEN
@@ -28,12 +36,62 @@ pub trait TiffValue {
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()>;
}
impl<T: TiffValue> TiffValue for &[T] {
const BYTE_LEN: u32 = T::BYTE_LEN;
const FIELD_TYPE: u16 = T::FIELD_TYPE;
impl TiffValue for &[u8] {
const BYTE_LEN: u32 = 1;
const FIELD_TYPE: ifd::Type = ifd::Type::BYTE;
fn count(&self) -> u32 {
self.iter().map(|x| x.count()).sum()
self.len() as u32
}
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
writer.write_bytes(self)?;
Ok(())
}
}
impl TiffValue for &[u16] {
const BYTE_LEN: u32 = 2;
const FIELD_TYPE: ifd::Type = ifd::Type::SHORT;
fn count(&self) -> u32 {
self.len() as u32
}
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
// We write using nativeedian so this sould be safe
let slice = unsafe {
std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()*2)
};
writer.write_bytes(slice)?;
Ok(())
}
}
impl TiffValue for &[u32] {
const BYTE_LEN: u32 = 4;
const FIELD_TYPE: ifd::Type = ifd::Type::LONG;
fn count(&self) -> u32 {
self.len() as u32
}
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
// We write using nativeedian so this sould be safe
let slice = unsafe {
std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()*4)
};
writer.write_bytes(slice)?;
Ok(())
}
}
impl TiffValue for &[Rational] {
const BYTE_LEN: u32 = 8;
const FIELD_TYPE: ifd::Type = ifd::Type::RATIONAL;
fn count(&self) -> u32 {
self.len() as u32
}
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
@@ -46,7 +104,7 @@ impl<T: TiffValue> TiffValue for &[T] {
impl TiffValue for u8 {
const BYTE_LEN: u32 = 1;
const FIELD_TYPE: u16 = 1;
const FIELD_TYPE: ifd::Type = ifd::Type::BYTE;
fn count(&self) -> u32 {
1
@@ -60,7 +118,7 @@ impl TiffValue for u8 {
impl TiffValue for u16 {
const BYTE_LEN: u32 = 2;
const FIELD_TYPE: u16 = 3;
const FIELD_TYPE: ifd::Type = ifd::Type::SHORT;
fn count(&self) -> u32 {
1
@@ -74,7 +132,7 @@ impl TiffValue for u16 {
impl TiffValue for u32 {
const BYTE_LEN: u32 = 4;
const FIELD_TYPE: u16 = 4;
const FIELD_TYPE: ifd::Type = ifd::Type::LONG;
fn count(&self) -> u32 {
1
@@ -88,7 +146,7 @@ impl TiffValue for u32 {
impl TiffValue for Rational {
const BYTE_LEN: u32 = 8;
const FIELD_TYPE: u16 = 5;
const FIELD_TYPE: ifd::Type = ifd::Type::RATIONAL;
fn count(&self) -> u32 {
1
@@ -103,7 +161,7 @@ impl TiffValue for Rational {
impl TiffValue for str {
const BYTE_LEN: u32 = 1;
const FIELD_TYPE: u16 = 2;
const FIELD_TYPE: ifd::Type = ifd::Type::ASCII;
fn count(&self) -> u32 {
self.len() as u32 + 1
@@ -132,15 +190,7 @@ impl TiffValue for str {
/// ```
/// # extern crate tempfile;
/// # let mut file = tempfile::tempfile().unwrap();
/// # let mut image_data = Vec::new();
/// # for x in 0..100 {
/// # for y in 0..100u8 {
/// # let val = x + y;
/// # image_data.push(val);
/// # image_data.push(val);
/// # image_data.push(val);
/// # }
/// # }
/// # let image_data = vec![0; 100*100*3];
/// use tiff::encoder::*;
///
/// let mut tiff = TiffEncoder::new(&mut file).unwrap();
@@ -174,7 +224,7 @@ impl<W: Write + Seek> TiffEncoder<W> {
}
/// Convenience function to write an entire image from memory.
pub fn write_image<C: ColorType>(&mut self, width: u32, height: u32, data: &[C::Inner]) -> TiffResult<()> {
pub fn write_image<'a, C: ColorType>(&mut self, width: u32, height: u32, data: &'a [C::Inner]) -> TiffResult<()> where &'a [C::Inner]: TiffValue {
let encoder = DirectoryEncoder::new(&mut self.writer)?;
let mut image: ImageEncoder<W, C> = ImageEncoder::new(encoder, width, height).unwrap();
@@ -222,7 +272,7 @@ impl<'a, W: Write + Seek> DirectoryEncoder<'a, W> {
value.write(&mut writer).unwrap();
}
self.ifd.insert(tag.to_u16(), (<T>::FIELD_TYPE, value.count(), bytes));
self.ifd.insert(tag.to_u16(), (<T>::FIELD_TYPE as u16, value.count(), bytes));
}
fn write_directory(&mut self) -> TiffResult<u64> {
@@ -302,15 +352,7 @@ impl<'a, W: Write + Seek> Drop for DirectoryEncoder<'a, W> {
/// ```
/// # extern crate tempfile;
/// # let mut file = tempfile::tempfile().unwrap();
/// # let mut image_data = Vec::new();
/// # for x in 0..100 {
/// # for y in 0..100u8 {
/// # let val = x + y;
/// # image_data.push(val);
/// # image_data.push(val);
/// # image_data.push(val);
/// # }
/// # }
/// # let image_data = vec![0; 100*100*3];
/// use tiff::encoder::*;
///
/// let mut tiff = TiffEncoder::new(&mut file).unwrap();
@@ -339,20 +381,20 @@ pub struct ImageEncoder<'a, W: Write + Seek, C: ColorType> {
impl<'a, W: Write + Seek, T: ColorType> ImageEncoder<'a, W, T> {
fn new(mut encoder: DirectoryEncoder<'a, W>, width: u32, height: u32) -> TiffResult<ImageEncoder<'a, W, T>> {
let row_samples = width as u64 * <T>::bits_per_sample().len() as u64;
let row_bytes = row_samples * <T::Inner>::BYTE_LEN as u64;
let row_samples = u64::from(width) * <T>::bits_per_sample().len() as u64;
let row_bytes = row_samples * u64::from(<T::Inner>::BYTE_LEN);
// As per tiff spec each strip should be about 8k long
let rows_per_strip = (8000 + row_bytes - 1) / row_bytes;
let strip_count = (height as u64 + rows_per_strip - 1) / rows_per_strip;
let strip_count = (u64::from(height) + rows_per_strip - 1) / rows_per_strip;
encoder.write_tag(Tag::ImageWidth, width);
encoder.write_tag(Tag::ImageLength, height);
encoder.write_tag(Tag::Compression, 1u16);
encoder.write_tag(Tag::BitsPerSample, &<T>::bits_per_sample() as &[u16]);
encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE);
encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE as u16);
encoder.write_tag(Tag::RowsPerStrip, rows_per_strip as u32);
@@ -381,14 +423,14 @@ impl<'a, W: Write + Seek, T: ColorType> ImageEncoder<'a, W, T> {
return 0
}
let start_row = std::cmp::min(self.height as u64, self.strip_idx * self.rows_per_strip);
let end_row = std::cmp::min(self.height as u64, (self.strip_idx+1)*self.rows_per_strip);
let start_row = std::cmp::min(u64::from(self.height), self.strip_idx * self.rows_per_strip);
let end_row = std::cmp::min(u64::from(self.height), (self.strip_idx+1)*self.rows_per_strip);
(end_row - start_row) * self.row_samples
}
/// Write a single strip.
pub fn write_strip(&mut self, value: &[T::Inner]) -> TiffResult<()> {
pub fn write_strip<'b>(&mut self, value: &'b [T::Inner]) -> TiffResult<()> where &'b [T::Inner]: TiffValue {
// TODO: Compression
let samples = self.next_strip_sample_count();
assert_eq!(value.len() as u64, samples);
@@ -401,6 +443,28 @@ impl<'a, W: Write + Seek, T: ColorType> ImageEncoder<'a, W, T> {
Ok(())
}
/// Set image resolution
pub fn resolution(&mut self, unit: ResolutionUnit, value: Rational) {
self.encoder.write_tag(Tag::ResolutionUnit, unit as u16);
self.encoder.write_tag(Tag::XResolution, value.clone());
self.encoder.write_tag(Tag::YResolution, value);
}
/// Set image resolution unit
pub fn resolution_unit(&mut self, unit: ResolutionUnit) {
self.encoder.write_tag(Tag::ResolutionUnit, unit as u16);
}
/// Set image x-resolution
pub fn x_resolution(&mut self, value: Rational) {
self.encoder.write_tag(Tag::XResolution, value);
}
/// Set image y-resolution
pub fn y_resolution(&mut self, value: Rational) {
self.encoder.write_tag(Tag::YResolution, value);
}
fn finish_internal(&mut self) -> TiffResult<()> {
self.encoder.write_tag(Tag::StripOffsets, &*self.strip_offsets);
self.encoder.write_tag(Tag::StripByteCounts, &*self.strip_byte_count);
@@ -409,6 +473,11 @@ impl<'a, W: Write + Seek, T: ColorType> ImageEncoder<'a, W, T> {
self.encoder.finish_internal()
}
/// Get a reference of the underlying `DirectoryEncoder`
pub fn encoder(&mut self) -> &mut DirectoryEncoder<'a, W> {
&mut self.encoder
}
/// Write out image and ifd directory.
pub fn finish(mut self) -> TiffResult<()> {
self.finish_internal()