Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
sharkAndshark committed Nov 20, 2024
1 parent 1699b88 commit cf4ac6f
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 148 deletions.
7 changes: 6 additions & 1 deletion martin/src/cog/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
268 changes: 121 additions & 147 deletions martin/src/cog/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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};
Expand Down Expand Up @@ -66,6 +65,7 @@ impl Source for CogSource {
Box::new(self.clone())
}

#[allow(clippy::too_many_lines)]
async fn get_tile(
&self,
xyz: TileCoord,
Expand Down Expand Up @@ -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<Vec<u8>, 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<T: Copy + NoUninit>(
no_data: T,
vec: Vec<T>,
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<Vec<u8>, 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<T: Copy>(
no_data: T,
vec: &[T],
tile_width: u32,
tile_height: u32,
data_width: u32,
data_height: u32,
components_count: u32,
) -> Vec<T> {
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<T: Copy>(
// no_data: T,
// vec: Vec<T>,
// tile_width: u32,
// tile_height: u32,
// data_width: u32,
// data_height: u32,
// byte_count_per_component: u8,
// components_count: u32,
// ) -> Vec<T> {
// 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 {
Expand Down

0 comments on commit cf4ac6f

Please sign in to comment.