Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
sharkAndshark committed Nov 19, 2024
1 parent 348108c commit d5fc2d4
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 18 deletions.
4 changes: 2 additions & 2 deletions martin/src/cog/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
125 changes: 109 additions & 16 deletions martin/src/cog/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod errors;

pub use errors::CogError;
use serde_yaml::with;

use std::collections::HashMap;
use std::fs::File;
Expand Down Expand Up @@ -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!(),
}?;
Expand All @@ -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<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))?;
}
}
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,
Expand All @@ -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))?;
Expand All @@ -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()
Expand Down Expand Up @@ -211,18 +303,19 @@ fn pad_data<T: Copy>(
tile_height: u32,
data_width: u32,
data_height: u32,
components_count: u32,
) -> Vec<T> {
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)]
Expand Down

0 comments on commit d5fc2d4

Please sign in to comment.