Files
DarkRoom/third_party/rawler-0.7.2/src/decoders/erf.rs
T
dtourolle 77a1925bac Vendor rawler 0.7.2 unmodified
The crate as crates.io publishes it, minus .cargo-ok, its Cargo.lock and
data/testdata (13 MB of sample files only its own tests read). Not yet
routed through [patch.crates-io]; the next commit is the patch.
2026-09-27 17:33:19 -04:00

114 lines
3.5 KiB
Rust

use log::warn;
use crate::RawlerError;
use crate::analyze::FormatDump;
use crate::rawsource::RawSource;
use crate::RawImage;
use crate::RawLoader;
use crate::Result;
use crate::bits::BEu16;
use crate::exif::Exif;
use crate::formats::tiff::GenericTiffReader;
use crate::formats::tiff::IFD;
use crate::formats::tiff::ifd::OffsetMode;
use crate::formats::tiff::reader::TiffReader;
use crate::packed::decode_12be_wcontrol;
use crate::tags::ExifTag;
use crate::tags::TiffCommonTag;
use super::BlackLevel;
use super::CFAConfig;
use super::Camera;
use super::Decoder;
use super::FormatHint;
use super::RawDecodeParams;
use super::RawMetadata;
use super::RawPhotometricInterpretation;
#[derive(Debug, Clone)]
pub struct ErfDecoder<'a> {
#[allow(unused)]
rawloader: &'a RawLoader,
tiff: GenericTiffReader,
makernote: IFD,
camera: Camera,
}
impl<'a> ErfDecoder<'a> {
pub fn new(file: &RawSource, tiff: GenericTiffReader, rawloader: &'a RawLoader) -> Result<ErfDecoder<'a>> {
let camera = rawloader.check_supported(tiff.root_ifd())?;
let makernote = if let Some(exif) = tiff.find_first_ifd_with_tag(ExifTag::MakerNotes) {
exif.parse_makernote(&mut file.reader(), OffsetMode::Absolute, &[])?
} else {
warn!("ERF makernote not found");
None
}
.ok_or("File has not makernotes")?;
Ok(ErfDecoder {
tiff,
rawloader,
camera,
makernote,
})
}
}
impl<'a> Decoder for ErfDecoder<'a> {
fn raw_image(&self, file: &RawSource, _params: &RawDecodeParams, dummy: bool) -> Result<RawImage> {
let raw = self
.tiff
.find_first_ifd_with_tag(TiffCommonTag::CFAPattern)
.ok_or_else(|| RawlerError::DecoderFailed(format!("Failed to find a IFD with CFAPattern tag")))?;
let width = fetch_tiff_tag!(raw, TiffCommonTag::ImageWidth).force_usize(0);
let height = fetch_tiff_tag!(raw, TiffCommonTag::ImageLength).force_usize(0);
let offset = fetch_tiff_tag!(raw, TiffCommonTag::StripOffsets).force_usize(0);
let src = file.subview_until_eof(offset as u64)?;
let image = decode_12be_wcontrol(src, width, height, dummy);
let cpp = 1;
let blacklevel = self.get_blacklevel(cpp);
let photometric = RawPhotometricInterpretation::Cfa(CFAConfig::new_from_camera(&self.camera));
let img = RawImage::new(self.camera.clone(), image, cpp, self.get_wb()?, photometric, blacklevel, None, dummy);
Ok(img)
}
fn format_dump(&self) -> FormatDump {
todo!()
}
fn raw_metadata(&self, _file: &RawSource, _params: &RawDecodeParams) -> Result<RawMetadata> {
let exif = Exif::new(self.tiff.root_ifd())?;
let mdata = RawMetadata::new(&self.camera, exif);
Ok(mdata)
}
fn format_hint(&self) -> FormatHint {
FormatHint::ERF
}
}
impl<'a> ErfDecoder<'a> {
fn get_wb(&self) -> Result<[f32; 4]> {
let levels = fetch_tiff_tag!(self.makernote, TiffCommonTag::EpsonWB);
if levels.count() != 256 {
Err(RawlerError::DecoderFailed("ERF: Levels count is off".to_string()))
} else {
let r = BEu16(levels.get_data(), 48) as f32;
let b = BEu16(levels.get_data(), 50) as f32;
Ok([r * 508.0 * 1.078 / 65536.0, 1.0, b * 382.0 * 1.173 / 65536.0, f32::NAN])
}
}
fn get_blacklevel(&self, cpp: usize) -> Option<BlackLevel> {
if let Some(levels) = self.makernote.get_entry(0x0401) {
let levels = [levels.force_u16(0), levels.force_u16(1), levels.force_u16(2), levels.force_u16(3)];
return Some(BlackLevel::new(&levels, self.camera.cfa.width, self.camera.cfa.height, cpp));
}
None
}
}