use std::f32::NAN;
use crate::decoders::*;
use crate::decoders::tiff::*;
use crate::decoders::basics::*;
use crate::decoders::ljpeg::*;
#[derive(Debug, Clone)]
pub struct MosDecoder<'a> {
buffer: &'a [u8],
rawloader: &'a RawLoader,
tiff: TiffIFD<'a>,
}
impl<'a> MosDecoder<'a> {
pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> MosDecoder<'a> {
MosDecoder {
buffer: buf,
tiff: tiff,
rawloader: rawloader,
}
}
}
impl<'a> Decoder for MosDecoder<'a> {
fn image(&self, dummy: bool) -> Result<RawImage,String> {
let make = self.xmp_tag("Make")?;
let model_full = self.xmp_tag("Model")?.to_string();
let model = model_full.split_terminator("(").next().unwrap();
let camera = self.rawloader.check_supported_with_everything(&make, &model, "")?;
let raw = fetch_ifd!(&self.tiff, Tag::TileOffsets);
let width = fetch_tag!(raw, Tag::ImageWidth).get_usize(0);
let height = fetch_tag!(raw, Tag::ImageLength).get_usize(0);
let offset = fetch_tag!(raw, Tag::TileOffsets).get_usize(0);
let src = &self.buffer[offset..];
let image = match fetch_tag!(raw, Tag::Compression).get_usize(0) {
1 => {
if self.tiff.little_endian() {
decode_16le(src, width, height, dummy)
} else {
decode_16be(src, width, height, dummy)
}
},
7 | 99 => {
self.decode_compressed(&camera, src, width, height, dummy)?
},
x => return Err(format!("MOS: unsupported compression {}", x).to_string())
};
ok_image(camera, width, height, self.get_wb()?, image)
}
}
impl<'a> MosDecoder<'a> {
fn get_wb(&self) -> Result<[f32;4], String> {
let meta = fetch_tag!(self.tiff, Tag::LeafMetadata).get_data();
let mut pos = 0;
while pos + 70 < meta.len() {
if meta[pos..pos+16] == b"NeutObj_neutrals"[..] {
let data = &meta[pos+44..];
if let Some(endpos) = data.iter().position(|&x| x == 0) {
let nums = String::from_utf8_lossy(&data[0..endpos])
.split_terminator("\n")
.map(|x| x.parse::<f32>().unwrap_or(NAN))
.collect::<Vec<f32>>();
if nums.len() == 4 {
return Ok([nums[0]/nums[1], nums[0]/nums[2], nums[0]/nums[3], NAN])
}
}
break;
}
pos += 1;
}
Ok([NAN,NAN,NAN,NAN])
}
fn xmp_tag(&self, tag: &str) -> Result<String, String> {
let xmp = fetch_tag!(self.tiff, Tag::Xmp).get_str();
let error = format!("MOS: Couldn't find XMP tag {}", tag).to_string();
let start = xmp.find(&format!("<tiff:{}>",tag)).ok_or(error.clone())?;
let end = xmp.find(&format!("</tiff:{}>",tag)).ok_or(error.clone())?;
Ok(xmp[start+tag.len()+7..end].to_string())
}
pub fn decode_compressed(&self, cam: &Camera, src: &[u8], width: usize, height: usize, dummy: bool) -> Result<Vec<u16>,String> {
let interlaced = cam.find_hint("interlaced");
Self::do_decode(src, interlaced, width, height, dummy)
}
pub(crate) fn do_decode(src: &[u8], interlaced:bool, width: usize, height: usize, dummy: bool) -> Result<Vec<u16>,String> {
if dummy {
return Ok(vec![0]);
}
let decompressor = LjpegDecompressor::new_full(src, true, true)?;
let ljpegout = decompressor.decode_leaf(width, height)?;
if interlaced {
let mut out = alloc_image_ok!(width, height, dummy);
for (row,line) in ljpegout.chunks_exact(width).enumerate() {
let orow = if row & 1 == 1 {height-1-row/2} else {row/2};
out[orow*width .. (orow+1)*width].copy_from_slice(line);
}
Ok(out)
} else {
Ok(ljpegout)
}
}
}