Skip to content

Commit

Permalink
ERF: add new format as seen in the Epson R-D1
Browse files Browse the repository at this point in the history
  • Loading branch information
pedrocr committed Dec 10, 2016
1 parent a4817c1 commit 6a0d67b
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ The library is still in its very beginning with only a few formats implemented:
* Mamiya MEF
* Olympus ORF
* Samsung SRW
* Epson ERF

Usage
-----
Expand Down
9 changes: 9 additions & 0 deletions data/cameras/epson/r-d1.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
make = "SEIKO EPSON CORP."
model = "R-D1"
canonical_make = "SEIKO EPSON CORP."
canonical_model = "R-D1"
blackpoint = 63
whitepoint = 4095
color_matrix = [6827, -1878, -732, -8429, 16012, 2564, -704, 592, 7145]
color_pattern = "RGGB"
crops = [0,0,0,0]
21 changes: 21 additions & 0 deletions src/decoders/basics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,27 @@ pub fn decode_12le_wcontrol(buf: &[u8], width: usize, height: usize) -> Vec<u16>
}))
}

pub fn decode_12be_wcontrol(buf: &[u8], width: usize, height: usize) -> Vec<u16> {
// Calulate expected bytes per line.
let perline = width * 12 / 8 + ((width+2) / 10);

decode_threaded(width, height, &(|out: &mut [u16], row| {
let inb = &buf[((row*perline) as usize)..];

for (oc, ic) in out.chunks_mut(10).zip(inb.chunks(16)) {
for (o, i) in oc.chunks_mut(2).zip(ic.chunks(3)) {
let g1: u16 = i[0] as u16;
let g2: u16 = i[1] as u16;
let g3: u16 = i[2] as u16;

o[0] = (g1 << 4) | (g2 >> 4);
o[1] = ((g2 & 0x0f) << 8) | g3;
}
}
}))
}


pub fn decode_12be_interlaced(buf: &[u8], width: usize, height: usize) -> Vec<u16> {
let half = (height+1) >> 1;
// Second field is 2048 byte aligned
Expand Down
55 changes: 55 additions & 0 deletions src/decoders/erf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct ErfDecoder<'a> {
buffer: &'a [u8],
rawloader: &'a RawLoader,
tiff: TiffIFD<'a>,
}

impl<'a> ErfDecoder<'a> {
pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> ErfDecoder<'a> {
ErfDecoder {
buffer: buf,
tiff: tiff,
rawloader: rawloader,
}
}
}

impl<'a> Decoder for ErfDecoder<'a> {
fn identify(&self) -> Result<&Camera, String> {
let make = fetch_tag!(self.tiff, Tag::Make, "ERF: Couldn't find Make").get_str();
let model = fetch_tag!(self.tiff, Tag::Model, "ERF: Couldn't find Model").get_str();
self.rawloader.check_supported(make, model)
}

fn image(&self) -> Result<Image,String> {
let camera = try!(self.identify());
let data = self.tiff.find_ifds_with_tag(Tag::StripOffsets);
let raw = data[1];
let width = fetch_tag!(raw, Tag::ImageWidth, "ERF: Couldn't find width").get_u32(0);
let height = fetch_tag!(raw, Tag::ImageLength, "ERF: Couldn't find height").get_u32(0);
let offset = fetch_tag!(raw, Tag::StripOffsets, "ERF: Couldn't find offset").get_u32(0) as usize;
let src = &self.buffer[offset .. self.buffer.len()];

let image = decode_12be_wcontrol(src, width as usize, height as usize);
ok_image(camera, width, height, try!(self.get_wb()), image)
}
}

impl<'a> ErfDecoder<'a> {
fn get_wb(&self) -> Result<[f32;4], String> {
let levels = fetch_tag!(self.tiff, Tag::EpsonWB, "ERF: No levels");
if levels.count() != 256 {
Err("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, NAN])
}
}
}
2 changes: 2 additions & 0 deletions src/decoders/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod arw;
mod mef;
mod orf;
mod srw;
mod erf;
use self::basics::*;
use self::tiff::*;

Expand Down Expand Up @@ -214,6 +215,7 @@ impl RawLoader {
"OLYMPUS CORPORATION" => use_decoder!(orf::OrfDecoder, buffer, tiff, self),
"OLYMPUS OPTICAL CO.,LTD" => use_decoder!(orf::OrfDecoder, buffer, tiff, self),
"SAMSUNG" => use_decoder!(srw::SrwDecoder, buffer, tiff, self),
"SEIKO EPSON CORP." => use_decoder!(erf::ErfDecoder, buffer, tiff, self),
make => Err(format!("Couldn't find a decoder for make \"{}\"", make).to_string()),
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/decoders/tiff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub enum Tag {
StripOffsets = 0x0111,
StripByteCounts= 0x0117,
SubIFDs = 0x014A,
EpsonWB = 0x0E80,
OlympusRedMul = 0x1017,
OlympusBlueMul = 0x1018,
OlympusImgProc = 0x2040,
Expand Down Expand Up @@ -140,6 +141,11 @@ impl<'a> TiffIFD<'a> {
}
}

// Epson starts the makernote with its own name
if data[0..5] == b"EPSON"[..] {
off += 8;
}

TiffIFD::new(buf, off, base_offset, depth, e)
}

Expand Down Expand Up @@ -235,4 +241,8 @@ impl<'a> TiffEntry<'a> {
Result::Err(err) => panic!(err),
}
}

pub fn get_data(&self) -> &[u8] {
self.data
}
}

0 comments on commit 6a0d67b

Please sign in to comment.