|
use crate::tiff::file::TiffRead; |
|
use crate::tiff::tags::{BitsPerSample, BlackLevel, CfaPattern, CfaPatternDim, Compression, ImageLength, ImageWidth, RowsPerStrip, StripByteCounts, StripOffsets, Tag, WhiteBalanceRggbLevels}; |
|
use crate::tiff::{Ifd, TiffError}; |
|
use crate::{RawImage, SubtractBlack, Transform}; |
|
use rawkit_proc_macros::Tag; |
|
use std::io::{Read, Seek}; |
|
|
|
#[allow(dead_code)] |
|
#[derive(Tag)] |
|
struct ArwUncompressedIfd { |
|
image_width: ImageWidth, |
|
image_height: ImageLength, |
|
rows_per_strip: RowsPerStrip, |
|
bits_per_sample: BitsPerSample, |
|
compression: Compression, |
|
black_level: BlackLevel, |
|
cfa_pattern: CfaPattern, |
|
cfa_pattern_dim: CfaPatternDim, |
|
strip_offsets: StripOffsets, |
|
strip_byte_counts: StripByteCounts, |
|
white_balance_levels: Option<WhiteBalanceRggbLevels>, |
|
} |
|
|
|
pub fn decode<R: Read + Seek>(ifd: Ifd, file: &mut TiffRead<R>) -> RawImage { |
|
let ifd = ifd.get_value::<ArwUncompressedIfd, _>(file).unwrap(); |
|
|
|
assert!(ifd.strip_offsets.len() == ifd.strip_byte_counts.len()); |
|
assert!(ifd.strip_offsets.len() == 1); |
|
assert!(ifd.compression == 1); |
|
|
|
let image_width: usize = ifd.image_width.try_into().unwrap(); |
|
let image_height: usize = ifd.image_height.try_into().unwrap(); |
|
let rows_per_strip: usize = ifd.rows_per_strip.try_into().unwrap(); |
|
let bits_per_sample: usize = ifd.bits_per_sample.into(); |
|
let [cfa_pattern_width, cfa_pattern_height] = ifd.cfa_pattern_dim; |
|
assert!(cfa_pattern_width == 2 && cfa_pattern_height == 2); |
|
|
|
let mut image: Vec<u16> = Vec::with_capacity(image_height * image_width); |
|
|
|
for i in 0..ifd.strip_offsets.len() { |
|
file.seek_from_start(ifd.strip_offsets[i]).unwrap(); |
|
|
|
let last = i == ifd.strip_offsets.len(); |
|
let rows = if last { image_height % rows_per_strip } else { rows_per_strip }; |
|
|
|
for _ in 0..rows { |
|
for _ in 0..image_width { |
|
image.push(file.read_u16().unwrap()); |
|
} |
|
} |
|
} |
|
|
|
RawImage { |
|
data: image, |
|
width: image_width, |
|
height: image_height, |
|
cfa_pattern: ifd.cfa_pattern.try_into().unwrap(), |
|
maximum: if bits_per_sample == 16 { u16::MAX } else { (1 << bits_per_sample) - 1 }, |
|
black: SubtractBlack::CfaGrid(ifd.black_level), |
|
transform: Transform::Horizontal, |
|
camera_model: None, |
|
camera_white_balance: ifd.white_balance_levels.map(|arr| arr.map(|x| x as f64)), |
|
white_balance: None, |
|
camera_to_rgb: None, |
|
} |
|
} |
|
|