diff --git a/Cargo.toml b/Cargo.toml index 52f23c8..4fc6d33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "src/metadata/camerametadata", "src/metadata/camerasxml_parser", "src/metadata/xmlparser", + "src/metadata/colorfilterarray", "src/metadata/xmltokendesparsifier", "src/metadata/xmltokenizer", "src/misc/md5", diff --git a/src/metadata/camerasxml_parser/Cargo.toml b/src/metadata/camerasxml_parser/Cargo.toml index 95c3f8c..a193551 100644 --- a/src/metadata/camerasxml_parser/Cargo.toml +++ b/src/metadata/camerasxml_parser/Cargo.toml @@ -13,6 +13,7 @@ license.workspace = true workspace = true [dependencies] +rawspeed-metadata-colorfilterarray = { path = "../colorfilterarray" } rawspeed-metadata-xmlparser = { path = "../xmlparser" } rawspeed-std = { path = "../../std" } rawspeed-std-ndslice = { path = "../../std/ndslice" } diff --git a/src/metadata/camerasxml_parser/camerasxml_parser/camera/tests.rs b/src/metadata/camerasxml_parser/camerasxml_parser/camera/tests.rs index 03a2d8e..19d6d9d 100644 --- a/src/metadata/camerasxml_parser/camerasxml_parser/camera/tests.rs +++ b/src/metadata/camerasxml_parser/camerasxml_parser/camera/tests.rs @@ -10,14 +10,10 @@ use super::super::blackareas::IndividualBlackAreas; use super::super::cfa::CFA; use super::super::cfa::CFAColors; use super::super::cfa2::CFA2; -use super::super::cfa2::CFA2Colors; use super::super::color; use super::super::color::Color; use super::super::colormatrices::ColorMatrices; use super::super::colormatrix::ColorMatrix; -use super::super::colorrow; -use super::super::colorrow::ColorRow; -use super::super::colorrow::ColorRowValues; use super::super::crop::Crop; use super::super::decoder_version::DecoderVersion; use super::super::height::Height; @@ -47,6 +43,8 @@ use super::model::Model; use super::sensor; use super::xmlparser; use crate::camerasxml_parser::crop; +use rawspeed_metadata_colorfilterarray::colorfilterarray::ColorFilterArray; +use rawspeed_metadata_colorfilterarray::colorfilterarray::ColorVariant; use rawspeed_std::coord_common::ColIndex; use rawspeed_std::coord_common::Coord2D; use rawspeed_std::coord_common::RowCount; @@ -630,24 +628,10 @@ fn parse_cfa2_test() { decoder_version: None, supported: Supported::Supported, id: None, - cfa: MaybeCFA::CFA2(CFA2 { - width: Width { - val: Int { val: 1 }, - }, - height: Height { - val: Int { val: 1 }, - }, - values: CFA2Colors { - values: vec![ColorRow { - y: Y { - val: Int { val: 0 }, - }, - value: ColorRowValues { - values: vec![colorrow::ColorVariant::G], - }, - }], - }, - }), + cfa: MaybeCFA::CFA2(CFA2::new(ColorFilterArray::new( + vec![ColorVariant::Green], + RowLength::new(1), + ))), crop: None, sensors: Sensors { values: vec![] }, blackaras: None, diff --git a/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/mod.rs b/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/mod.rs index 1ede242..1ba0c7a 100644 --- a/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/mod.rs +++ b/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/mod.rs @@ -1,38 +1,74 @@ -use super::super::camerasxml_parser::colorrow; -use super::height; -use super::width; -use super::xmlparser; +use rawspeed_metadata_colorfilterarray::colorfilterarray::ColorFilterArray; +use rawspeed_metadata_colorfilterarray::colorfilterarray::ColorVariant; +use rawspeed_metadata_xmlparser::xmlparser; +use rawspeed_std::coord_common::ColIndex; +use rawspeed_std::coord_common::Coord2D; +use rawspeed_std::coord_common::RowIndex; +use rawspeed_std::coord_common::RowLength; + +use crate::camerasxml_parser::colorrow; + +mod repr; #[derive(Debug, Clone, PartialEq)] -pub struct CFA2Colors { - pub values: Vec, +#[non_exhaustive] +pub struct CFA2 { + data: ColorFilterArray, +} + +impl CFA2 { + pub const fn new(data: ColorFilterArray) -> Self { + Self { data } + } +} + +impl core::ops::Deref for CFA2 { + type Target = ColorFilterArray; + + fn deref(&self) -> &Self::Target { + &self.data + } } -impl<'a, 'b> xmlparser::Parse<'a, 'b> for CFA2Colors { +impl<'a, 'b> xmlparser::Parse<'a, 'b> for CFA2 { fn parse( input: &'b mut xmlparser::ParseStream<'a>, ) -> xmlparser::Result { - let mut values = Vec::new(); - while let Ok(row) = input.parse() { - values.push(row); + let cfa = input.parse::()?; + let mat = cfa.body.mat(); + let real_height = mat.num_rows(); + let real_width = mat.row_length(); + if Ok(real_height) != (**cfa.height).try_into() { + return Err(format!( + "unexpected CFA matrix row count, got {} expected {}", + real_height, **cfa.height + )); } - if values.is_empty() { - return Err( - "unexpected end of input, expected `ColorRow`".to_owned() - ); + if Ok(real_width) != (**cfa.width).try_into() { + return Err(format!( + "unexpected CFA matrix row length, got {} expected {}", + real_width, **cfa.width + )); } - Ok(Self { values }) + let mut data = + Vec::with_capacity(real_width.checked_mul(real_height).unwrap()); + for row in 0..real_height { + for col in 0..real_width { + let e = + mat[Coord2D::new(RowIndex::new(row), ColIndex::new(col))]; + let e = match e { + colorrow::ColorVariant::R => ColorVariant::Red, + colorrow::ColorVariant::G => ColorVariant::Green, + colorrow::ColorVariant::B => ColorVariant::Blue, + }; + data.push(e); + } + } + Ok(Self { + data: ColorFilterArray::new(data, RowLength::new(real_width)), + }) } } -impl_elt_with_body_matcher!( - #[derive(Debug, Clone, PartialEq)] - struct CFA2 { - width: width::Width, - height: height::Height, - values: CFA2Colors, - } -); - #[cfg(test)] mod tests; diff --git a/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/repr/mod.rs b/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/repr/mod.rs new file mode 100644 index 0000000..e73e576 --- /dev/null +++ b/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/repr/mod.rs @@ -0,0 +1,81 @@ +use super::super::height::Height; +use super::super::width::Width; +use crate::camerasxml_parser::colorrow::{self, ColorVariant}; +use rawspeed_metadata_xmlparser::xmlparser; +use rawspeed_std::coord_common::{RowLength, RowPitch}; +use rawspeed_std_ndslice::array2dref::Array2DRef; + +#[derive(Debug, Clone, PartialEq)] +#[non_exhaustive] +pub struct Matrix { + data: Vec, + row_length: RowLength, +} + +impl Matrix { + pub const fn new(data: Vec, row_length: RowLength) -> Self { + let ret = Self { data, row_length }; + let _ = ret.mat(); + ret + } + + #[inline] + #[must_use] + pub const fn mat(&self) -> Array2DRef<'_, ColorVariant> { + Array2DRef::new( + self.data.as_slice(), + self.row_length, + RowPitch::new(self.row_length.val()), + ) + } +} + +impl<'a, 'b> xmlparser::Parse<'a, 'b> for Matrix { + fn parse( + input: &'b mut xmlparser::ParseStream<'a>, + ) -> xmlparser::Result { + let mut rows = Vec::>::new(); + while let Ok(row) = input.parse::() { + if (**row.y).try_into() != Ok(rows.len()) { + return Err(format!( + "unexpected row index, expected {} got {}", + rows.len(), + **row.y + )); + } + if let Some(first_row) = rows.first() + && let first_row_length = first_row.len() + && let curr_row_length = row.value.values.len() + && curr_row_length != first_row_length + { + return Err(format!( + "inconsistent row length, expected {first_row_length} got {curr_row_length}", + )); + } + rows.push(row.value.values); + } + if rows.is_empty() { + return Err( + "unexpected end of input, expected `ColorRow`".to_owned() + ); + } + let matrix_elts = rows.iter().flat_map(|row| row.iter().copied()); + let data: Vec = matrix_elts.collect(); + Ok(Matrix::new( + data, + RowLength::new(rows.first().unwrap().len()), + )) + } +} + +impl_elt_with_body_matcher!( + #[derive(Debug, Clone, PartialEq)] + struct CFA2 { + width: Width, + height: Height, + body: Matrix, + } +); + +#[cfg(test)] +mod tests; diff --git a/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/repr/tests.rs b/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/repr/tests.rs new file mode 100644 index 0000000..3bcb21c --- /dev/null +++ b/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/repr/tests.rs @@ -0,0 +1,636 @@ +use crate::camerasxml_parser::{ + Int, + cfa2::repr::{CFA2, Matrix}, + colorrow::ColorVariant, + height::Height, + width::Width, +}; +use rawspeed_metadata_xmlparser::xmlparser; +use rawspeed_std::coord_common::RowLength; + +type T<'a> = CFA2; + +#[expect(non_snake_case)] +fn Err(str: &'static str) -> Result, String> { + Result::Err(str.to_owned()) +} + +#[test] +#[expect(clippy::too_many_lines)] +fn parse_test() { + let inputs: Vec<&'static str> = vec![ + "", + "<", + "", + " + G", + " + G + <", + " + G + + G + + G + + G + + G + ", + " + G + ", + " + G + G + ", + // + " + R + ", + " + R + G + ", + " + R + GB + ", + " + RG + ", + " + RG + G + ", + " + RG + GB + ", + " + R + ", + " + R + G + ", + " + R + GB + ", + " + RG + ", + " + RG + G + ", + " + RG + GB + ", + " + R + ", + " + R + G + ", + " + R + GB + ", + " + RG + ", + " + RG + G + ", + " + RG + GB + ", + " + R + ", + " + R + G + ", + " + R + GB + ", + " + RG + ", + " + RG + G + ", + " + RG + GB + ", + ]; + let expected: Vec<(&str, xmlparser::Result>)> = vec![ + ( + "", + Err("While trying to match `\"Lt\"`, encountered end of stream"), + ), + ( + "<", + Err( + "While trying to match `\"ElementName\"`, encountered end of stream", + ), + ), + ( + "", + Err("unexpected end of input, expected `ColorRow`"), + ), + ( + "\n G", + Err("While trying to match `\"Lt\"`, encountered end of stream"), + ), + ( + "\n G\n <", + Err( + "While trying to match `\"ElementSlash\"`, encountered end of stream", + ), + ), + ( + "\n G\n \n G\n \n G\n \n G\n \n G\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 1 }, + }, + height: Height { + val: Int { val: 1 }, + }, + body: Matrix { + data: vec![ColorVariant::G], + row_length: RowLength::new(1), + }, + }), + ), + ( + "\n G\n ", + Err("unexpected row index, expected 0 got 1"), + ), + ( + "\n G\n G\n ", + Err("unexpected row index, expected 1 got 0"), + ), + ( + "\n R\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 1 }, + }, + height: Height { + val: Int { val: 1 }, + }, + body: Matrix { + data: vec![ColorVariant::R], + row_length: RowLength::new(1), + }, + }), + ), + ( + "\n R\n G\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 1 }, + }, + height: Height { + val: Int { val: 1 }, + }, + body: Matrix { + data: vec![ColorVariant::R, ColorVariant::G], + row_length: RowLength::new(1), + }, + }), + ), + ( + "\n R\n GB\n ", + Err("inconsistent row length, expected 1 got 2"), + ), + ( + "\n RG\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 1 }, + }, + height: Height { + val: Int { val: 1 }, + }, + body: Matrix { + data: vec![ColorVariant::R, ColorVariant::G], + row_length: RowLength::new(2), + }, + }), + ), + ( + "\n RG\n G\n ", + Err("inconsistent row length, expected 2 got 1"), + ), + ( + "\n RG\n GB\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 1 }, + }, + height: Height { + val: Int { val: 1 }, + }, + body: Matrix { + data: vec![ + ColorVariant::R, + ColorVariant::G, + ColorVariant::G, + ColorVariant::B, + ], + row_length: RowLength::new(2), + }, + }), + ), + ( + "\n R\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 1 }, + }, + height: Height { + val: Int { val: 2 }, + }, + body: Matrix { + data: vec![ColorVariant::R], + row_length: RowLength::new(1), + }, + }), + ), + ( + "\n R\n G\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 1 }, + }, + height: Height { + val: Int { val: 2 }, + }, + body: Matrix { + data: vec![ColorVariant::R, ColorVariant::G], + row_length: RowLength::new(1), + }, + }), + ), + ( + "\n R\n GB\n ", + Err("inconsistent row length, expected 1 got 2"), + ), + ( + "\n RG\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 1 }, + }, + height: Height { + val: Int { val: 2 }, + }, + body: Matrix { + data: vec![ColorVariant::R, ColorVariant::G], + row_length: RowLength::new(2), + }, + }), + ), + ( + "\n RG\n G\n ", + Err("inconsistent row length, expected 2 got 1"), + ), + ( + "\n RG\n GB\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 1 }, + }, + height: Height { + val: Int { val: 2 }, + }, + body: Matrix { + data: vec![ + ColorVariant::R, + ColorVariant::G, + ColorVariant::G, + ColorVariant::B, + ], + row_length: RowLength::new(2), + }, + }), + ), + ( + "\n R\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 2 }, + }, + height: Height { + val: Int { val: 1 }, + }, + body: Matrix { + data: vec![ColorVariant::R], + row_length: RowLength::new(1), + }, + }), + ), + ( + "\n R\n G\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 2 }, + }, + height: Height { + val: Int { val: 1 }, + }, + body: Matrix { + data: vec![ColorVariant::R, ColorVariant::G], + row_length: RowLength::new(1), + }, + }), + ), + ( + "\n R\n GB\n ", + Err("inconsistent row length, expected 1 got 2"), + ), + ( + "\n RG\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 2 }, + }, + height: Height { + val: Int { val: 1 }, + }, + body: Matrix { + data: vec![ColorVariant::R, ColorVariant::G], + row_length: RowLength::new(2), + }, + }), + ), + ( + "\n RG\n G\n ", + Err("inconsistent row length, expected 2 got 1"), + ), + ( + "\n RG\n GB\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 2 }, + }, + height: Height { + val: Int { val: 1 }, + }, + body: Matrix { + data: vec![ + ColorVariant::R, + ColorVariant::G, + ColorVariant::G, + ColorVariant::B, + ], + row_length: RowLength::new(2), + }, + }), + ), + ( + "\n R\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 2 }, + }, + height: Height { + val: Int { val: 2 }, + }, + body: Matrix { + data: vec![ColorVariant::R], + row_length: RowLength::new(1), + }, + }), + ), + ( + "\n R\n G\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 2 }, + }, + height: Height { + val: Int { val: 2 }, + }, + body: Matrix { + data: vec![ColorVariant::R, ColorVariant::G], + row_length: RowLength::new(1), + }, + }), + ), + ( + "\n R\n GB\n ", + Err("inconsistent row length, expected 1 got 2"), + ), + ( + "\n RG\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 2 }, + }, + height: Height { + val: Int { val: 2 }, + }, + body: Matrix { + data: vec![ColorVariant::R, ColorVariant::G], + row_length: RowLength::new(2), + }, + }), + ), + ( + "\n RG\n G\n ", + Err("inconsistent row length, expected 2 got 1"), + ), + ( + "\n RG\n GB\n ", + Ok(CFA2 { + width: Width { + val: Int { val: 2 }, + }, + height: Height { + val: Int { val: 2 }, + }, + body: Matrix { + data: vec![ + ColorVariant::R, + ColorVariant::G, + ColorVariant::G, + ColorVariant::B, + ], + row_length: RowLength::new(2), + }, + }), + ), + ]; + let mut results = vec![]; + for input in inputs { + results.push((input, xmlparser::parse_str::>(input))); + } + assert_eq!(results, expected); +} diff --git a/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/tests.rs b/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/tests.rs index a3d915a..fe2ed51 100644 --- a/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/tests.rs +++ b/src/metadata/camerasxml_parser/camerasxml_parser/cfa2/tests.rs @@ -1,13 +1,9 @@ -use super::super::Int; -use super::super::colorrow::ColorRow; -use super::super::colorrow::ColorRowValues; -use super::super::colorrow::ColorVariant; -use super::super::height::Height; -use super::super::width::Width; -use super::super::y::Y; -use super::CFA2; -use super::CFA2Colors; -use super::xmlparser; +use crate::camerasxml_parser::cfa2::CFA2; +use rawspeed_metadata_colorfilterarray::colorfilterarray::{ + ColorFilterArray, ColorVariant, +}; +use rawspeed_metadata_xmlparser::xmlparser; +use rawspeed_std::coord_common::RowLength; type T<'a> = CFA2; @@ -42,28 +38,120 @@ fn parse_test() { "", " - G", + G", " - G + G <", " - G + G - G + G - G + G - G + G - G + G + ", + " + G ", " G - R + G + ", + // + " + R + ", + " + R + G + ", + " + R + GB + ", + " + RG + ", + " + RG + G + ", + " + RG + GB + ", + " + R + ", + " + R + G + ", + " + R + GB + ", + " + RG + ", + " + RG + G + ", + " + RG + GB + ", + " + R + ", + " + R + G + ", + " + R + GB + ", + " + RG + ", + " + RG + G + ", + " + RG + GB + ", + " + R + ", + " + R + G + ", + " + R + GB + ", + " + RG + ", + " + RG + G + ", + " + RG + GB ", ]; let expected: Vec<(&str, xmlparser::Result>)> = vec![ @@ -188,89 +276,175 @@ fn parse_test() { Err("unexpected end of input, expected `ColorRow`"), ), ( - "\n G", + "\n G", Err("While trying to match `\"Lt\"`, encountered end of stream"), ), ( - "\n G\n <", + "\n G\n <", Err( "While trying to match `\"ElementSlash\"`, encountered end of stream", ), ), ( - "\n G\n \n G\n \n G\n \n G\n \n G\n \n G\n \n G\n \n G\n \n G\n ", + "\n G\n ", + Ok(CFA2 { + data: ColorFilterArray::new( + vec![ColorVariant::Green], + RowLength::new(1), + ), + }), + ), + ( + "\n G\n ", + Err("unexpected row index, expected 0 got 1"), + ), + ( + "\n G\n G\n ", + Err("unexpected row index, expected 1 got 0"), + ), + ( + "\n R\n ", Ok(CFA2 { - width: Width { - val: Int { val: 1 }, - }, - height: Height { - val: Int { val: 1 }, - }, - values: CFA2Colors { - values: vec![ColorRow { - y: Y { - val: Int { val: 11 }, - }, - value: ColorRowValues { - values: vec![ColorVariant::G], - }, - }], - }, + data: ColorFilterArray::new( + vec![ColorVariant::Red], + RowLength::new(1), + ), }), ), ( - "\n G\n R\n ", + "\n R\n G\n ", + Err("unexpected CFA matrix row count, got 2 expected 1"), + ), + ( + "\n R\n GB\n ", + Err("inconsistent row length, expected 1 got 2"), + ), + ( + "\n RG\n ", + Err("unexpected CFA matrix row length, got 2 expected 1"), + ), + ( + "\n RG\n G\n ", + Err("inconsistent row length, expected 2 got 1"), + ), + ( + "\n RG\n GB\n ", + Err("unexpected CFA matrix row count, got 2 expected 1"), + ), + ( + "\n R\n ", + Err("unexpected CFA matrix row count, got 1 expected 2"), + ), + ( + "\n R\n G\n ", + Ok(CFA2 { + data: ColorFilterArray::new( + vec![ColorVariant::Red, ColorVariant::Green], + RowLength::new(1), + ), + }), + ), + ( + "\n R\n GB\n ", + Err("inconsistent row length, expected 1 got 2"), + ), + ( + "\n RG\n ", + Err("unexpected CFA matrix row count, got 1 expected 2"), + ), + ( + "\n RG\n G\n ", + Err("inconsistent row length, expected 2 got 1"), + ), + ( + "\n RG\n GB\n ", + Err("unexpected CFA matrix row length, got 2 expected 1"), + ), + ( + "\n R\n ", + Err("unexpected CFA matrix row length, got 1 expected 2"), + ), + ( + "\n R\n G\n ", + Err("unexpected CFA matrix row count, got 2 expected 1"), + ), + ( + "\n R\n GB\n ", + Err("inconsistent row length, expected 1 got 2"), + ), + ( + "\n RG\n ", + Ok(CFA2 { + data: ColorFilterArray::new( + vec![ColorVariant::Red, ColorVariant::Green], + RowLength::new(2), + ), + }), + ), + ( + "\n RG\n G\n ", + Err("inconsistent row length, expected 2 got 1"), + ), + ( + "\n RG\n GB\n ", + Err("unexpected CFA matrix row count, got 2 expected 1"), + ), + ( + "\n R\n ", + Err("unexpected CFA matrix row count, got 1 expected 2"), + ), + ( + "\n R\n G\n ", + Err("unexpected CFA matrix row length, got 1 expected 2"), + ), + ( + "\n R\n GB\n ", + Err("inconsistent row length, expected 1 got 2"), + ), + ( + "\n RG\n ", + Err("unexpected CFA matrix row count, got 1 expected 2"), + ), + ( + "\n RG\n G\n ", + Err("inconsistent row length, expected 2 got 1"), + ), + ( + "\n RG\n GB\n ", Ok(CFA2 { - width: Width { - val: Int { val: 1 }, - }, - height: Height { - val: Int { val: 1 }, - }, - values: CFA2Colors { - values: vec![ - ColorRow { - y: Y { - val: Int { val: 0 }, - }, - value: ColorRowValues { - values: vec![ColorVariant::G], - }, - }, - ColorRow { - y: Y { - val: Int { val: 1 }, - }, - value: ColorRowValues { - values: vec![ColorVariant::R], - }, - }, + data: ColorFilterArray::new( + vec![ + ColorVariant::Red, + ColorVariant::Green, + ColorVariant::Green, + ColorVariant::Blue, ], - }, + RowLength::new(2), + ), }), ), ]; diff --git a/src/metadata/colorfilterarray/Cargo.toml b/src/metadata/colorfilterarray/Cargo.toml new file mode 100644 index 0000000..bf68802 --- /dev/null +++ b/src/metadata/colorfilterarray/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "rawspeed-metadata-colorfilterarray" +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +documentation.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true + +[lints] +workspace = true + +[dependencies] +rawspeed-std = { path = "../../std" } +rawspeed-std-ndslice = { path = "../../std/ndslice" } + +[lib] +path = "mod.rs" diff --git a/src/metadata/colorfilterarray/colorfilterarray/mod.rs b/src/metadata/colorfilterarray/colorfilterarray/mod.rs new file mode 100644 index 0000000..fee3975 --- /dev/null +++ b/src/metadata/colorfilterarray/colorfilterarray/mod.rs @@ -0,0 +1,41 @@ +use rawspeed_std::coord_common::{RowLength, RowPitch}; +use rawspeed_std_ndslice::array2dref::Array2DRef; + +#[derive(Debug, Clone, Copy, PartialEq)] +#[non_exhaustive] +pub enum ColorVariant { + Red, + Green, + Blue, + FujiGreen, + Magenta, + Yellow, + Cyan, +} + +#[derive(Debug, Clone, PartialEq)] +#[non_exhaustive] +pub struct ColorFilterArray { + data: Vec, + row_length: RowLength, +} + +impl ColorFilterArray { + #[inline] + #[must_use] + pub const fn new(data: Vec, row_length: RowLength) -> Self { + let ret = Self { data, row_length }; + let _ = ret.mat(); + ret + } + + #[inline] + #[must_use] + pub const fn mat(&self) -> Array2DRef<'_, ColorVariant> { + Array2DRef::new( + self.data.as_slice(), + self.row_length, + RowPitch::new(self.row_length.val()), + ) + } +} diff --git a/src/metadata/colorfilterarray/mod.rs b/src/metadata/colorfilterarray/mod.rs new file mode 100644 index 0000000..2a24ec8 --- /dev/null +++ b/src/metadata/colorfilterarray/mod.rs @@ -0,0 +1 @@ +pub mod colorfilterarray;