diff --git a/martin/src/cog/errors.rs b/martin/src/cog/errors.rs index 9998dc5b6..13e06f407 100644 --- a/martin/src/cog/errors.rs +++ b/martin/src/cog/errors.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use png::EncodingError; +use png::{ColorType, EncodingError}; use tiff::TiffError; #[derive(thiserror::Error, Debug)] @@ -37,4 +37,9 @@ pub enum CogError { #[error("Failed to write pixel bytes to png file at {0}: {1}")] WriteToPngFailed(PathBuf, EncodingError), + + #[error( + "The bit depth {} of the tiff file {1} is not accepted by png crate when encoding tif chunk data to png" + )] + PngBitDepthNotAccepted(u8, PathBuf, ColorType), } diff --git a/martin/src/cog/mod.rs b/martin/src/cog/mod.rs index c6c118154..6bf0be40a 100644 --- a/martin/src/cog/mod.rs +++ b/martin/src/cog/mod.rs @@ -1,6 +1,7 @@ mod errors; pub use errors::CogError; +use png::BitDepth; use serde_yaml::with; use std::collections::HashMap; @@ -114,23 +115,32 @@ impl Source for CogSource { let tile_height = decoder.chunk_dimensions().1; let (data_width, data_height) = decoder.chunk_data_dimensions(tile_idx); let png_bytes = match color_type { - ColorType::Gray(_) => todo!(), + ColorType::Gray(n_bits_per_sample) => gray_to_png( + decode_result, + tile_width, + tile_height, + data_width, + data_height, + &self.path, + ), ColorType::RGB(_) => rgb_to_png( decode_result, tile_width, tile_height, data_width, data_height, + false, &self.path, ), ColorType::Palette(_) => todo!(), ColorType::GrayA(_) => todo!(), - ColorType::RGBA(_) => rgba_to_png( + ColorType::RGBA(_) => rgb_to_png( decode_result, tile_width, tile_height, data_width, data_height, + true, &self.path, ), ColorType::CMYK(_) => todo!(), @@ -141,7 +151,39 @@ impl Source for CogSource { } } -fn rgba_to_png( +fn gray_to_png( + data: DecodingResult, + tile_width: u32, + tile_height: u32, + data_width: u32, + data_height: u32, + path: &PathBuf, +) -> Result, CogError> { + let is_padded = data_width != tile_width; + + let mut buffer = Vec::new(); + let mut encoder = png::Encoder::new(BufWriter::new(&mut buffer), tile_width, tile_height); + encoder.set_color(png::ColorType::Grayscale); + match data { + DecodingResult::U8(vec) => { + encoder.set_depth(BitDepth::Eight); + + todo!() + } + DecodingResult::U16(vec) => todo!(), + DecodingResult::U32(vec) => todo!(), + DecodingResult::U64(vec) => todo!(), + DecodingResult::F32(vec) => todo!(), + DecodingResult::F64(vec) => todo!(), + DecodingResult::I8(vec) => todo!(), + DecodingResult::I16(vec) => todo!(), + DecodingResult::I32(vec) => todo!(), + DecodingResult::I64(vec) => todo!(), + } + todo!() +} + +fn rgb_to_png( data: DecodingResult, tile_width: u32, tile_height: u32, @@ -229,73 +271,6 @@ fn rgba_to_png( } } -fn rgb_to_png( - data: DecodingResult, - tile_width: u32, - tile_height: u32, - data_width: u32, - data_height: u32, - path: &PathBuf, -) -> Result, CogError> { - let is_padded = data_width != tile_width; - match data { - DecodingResult::U8(vec) => { - let mut buffer = Vec::new(); - { - let w = BufWriter::new(&mut buffer); - let mut encoder = png::Encoder::new(w, tile_width, tile_height); - encoder.set_color(png::ColorType::Rgb); - encoder.set_depth(png::BitDepth::Eight); - let mut writer = encoder - .write_header() - .map_err(|e| CogError::WritePngHeaderFailed(path.clone(), e))?; - if is_padded { - //todo the no_data value should read from the tiff file, or from configuration - let arr = - pad_data(0, &vec, tile_width, tile_height, data_width, data_height, 3); - writer - .write_image_data(&arr) - .map_err(|e| CogError::WriteToPngFailed(path.clone(), e))?; - } else { - writer - .write_image_data(&vec) - .map_err(|e| CogError::WriteToPngFailed(path.clone(), e))?; - } - } - Ok(buffer) - } - DecodingResult::U16(vec) => { - let mut buffer = Vec::new(); - let w = BufWriter::new(&mut buffer); - let mut encoder = png::Encoder::new(w, tile_width, tile_height); - encoder.set_color(png::ColorType::Rgb); - encoder.set_depth(png::BitDepth::Sixteen); - - if is_padded { - //todo the no_data value should read from the tiff file - let arr = pad_data(0, &vec, tile_width, tile_height, data_width, data_height, 3); - let u8_vec: &[u8] = bytemuck::cast_slice(&arr); - let mut writer = encoder - .write_header() - .map_err(|e| CogError::WriteToPngFailed(path.clone(), e))?; - writer - .write_image_data(u8_vec) - .map_err(|e| CogError::WriteToPngFailed(path.clone(), e))?; - } else { - let u8_vec: &[u8] = bytemuck::cast_slice(&vec); - let mut writer = encoder - .write_header() - .map_err(|e| CogError::WriteToPngFailed(path.clone(), e))?; - writer - .write_image_data(u8_vec) - .map_err(|e| CogError::WriteToPngFailed(path.clone(), e))?; - } - Ok(buffer) - } - _ => todo!(), - } -} - fn pad_data( no_data: T, vec: &[T],