From af8a8d660f8395ad61f2920696cc2d086e9b3739 Mon Sep 17 00:00:00 2001 From: "A. Molzer" <5550310+197g@users.noreply.github.com> Date: Sun, 28 Dec 2025 18:48:30 +0100 Subject: [PATCH] Write decoded planar data in example --- examples/decode.rs | 93 +++++++++++++++++++++++++++++++++++++++++++--- src/decoder/mod.rs | 25 +++++++++++-- 2 files changed, 109 insertions(+), 9 deletions(-) diff --git a/examples/decode.rs b/examples/decode.rs index e40476c..023ce0d 100644 --- a/examples/decode.rs +++ b/examples/decode.rs @@ -1,4 +1,4 @@ -use tiff::decoder::Decoder; +use tiff::decoder::{BufferLayoutPreference, Decoder, DecodingBuffer, DecodingResult}; fn main() -> Result<(), Box> { let Some(image) = std::env::args_os().nth(1) else { @@ -10,10 +10,93 @@ fn main() -> Result<(), Box> { let io = std::io::BufReader::new(file); let mut reader = Decoder::new(io)?; - while { - reader.read_image()?; - reader.more_images() - } {} + for i in 0u32.. { + let layout = reader.image_buffer_layout()?; + let colortype = reader.colortype()?; + let dimensions = reader.dimensions()?; + + let mut data = reader.read_image()?; + debug_planes(i, &mut data, &layout, &colortype, dimensions); + + if !reader.more_images() { + break; + } + + reader.next_image()? + } Ok(()) } + +fn debug_planes( + index: u32, + data: &mut DecodingResult, + layout: &BufferLayoutPreference, + colortype: &tiff::ColorType, + (width, height): (u32, u32), +) { + let (depth, mut tupltype) = match colortype { + tiff::ColorType::Gray(_) => (1, "GRAYSCALE"), + tiff::ColorType::RGB(_) => (3, "RGB"), + tiff::ColorType::RGBA(_) => (4, "RGB_ALPHA"), + tiff::ColorType::Palette(_) => (1, "PALETTE"), + tiff::ColorType::CMYK(_) => (4, "CMYK"), + tiff::ColorType::Multiband { num_samples: 2, .. } => (2, "GRAYSCALE_ALPHA"), + _ => { + eprintln!("Unsupported color type for PAM output: {:?}", colortype); + return; + } + }; + + let maxval = match data.as_buffer(0) { + DecodingBuffer::U8(_) => u64::from(u8::MAX), + DecodingBuffer::U16(_) => u64::from(u16::MAX), + DecodingBuffer::U32(_) => u64::from(u32::MAX), + DecodingBuffer::U64(_) => u64::MAX, + // Eh, this is a good effort I guess. + DecodingBuffer::I8(items) => { + items.iter_mut().for_each(|v| *v = 0.max(*v)); + u64::from(i8::MAX as u8) + } + DecodingBuffer::I16(items) => { + items.iter_mut().for_each(|v| *v = 0.max(*v)); + u64::from(i16::MAX as u16) + } + DecodingBuffer::I32(items) => { + items.iter_mut().for_each(|v| *v = 0.max(*v)); + u64::from(i32::MAX as u32) + } + DecodingBuffer::I64(items) => { + items.iter_mut().for_each(|v| *v = 0.max(*v)); + i64::MAX as u64 + } + // Not supported by PAM. + DecodingBuffer::F16(_) | DecodingBuffer::F32(_) | DecodingBuffer::F64(_) => return, + }; + + let byte_len = if layout.planes > 1 { + tupltype = "GRAYSCALE"; + layout.plane_stride.unwrap().get() + } else { + data.as_buffer(0).byte_len() + }; + + // Write out this image's planes to PAM files. + let header = format!("P7\nWIDTH {width}\nHEIGHT {height}\nDEPTH {depth}\nMAXVAL {maxval}\nTUPLTYPE {tupltype}\nENDHDR\n"); + + for (plane, plane_data) in data + .as_buffer(0) + .as_bytes_mut() + .chunks_exact(byte_len) + .enumerate() + { + let filename = format!("image_{index:03}_plane_{plane:03}.pam"); + let mut file = std::fs::File::create(filename).expect("Failed to create output file"); + + use std::io::Write; + file.write_all(header.as_bytes()) + .expect("Failed to write PAM header"); + file.write_all(plane_data) + .expect("Failed to write PAM data"); + } +} diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 2c4a8ac..6c97390 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -110,6 +110,7 @@ impl DecodingResult { Self::new(size, limits, DecodingResult::I64) } + /// Get a view of this buffer starting from the nth _sample_ of the current type. pub fn as_buffer(&mut self, start: usize) -> DecodingBuffer<'_> { match *self { DecodingResult::U8(ref mut buf) => DecodingBuffer::U8(&mut buf[start..]), @@ -154,9 +155,25 @@ pub enum DecodingBuffer<'a> { } impl<'a> DecodingBuffer<'a> { - fn as_bytes_mut(&mut self) -> &mut [u8] { + pub fn as_bytes(&self) -> &[u8] { match self { - DecodingBuffer::U8(ref mut buf) => buf, + DecodingBuffer::U8(buf) => buf, + DecodingBuffer::I8(buf) => bytecast::i8_as_ne_bytes(buf), + DecodingBuffer::U16(buf) => bytecast::u16_as_ne_bytes(buf), + DecodingBuffer::I16(buf) => bytecast::i16_as_ne_bytes(buf), + DecodingBuffer::U32(buf) => bytecast::u32_as_ne_bytes(buf), + DecodingBuffer::I32(buf) => bytecast::i32_as_ne_bytes(buf), + DecodingBuffer::U64(buf) => bytecast::u64_as_ne_bytes(buf), + DecodingBuffer::I64(buf) => bytecast::i64_as_ne_bytes(buf), + DecodingBuffer::F16(buf) => bytecast::f16_as_ne_bytes(buf), + DecodingBuffer::F32(buf) => bytecast::f32_as_ne_bytes(buf), + DecodingBuffer::F64(buf) => bytecast::f64_as_ne_bytes(buf), + } + } + + pub fn as_bytes_mut(&mut self) -> &mut [u8] { + match self { + DecodingBuffer::U8(buf) => buf, DecodingBuffer::I8(buf) => bytecast::i8_as_ne_mut_bytes(buf), DecodingBuffer::U16(buf) => bytecast::u16_as_ne_mut_bytes(buf), DecodingBuffer::I16(buf) => bytecast::i16_as_ne_mut_bytes(buf), @@ -170,8 +187,8 @@ impl<'a> DecodingBuffer<'a> { } } - pub fn byte_len(&mut self) -> usize { - self.as_bytes_mut().len() + pub fn byte_len(&self) -> usize { + self.as_bytes().len() } }