From d5fc2d410ac985e23eec6acea685f93a95627912 Mon Sep 17 00:00:00 2001 From: sharkAndshar Date: Tue, 19 Nov 2024 16:06:42 +0800 Subject: [PATCH] wip --- martin/src/cog/errors.rs | 4 +- martin/src/cog/mod.rs | 125 ++++++++++++++++++++++++++++++++++----- 2 files changed, 111 insertions(+), 18 deletions(-) diff --git a/martin/src/cog/errors.rs b/martin/src/cog/errors.rs index 6501cfeff..9998dc5b6 100644 --- a/martin/src/cog/errors.rs +++ b/martin/src/cog/errors.rs @@ -32,8 +32,8 @@ pub enum CogError { #[error("Failed to read {1}th chunk(0 based index) at ifd {2} from tiff file {3}: {0}")] ReadChunkFailed(TiffError, u32, usize, PathBuf), - #[error("Failed to write header of png file at {0}, the color type is {1:?}, the bit depth is {2:?}: {3}")] - WritePngHeaderFailed(PathBuf, png::ColorType, png::BitDepth, EncodingError), + #[error("Failed to write header of png file at {0}: {1}")] + WritePngHeaderFailed(PathBuf, EncodingError), #[error("Failed to write pixel bytes to png file at {0}: {1}")] WriteToPngFailed(PathBuf, EncodingError), diff --git a/martin/src/cog/mod.rs b/martin/src/cog/mod.rs index ad4493fbc..c6c118154 100644 --- a/martin/src/cog/mod.rs +++ b/martin/src/cog/mod.rs @@ -1,6 +1,7 @@ mod errors; pub use errors::CogError; +use serde_yaml::with; use std::collections::HashMap; use std::fs::File; @@ -124,7 +125,14 @@ impl Source for CogSource { ), ColorType::Palette(_) => todo!(), ColorType::GrayA(_) => todo!(), - ColorType::RGBA(_) => todo!(), + ColorType::RGBA(_) => rgba_to_png( + decode_result, + tile_width, + tile_height, + data_width, + data_height, + &self.path, + ), ColorType::CMYK(_) => todo!(), ColorType::YCbCr(_) => todo!(), }?; @@ -133,6 +141,94 @@ impl Source for CogSource { } } +fn rgba_to_png( + data: DecodingResult, + tile_width: u32, + tile_height: u32, + data_width: u32, + data_height: u32, + with_alpha: bool, + 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); + + let components_count; + if with_alpha { + encoder.set_color(png::ColorType::Rgba); + components_count = 4; + } else { + encoder.set_color(png::ColorType::Rgb); + components_count = 3; + } + + match data { + DecodingResult::U8(vec) => { + { + 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, + components_count, + ); + 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) => { + 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, + components_count, + ); + 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 rgb_to_png( data: DecodingResult, tile_width: u32, @@ -150,17 +246,13 @@ fn rgb_to_png( 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(), - png::ColorType::Rgb, - png::BitDepth::Eight, - e, - ) - })?; + 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); + 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))?; @@ -181,7 +273,7 @@ fn rgb_to_png( 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); + 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() @@ -211,18 +303,19 @@ fn pad_data( tile_height: u32, data_width: u32, data_height: u32, + components_count: u32, ) -> Vec { - let mut arr = vec![no_data; (tile_width * tile_height * 3) as usize]; + let mut result = vec![no_data; (tile_width * tile_height * 3) as usize]; for row in 0..data_height { for col in 0..data_width { let idx = row * data_width * 3 + col * 3; let arr_idx = row * tile_width * 3 + col * 3; - arr[arr_idx as usize] = vec[idx as usize]; // r - arr[(arr_idx + 1) as usize] = vec[(idx + 1) as usize]; // g - arr[(arr_idx + 2) as usize] = vec[(idx + 2) as usize]; // b + for component_idx in 0..components_count { + result[(arr_idx + component_idx) as usize] = vec[(idx + component_idx) as usize]; + } } } - arr + result } #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]