use std::f32::NAN;
use crate::decoders::*;
use crate::decoders::tiff::*;
use crate::decoders::basics::*;
pub fn is_x3f(buf: &[u8]) -> bool {
buf[0..4] == b"FOVb"[..]
}
struct X3fFile {
images: Vec<X3fImage>,
}
struct X3fDirectory {
offset: usize,
id: String,
}
struct X3fImage {
typ: usize,
format: usize,
width: usize,
height: usize,
doffset: usize,
}
impl X3fFile {
fn new(buf: &Buffer) -> Result<X3fFile, String> {
let offset = LEu32(&buf.buf, buf.size-4) as usize;
let data = &buf.buf[offset..];
let version = LEu32(data, 4);
if version < 0x00020000 {
return Err(format!("X3F: Directory version too old {}", version).to_string())
}
let entries = LEu32(data, 8) as usize;
let mut dirs = Vec::new();
let mut images = Vec::new();
for i in 0..entries {
let dir = X3fDirectory::new(data, 12+i*12)?;
if dir.id == "IMA2" {
let img = X3fImage::new(&buf.buf, dir.offset)?;
images.push(img);
}
dirs.push(dir);
}
Ok(X3fFile{
images: images,
})
}
}
impl X3fDirectory {
fn new(buf: &[u8], offset: usize) -> Result<X3fDirectory, String> {
let data = &buf[offset..];
let off = LEu32(data, 0) as usize;
let name = String::from_utf8_lossy(&data[8..12]).to_string();
Ok(X3fDirectory {
offset: off,
id: name,
})
}
}
impl X3fImage {
fn new(buf: &[u8], offset: usize) -> Result<X3fImage, String> {
let data = &buf[offset..];
Ok(X3fImage {
typ: LEu32(data, 8) as usize,
format: LEu32(data, 12) as usize,
width: LEu32(data, 16) as usize,
height: LEu32(data, 20) as usize,
doffset: offset+28,
})
}
}
pub struct X3fDecoder<'a> {
buffer: &'a [u8],
rawloader: &'a RawLoader,
dir: X3fFile,
}
impl<'a> X3fDecoder<'a> {
pub fn new(buf: &'a Buffer, rawloader: &'a RawLoader) -> X3fDecoder<'a> {
let dir = X3fFile::new(buf).unwrap();
X3fDecoder {
buffer: &buf.buf,
rawloader: rawloader,
dir: dir,
}
}
}
impl<'a> Decoder for X3fDecoder<'a> {
fn image(&self, dummy: bool) -> Result<RawImage,String> {
let caminfo = self.dir.images
.iter()
.find(|i| i.typ == 2 && i.format == 0x12)
.ok_or("X3F: Couldn't find camera info".to_string())?;
let data = &self.buffer[caminfo.doffset+6..];
if data[0..4] != b"Exif"[..] {
return Err("X3F: Couldn't find EXIF info".to_string())
}
let tiff = TiffIFD::new_root(self.buffer, caminfo.doffset+12)?;
let camera = self.rawloader.check_supported(&tiff)?;
let imginfo = self.dir.images
.iter()
.find(|i| i.typ == 1 || i.typ == 3)
.ok_or("X3F: Couldn't find image".to_string())?;
let width = imginfo.width;
let height = imginfo.height;
let offset = imginfo.doffset;
let src = &self.buffer[offset..];
let image = match imginfo.format {
35 => self.decode_compressed(src, width, height, dummy)?,
x => return Err(format!("X3F Don't know how to decode format {}", x).to_string())
};
let mut img = RawImage::new(camera, width, height, self.get_wb()?, image, dummy);
img.cpp = 3;
Ok(img)
}
}
impl<'a> X3fDecoder<'a> {
fn get_wb(&self) -> Result<[f32;4], String> {
Ok([NAN,NAN,NAN,NAN])
}
fn decode_compressed(&self, _buf: &[u8], _width: usize, _height: usize, _dummy: bool) -> Result<Vec<u16>, String> {
return Err("X3F decoding not implemented yet".to_string())
}
}