From cf4ac6f5348dd8e9da1cc0139d5278aa6cb700a4 Mon Sep 17 00:00:00 2001 From: sharkAndshar Date: Wed, 20 Nov 2024 12:16:13 +0800 Subject: [PATCH] wip --- martin/src/cog/errors.rs | 7 +- martin/src/cog/mod.rs | 268 ++++++++++++++++++--------------------- 2 files changed, 127 insertions(+), 148 deletions(-) diff --git a/martin/src/cog/errors.rs b/martin/src/cog/errors.rs index 13e06f407..89d414b29 100644 --- a/martin/src/cog/errors.rs +++ b/martin/src/cog/errors.rs @@ -39,7 +39,12 @@ pub enum CogError { 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" + "The combination of bit depth {0} and colory typr {2:?} of the tiff file {1} is not accepted by png crate when encoding tif chunk data to png" )] PngBitDepthNotAccepted(u8, PathBuf, ColorType), + + #[error( + "The color type {0:?} and its bit depth of the tiff file {1} is not supported by png crate" + )] + NotSupportedColorTypeAndBitDepth(tiff::ColorType, PathBuf), } diff --git a/martin/src/cog/mod.rs b/martin/src/cog/mod.rs index 6bf0be40a..1f15e450d 100644 --- a/martin/src/cog/mod.rs +++ b/martin/src/cog/mod.rs @@ -1,8 +1,8 @@ mod errors; +use bytemuck::NoUninit; pub use errors::CogError; -use png::BitDepth; -use serde_yaml::with; +use png::{BitDepth, ColorType}; use std::collections::HashMap; use std::fs::File; @@ -13,7 +13,6 @@ use std::{fmt::Debug, path::PathBuf}; use std::io::BufWriter; use tiff::decoder::{Decoder, DecodingResult}; use tiff::tags::Tag; -use tiff::ColorType; use async_trait::async_trait; use martin_tile_utils::{Format, TileCoord, TileInfo}; @@ -66,6 +65,7 @@ impl Source for CogSource { Box::new(self.clone()) } + #[allow(clippy::too_many_lines)] async fn get_tile( &self, xyz: TileCoord, @@ -114,184 +114,158 @@ impl Source for CogSource { let tile_width = decoder.chunk_dimensions().0; 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(n_bits_per_sample) => gray_to_png( - decode_result, + + let png_file_bytes = match (decode_result, color_type) { + (DecodingResult::U8(vec), tiff::ColorType::Gray(_)) => to_png( + 0, + vec, + ColorType::Grayscale, + BitDepth::Eight, + tile_width, + tile_height, + data_width, + data_height, + 1, + &self.path, + ), + (DecodingResult::U8(vec), tiff::ColorType::RGB(_)) => to_png( + 0, + vec, + ColorType::Rgb, + BitDepth::Eight, tile_width, tile_height, data_width, data_height, + 3, &self.path, ), - ColorType::RGB(_) => rgb_to_png( - decode_result, + (DecodingResult::U8(vec), tiff::ColorType::RGBA(_)) => to_png( + 0, + vec, + ColorType::Rgba, + BitDepth::Eight, tile_width, tile_height, data_width, data_height, - false, + 4, &self.path, ), - ColorType::Palette(_) => todo!(), - ColorType::GrayA(_) => todo!(), - ColorType::RGBA(_) => rgb_to_png( - decode_result, + (DecodingResult::U16(vec), tiff::ColorType::Gray(_)) => to_png( + 0, + vec, + ColorType::Grayscale, + BitDepth::Sixteen, tile_width, tile_height, data_width, data_height, - true, + 1, &self.path, ), - ColorType::CMYK(_) => todo!(), - ColorType::YCbCr(_) => todo!(), + (DecodingResult::U16(vec), tiff::ColorType::RGB(_)) => to_png( + 0, + vec, + ColorType::Rgb, + BitDepth::Sixteen, + tile_width, + tile_height, + data_width, + data_height, + 3, + &self.path, + ), + (DecodingResult::U16(vec), tiff::ColorType::RGBA(_)) => to_png( + 0, + vec, + ColorType::Rgba, + BitDepth::Sixteen, + tile_width, + tile_height, + data_width, + data_height, + 4, + &self.path, + ), + (_, _) => Err(CogError::NotSupportedColorTypeAndBitDepth( + color_type, + self.path.clone(), + )), }?; - - Ok(png_bytes) - } -} - -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!(), + Ok(png_file_bytes) } - todo!() } -fn rgb_to_png( - data: DecodingResult, +#[allow(clippy::too_many_arguments)] +fn to_png( + no_data: T, + vec: Vec, + color_type: ColorType, + bit_depth: BitDepth, tile_width: u32, tile_height: u32, data_width: u32, data_height: u32, - with_alpha: bool, - path: &PathBuf, + components_count: u32, + path: &Path, ) -> 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))?; + { + let mut encoder = png::Encoder::new(BufWriter::new(&mut buffer), tile_width, tile_height); + encoder.set_color(color_type); + encoder.set_depth(bit_depth); + + let mut writer = encoder + .write_header() + .map_err(|e| CogError::WritePngHeaderFailed(path.to_path_buf(), e))?; + let data = if is_padded { + 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 * components_count + col * components_count; + let arr_idx = row * tile_width * components_count + col * components_count; + for component_idx in 0..components_count { + result[(arr_idx + component_idx) as usize] = + vec[(idx + component_idx) as usize]; + } } } - 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!(), + result + } else { + vec + }; + let u8_vec: &[u8] = bytemuck::cast_slice(&data); + writer + .write_image_data(u8_vec) + .map_err(|e| CogError::WriteToPngFailed(path.to_path_buf(), e))?; } + Ok(buffer) } -fn pad_data( - no_data: T, - vec: &[T], - tile_width: u32, - tile_height: u32, - data_width: u32, - data_height: u32, - components_count: u32, -) -> Vec { - 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; - for component_idx in 0..components_count { - result[(arr_idx + component_idx) as usize] = vec[(idx + component_idx) as usize]; - } - } - } - result -} +// fn pad_data( +// no_data: T, +// vec: Vec, +// tile_width: u32, +// tile_height: u32, +// data_width: u32, +// data_height: u32, +// byte_count_per_component: u8, +// components_count: u32, +// ) -> Vec { +// 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; +// for component_idx in 0..components_count { +// result[(arr_idx + component_idx) as usize] = vec[(idx + component_idx) as usize]; +// } +// } +// } +// result +// } #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct CogConfig {