diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index fe3ebab..3462807 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -9,14 +9,14 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust: ["1.85.0", stable, beta, nightly] + rust: ["1.88.0", stable, beta, nightly] steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@nightly - if: ${{ matrix.rust == '1.85.0' }} + if: ${{ matrix.rust == '1.88.0' }} - name: Generate Cargo.lock with minimal-version dependencies - if: ${{ matrix.rust == '1.85.0' }} + if: ${{ matrix.rust == '1.88.0' }} run: cargo -Zminimal-versions generate-lockfile - uses: dtolnay/rust-toolchain@v1 @@ -29,7 +29,7 @@ jobs: - name: build run: cargo build -v - name: test - if: ${{ matrix.rust != '1.85.0' }} + if: ${{ matrix.rust != '1.88.0' }} run: cargo test -v && cargo doc -v features: diff --git a/Cargo.toml b/Cargo.toml index bacd5d9..c1a7f0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" resolver = "2" # note: when changed, also update test runner in `.github/workflows/rust.yml` -rust-version = "1.85.0" +rust-version = "1.88.0" license = "MIT" description = "TIFF decoding and encoding library in pure Rust" @@ -32,6 +32,8 @@ image-webp = {version = "0.2.4", optional = true } criterion = "0.3.1" # We may already depend on this via flate2 crc32fast = "1.5" +libtest-mimic = "0.8.1" +walkdir = "2.5" [features] default = ["deflate", "fax", "jpeg", "lzw"] @@ -47,3 +49,8 @@ zstd = ["dep:zstd"] [[bench]] name = "lzw" harness = false + +[[test]] +name = "decode_libtiffpic" +path = "tests/decode_libtiffpic.rs" +harness = false diff --git a/examples/decode.rs b/examples/decode.rs index 10a7d10..2bad4a1 100644 --- a/examples/decode.rs +++ b/examples/decode.rs @@ -36,6 +36,31 @@ fn debug_planes( colortype: &tiff::ColorType, (width, height): (u32, u32), ) { + match data { + DecodingResult::F16(v) => { + let samples = v + .iter() + .map(|&f| (f64::from(f) * f64::from(u16::MAX)) as u16) + .collect::>(); + *data = DecodingResult::U16(samples); + } + DecodingResult::F32(v) => { + let samples = v + .iter() + .map(|&f| (f64::from(f) * f64::from(u16::MAX)) as u16) + .collect::>(); + *data = DecodingResult::U16(samples); + } + DecodingResult::F64(v) => { + let samples = v + .iter() + .map(|&f| (f * f64::from(u16::MAX)) as u16) + .collect::>(); + *data = DecodingResult::U16(samples); + } + _ => {} + } + let (depth, mut tupltype) = match colortype { // Note: we will expand, so this is in fact not BLACKANDWHITE tiff::ColorType::Gray(_) => (1, "GRAYSCALE"), diff --git a/src/decoder/image.rs b/src/decoder/image.rs index 5330328..2a4366f 100644 --- a/src/decoder/image.rs +++ b/src/decoder/image.rs @@ -4,8 +4,8 @@ use super::tag_reader::TagReader; use super::ChunkType; use super::{predict_f16, predict_f32, predict_f64, ValueReader}; use crate::tags::{ - CompressionMethod, ExtraSamples, PhotometricInterpretation, PlanarConfiguration, Predictor, - SampleFormat, Tag, + ByteOrder, CompressionMethod, ExtraSamples, PhotometricInterpretation, PlanarConfiguration, + Predictor, SampleFormat, Tag, }; use crate::{ ColorType, Directory, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError, UsageError, @@ -86,6 +86,13 @@ pub(crate) struct Image { pub chunk_offsets: Vec, pub chunk_bytes: Vec, pub chroma_subsampling: (u16, u16), + /// Will decompression yield host-endian samples? + /// + /// Standard compression algorithms run on pure bytes, taking the sample slice as it would be + /// encoded in the file. However some compression algorithms (currently only SGILog/SGILog24) + /// run on samples directly and thus skip the outer byte order entirely, except potentially + /// they have interior byte order treatment. + pub decompression_to_host_endian: bool, } /// Describes how to read a tile-aligned portion of the image. @@ -330,15 +337,28 @@ impl Image { strip_decoder = Some(StripDecodeState { rows_per_strip }); tile_attributes = None; - if chunk_offsets.len() != chunk_bytes.len() - || rows_per_strip == 0 - || u32::try_from(chunk_offsets.len())? - != (height.saturating_sub(1) / rows_per_strip + 1) * planes as u32 - { + if chunk_offsets.len() != chunk_bytes.len() { return Err(TiffError::FormatError( TiffFormatError::InconsistentSizesEncountered, )); } + + if rows_per_strip == 0 { + return Err(TiffError::FormatError( + TiffFormatError::InconsistentSizesEncountered, + )); + } + + if u32::try_from(chunk_offsets.len())? + != height.div_ceil(rows_per_strip) * planes as u32 + { + return Err(TiffError::FormatError( + TiffFormatError::IncorrectChunkCount { + expected: height.div_ceil(rows_per_strip) * planes as u32, + found: chunk_offsets.len() as u32, + }, + )); + } } (false, false, true, true) => { chunk_type = ChunkType::Tile; @@ -371,14 +391,23 @@ impl Image { .into_u64_vec()?; let tile = tile_attributes.as_ref().unwrap(); - if chunk_offsets.len() != chunk_bytes.len() - || chunk_offsets.len() - != tile.tiles_down() * tile.tiles_across() * planes as usize - { + + if chunk_offsets.len() != chunk_bytes.len() { return Err(TiffError::FormatError( TiffFormatError::InconsistentSizesEncountered, )); } + + if chunk_offsets.len() != tile.tiles_down() * tile.tiles_across() * planes as usize + { + return Err(TiffError::FormatError( + TiffFormatError::IncorrectChunkCount { + expected: (tile.tiles_down() * tile.tiles_across() * planes as usize) + as u32, + found: chunk_offsets.len() as u32, + }, + )); + } } (_, _, _, _) => { return Err(TiffError::FormatError( @@ -387,11 +416,29 @@ impl Image { } }; + let mut sample_format = sample_format; + let mut bits_per_sample = bits_per_sample[0]; + + // These compression methods only work for specific sample types. They pack each pixel into + // a pixel format. And when we decompress them we run an inverse transform inside the + // decompression step because that makes sense. (Even for 'raw' data you will not be able + // to handle the samples well otherwise). All we are doing is setting up the internal + // buffer here. There's an additional transform before the color readout as yo will receive + // the color as 32-bit floats (the encoding relies on very specific quantization so + // everything else would be very lossy). + if let CompressionMethod::SgiLog = compression_method { + sample_format = SampleFormat::IEEEFP; + bits_per_sample = 32; + } else if let CompressionMethod::SgiLog24 = compression_method { + sample_format = SampleFormat::IEEEFP; + bits_per_sample = 32; + } + Ok(Image { ifd: Some(ifd), width, height, - bits_per_sample: bits_per_sample[0], + bits_per_sample, samples, extra_samples, photometric_samples, @@ -407,6 +454,10 @@ impl Image { chunk_offsets, chunk_bytes, chroma_subsampling, + decompression_to_host_endian: matches!( + compression_method, + CompressionMethod::SgiLog | CompressionMethod::SgiLog24 + ), }) } @@ -501,6 +552,46 @@ impl Image { vec![self.bits_per_sample; self.samples as usize], ), )), + PhotometricInterpretation::CIELogL => match self.samples { + 1 if matches!(self.bits_per_sample, 32) + && matches!(self.sample_format, SampleFormat::IEEEFP) => + { + // We do this transform internally while reading. + Ok(ColorType::Gray(32)) + } + _ => Err(TiffError::UnsupportedError( + TiffUnsupportedError::InterpretationWithBits( + self.photometric_interpretation, + vec![self.bits_per_sample; self.samples as usize], + ), + )), + }, + PhotometricInterpretation::CIELogLuv => match self.samples { + // Only fully supported for the compression format `SGILog`/`SGILog24` which must + // be used with 16-bit per sample. + // + // It's actually an interesting point what we should output here. Note that in + // libtiff there is a RAW mode (a single unsigned sample per pixel) as well as a + // 32-bit floating point mode for XYZ data. The `Lu'v'` variant is a heavily + // customized quantization so we should not return it directly. The format itself + // describes being based off `xyY` so that may make sense but there is a pole in + // the relation to `XYZ` (at y=0) which is absent in the chosen quantization since + // we assume a bias of `.5` so `v >= 1/820` and thus `y >= 0.49/820` in practice. + // Also we lose a bit of accuracy with just 16-bit precision. + // + // In `libtiff` data is always transformed through XYZ. So let's do that. + 3 if matches!(self.bits_per_sample, 32) + && matches!(self.sample_format, SampleFormat::IEEEFP) => + { + Ok(ColorType::RGB(32)) + } + _ => Err(TiffError::UnsupportedError( + TiffUnsupportedError::InterpretationWithBits( + self.photometric_interpretation, + vec![self.bits_per_sample; self.samples as usize], + ), + )), + }, // Unsupported due to extra unfiltering and conversion steps. We need to find the // Decode tag (SRATIONAL; 2 * SamplesPerPixel) and apply the following conversion: // @@ -532,11 +623,35 @@ impl Image { compressed_length: u64, // FIXME: these should be `expect` attributes or we choose another way of passing them. #[cfg_attr(not(feature = "jpeg"), allow(unused_variables))] jpeg_tables: Option<&[u8]>, - #[cfg_attr(not(feature = "fax"), allow(unused_variables))] dimensions: (u32, u32), - #[cfg_attr(not(feature = "webp"), allow(unused_variables))] samples: u16, + dimensions: (u32, u32), + samples: u16, ) -> TiffResult> { Ok(match compression_method { CompressionMethod::None => Box::new(reader), + CompressionMethod::SgiLog => match samples { + 1 => Box::new(super::logluv::LogLuv16::new( + reader, + compressed_length, + dimensions.0, + )?), + 3 => Box::new(super::logluv::LogLuv32::new( + reader, + compressed_length, + dimensions.0, + )?), + _ => { + return Err(TiffError::UnsupportedError( + TiffUnsupportedError::UnsupportedCompressionMethod( + CompressionMethod::SgiLog, + ), + )) + } + }, + CompressionMethod::SgiLog24 => Box::new(super::logluv::LogLuv24::new( + reader, + compressed_length, + dimensions.0, + )?), #[cfg(feature = "lzw")] CompressionMethod::LZW => Box::new(super::stream::LZWReader::new( reader, @@ -824,7 +939,12 @@ impl Image { limits, } = reader; - let byte_order = reader.byte_order; + let decompressed_byte_order = if self.decompression_to_host_endian { + ByteOrder::native() + } else { + // Convert from the byte order of the file. + reader.byte_order + }; // Validate that the color type is supported. let color_type = layout.color; @@ -940,7 +1060,7 @@ impl Image { row, color_type.bit_depth(), samples, - byte_order, + decompressed_byte_order, predictor, ); } @@ -986,7 +1106,7 @@ impl Image { row, color_type.bit_depth(), samples, - byte_order, + decompressed_byte_order, predictor, ); @@ -1007,7 +1127,7 @@ impl Image { debug_assert!(bits_per_pixel >= photometric_bit_end); - if bits_per_pixel % 8 != 0 || photometric_bit_end % 8 != 0 { + if !bits_per_pixel.is_multiple_of(8) || !photometric_bit_end.is_multiple_of(8) { return Err(TiffError::UnsupportedError( TiffUnsupportedError::InterpretationWithBits( self.photometric_interpretation, @@ -1027,7 +1147,7 @@ impl Image { row, color_type.bit_depth(), samples, - byte_order, + decompressed_byte_order, predictor, ); diff --git a/src/decoder/logluv.rs b/src/decoder/logluv.rs new file mode 100644 index 0000000..6216fbf --- /dev/null +++ b/src/decoder/logluv.rs @@ -0,0 +1,541 @@ +use std::io::{Read, Take}; + +use crate::TiffError; + +pub struct LogLuv24 { + reader: Take, + /// The required buffer size. We only decompressed all samples at once. + chunk_sz: usize, +} + +impl LogLuv24 { + pub fn new(reader: R, n: u64, npixels: u32) -> Result + where + R: Read, + { + let chunk_sz = usize::try_from( + u64::from(npixels) + .checked_mul(4 * 3) + .ok_or(TiffError::LimitsExceeded)?, + )?; + + let reader = reader.take(n); + Ok(LogLuv24 { reader, chunk_sz }) + } + + fn expand_buf(buf: &mut [u8]) { + let data_len = buf.len() / 4; + + for i in (0..data_len / 3).rev() { + let ch = buf.as_chunks_mut::<3>().0[i]; + let [a, b, c] = ch.map(u32::from); + + let raw = a << 16 | b << 8 | c; + let l = (raw >> 14) & 0x3ff; + let uv = decode_quantized_uv(raw & 0x3fff); + + let by = dequantize_24_luma(l); + let (u, v) = dequantize_24(uv); + + let s = 1. / (6. * u - 16. * v + 12.); + let x = 9. * u * s; + let y = 4. * v * s; + + let bx = x / y * by; + let bz = (1. - x - y) / y * by; + + let [r, g, b] = xyz_to_rgb([bx, by, bz]); + + let into = &mut buf.as_chunks_mut::<12>().0[i]; + into[0..4].copy_from_slice(&f32::to_ne_bytes(r)); + into[4..8].copy_from_slice(&f32::to_ne_bytes(g)); + into[8..12].copy_from_slice(&f32::to_ne_bytes(b)); + } + } +} + +impl Read for LogLuv24 { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.read_exact(buf)?; + Ok(buf.len()) + } + + // FIXME: this is the interface we have for compressed chunks but it is not optimal for what we + // want. Note `fill_buf` is not super helpful since it does not guarantee any size of the + // filled buffer but we need 24-bits at a time. Two code paths is even more awkward. + fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> { + if !buf.len().is_multiple_of(self.chunk_sz) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!( + "buffer size {0} must match the chunk size for compression method SGILog24 {1}", + buf.len(), + self.chunk_sz, + ), + )); + } + + let data_len = buf.len() / 4; + self.reader.read_exact(&mut buf[..data_len])?; + Self::expand_buf(buf); + + Ok(()) + } +} + +fn packbits_decode( + reader: &mut R, + buf: &mut [[u8; N]], +) -> std::io::Result<()> { + for offset in (0..N).rev() { + let mut i = 0; + let mut code = [0u8; 1]; + + loop { + let Some(pixels) = buf.get_mut(i..) else { + break; + }; + + if pixels.is_empty() { + break; + } + + let pixels = pixels.iter_mut(); + reader.read_exact(&mut code)?; + let [repeat] = code; + + if repeat >= 128 { + reader.read_exact(&mut code)?; + let [value] = code; + let rc = (repeat - 128) + 2; + + for (_, px) in (0..rc).zip(pixels) { + px[offset] = value; + } + + i += usize::from(rc); + } else { + for (_, px) in (0..repeat).zip(pixels) { + reader.read_exact(&mut code)?; + let [value] = code; + px[offset] = value; + } + + i += usize::from(repeat); + } + } + } + + Ok(()) +} + +pub struct LogLuv32 { + reader: Take, + /// The required buffer size. We only decompressed all samples at once. + chunk_sz: usize, +} + +impl LogLuv32 { + pub fn new(reader: R, n: u64, npixels: u32) -> Result { + let chunk_sz = usize::try_from( + u64::from(npixels) + .checked_mul(4 * 3) + .ok_or(TiffError::LimitsExceeded)?, + )?; + + let reader = reader.take(n); + Ok(LogLuv32 { reader, chunk_sz }) + } + + fn decode_rle_row(&mut self, row: &mut [u8]) -> std::io::Result<()> + where + R: Read, + { + // 32-bit per pixel format. + let n_pixels = self.chunk_sz / 12; + // buffer for reading (using only 32-bit per pixel) + let raw = &mut row.as_chunks_mut::<4>().0[..n_pixels]; + packbits_decode::<_, 4>(&mut self.reader, raw)?; + + Ok(()) + } + + fn expand_row(row: &mut [u8]) { + let uvscale = 1.0 / 410.0; + let n_pixels = row.len() / 12; + + // Work backwards, the 32-bit compressed raw data is at the front of the row buffer and + // this avoids overwriting data before we read it. + for i in (0..n_pixels).rev() { + let raw = row.as_chunks_mut::<4>().0[i]; + + let l = u16::from(raw[0]) << 8 | u16::from(raw[1]); + let by = log16_to_y(l); + + let u = uvscale * (f32::from(raw[2]) + 0.5); + let v = uvscale * (f32::from(raw[3]) + 0.5); + + let s = 1. / (6. * u - 16. * v + 12.); + let x = 9. * u * s; + let y = 4. * v * s; + + let bx = x / y * by; + let bz = (1. - x - y) / y * by; + + let [r, g, b] = xyz_to_rgb([bx, by, bz]); + let into = &mut row.as_chunks_mut::<12>().0[i]; + into[0..4].copy_from_slice(&f32::to_ne_bytes(r)); + into[4..8].copy_from_slice(&f32::to_ne_bytes(g)); + into[8..12].copy_from_slice(&f32::to_ne_bytes(b)); + } + } +} + +impl Read for LogLuv32 { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.read_exact(buf)?; + Ok(buf.len()) + } + + // FIXME: See `LogLuv24::read_exact` + fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> { + for row in buf.chunks_exact_mut(self.chunk_sz) { + self.decode_rle_row(row)?; + Self::expand_row(row); + } + + Ok(()) + } +} + +/// Pack-Bits like encoding for a single 16-bit log-L sample. +pub struct LogLuv16 { + reader: Take, + /// The required buffer size. We only decompressed all samples at once. + chunk_sz: usize, +} + +impl LogLuv16 { + pub fn new(reader: R, n: u64, npixels: u32) -> Result { + let chunk_sz = usize::try_from( + u64::from(npixels) + .checked_mul(4) + .ok_or(TiffError::LimitsExceeded)?, + )?; + + let reader = reader.take(n); + Ok(LogLuv16 { reader, chunk_sz }) + } + + fn decode_rle_row(&mut self, row: &mut [u8]) -> std::io::Result<()> + where + R: Read, + { + // 32-bit per pixel format. + let n_pixels = self.chunk_sz / 4; + // buffer for reading (16-bit per pixel) + let raw = &mut row.as_chunks_mut::<2>().0[..n_pixels]; + packbits_decode::<_, 2>(&mut self.reader, raw)?; + + Ok(()) + } + + fn expand_row(row: &mut [u8]) { + let n_pixels = row.len() / 4; + + // Work backwards, the 32-bit compressed raw data is at the front of the row buffer and + // this avoids overwriting data before we read it. + for i in (0..n_pixels).rev() { + let raw = row.as_chunks_mut::<2>().0[i]; + + let l = u16::from(raw[0]) << 8 | u16::from(raw[1]); + let by = log16_to_y(l); + + let into = &mut row.as_chunks_mut::<4>().0[i]; + into[0..4].copy_from_slice(&f32::to_ne_bytes(by)); + } + } +} + +impl Read for LogLuv16 { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.read_exact(buf)?; + Ok(buf.len()) + } + + // FIXME: See `LogLuv24::read_exact` + fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> { + for row in buf.chunks_exact_mut(self.chunk_sz) { + self.decode_rle_row(row)?; + Self::expand_row(row); + } + + Ok(()) + } +} + +// Table information from: `libtiff`, 1997 by Greg Ward Larson, SGI +#[doc(alias = "UV_SQSIZ")] +const UV_QUANTIZATION_WIDTH: f32 = 0.003500; + +// The `v` value corresonding to the bottom most row (quantized v' = 0). +const UV_VSTART: f32 = 0.016940; + +/// Number of distinct 'u' rows, each at a different v level. Each is quantized individually with +/// the first quantization level starting at its `ustart` and `UV_QUANTIZATION_WIDTH` wide. +const UV_NVS: usize = 163; + +/// Contrary to the original C code we calculate the dependent values (cumulative sum). +struct UvRow { + ustart: f32, + num_us: u16, +} + +#[rustfmt::skip] +const UV_ROWS: [UvRow; UV_NVS] = [ + UvRow { ustart: 0.247663, num_us: 4, }, + UvRow { ustart: 0.243779, num_us: 6, }, + UvRow { ustart: 0.241684, num_us: 7, }, + UvRow { ustart: 0.237874, num_us: 9, }, + UvRow { ustart: 0.235906, num_us: 10, }, + UvRow { ustart: 0.232153, num_us: 12, }, + UvRow { ustart: 0.228352, num_us: 14, }, + UvRow { ustart: 0.226259, num_us: 15, }, + UvRow { ustart: 0.222371, num_us: 17, }, + UvRow { ustart: 0.220410, num_us: 18, }, + UvRow { ustart: 0.214710, num_us: 21, }, + UvRow { ustart: 0.212714, num_us: 22, }, + UvRow { ustart: 0.210721, num_us: 23, }, + UvRow { ustart: 0.204976, num_us: 26, }, + UvRow { ustart: 0.202986, num_us: 27, }, + UvRow { ustart: 0.199245, num_us: 29, }, + UvRow { ustart: 0.195525, num_us: 31, }, + UvRow { ustart: 0.193560, num_us: 32, }, + UvRow { ustart: 0.189878, num_us: 34, }, + UvRow { ustart: 0.186216, num_us: 36, }, + UvRow { ustart: 0.186216, num_us: 36, }, + UvRow { ustart: 0.182592, num_us: 38, }, + UvRow { ustart: 0.179003, num_us: 40, }, + UvRow { ustart: 0.175466, num_us: 42, }, + UvRow { ustart: 0.172001, num_us: 44, }, + UvRow { ustart: 0.172001, num_us: 44, }, + UvRow { ustart: 0.168612, num_us: 46, }, + UvRow { ustart: 0.168612, num_us: 46, }, + UvRow { ustart: 0.163575, num_us: 49, }, + UvRow { ustart: 0.158642, num_us: 52, }, + UvRow { ustart: 0.158642, num_us: 52, }, + UvRow { ustart: 0.158642, num_us: 52, }, + UvRow { ustart: 0.153815, num_us: 55, }, + UvRow { ustart: 0.153815, num_us: 55, }, + UvRow { ustart: 0.149097, num_us: 58, }, + UvRow { ustart: 0.149097, num_us: 58, }, + UvRow { ustart: 0.142746, num_us: 62, }, + UvRow { ustart: 0.142746, num_us: 62, }, + UvRow { ustart: 0.142746, num_us: 62, }, + UvRow { ustart: 0.138270, num_us: 65, }, + UvRow { ustart: 0.138270, num_us: 65, }, + UvRow { ustart: 0.138270, num_us: 65, }, + UvRow { ustart: 0.132166, num_us: 69, }, + UvRow { ustart: 0.132166, num_us: 69, }, + UvRow { ustart: 0.126204, num_us: 73, }, + UvRow { ustart: 0.126204, num_us: 73, }, + UvRow { ustart: 0.126204, num_us: 73, }, + UvRow { ustart: 0.120381, num_us: 77, }, + UvRow { ustart: 0.120381, num_us: 77, }, + UvRow { ustart: 0.120381, num_us: 77, }, + UvRow { ustart: 0.120381, num_us: 77, }, + UvRow { ustart: 0.112962, num_us: 82, }, + UvRow { ustart: 0.112962, num_us: 82, }, + UvRow { ustart: 0.112962, num_us: 82, }, + UvRow { ustart: 0.107450, num_us: 86, }, + UvRow { ustart: 0.107450, num_us: 86, }, + UvRow { ustart: 0.107450, num_us: 86, }, + UvRow { ustart: 0.107450, num_us: 86, }, + UvRow { ustart: 0.100343, num_us: 91, }, + UvRow { ustart: 0.100343, num_us: 91, }, + UvRow { ustart: 0.100343, num_us: 91, }, + UvRow { ustart: 0.095126, num_us: 95, }, + UvRow { ustart: 0.095126, num_us: 95, }, + UvRow { ustart: 0.095126, num_us: 95, }, + UvRow { ustart: 0.095126, num_us: 95, }, + UvRow { ustart: 0.088276, num_us: 100, }, + UvRow { ustart: 0.088276, num_us: 100, }, + UvRow { ustart: 0.088276, num_us: 100, }, + UvRow { ustart: 0.088276, num_us: 100, }, + UvRow { ustart: 0.081523, num_us: 105, }, + UvRow { ustart: 0.081523, num_us: 105, }, + UvRow { ustart: 0.081523, num_us: 105, }, + UvRow { ustart: 0.081523, num_us: 105, }, + UvRow { ustart: 0.074861, num_us: 110, }, + UvRow { ustart: 0.074861, num_us: 110, }, + UvRow { ustart: 0.074861, num_us: 110, }, + UvRow { ustart: 0.074861, num_us: 110, }, + UvRow { ustart: 0.068290, num_us: 115, }, + UvRow { ustart: 0.068290, num_us: 115, }, + UvRow { ustart: 0.068290, num_us: 115, }, + UvRow { ustart: 0.068290, num_us: 115, }, + UvRow { ustart: 0.063573, num_us: 119, }, + UvRow { ustart: 0.063573, num_us: 119, }, + UvRow { ustart: 0.063573, num_us: 119, }, + UvRow { ustart: 0.063573, num_us: 119, }, + UvRow { ustart: 0.057219, num_us: 124, }, + UvRow { ustart: 0.057219, num_us: 124, }, + UvRow { ustart: 0.057219, num_us: 124, }, + UvRow { ustart: 0.057219, num_us: 124, }, + UvRow { ustart: 0.050985, num_us: 129, }, + UvRow { ustart: 0.050985, num_us: 129, }, + UvRow { ustart: 0.050985, num_us: 129, }, + UvRow { ustart: 0.050985, num_us: 129, }, + UvRow { ustart: 0.050985, num_us: 129, }, + UvRow { ustart: 0.044859, num_us: 134, }, + UvRow { ustart: 0.044859, num_us: 134, }, + UvRow { ustart: 0.044859, num_us: 134, }, + UvRow { ustart: 0.044859, num_us: 134, }, + UvRow { ustart: 0.040571, num_us: 138, }, + UvRow { ustart: 0.040571, num_us: 138, }, + UvRow { ustart: 0.040571, num_us: 138, }, + UvRow { ustart: 0.040571, num_us: 138, }, + UvRow { ustart: 0.036339, num_us: 142, }, + UvRow { ustart: 0.036339, num_us: 142, }, + UvRow { ustart: 0.036339, num_us: 142, }, + UvRow { ustart: 0.036339, num_us: 142, }, + UvRow { ustart: 0.032139, num_us: 146, }, + UvRow { ustart: 0.032139, num_us: 146, }, + UvRow { ustart: 0.032139, num_us: 146, }, + UvRow { ustart: 0.032139, num_us: 146, }, + UvRow { ustart: 0.027947, num_us: 150, }, + UvRow { ustart: 0.027947, num_us: 150, }, + UvRow { ustart: 0.027947, num_us: 150, }, + UvRow { ustart: 0.023739, num_us: 154, }, + UvRow { ustart: 0.023739, num_us: 154, }, + UvRow { ustart: 0.023739, num_us: 154, }, + UvRow { ustart: 0.023739, num_us: 154, }, + UvRow { ustart: 0.019504, num_us: 158, }, + UvRow { ustart: 0.019504, num_us: 158, }, + UvRow { ustart: 0.019504, num_us: 158, }, + UvRow { ustart: 0.016976, num_us: 161, }, + UvRow { ustart: 0.016976, num_us: 161, }, + UvRow { ustart: 0.016976, num_us: 161, }, + UvRow { ustart: 0.016976, num_us: 161, }, + UvRow { ustart: 0.012639, num_us: 165, }, + UvRow { ustart: 0.012639, num_us: 165, }, + UvRow { ustart: 0.012639, num_us: 165, }, + UvRow { ustart: 0.009991, num_us: 168, }, + UvRow { ustart: 0.009991, num_us: 168, }, + UvRow { ustart: 0.009991, num_us: 168, }, + UvRow { ustart: 0.009016, num_us: 170, }, + UvRow { ustart: 0.009016, num_us: 170, }, + UvRow { ustart: 0.009016, num_us: 170, }, + UvRow { ustart: 0.006217, num_us: 173, }, + UvRow { ustart: 0.006217, num_us: 173, }, + UvRow { ustart: 0.005097, num_us: 175, }, + UvRow { ustart: 0.005097, num_us: 175, }, + UvRow { ustart: 0.005097, num_us: 175, }, + UvRow { ustart: 0.003909, num_us: 177, }, + UvRow { ustart: 0.003909, num_us: 177, }, + UvRow { ustart: 0.002340, num_us: 177, }, + UvRow { ustart: 0.002389, num_us: 170, }, + UvRow { ustart: 0.001068, num_us: 164, }, + UvRow { ustart: 0.001653, num_us: 157, }, + UvRow { ustart: 0.000717, num_us: 150, }, + UvRow { ustart: 0.001614, num_us: 143, }, + UvRow { ustart: 0.000270, num_us: 136, }, + UvRow { ustart: 0.000484, num_us: 129, }, + UvRow { ustart: 0.001103, num_us: 123, }, + UvRow { ustart: 0.001242, num_us: 115, }, + UvRow { ustart: 0.001188, num_us: 109, }, + UvRow { ustart: 0.001011, num_us: 103, }, + UvRow { ustart: 0.000709, num_us: 97, }, + UvRow { ustart: 0.000301, num_us: 89, }, + UvRow { ustart: 0.002416, num_us: 82, }, + UvRow { ustart: 0.003251, num_us: 76, }, + UvRow { ustart: 0.003246, num_us: 69, }, + UvRow { ustart: 0.004141, num_us: 62, }, + UvRow { ustart: 0.005963, num_us: 55, }, + UvRow { ustart: 0.008839, num_us: 47, }, + UvRow { ustart: 0.010490, num_us: 40, }, + UvRow { ustart: 0.016994, num_us: 31, }, + UvRow { ustart: 0.023659, num_us: 21, }, +]; + +const UV_CUMULATIVE: [u16; UV_NVS] = { + let mut arr = [0u16; UV_NVS]; + let mut sum = 0; + let mut i = 0; + while i < UV_NVS { + arr[i] = sum; + sum += UV_ROWS[i].num_us; + i += 1; + } + arr +}; + +const UV_NDIVS: u16 = UV_CUMULATIVE[UV_NVS - 1] + UV_ROWS[UV_NVS - 1].num_us; + +fn decode_quantized_uv(uv: u32) -> (u8, u8) { + if uv >= UV_NDIVS as u32 { + return (0, 0); + } + + // Find the start of the row, or the index after that. + let v_index = match UV_CUMULATIVE.binary_search(&(uv as u16)) { + Ok(n) => n, + Err(n) => n - 1, + }; + + let u_index = uv as u16 - UV_CUMULATIVE[v_index]; + (u_index as u8, v_index as u8) +} + +fn dequantize_24_luma(l: u32) -> f32 { + if l == 0 { + 0.0 + } else { + let le = (l & 0x3ff) as f32; + let exponent = ((le / 64.0).floor() as i32) - 24; + let mantissa = le - (exponent as f32 + 24.0) * 64.0; + (mantissa + 64.0) / 64.0 * 2f32.powi(exponent) + } +} + +fn dequantize_24((u, v): (u8, u8)) -> (f32, f32) { + let v_f = UV_VSTART + (v as f32) * UV_QUANTIZATION_WIDTH; + let u_row = &UV_ROWS[v as usize]; + let u_f = u_row.ustart + (u as f32) * UV_QUANTIZATION_WIDTH; + (u_f, v_f) +} + +fn log16_to_y(l: u16) -> f32 { + if l == 0 { + return 0.0; + } + + let le = f32::from(l & 0x7fff); + // Y = exp(M_LN2 / 256. * (Le + .5) - M_LN2 * 64.); + let y = (std::f32::consts::LN_2 / 256.0 * (le + 0.5) - std::f32::consts::LN_2 * 64.0).exp(); + + if l & 0x8000 != 0 { + -y + } else { + y + } +} + +fn xyz_to_rgb([l, u, v]: [f32; 3]) -> [f32; 3] { + // XYZ to sRGB primaries at D65 + let r = 3.2404542 * l + -1.5371385 * u + -0.4985314 * v; + let g = -0.969266 * l + 1.8760108 * u + 0.0415560 * v; + let b = 0.0556434 * l + -0.2040259 * u + 1.0572252 * v; + [r, g, b] +} + +#[test] +fn test_decode_quantized_uv() { + // Test some known values from the original C code. + assert_eq!(decode_quantized_uv(0), (0, 0)); + assert_eq!(decode_quantized_uv(3), (3, 0)); + assert_eq!(decode_quantized_uv(4), (0, 1)); + assert_eq!(decode_quantized_uv(9), (5, 1)); + assert_eq!(decode_quantized_uv(16288), (20, 162)); + assert_eq!(decode_quantized_uv(16289), (0, 0)); // Out of range +} diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 12009f3..ef0d183 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -19,6 +19,7 @@ use self::stream::{ByteOrder, EndianReader}; mod cycles; pub mod ifd; mod image; +mod logluv; mod stream; mod tag_reader; @@ -861,6 +862,7 @@ impl Decoder { chunk_offsets: Vec::new(), chunk_bytes: Vec::new(), chroma_subsampling: (2, 2), + decompression_to_host_endian: false, }, }; decoder.next_image()?; diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index 8f1cb20..b043a4d 100644 --- a/src/encoder/mod.rs +++ b/src/encoder/mod.rs @@ -403,7 +403,7 @@ impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> { /// Returns an [`Entry`]. If the value is short enough it will *not* be written in the file but /// stored in the entry's offset field. pub fn write_entry_bytes(&mut self, ty: Type, data: &[u8]) -> TiffResult { - if data.len() % usize::from(ty.byte_len()) != 0 { + if !data.len().is_multiple_of(usize::from(ty.byte_len())) { return Err(TiffError::UsageError(UsageError::MismatchedEntryLength { ty, found: data.len(), diff --git a/src/encoder/writer.rs b/src/encoder/writer.rs index 6b7eb16..468ddf5 100644 --- a/src/encoder/writer.rs +++ b/src/encoder/writer.rs @@ -172,7 +172,7 @@ impl TiffWriter { } pub fn pad_word_boundary(&mut self) -> Result<(), io::Error> { - if self.offset % 4 != 0 { + if !self.offset.is_multiple_of(4) { let padding = [0, 0, 0]; let padd_len = 4 - (self.offset % 4); self.writer.write_all(&padding[..padd_len as usize])?; diff --git a/src/error.rs b/src/error.rs index 9311915..95c0a65 100644 --- a/src/error.rs +++ b/src/error.rs @@ -70,6 +70,9 @@ quick_error! { InconsistentSizesEncountered { display("inconsistent sizes encountered") } + IncorrectChunkCount {expected: u32, found: u32} { + display("incorrect number of chunk offsets encoded for the tile count of the image, expected {expected} but found {found}") + } InvalidDimensions(width: u32, height: u32) { display("invalid dimensions: {width}x{height}") } diff --git a/src/tags.rs b/src/tags.rs index 9d18084..ab1ffba 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -283,6 +283,14 @@ pub enum CompressionMethod(u16) unknown( // Self-assigned by libtiff WebP = 0xC351, + + // Self-assigned by libtiff/SGI + // A packbit like scheme on specific 32-bit samples (16 sint luma, 8 sint u,v). Only really + // compatible with PhotometricInterpretation CIELogLuv. + SgiLog = 34676, + // A packbit like scheme on specific 24-bit samples (10 packed bits luma, 14-bit uv index). + // Only really compatible with PhotometricInterpretation CIELogLuv. + SgiLog24 = 34677, } } @@ -295,9 +303,41 @@ pub enum PhotometricInterpretation(u16) { TransparencyMask = 4, CMYK = 5, YCbCr = 6, + /// Biased Lab with all coefficients stored as unsigned integers. CIELab = 8, IccLab = 9, ItuLab = 10, + /// Logarithmic L* color space, + /// + /// see: + /// References: + /// + /// The `uv` coordinates are based on: + /// + /// ```text + /// (6*u - 16*v + 12) * (-2x + 12y + 3) = 36 + /// + /// u' = 4x / ( -2x + 12y + 3 ) + /// v' = 9y / ( -2x + 12y + 3 ) + /// x = 9u' / (6u' - 16v' + 12) + /// y = 4v' / (6u' - 16v' + 12) + /// ``` + /// + /// Since `(-2x + 12y + 3) <= 15` it holds `(6u' - 16v' + 12) >= 36/15` for all XYZ colors + /// which makes the back transform to `xyY` well-defined. Also `v' <= 9/15 = 0.6` and also + /// by practical means `u' <= 2/3`. + /// + /// The compression format that is supposed to be used with this constrains them as well. It + /// encodes each component as a 16-bit unsigned integer scaled and clamped to a quantization + /// using 256 out of 410 levels or an index into a table based on a quantization to 177 levels + /// each `0.0035` (~1/286) wide and 163 levels of `v` (same quantization width). + /// + /// > Larson, G.W., ``Overcoming Gamut and Dynamic Range Limitations in Digital Images,'' Proceedings of the Sixth Color Imaging Conference, November 1998. + CIELogL = 32844, + /// Logarithmic L*u'v' color space, + /// + /// See references under [`Self::CIELogL`]. + CIELogLuv = 32845, } } diff --git a/tests/COPYRIGHT b/tests/COPYRIGHT index 0d8a28a..7b9e2b7 100644 --- a/tests/COPYRIGHT +++ b/tests/COPYRIGHT @@ -6,3 +6,7 @@ usda/*.tif url: https://registry.opendata.aws/naip/index.html credit: NAIP on AWS was accessed on 2026-01-28 from https://registry.opendata.aws/naip. license: Public Domain +libtiffpic/ + url: https://download.osgeo.org/libtiff/ + credit: libtiff + license: CC0 diff --git a/tests/decode_libtiffpic.rs b/tests/decode_libtiffpic.rs new file mode 100644 index 0000000..0ab0dca --- /dev/null +++ b/tests/decode_libtiffpic.rs @@ -0,0 +1,169 @@ +use std::collections::HashMap; +use std::{fs::File, path}; + +use tiff::decoder::{Decoder, DecodingResult}; + +use libtest_mimic::{Arguments, Failed, Trial}; +use walkdir::WalkDir; + +const REFERENCE_DIR: &str = "tests/libtiffpic"; + +// `find test/libtiffpic -type f | sort` +const FILES: &[(&str, bool)] = &[ + ("tests/libtiffpic/caspian.tif", true), + ("tests/libtiffpic/cramps.tif", true), + // FIXME: See , this has tiles as + // StripOffsets and has a RowsPerStrip. + ("tests/libtiffpic/cramps-tile.tif", false), + ("tests/libtiffpic/CVS/Entries", false), + ("tests/libtiffpic/CVS/Repository", false), + ("tests/libtiffpic/CVS/Root", false), + ("tests/libtiffpic/depth/CVS/Entries", false), + ("tests/libtiffpic/depth/CVS/Repository", false), + ("tests/libtiffpic/depth/CVS/Root", false), + ("tests/libtiffpic/depth/flower-minisblack-02.tif", true), + ("tests/libtiffpic/depth/flower-minisblack-04.tif", true), + ("tests/libtiffpic/depth/flower-minisblack-06.tif", true), + ("tests/libtiffpic/depth/flower-minisblack-08.tif", true), + ("tests/libtiffpic/depth/flower-minisblack-10.tif", true), + ("tests/libtiffpic/depth/flower-minisblack-12.tif", true), + ("tests/libtiffpic/depth/flower-minisblack-14.tif", true), + ("tests/libtiffpic/depth/flower-minisblack-16.tif", true), + ("tests/libtiffpic/depth/flower-minisblack-24.tif", true), + ("tests/libtiffpic/depth/flower-minisblack-32.tif", true), + ("tests/libtiffpic/depth/flower-palette-02.tif", true), + ("tests/libtiffpic/depth/flower-palette-04.tif", true), + ("tests/libtiffpic/depth/flower-palette-08.tif", true), + ("tests/libtiffpic/depth/flower-palette-16.tif", true), + ("tests/libtiffpic/depth/flower-rgb-contig-02.tif", true), + ("tests/libtiffpic/depth/flower-rgb-contig-04.tif", true), + ("tests/libtiffpic/depth/flower-rgb-contig-08.tif", true), + ("tests/libtiffpic/depth/flower-rgb-contig-10.tif", true), + ("tests/libtiffpic/depth/flower-rgb-contig-12.tif", true), + ("tests/libtiffpic/depth/flower-rgb-contig-14.tif", true), + ("tests/libtiffpic/depth/flower-rgb-contig-16.tif", true), + ("tests/libtiffpic/depth/flower-rgb-contig-24.tif", true), + ("tests/libtiffpic/depth/flower-rgb-contig-32.tif", true), + ("tests/libtiffpic/depth/flower-rgb-planar-02.tif", true), + ("tests/libtiffpic/depth/flower-rgb-planar-04.tif", true), + ("tests/libtiffpic/depth/flower-rgb-planar-08.tif", true), + ("tests/libtiffpic/depth/flower-rgb-planar-10.tif", true), + ("tests/libtiffpic/depth/flower-rgb-planar-12.tif", true), + ("tests/libtiffpic/depth/flower-rgb-planar-14.tif", true), + ("tests/libtiffpic/depth/flower-rgb-planar-16.tif", true), + ("tests/libtiffpic/depth/flower-rgb-planar-24.tif", true), + ("tests/libtiffpic/depth/flower-rgb-planar-32.tif", true), + ( + "tests/libtiffpic/depth/flower-separated-contig-08.tif", + true, + ), + ( + "tests/libtiffpic/depth/flower-separated-contig-16.tif", + true, + ), + ( + "tests/libtiffpic/depth/flower-separated-planar-08.tif", + true, + ), + ( + "tests/libtiffpic/depth/flower-separated-planar-16.tif", + true, + ), + ("tests/libtiffpic/depth/genimages", false), + ("tests/libtiffpic/depth/README.txt", false), + ("tests/libtiffpic/depth/summary.txt", false), + ("tests/libtiffpic/dscf0013.tif", true), + ("tests/libtiffpic/fax2d.tif", true), + // No support for direct CCITT Group 3 1D format + ("tests/libtiffpic/g3test.g3", false), + ("tests/libtiffpic/g3test.tif", true), + ("tests/libtiffpic/jello.tif", true), + ("tests/libtiffpic/jim___ah.tif", true), + ("tests/libtiffpic/jim___cg.tif", true), + ("tests/libtiffpic/jim___dg.tif", true), + ("tests/libtiffpic/jim___gg.tif", true), + ("tests/libtiffpic/ladoga.tif", true), + ("tests/libtiffpic/off_l16.tif", true), + ("tests/libtiffpic/off_luv24.tif", true), + ("tests/libtiffpic/off_luv32.tif", true), + ("tests/libtiffpic/oxford.tif", true), + ("tests/libtiffpic/pc260001.tif", true), + ("tests/libtiffpic/quad-jpeg.tif", true), + ("tests/libtiffpic/quad-lzw.tif", true), + // FIXME: See , this has tiles as + // StripOffsets and has a RowsPerStrip. + ("tests/libtiffpic/quad-tile.tif", false), + ("tests/libtiffpic/README", false), + ("tests/libtiffpic/smallliz.tif", true), + ("tests/libtiffpic/strike.tif", true), + ("tests/libtiffpic/text.tif", true), + ("tests/libtiffpic/ycbcr-cat.tif", true), + ("tests/libtiffpic/zackthecat.tif", true), +]; + +fn main() { + let mut candidates: HashMap<_, _> = FILES.iter().copied().collect(); + let mut trials = Vec::new(); + + for entry in WalkDir::new(REFERENCE_DIR) { + let entry = entry.unwrap(); + + if !entry.file_type().is_file() { + continue; + } + + let Some(path) = entry.path().to_str() else { + continue; + }; + + // Mark this path as consumed in either case by removing it. + let Some(should_decode) = candidates.remove(path) else { + panic!("File {} not in reference list", path); + }; + + // Check if we should turn it into a test case. + if !should_decode { + continue; + } + + let path = path.to_string(); + trials.push(Trial::test( + path.to_string(), + move || -> Result<(), Failed> { + decode_libtiffpic(&path) + .map_err(|e| Failed::from(format_args!("Decoding failed for {}: {}", path, e))) + }, + )); + } + + if !candidates.is_empty() { + for (path, _) in candidates { + eprintln!("Reference file {} not found in directory walk", path); + } + + panic!("Some reference files were not found"); + } + + let args = Arguments::from_args(); + libtest_mimic::run(&args, trials).exit(); +} + +fn decode_libtiffpic(path: &str) -> Result<(), tiff::TiffError> { + let path = path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(path); + + let img_file = File::open(path)?; + let mut decoder = Decoder::new(img_file)?; + let mut buffer = DecodingResult::U8(vec![]); + + loop { + let _layout = decoder.read_image_to_buffer(&mut buffer); + + if !decoder.more_images() { + break; + } + + decoder.next_image()?; + } + + Ok(()) +} diff --git a/tests/libtiffpic/CVS/Entries b/tests/libtiffpic/CVS/Entries new file mode 100644 index 0000000..40cd74e --- /dev/null +++ b/tests/libtiffpic/CVS/Entries @@ -0,0 +1,28 @@ +/cramps-tile.tif/1.1/Sat Nov 23 05:17:31 2002/-kb/ +/cramps.tif/1.1/Sat Nov 23 05:17:31 2002/-kb/ +/fax2d.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/g3test.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/jello.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/jim___ah.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/jim___cg.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/jim___dg.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/jim___gg.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/off_l16.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/off_luv24.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/off_luv32.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/oxford.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/quad-jpeg.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/quad-lzw.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/quad-tile.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/smallliz.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/strike.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/text.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +/ycbcr-cat.tif/1.1/Sat Nov 23 05:17:32 2002/-kb/ +D/depth//// +/README/1.2/Thu Dec 29 22:06:14 2005// +/caspian.tif/1.1/Thu Dec 29 22:06:43 2005/-kb/ +/dscf0013.tif/1.1/Thu Dec 29 22:07:23 2005/-kb/ +/g3test.g3/1.1/Thu Dec 29 22:07:27 2005/-kb/ +/ladoga.tif/1.1/Thu Dec 29 22:07:29 2005/-kb/ +/pc260001.tif/1.1/Mon Dec 26 14:54:00 2005/-kb/ +/zackthecat.tif/1.1/Thu Dec 29 22:08:43 2005/-kb/ diff --git a/tests/libtiffpic/CVS/Repository b/tests/libtiffpic/CVS/Repository new file mode 100644 index 0000000..ff4dfe3 --- /dev/null +++ b/tests/libtiffpic/CVS/Repository @@ -0,0 +1 @@ +libtiffpic diff --git a/tests/libtiffpic/CVS/Root b/tests/libtiffpic/CVS/Root new file mode 100644 index 0000000..9f5c5d4 --- /dev/null +++ b/tests/libtiffpic/CVS/Root @@ -0,0 +1 @@ +:pserver:dron@cvs.maptools.org:/cvs/maptools/cvsroot diff --git a/tests/libtiffpic/README b/tests/libtiffpic/README new file mode 100644 index 0000000..5ea0435 --- /dev/null +++ b/tests/libtiffpic/README @@ -0,0 +1,101 @@ +The following image files are included for testing. Note that a wide +variety of images can be generated using the tools provided with the +library (e.g. tiffcp, tiff2bw, tiffmedian, etc.); see below for some +hints on this. + +PlanarConfiguration = 1 (packed data) +------------------------------------- +caspian.tif 279x220 64-bit floating point (deflate) Caspian Sea from space +cramps.tif 800x607 8-bit b&w (packbits) "cramps poster" +cramps-tile.tif 256x256 tiled version of cramps.tif (no compression) +dscf0013.tif 640x480 YCbCr digital camera image which lacks Reference + Black/White values. Contains EXIF SubIFD. No compression. +fax2d.tif 1728x1082 1-bit b&w (G3/2D) facsimile +g3test.g3 raw Group 3 encoded fax file +g3test.tif TIFF equivalent of g3test.g3 created by fax2tiff +jello.tif 256x192 8-bit RGB (lzw palette) Paul Heckbert "jello" +ladoga.tif 158x118 16-bit unsigned, single band, deflate +off_l16.tif 333x225 8-bit CIE LogL (SGILog) office from Greg Larson +off_luv24.tif 333x225 8-bit CIE LogLuv (SGILog24) office from " " +off_luv32.tif 333x225 8-bit CIE LogLuv (SGILog) office from " " +pc260001.tif 640x480 8-bit RGB digital camera image. Contains EXIF SubIFD. + No compression. +quad-jpeg.tif 512x384 8-bit YCbCr (jpeg) version of quad-lzw.tif +quad-lzw.tif 512x384 8-bit RGB (lzw) "quadric surfaces" +quad-tile.tif 512x384 tiled version of quad-lzw.tif (lzw) +strike.tif 256x200 8-bit RGBA (lzw) "bowling pins" from Pixar +text.tif 1512x359 4-bit b&w (thunderscan) am-express credit card +ycbcr-cat.tif 250x325 8-bit YCbCr (lzw) "kitty" created by rgb2ycbcr + +smallliz.tif 160x160 8-bit YCbCr (OLD jpeg) lizard from HP** +zackthecat.tif 234x213 8-bit YCbCr (OLD jpeg) tiled "ZackTheCat" from NeXT** + +** These images are in a deprecated format and are included only for testing + backwards compatibility. JPEG-encoded TIFF images use a different scheme + described in TIFF Technical Note #2 and implemented by libtiff. + +PlanarConfiguration = 2 (separated samples) +------------------------------------------- +oxford.tif 601x81 8-bit RGB (lzw) screendump off oxford + +The other images are from Hewlett Packard and exemplify the use of the +HalftoneHints tag (in their words): + +The images are all the same subject, and should all appear the same +after rendering. Each of the images is slightly different as outlined +by the following table: + + FileName ToneRange HalftoneHints +jim___cg.tif A Y +jim___dg.tif B N +jim___gg.tif B Y + +The images with tone range A are 0-100% linear reflectance images, +in other words, fixed full gamut tone range. The images with tone +range B are what we call "normalized", meaning that the image has +been tone adjusted such the Highlight and Shadow are at gray levels +1 & 2**BitsPerSample-2. + +Each of the three grayscale images should be rendered to look like +the halftone in pics/jim___ah.tif when printed on a Canon SX engine. + +Generated Images +---------------- +The file g3test.tif was created from g3test.g3 with the command: + + fax2tiff -o t.tif -1 -p -M -R 98 g3test.g3 + +Tiled images can be created with tiffcp; e.g. + + tiffcp -t -c none cramps.tif cramps-tile.tif + +(but the tiled images included here were actually generated by the +Silicon Graphics Image Library). + +The file quad-jpeg.tif was created from quad-lzw.tif with the command: + + tiffcp -c jpeg quad-lzw.tif quad-jpeg.tif + +To generate a tiled image with separated samples the following might +be used: + + tiffcp -t -p separate quad-lzw.tif t.tif + +[ Beware that tiffcp does not handle every format TIFF image. In particular, + when conversion between tiled and strip'd images is reliable only when + BitsPerSample is 8. ] + +To generate a G4-encoded image with a single strip the following would work: + + tiffcp -c g4 -r 1082 fax2d.tif t.tif + +Contributing New Images +----------------------- +If you have images that are significantly different from those included +in this package and that do NOT HAVE A COPYRIGHT; feel free to send them +to me at sam@engr.sgi.com. I prefer to receive a URL to a location from +which I can retrieve the image by public FTP. However if that is not +possible you can send it to me in a mail message uuencode'd. Please do +not send large images by mail. Also, please do not send me an image +unless it is notably unique; e.g. not easily generated using the tools +I provide. diff --git a/tests/libtiffpic/caspian.tif b/tests/libtiffpic/caspian.tif new file mode 100644 index 0000000..a907840 Binary files /dev/null and b/tests/libtiffpic/caspian.tif differ diff --git a/tests/libtiffpic/cramps-tile.tif b/tests/libtiffpic/cramps-tile.tif new file mode 100644 index 0000000..d2dec76 Binary files /dev/null and b/tests/libtiffpic/cramps-tile.tif differ diff --git a/tests/libtiffpic/cramps.tif b/tests/libtiffpic/cramps.tif new file mode 100644 index 0000000..b54c572 Binary files /dev/null and b/tests/libtiffpic/cramps.tif differ diff --git a/tests/libtiffpic/depth/CVS/Entries b/tests/libtiffpic/depth/CVS/Entries new file mode 100644 index 0000000..b496d98 --- /dev/null +++ b/tests/libtiffpic/depth/CVS/Entries @@ -0,0 +1,40 @@ +/README.txt/1.1/Sun Jan 30 23:03:00 2005// +/genimages/1.1/Mon Jan 31 02:49:00 2005// +/summary.txt/1.1/Mon Jan 31 02:49:00 2005// +/flower-minisblack-24.tif/1.2/Sun Nov 13 17:25:25 2005/-kb/ +/flower-rgb-contig-24.tif/1.2/Sun Nov 13 17:22:46 2005/-kb/ +/flower-rgb-planar-24.tif/1.2/Sun Nov 13 17:20:24 2005/-kb/ +/flower-minisblack-02.tif/1.1/Thu Dec 29 22:08:43 2005/-kb/ +/flower-minisblack-04.tif/1.1/Thu Dec 29 22:08:43 2005/-kb/ +/flower-minisblack-06.tif/1.1/Thu Dec 29 22:08:43 2005/-kb/ +/flower-minisblack-08.tif/1.1/Thu Dec 29 22:08:44 2005/-kb/ +/flower-minisblack-10.tif/1.1/Thu Dec 29 22:08:44 2005/-kb/ +/flower-minisblack-12.tif/1.1/Thu Dec 29 22:08:45 2005/-kb/ +/flower-minisblack-14.tif/1.1/Thu Dec 29 22:08:45 2005/-kb/ +/flower-minisblack-16.tif/1.1/Thu Dec 29 22:08:46 2005/-kb/ +/flower-minisblack-32.tif/1.1/Thu Dec 29 22:08:47 2005/-kb/ +/flower-palette-02.tif/1.1/Thu Dec 29 22:08:47 2005/-kb/ +/flower-palette-04.tif/1.1/Thu Dec 29 22:08:47 2005/-kb/ +/flower-palette-08.tif/1.1/Thu Dec 29 22:08:47 2005/-kb/ +/flower-palette-16.tif/1.1/Thu Dec 29 22:08:49 2005/-kb/ +/flower-rgb-contig-02.tif/1.1/Thu Dec 29 22:08:49 2005/-kb/ +/flower-rgb-contig-04.tif/1.1/Thu Dec 29 22:08:49 2005/-kb/ +/flower-rgb-contig-08.tif/1.1/Thu Dec 29 22:08:50 2005/-kb/ +/flower-rgb-contig-10.tif/1.1/Thu Dec 29 22:08:51 2005/-kb/ +/flower-rgb-contig-12.tif/1.1/Thu Dec 29 22:08:52 2005/-kb/ +/flower-rgb-contig-14.tif/1.1/Thu Dec 29 22:08:53 2005/-kb/ +/flower-rgb-contig-16.tif/1.1/Thu Dec 29 22:08:55 2005/-kb/ +/flower-rgb-contig-32.tif/1.1/Thu Dec 29 22:08:58 2005/-kb/ +/flower-rgb-planar-02.tif/1.1/Thu Dec 29 22:08:58 2005/-kb/ +/flower-rgb-planar-04.tif/1.1/Thu Dec 29 22:08:58 2005/-kb/ +/flower-rgb-planar-08.tif/1.1/Thu Dec 29 22:08:59 2005/-kb/ +/flower-rgb-planar-10.tif/1.1/Thu Dec 29 22:09:00 2005/-kb/ +/flower-rgb-planar-12.tif/1.1/Thu Dec 29 22:09:02 2005/-kb/ +/flower-rgb-planar-14.tif/1.1/Thu Dec 29 22:09:02 2005/-kb/ +/flower-rgb-planar-16.tif/1.1/Thu Dec 29 22:09:04 2005/-kb/ +/flower-rgb-planar-32.tif/1.1/Thu Dec 29 22:09:08 2005/-kb/ +/flower-separated-contig-08.tif/1.1/Thu Dec 29 22:09:10 2005/-kb/ +/flower-separated-contig-16.tif/1.1/Thu Dec 29 22:09:12 2005/-kb/ +/flower-separated-planar-08.tif/1.1/Thu Dec 29 22:09:12 2005/-kb/ +/flower-separated-planar-16.tif/1.1/Thu Dec 29 22:09:14 2005/-kb/ +D diff --git a/tests/libtiffpic/depth/CVS/Repository b/tests/libtiffpic/depth/CVS/Repository new file mode 100644 index 0000000..6288864 --- /dev/null +++ b/tests/libtiffpic/depth/CVS/Repository @@ -0,0 +1 @@ +libtiffpic/depth diff --git a/tests/libtiffpic/depth/CVS/Root b/tests/libtiffpic/depth/CVS/Root new file mode 100644 index 0000000..9f5c5d4 --- /dev/null +++ b/tests/libtiffpic/depth/CVS/Root @@ -0,0 +1 @@ +:pserver:dron@cvs.maptools.org:/cvs/maptools/cvsroot diff --git a/tests/libtiffpic/depth/README.txt b/tests/libtiffpic/depth/README.txt new file mode 100644 index 0000000..dd74611 --- /dev/null +++ b/tests/libtiffpic/depth/README.txt @@ -0,0 +1,9 @@ +These sample TIFF image files are prepared by Bob Friesenhahn + using a development version of +GraphicsMagick 1.2. + +See the file summary.txt for a description of the images. + +These files are hereby placed in the public domain. + + diff --git a/tests/libtiffpic/depth/flower-minisblack-02.tif b/tests/libtiffpic/depth/flower-minisblack-02.tif new file mode 100644 index 0000000..2278aff Binary files /dev/null and b/tests/libtiffpic/depth/flower-minisblack-02.tif differ diff --git a/tests/libtiffpic/depth/flower-minisblack-04.tif b/tests/libtiffpic/depth/flower-minisblack-04.tif new file mode 100644 index 0000000..2583c42 Binary files /dev/null and b/tests/libtiffpic/depth/flower-minisblack-04.tif differ diff --git a/tests/libtiffpic/depth/flower-minisblack-06.tif b/tests/libtiffpic/depth/flower-minisblack-06.tif new file mode 100644 index 0000000..a9c0c3d Binary files /dev/null and b/tests/libtiffpic/depth/flower-minisblack-06.tif differ diff --git a/tests/libtiffpic/depth/flower-minisblack-08.tif b/tests/libtiffpic/depth/flower-minisblack-08.tif new file mode 100644 index 0000000..f7d8340 Binary files /dev/null and b/tests/libtiffpic/depth/flower-minisblack-08.tif differ diff --git a/tests/libtiffpic/depth/flower-minisblack-10.tif b/tests/libtiffpic/depth/flower-minisblack-10.tif new file mode 100644 index 0000000..d93960c Binary files /dev/null and b/tests/libtiffpic/depth/flower-minisblack-10.tif differ diff --git a/tests/libtiffpic/depth/flower-minisblack-12.tif b/tests/libtiffpic/depth/flower-minisblack-12.tif new file mode 100644 index 0000000..1673be8 Binary files /dev/null and b/tests/libtiffpic/depth/flower-minisblack-12.tif differ diff --git a/tests/libtiffpic/depth/flower-minisblack-14.tif b/tests/libtiffpic/depth/flower-minisblack-14.tif new file mode 100644 index 0000000..1d53867 Binary files /dev/null and b/tests/libtiffpic/depth/flower-minisblack-14.tif differ diff --git a/tests/libtiffpic/depth/flower-minisblack-16.tif b/tests/libtiffpic/depth/flower-minisblack-16.tif new file mode 100644 index 0000000..3c2a6dd Binary files /dev/null and b/tests/libtiffpic/depth/flower-minisblack-16.tif differ diff --git a/tests/libtiffpic/depth/flower-minisblack-24.tif b/tests/libtiffpic/depth/flower-minisblack-24.tif new file mode 100644 index 0000000..5035df4 Binary files /dev/null and b/tests/libtiffpic/depth/flower-minisblack-24.tif differ diff --git a/tests/libtiffpic/depth/flower-minisblack-32.tif b/tests/libtiffpic/depth/flower-minisblack-32.tif new file mode 100644 index 0000000..36d48d4 Binary files /dev/null and b/tests/libtiffpic/depth/flower-minisblack-32.tif differ diff --git a/tests/libtiffpic/depth/flower-palette-02.tif b/tests/libtiffpic/depth/flower-palette-02.tif new file mode 100644 index 0000000..6bd445d Binary files /dev/null and b/tests/libtiffpic/depth/flower-palette-02.tif differ diff --git a/tests/libtiffpic/depth/flower-palette-04.tif b/tests/libtiffpic/depth/flower-palette-04.tif new file mode 100644 index 0000000..b50ac8c Binary files /dev/null and b/tests/libtiffpic/depth/flower-palette-04.tif differ diff --git a/tests/libtiffpic/depth/flower-palette-08.tif b/tests/libtiffpic/depth/flower-palette-08.tif new file mode 100644 index 0000000..b778037 Binary files /dev/null and b/tests/libtiffpic/depth/flower-palette-08.tif differ diff --git a/tests/libtiffpic/depth/flower-palette-16.tif b/tests/libtiffpic/depth/flower-palette-16.tif new file mode 100644 index 0000000..cf3de60 Binary files /dev/null and b/tests/libtiffpic/depth/flower-palette-16.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-contig-02.tif b/tests/libtiffpic/depth/flower-rgb-contig-02.tif new file mode 100644 index 0000000..3813313 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-contig-02.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-contig-04.tif b/tests/libtiffpic/depth/flower-rgb-contig-04.tif new file mode 100644 index 0000000..b469f94 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-contig-04.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-contig-08.tif b/tests/libtiffpic/depth/flower-rgb-contig-08.tif new file mode 100644 index 0000000..2ea0944 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-contig-08.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-contig-10.tif b/tests/libtiffpic/depth/flower-rgb-contig-10.tif new file mode 100644 index 0000000..b6a2240 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-contig-10.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-contig-12.tif b/tests/libtiffpic/depth/flower-rgb-contig-12.tif new file mode 100644 index 0000000..2048573 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-contig-12.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-contig-14.tif b/tests/libtiffpic/depth/flower-rgb-contig-14.tif new file mode 100644 index 0000000..c9e27c0 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-contig-14.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-contig-16.tif b/tests/libtiffpic/depth/flower-rgb-contig-16.tif new file mode 100644 index 0000000..869fe05 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-contig-16.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-contig-24.tif b/tests/libtiffpic/depth/flower-rgb-contig-24.tif new file mode 100644 index 0000000..6037f52 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-contig-24.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-contig-32.tif b/tests/libtiffpic/depth/flower-rgb-contig-32.tif new file mode 100644 index 0000000..17875ee Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-contig-32.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-planar-02.tif b/tests/libtiffpic/depth/flower-rgb-planar-02.tif new file mode 100644 index 0000000..afd364c Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-planar-02.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-planar-04.tif b/tests/libtiffpic/depth/flower-rgb-planar-04.tif new file mode 100644 index 0000000..ec97dc3 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-planar-04.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-planar-08.tif b/tests/libtiffpic/depth/flower-rgb-planar-08.tif new file mode 100644 index 0000000..bbe287f Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-planar-08.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-planar-10.tif b/tests/libtiffpic/depth/flower-rgb-planar-10.tif new file mode 100644 index 0000000..9d21bbe Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-planar-10.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-planar-12.tif b/tests/libtiffpic/depth/flower-rgb-planar-12.tif new file mode 100644 index 0000000..34a3944 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-planar-12.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-planar-14.tif b/tests/libtiffpic/depth/flower-rgb-planar-14.tif new file mode 100644 index 0000000..2c69002 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-planar-14.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-planar-16.tif b/tests/libtiffpic/depth/flower-rgb-planar-16.tif new file mode 100644 index 0000000..9356666 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-planar-16.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-planar-24.tif b/tests/libtiffpic/depth/flower-rgb-planar-24.tif new file mode 100644 index 0000000..e9365d1 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-planar-24.tif differ diff --git a/tests/libtiffpic/depth/flower-rgb-planar-32.tif b/tests/libtiffpic/depth/flower-rgb-planar-32.tif new file mode 100644 index 0000000..fa10e31 Binary files /dev/null and b/tests/libtiffpic/depth/flower-rgb-planar-32.tif differ diff --git a/tests/libtiffpic/depth/flower-separated-contig-08.tif b/tests/libtiffpic/depth/flower-separated-contig-08.tif new file mode 100644 index 0000000..7eefd53 Binary files /dev/null and b/tests/libtiffpic/depth/flower-separated-contig-08.tif differ diff --git a/tests/libtiffpic/depth/flower-separated-contig-16.tif b/tests/libtiffpic/depth/flower-separated-contig-16.tif new file mode 100644 index 0000000..5df4246 Binary files /dev/null and b/tests/libtiffpic/depth/flower-separated-contig-16.tif differ diff --git a/tests/libtiffpic/depth/flower-separated-planar-08.tif b/tests/libtiffpic/depth/flower-separated-planar-08.tif new file mode 100644 index 0000000..6994a12 Binary files /dev/null and b/tests/libtiffpic/depth/flower-separated-planar-08.tif differ diff --git a/tests/libtiffpic/depth/flower-separated-planar-16.tif b/tests/libtiffpic/depth/flower-separated-planar-16.tif new file mode 100644 index 0000000..380b9b4 Binary files /dev/null and b/tests/libtiffpic/depth/flower-separated-planar-16.tif differ diff --git a/tests/libtiffpic/depth/genimages b/tests/libtiffpic/depth/genimages new file mode 100755 index 0000000..d43dd11 --- /dev/null +++ b/tests/libtiffpic/depth/genimages @@ -0,0 +1,73 @@ +#!/usr/bin/ksh + +GM=/scratch/bfriesen/build/GraphicsMagick-32-static/utilities/gm +GM_STD_OPT="-compress none" +MASTER_IMAGE_ORIGINAL='/home/bfriesen/images/david/112_1201-flowers.jpg' +MASTER_IMAGE_GRAY=gray.miff +MASTER_IMAGE_RGB=rgb.miff +MASTER_IMAGE_CMYK=cmyk.miff +COLUMNS=73 +ROWS=43 + +GRAY_DEPTHS='2 4 6 8 10 12 14 16 24 32' +PSEUDO_DEPTHS='2 4 8 16' +TRUE_COLORS='2 4 8 10 12 14 16 24 32' +CMYK_COLORS='8 16' + +SUMMARY=summary.txt +echo > $SUMMARY + +$GM convert $MASTER_IMAGE_ORIGINAL +profile '*' -depth 32 -type Grayscale -density 72x72 -geometry "${COLUMNS}x${ROWS}" $MASTER_IMAGE_GRAY +$GM convert $MASTER_IMAGE_ORIGINAL +profile '*' -depth 32 -density 72x72 -geometry "${COLUMNS}x${ROWS}" $MASTER_IMAGE_RGB +$GM convert $MASTER_IMAGE_ORIGINAL +profile '*' -colorspace cmyk -depth 32 -density 72x72 -geometry "${COLUMNS}x${ROWS}" $MASTER_IMAGE_CMYK + +# Gray images +for depth in $GRAY_DEPTHS +do + outname=`printf "flower-minisblack-%02d.tif" $depth` + echo "$outname\t${COLUMNS}x${ROWS} $depth-bit minisblack gray image" >> $SUMMARY + $GM convert -verbose $MASTER_IMAGE_GRAY $GM_STD_OPT -type Grayscale -define tiff:bits-per-sample=$depth $outname +done + +# Colormapped images +for depth in $PSEUDO_DEPTHS +do + colors=`echo "2^${depth}" | bc` + outname=`printf "flower-palette-%02d.tif" $depth` + echo "$outname\t${COLUMNS}x${ROWS} ${colors}-entry colormapped image" >> $SUMMARY + $GM convert -verbose $MASTER_IMAGE_RGB $GM_STD_OPT -colors $colors $outname +done + +# Truecolor images +for depth in $TRUE_COLORS +do + outname=`printf "flower-rgb-contig-%02d.tif" $depth` + echo "$outname\t${COLUMNS}x${ROWS} $depth-bit contiguous RGB image" >> $SUMMARY + $GM convert -verbose $MASTER_IMAGE_RGB $GM_STD_OPT -type TrueColor -define tiff:bits-per-sample=$depth $outname +done + +# Truecolor planar images +for depth in $TRUE_COLORS +do + outname=`printf "flower-rgb-planar-%02d.tif" $depth` + echo "$outname\t${COLUMNS}x${ROWS} $depth-bit seperated RGB image" >> $SUMMARY + $GM convert -verbose $MASTER_IMAGE_RGB $GM_STD_OPT -type TrueColor -interlace plane -define tiff:bits-per-sample=$depth $outname +done + +# CMYK images +for depth in $CMYK_COLORS +do + outname=`printf "flower-separated-contig-%02d.tif" $depth` + echo "$outname\t${COLUMNS}x${ROWS} $depth-bit contiguous CMYK image" >> $SUMMARY + $GM convert -verbose $MASTER_IMAGE_RGB $GM_STD_OPT -type ColorSeparation -define tiff:bits-per-sample=$depth $outname +done + +# CMYK planar images +for depth in $CMYK_COLORS +do + outname=`printf "flower-separated-planar-%02d.tif" $depth` + echo "$outname\t${COLUMNS}x${ROWS} $depth-bit separated CMYK image" >> $SUMMARY + $GM convert -verbose $MASTER_IMAGE_RGB $GM_STD_OPT -type ColorSeparation -interlace plane -define tiff:bits-per-sample=$depth $outname +done + +rm -f $MASTER_IMAGE_GRAY $MASTER_IMAGE_RGB $MASTER_IMAGE_CMYK \ No newline at end of file diff --git a/tests/libtiffpic/depth/summary.txt b/tests/libtiffpic/depth/summary.txt new file mode 100644 index 0000000..19f3aab --- /dev/null +++ b/tests/libtiffpic/depth/summary.txt @@ -0,0 +1,37 @@ + +flower-minisblack-02.tif 73x43 2-bit minisblack gray image +flower-minisblack-04.tif 73x43 4-bit minisblack gray image +flower-minisblack-06.tif 73x43 6-bit minisblack gray image +flower-minisblack-08.tif 73x43 8-bit minisblack gray image +flower-minisblack-10.tif 73x43 10-bit minisblack gray image +flower-minisblack-12.tif 73x43 12-bit minisblack gray image +flower-minisblack-14.tif 73x43 14-bit minisblack gray image +flower-minisblack-16.tif 73x43 16-bit minisblack gray image +flower-minisblack-24.tif 73x43 24-bit minisblack gray image +flower-minisblack-32.tif 73x43 32-bit minisblack gray image +flower-palette-02.tif 73x43 4-entry colormapped image +flower-palette-04.tif 73x43 16-entry colormapped image +flower-palette-08.tif 73x43 256-entry colormapped image +flower-palette-16.tif 73x43 65536-entry colormapped image +flower-rgb-contig-02.tif 73x43 2-bit contiguous RGB image +flower-rgb-contig-04.tif 73x43 4-bit contiguous RGB image +flower-rgb-contig-08.tif 73x43 8-bit contiguous RGB image +flower-rgb-contig-10.tif 73x43 10-bit contiguous RGB image +flower-rgb-contig-12.tif 73x43 12-bit contiguous RGB image +flower-rgb-contig-14.tif 73x43 14-bit contiguous RGB image +flower-rgb-contig-16.tif 73x43 16-bit contiguous RGB image +flower-rgb-contig-24.tif 73x43 24-bit contiguous RGB image +flower-rgb-contig-32.tif 73x43 32-bit contiguous RGB image +flower-rgb-planar-02.tif 73x43 2-bit seperated RGB image +flower-rgb-planar-04.tif 73x43 4-bit seperated RGB image +flower-rgb-planar-08.tif 73x43 8-bit seperated RGB image +flower-rgb-planar-10.tif 73x43 10-bit seperated RGB image +flower-rgb-planar-12.tif 73x43 12-bit seperated RGB image +flower-rgb-planar-14.tif 73x43 14-bit seperated RGB image +flower-rgb-planar-16.tif 73x43 16-bit seperated RGB image +flower-rgb-planar-24.tif 73x43 24-bit seperated RGB image +flower-rgb-planar-32.tif 73x43 32-bit seperated RGB image +flower-separated-contig-08.tif 73x43 8-bit contiguous CMYK image +flower-separated-contig-16.tif 73x43 16-bit contiguous CMYK image +flower-separated-planar-08.tif 73x43 8-bit separated CMYK image +flower-separated-planar-16.tif 73x43 16-bit separated CMYK image diff --git a/tests/libtiffpic/dscf0013.tif b/tests/libtiffpic/dscf0013.tif new file mode 100644 index 0000000..4c4792c Binary files /dev/null and b/tests/libtiffpic/dscf0013.tif differ diff --git a/tests/libtiffpic/fax2d.tif b/tests/libtiffpic/fax2d.tif new file mode 100644 index 0000000..ce38c00 Binary files /dev/null and b/tests/libtiffpic/fax2d.tif differ diff --git a/tests/libtiffpic/g3test.g3 b/tests/libtiffpic/g3test.g3 new file mode 100644 index 0000000..9382efe Binary files /dev/null and b/tests/libtiffpic/g3test.g3 differ diff --git a/tests/libtiffpic/g3test.tif b/tests/libtiffpic/g3test.tif new file mode 100644 index 0000000..2a8eb1e Binary files /dev/null and b/tests/libtiffpic/g3test.tif differ diff --git a/tests/libtiffpic/jello.tif b/tests/libtiffpic/jello.tif new file mode 100644 index 0000000..535ad05 Binary files /dev/null and b/tests/libtiffpic/jello.tif differ diff --git a/tests/libtiffpic/jim___ah.tif b/tests/libtiffpic/jim___ah.tif new file mode 100644 index 0000000..21a897d Binary files /dev/null and b/tests/libtiffpic/jim___ah.tif differ diff --git a/tests/libtiffpic/jim___cg.tif b/tests/libtiffpic/jim___cg.tif new file mode 100644 index 0000000..447df0f Binary files /dev/null and b/tests/libtiffpic/jim___cg.tif differ diff --git a/tests/libtiffpic/jim___dg.tif b/tests/libtiffpic/jim___dg.tif new file mode 100644 index 0000000..856811f Binary files /dev/null and b/tests/libtiffpic/jim___dg.tif differ diff --git a/tests/libtiffpic/jim___gg.tif b/tests/libtiffpic/jim___gg.tif new file mode 100644 index 0000000..d660f43 Binary files /dev/null and b/tests/libtiffpic/jim___gg.tif differ diff --git a/tests/libtiffpic/ladoga.tif b/tests/libtiffpic/ladoga.tif new file mode 100644 index 0000000..e44f8c0 Binary files /dev/null and b/tests/libtiffpic/ladoga.tif differ diff --git a/tests/libtiffpic/off_l16.tif b/tests/libtiffpic/off_l16.tif new file mode 100644 index 0000000..730d10f Binary files /dev/null and b/tests/libtiffpic/off_l16.tif differ diff --git a/tests/libtiffpic/off_luv24.tif b/tests/libtiffpic/off_luv24.tif new file mode 100644 index 0000000..48c7721 Binary files /dev/null and b/tests/libtiffpic/off_luv24.tif differ diff --git a/tests/libtiffpic/off_luv32.tif b/tests/libtiffpic/off_luv32.tif new file mode 100644 index 0000000..ddf4924 Binary files /dev/null and b/tests/libtiffpic/off_luv32.tif differ diff --git a/tests/libtiffpic/oxford.tif b/tests/libtiffpic/oxford.tif new file mode 100644 index 0000000..7ec417b Binary files /dev/null and b/tests/libtiffpic/oxford.tif differ diff --git a/tests/libtiffpic/pc260001.tif b/tests/libtiffpic/pc260001.tif new file mode 100644 index 0000000..05b97ad Binary files /dev/null and b/tests/libtiffpic/pc260001.tif differ diff --git a/tests/libtiffpic/quad-jpeg.tif b/tests/libtiffpic/quad-jpeg.tif new file mode 100644 index 0000000..e14f4c2 Binary files /dev/null and b/tests/libtiffpic/quad-jpeg.tif differ diff --git a/tests/libtiffpic/quad-lzw.tif b/tests/libtiffpic/quad-lzw.tif new file mode 100644 index 0000000..ec614bf Binary files /dev/null and b/tests/libtiffpic/quad-lzw.tif differ diff --git a/tests/libtiffpic/quad-tile.tif b/tests/libtiffpic/quad-tile.tif new file mode 100644 index 0000000..4ed11dd Binary files /dev/null and b/tests/libtiffpic/quad-tile.tif differ diff --git a/tests/libtiffpic/smallliz.tif b/tests/libtiffpic/smallliz.tif new file mode 100755 index 0000000..ee9dbb0 Binary files /dev/null and b/tests/libtiffpic/smallliz.tif differ diff --git a/tests/libtiffpic/strike.tif b/tests/libtiffpic/strike.tif new file mode 100644 index 0000000..21bc748 Binary files /dev/null and b/tests/libtiffpic/strike.tif differ diff --git a/tests/libtiffpic/text.tif b/tests/libtiffpic/text.tif new file mode 100644 index 0000000..4f5206d Binary files /dev/null and b/tests/libtiffpic/text.tif differ diff --git a/tests/libtiffpic/ycbcr-cat.tif b/tests/libtiffpic/ycbcr-cat.tif new file mode 100644 index 0000000..445e6ac Binary files /dev/null and b/tests/libtiffpic/ycbcr-cat.tif differ diff --git a/tests/libtiffpic/zackthecat.tif b/tests/libtiffpic/zackthecat.tif new file mode 100644 index 0000000..15185b6 Binary files /dev/null and b/tests/libtiffpic/zackthecat.tif differ