Skip to main content

flashraw_core/
decoder.rs

1//! The contract between container/format decoders and the high-level API.
2
3use crate::Result;
4use crate::image::{Limits, RawImage};
5use crate::metadata::RawMetadata;
6use crate::profile::Profiler;
7use crate::types::*;
8
9/// Numeric format of decoded samples.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[non_exhaustive]
13pub enum SampleFormat {
14    /// Unsigned integer samples (`u16`).
15    U16,
16    /// Floating-point samples (`f32`, e.g. floating-point DNG).
17    F32,
18}
19
20/// Geometry and calibration of the decoded sensor buffer.
21///
22/// Everything here is known after parsing, before any pixel is decoded.
23#[derive(Debug, Clone, PartialEq)]
24#[non_exhaustive]
25pub struct FrameInfo {
26    /// Full decoded buffer width (including masked areas).
27    pub width: u32,
28    /// Full decoded buffer height (including masked areas).
29    pub height: u32,
30    /// Samples per pixel.
31    pub cpp: u32,
32    /// Significant bits per sample (e.g. 12 or 14).
33    pub bits_per_sample: u8,
34    /// Numeric format of the decoded samples.
35    pub sample_format: SampleFormat,
36    /// Colour filter pattern anchored at buffer `(0, 0)`; `None` for monochrome and
37    /// multi-sample (linear, Foveon) data.
38    pub cfa: Option<CfaPattern>,
39    /// How samples are arranged on the sensor.
40    pub layout: SensorLayout,
41    /// Region of valid image pixels (excludes optical black / masked borders).
42    pub active_area: Rect,
43    /// Recommended default crop (DNG DefaultCrop or vendor equivalent); inside `active_area`.
44    pub crop: Rect,
45    /// Masked (optical black) regions usable for black-level estimation.
46    pub masked_areas: Vec<Rect>,
47    /// Black level (see also `black_from_masked`).
48    pub black_level: BlackLevel,
49    /// When true, `black_level` is a fallback: the actual per-CFA-colour black is measured
50    /// from `masked_areas` after decoding (done by the high-level API).
51    pub black_from_masked: bool,
52    /// Saturation level of the stored samples.
53    pub white_level: WhiteLevel,
54    /// As-shot white balance; `None` when the file records none.
55    pub white_balance: Option<WhiteBalance>,
56    /// True when the camera already applied `white_balance` to the stored samples (Sony
57    /// lossless YCbCr M/S, Nikon sNEF): developing them needs unit multipliers, and
58    /// `white_balance` (still the as-shot multipliers) only serves to change the balance.
59    pub white_balance_applied: bool,
60    /// Colour calibration (file or camera database).
61    pub color_matrices: ColorMatrices,
62    /// Orientation to apply for display.
63    pub orientation: Orientation,
64    /// Pixel aspect ratio (width / height of a sensor site); 1.0 for almost all cameras.
65    pub pixel_aspect: f32,
66    /// Payload compression scheme.
67    pub compression: Compression,
68    /// DNG opcode lists carried by the file (applied by the high-level API).
69    pub opcodes: Option<std::sync::Arc<OpcodeLists>>,
70}
71
72/// DNG opcode lists exactly as stored (big-endian opcode data, DNG spec chapter 7).
73/// List 1 applies to stored values, list 2 to linear reference values of the active
74/// area, list 3 to the demosaiced camera-RGB image.
75#[derive(Debug, Clone, PartialEq, Default)]
76pub struct OpcodeLists {
77    /// OpcodeList1, OpcodeList2 and OpcodeList3 (empty when absent).
78    pub lists: [Vec<u8>; 3],
79}
80
81impl OpcodeLists {
82    /// True if every list is absent or holds no opcodes (at most its 4-byte count).
83    pub fn is_empty(&self) -> bool {
84        self.lists.iter().all(|l| l.len() <= 4)
85    }
86}
87
88impl FrameInfo {
89    /// A default description for a `width x height` CFA buffer; formats fill in the rest.
90    pub fn new(width: u32, height: u32, bits: u8) -> Self {
91        FrameInfo {
92            width,
93            height,
94            cpp: 1,
95            bits_per_sample: bits,
96            sample_format: SampleFormat::U16,
97            cfa: None,
98            layout: SensorLayout::Bayer,
99            active_area: Rect::full(width, height),
100            crop: Rect::full(width, height),
101            masked_areas: Vec::new(),
102            black_level: BlackLevel::uniform(0.0),
103            black_from_masked: false,
104            white_level: WhiteLevel::uniform(if bits >= 16 { 65535 } else { (1u32 << bits) - 1 }),
105            white_balance: None,
106            white_balance_applied: false,
107            color_matrices: ColorMatrices::default(),
108            orientation: Orientation::Normal,
109            pixel_aspect: 1.0,
110            compression: Compression::Uncompressed,
111            opcodes: None,
112        }
113    }
114
115    /// Clamp `active_area`/`crop`/masked areas into the buffer so later stages can trust them.
116    pub fn sanitize(&mut self) {
117        self.active_area = self.active_area.clamp_to(self.width, self.height);
118        if self.active_area.is_empty() {
119            self.active_area = Rect::full(self.width, self.height);
120        }
121        self.crop = self.crop.intersect(&self.active_area).unwrap_or(self.active_area);
122        let (w, h) = (self.width, self.height);
123        self.masked_areas.retain_mut(|r| {
124            *r = r.clamp_to(w, h);
125            !r.is_empty()
126        });
127        if self.white_level.values.is_empty() {
128            self.white_level = WhiteLevel::uniform((1u32 << self.bits_per_sample.min(16)) - 1);
129        }
130    }
131}
132
133/// Context passed to decoders.
134pub struct DecodeContext<'p> {
135    /// Safety limits for allocations and dimensions.
136    pub limits: Limits,
137    /// Allow multithreaded decoding.
138    pub parallel: bool,
139    /// Allow explicit SIMD kernels (scalar reference paths otherwise).
140    pub simd: bool,
141    /// Receives per-stage timings.
142    pub profiler: &'p Profiler,
143    /// Recover from truncated sensor data (zero-fill and warn) instead of failing.
144    /// Default: true (the high-level API's default policy). See [`crate::integrity`].
145    pub recover: bool,
146    /// Problems repaired under `recover` (see [`DecodeContext::recovered`]).
147    pub(crate) warnings: std::sync::Mutex<Vec<crate::DecodeWarning>>,
148}
149
150impl<'p> DecodeContext<'p> {
151    /// A context with default limits, parallelism and SIMD enabled.
152    pub fn new(profiler: &'p Profiler) -> Self {
153        DecodeContext {
154            limits: Limits::default(),
155            parallel: true,
156            simd: true,
157            profiler,
158            recover: true,
159            warnings: std::sync::Mutex::new(Vec::new()),
160        }
161    }
162}
163
164/// How the payload can be accessed independently.
165#[derive(Debug, Clone, Copy, PartialEq, Eq)]
166#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
167#[non_exhaustive]
168pub enum RandomAccess {
169    /// A single sequential stream; any region requires decoding from the start.
170    Sequential,
171    /// Independent rows (e.g. uncompressed / packed data): any region is directly addressable.
172    Rows,
173    /// Independent strips of `rows` rows.
174    Strips {
175        /// Rows per strip (the last strip may be shorter).
176        rows: u32,
177    },
178    /// Independent tiles.
179    Tiles {
180        /// Tile width in pixels.
181        width: u32,
182        /// Tile height in pixels.
183        height: u32,
184    },
185    /// Independent vertical slices/blocks of varying geometry.
186    Blocks,
187}
188
189/// An independently decodable unit of the payload.
190#[derive(Debug, Clone, PartialEq)]
191#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
192pub struct DecodeUnit {
193    /// Area of the output buffer covered by this unit.
194    pub rect: Rect,
195    /// Byte range of the compressed data in the source file (for range-request planning).
196    pub offset: u64,
197    /// Length of the compressed data in bytes.
198    pub length: u64,
199}
200
201/// Bit packing order of uncompressed payloads exposed to the GPU unpacker.
202#[derive(Debug, Clone, Copy, PartialEq, Eq)]
203pub enum PackOrder {
204    /// Bits packed MSB-first, bytes in order (big-endian packed).
205    MsbBytes,
206    /// Bits packed LSB-first, bytes in order (little-endian packed).
207    LsbBytes,
208    /// MSB-first within 16-bit little-endian words.
209    Msb16,
210    /// MSB-first within 32-bit little-endian words.
211    Msb32,
212}
213
214/// A uniformly bit-packed payload that can be unpacked without entropy decoding
215/// (directly on the GPU, or with SIMD kernels).
216#[derive(Debug, Clone, Copy)]
217pub struct PackedPayload<'a> {
218    /// Packed bytes, starting at the first row.
219    pub data: &'a [u8],
220    /// Width in samples.
221    pub width: u32,
222    /// Height in rows.
223    pub height: u32,
224    /// Bits per sample.
225    pub bits: u32,
226    /// Bit packing order.
227    pub order: PackOrder,
228    /// Bytes from the start of one row to the next.
229    pub row_stride: usize,
230}
231
232impl PackedPayload<'_> {
233    /// True when `data` holds every sample (only complete payloads take the GPU unpack
234    /// path; truncated ones are decoded on the CPU under the corruption policy).
235    pub fn is_complete(&self) -> bool {
236        let g = crate::RowGeometry::packed(self.height as usize, self.width as usize, self.bits, self.row_stride);
237        self.data.len() >= g.needed()
238    }
239}
240
241/// A parsed RAW file ready for decoding.
242pub trait RawDecoder: Send + Sync {
243    /// Container format.
244    fn format(&self) -> RawFormat;
245    /// Normalised metadata.
246    fn metadata(&self) -> &RawMetadata;
247    /// Geometry and calibration of the sensor buffer.
248    fn frame_info(&self) -> &FrameInfo;
249
250    /// Decode the full sensor buffer.
251    fn decode(&self, ctx: &DecodeContext) -> Result<RawImage>;
252
253    /// How the payload can be randomly accessed.
254    fn random_access(&self) -> RandomAccess {
255        RandomAccess::Sequential
256    }
257
258    /// Independently decodable units (tiles/strips), if any.
259    fn units(&self) -> Vec<DecodeUnit> {
260        Vec::new()
261    }
262
263    /// Decode only `region` (buffer coordinates). Formats with random access override
264    /// this to avoid decoding unrelated data; the default decodes everything and crops.
265    fn decode_region(&self, ctx: &DecodeContext, region: Rect) -> Result<RawImage> {
266        self.decode(ctx)?.crop(region)
267    }
268
269    /// The payload as a uniformly packed bit stream, when the format stores it that way.
270    fn packed_payload(&self) -> Option<PackedPayload<'_>> {
271        None
272    }
273}