-
Notifications
You must be signed in to change notification settings - Fork 1
/
fujifilm.rs
132 lines (118 loc) · 3.96 KB
/
fujifilm.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use super::*;
use once_cell::sync::Lazy;
static FUJI_SENSOR_TABLE: phf::Map<&'static str, u8> = phf::phf_map! {
"X-T1" => 0, // RBGBRG by default
"X-T3" => 1, // GGRGGB
"X-T4" => 1,
"X-T30" => 1,
"X-S10" => 1,
"X-Pro3" => 1,
"X-Pro4" => 1,
"X-E4" => 1,
"X100V" => 1,
"GFX50R" => 100, // RGGB
"GFX50S" => 100,
"GFX100" => 100,
"GFX50SII" => 100,
"GFX100S" => 100,
};
pub(super) struct General {
info: quickexif::ParsedInfo,
}
pub(super) static THUMBNAIL_RULE: Lazy<quickexif::ParsingRule> = Lazy::new(|| {
quickexif::describe_rule!(tiff {
0x0112 / orientation
next {
0x0201 / thumbnail
0x0202 / thumbnail_len
}
})
});
pub(super) static IMAGE_RULE: Lazy<quickexif::ParsingRule> = Lazy::new(|| {
quickexif::describe_rule!(tiff {
0x0112 / orientation
offset + 8 {
scan [0x49, 0x49, 0x2a, 0x00] / tiff_offset {
tiff {
0xf000 {
0xf001 / width
0xf002 / height
0xf003 / bps
0xf007 / strip
0xf008 / strip_len
0xf00a {
u32 + 0 / black_level
}
0xf00d {
u32 + 0 / white_balance_g
u32 + 1 / white_balance_r
u32 + 2 / white_balance_b
}
}
}
}
}
})
});
impl RawDecoder for General {
fn new(info: quickexif::ParsedInfo) -> Self {
General { info }
}
fn get_info(&self) -> &quickexif::ParsedInfo {
&self.info
}
fn into_info(self) -> quickexif::ParsedInfo {
self.info
}
fn get_crop(&self) -> Option<Crop> {
None
}
fn get_cfa_pattern(&self) -> Result<CFAPattern, DecodingError> {
let model = self
.info
.str("model")?
.split_whitespace()
.collect::<String>();
let pattern = FUJI_SENSOR_TABLE.get(model.as_str()).unwrap_or(&0);
let result = match pattern {
1 => CFAPattern::XTrans1,
100 => CFAPattern::RGGB,
_ => CFAPattern::XTrans0,
};
Ok(result)
}
fn decode_with_preprocess(&self, buffer: &[u8]) -> Result<Vec<u16>, DecodingError> {
let jpeg_header_offset = 12;
let tiff_offset = self.info.usize("tiff_offset")?;
let strip_offset = self.info.usize("strip")?;
let strip_len = self.info.usize("strip_len")?;
let width = self.info.usize("width")?;
let height = self.info.usize("height")?;
let black_level = self.info.u16("black_level")?;
let bps_scale = self.get_bps_scale()?;
let data_offset = jpeg_header_offset + tiff_offset + strip_offset;
let buf = &buffer[data_offset..data_offset + strip_len];
let image: Vec<u16> = utility::to_14bit_iter(buf, self.info.is_le)
.map(|x| bps_scale.saturating_mul(x.saturating_sub(black_level)))
.collect();
if image.len() != width * height {
Err(DecodingError::InvalidDecodedImageSize(image.len(), width * height))
} else {
Ok(image)
}
}
fn get_thumbnail<'a>(&self, buffer: &'a [u8]) -> Result<&'a [u8], DecodingError> {
let offset = self.info.usize("thumbnail")?;
let len = self.info.usize("thumbnail_len")?;
let jpeg_header_offset = 12;
let tiny_thumbnail_offset = jpeg_header_offset + offset + len;
let jpeg_eoi = &buffer[tiny_thumbnail_offset..]
.windows(2)
.enumerate()
.find(|(_, data)| data == &[0xff, 0xd9]);
match jpeg_eoi {
None => Ok(&buffer[offset..tiny_thumbnail_offset]),
&Some((index, _)) => Ok(&buffer[..tiny_thumbnail_offset + index + 2]),
}
}
}