use crate::opbasics::*;
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct OpGoFloat {
pub crop_top: usize,
pub crop_right: usize,
pub crop_bottom: usize,
pub crop_left: usize,
pub is_cfa: bool,
pub blacklevels: [f32;4],
pub whitelevels: [f32;4],
}
fn from_int4(arr: [u16;4]) -> [f32;4] {
[arr[0] as f32, arr[1] as f32, arr[2] as f32, arr[3] as f32]
}
impl OpGoFloat {
pub fn new(img: &ImageSource) -> OpGoFloat {
match img {
ImageSource::Raw(img) => {
OpGoFloat{
crop_top: img.crops[0],
crop_right: img.crops[1],
crop_bottom: img.crops[2],
crop_left: img.crops[3],
is_cfa: img.cfa.is_valid(),
blacklevels: from_int4(img.blacklevels),
whitelevels: from_int4(img.whitelevels),
}
},
ImageSource::Other(_) => {
OpGoFloat{
crop_top: 0,
crop_right: 0,
crop_bottom: 0,
crop_left: 0,
is_cfa: false,
blacklevels: [0.0, 0.0, 0.0, 0.0], whitelevels: [0.0, 0.0, 0.0, 0.0], }
}
}
}
}
impl<'a> ImageOp<'a> for OpGoFloat {
fn name(&self) -> &str {"gofloat"}
fn run(&self, pipeline: &PipelineGlobals, _buf: Arc<OpBuffer>) -> Arc<OpBuffer> {
match &pipeline.image {
ImageSource::Raw(img) => {
self.run_raw(img)
},
ImageSource::Other(img) => {
self.run_other(img)
}
}
}
fn transform_forward(&mut self, width: usize, height: usize) -> (usize, usize) {
let (_, _, width, height) = self.size_image(width, height);
(width, height)
}
}
impl OpGoFloat {
fn size_image(&self, owidth: usize, oheight: usize) -> (usize, usize, usize, usize) {
let x = cmp::min(self.crop_left, owidth-10);
let y = cmp::min(self.crop_top, oheight-10);
let width = owidth - cmp::min(self.crop_left + self.crop_right, owidth-10);
let height = oheight - cmp::min(self.crop_top + self.crop_bottom, oheight-10);
(x, y, width, height)
}
fn run_raw(&self, img: &RawImage) -> Arc<OpBuffer> {
let mins = self.blacklevels;
let ranges = self.whitelevels.iter().enumerate().map(|(i, &x)| {
x - mins[i]
}).collect::<Vec<f32>>();
let owidth = img.width;
let oheight = img.height;
let (x, y, width, height) = self.size_image(owidth, oheight);
Arc::new(match img.data {
RawImageData::Integer(ref data) => {
if img.cpp == 1 && !self.is_cfa {
let mut out = OpBuffer::new(width, height, 4, true);
out.mutate_lines(&(|line: &mut [f32], row| {
for (o, i) in line.chunks_exact_mut(4).zip(data[owidth*(row+y)+x..].chunks_exact(1)) {
let val = ((i[0] as f32 - mins[0]) / ranges[0]).min(1.0);
o[0] = val;
o[1] = val;
o[2] = val;
o[3] = 0.0;
}
}));
out
} else if img.cpp == 3 {
let mut out = OpBuffer::new(width, height, 4, false);
out.mutate_lines(&(|line: &mut [f32], row| {
for (o, i) in line.chunks_exact_mut(4).zip(data[(owidth*(row+y)+x)*3..].chunks_exact(3)) {
o[0] = ((i[0] as f32 - mins[0]) / ranges[0]).min(1.0);
o[1] = ((i[1] as f32 - mins[1]) / ranges[1]).min(1.0);
o[2] = ((i[2] as f32 - mins[2]) / ranges[2]).min(1.0);
o[3] = 0.0;
}
}));
out
} else {
let mut out = OpBuffer::new(width, height, img.cpp, false);
out.mutate_lines(&(|line: &mut [f32], row| {
for (o, i) in line.chunks_exact_mut(1).zip(data[owidth*(row+y)+x..].chunks_exact(1)) {
o[0] = ((i[0] as f32 - mins[0]) / ranges[0]).min(1.0);
}
}));
out
}
},
RawImageData::Float(ref data) => {
if img.cpp == 1 && !self.is_cfa {
let mut out = OpBuffer::new(width, height, 4, true);
out.mutate_lines(&(|line: &mut [f32], row| {
for (o, i) in line.chunks_exact_mut(4).zip(data[owidth*(row+y)+x..].chunks_exact(1)) {
let val = ((i[0] as f32 - mins[0]) / ranges[0]).min(1.0);
o[0] = val;
o[1] = val;
o[2] = val;
o[3] = 0.0;
}
}));
out
} else if img.cpp == 3 {
let mut out = OpBuffer::new(width, height, 4, false);
out.mutate_lines(&(|line: &mut [f32], row| {
for (o, i) in line.chunks_exact_mut(4).zip(data[(owidth*(row+y)+x)*3..].chunks_exact(3)) {
o[0] = ((i[0] as f32 - mins[0]) / ranges[0]).min(1.0);
o[1] = ((i[1] as f32 - mins[1]) / ranges[1]).min(1.0);
o[2] = ((i[2] as f32 - mins[2]) / ranges[2]).min(1.0);
o[3] = 0.0;
}
}));
out
} else {
let mut out = OpBuffer::new(width, height, img.cpp, false);
out.mutate_lines(&(|line: &mut [f32], row| {
for (o, i) in line.chunks_exact_mut(1).zip(data[owidth*(row+y)+x..].chunks_exact(1)) {
o[0] = ((i[0] as f32 - mins[0]) / ranges[0]).min(1.0);
}
}));
out
}
},
})
}
fn run_other(&self, img: &OtherImage) -> Arc<OpBuffer> {
let owidth = img.width() as usize;
let oheight = img.height() as usize;
let (x, y, width, height) = self.size_image(owidth, oheight);
let mut out = OpBuffer::new(width, height, 4, false);
let bits_per_channel = img.color().bits_per_pixel() / img.color().channel_count() as u16;
if bits_per_channel == 8 {
let data = img.to_rgb8().into_raw();
out.mutate_lines(&(|line: &mut [f32], row| {
for (o, i) in line.chunks_exact_mut(4).zip(data[(owidth*(row+y)+x)*3..].chunks_exact(3)) {
o[0] = expand_srgb_gamma(input8bit(i[0]));
o[1] = expand_srgb_gamma(input8bit(i[1]));
o[2] = expand_srgb_gamma(input8bit(i[2]));
o[3] = 0.0;
}
}));
} else {
let data = img.to_rgb16().into_raw();
out.mutate_lines(&(|line: &mut [f32], row| {
for (o, i) in line.chunks_exact_mut(4).zip(data[(owidth*(row+y)+x)*3..].chunks_exact(3)) {
o[0] = input16bit(i[0]);
o[1] = input16bit(i[1]);
o[2] = input16bit(i[2]);
o[3] = 0.0;
}
}));
}
Arc::new(out)
}
}