use std::io::BufReader;
use std::path::Path;
use image::{DynamicImage, RgbImage};
use tiff::ColorType as TiffColorType;
use tiff::decoder::{Decoder, DecodingResult};
use crate::error::{Error, Result};
pub fn load_tiff_pages(path: impl AsRef<Path>) -> Result<Vec<RgbImage>> {
let path = path.as_ref();
let file = BufReader::new(std::fs::File::open(path)?);
let mut dec = Decoder::new(file)
.map_err(|e| Error::Tiff(format!("init decoder: {e}")))?;
let mut pages = Vec::new();
loop {
let page = decode_current(&mut dec, pages.len())?;
pages.push(page);
if dec.more_images() {
dec.next_image()
.map_err(|e| Error::Tiff(format!("next_image pag.{}: {e}", pages.len())))?;
} else {
break;
}
}
Ok(pages)
}
fn decode_current<R: std::io::Read + std::io::Seek>(
dec: &mut Decoder<R>,
page_idx: usize,
) -> Result<RgbImage> {
let (w, h) = dec.dimensions()
.map_err(|e| Error::Tiff(format!("dimensions pag.{page_idx}: {e}")))?;
let color = dec.colortype()
.map_err(|e| Error::Tiff(format!("colortype pag.{page_idx}: {e}")))?;
let buf = dec.read_image()
.map_err(|e| Error::Tiff(format!("read_image pag.{page_idx}: {e}")))?;
let dyn_img: DynamicImage = match (color, buf) {
(TiffColorType::Gray(8), DecodingResult::U8(b)) =>
DynamicImage::ImageLuma8(
image::ImageBuffer::from_raw(w, h, b)
.ok_or_else(|| tiff_err(page_idx, "Luma8 from_raw"))?),
(TiffColorType::RGB(8), DecodingResult::U8(b)) =>
DynamicImage::ImageRgb8(
image::ImageBuffer::from_raw(w, h, b)
.ok_or_else(|| tiff_err(page_idx, "RGB8 from_raw"))?),
(TiffColorType::RGBA(8), DecodingResult::U8(b)) =>
DynamicImage::ImageRgba8(
image::ImageBuffer::from_raw(w, h, b)
.ok_or_else(|| tiff_err(page_idx, "RGBA8 from_raw"))?),
(TiffColorType::Gray(16), DecodingResult::U16(b)) => {
let b8: Vec<u8> = b.iter().map(|&v| (v >> 8) as u8).collect();
DynamicImage::ImageLuma8(
image::ImageBuffer::from_raw(w, h, b8)
.ok_or_else(|| tiff_err(page_idx, "Gray16→8 from_raw"))?)
}
(TiffColorType::RGB(16), DecodingResult::U16(b)) => {
let b8: Vec<u8> = b.iter().map(|&v| (v >> 8) as u8).collect();
DynamicImage::ImageRgb8(
image::ImageBuffer::from_raw(w, h, b8)
.ok_or_else(|| tiff_err(page_idx, "RGB16→8 from_raw"))?)
}
(ct, _) => return Err(Error::Tiff(
format!("pag.{page_idx}: tipo colore non gestito: {ct:?}"))),
};
Ok(dyn_img.to_rgb8())
}
fn tiff_err(page: usize, msg: &str) -> Error {
Error::Tiff(format!("pag.{page}: {msg} fallito"))
}