Learn a photograph's shape from its header

A panorama the merge did not make, a stitch from another program or a
phone's sweep, never had a width or height in the catalog, so it could
never be given a wide cell. The header read that dates a photograph now
records its size as it is seen, orientation applied, alongside the date.
This commit is contained in:
2026-09-28 19:57:37 -04:00
parent 6050a8e703
commit 3b7d7129ff
3 changed files with 40 additions and 1 deletions
+37 -1
View File
@@ -28,6 +28,23 @@ pub struct MetadataFound {
pub camera: Option<String>,
pub lens: Option<String>,
pub iso: Option<u32>,
/// TRACES: FR-MRG-6
/// Width and height as the photograph is seen — orientation applied —
/// where the header says: what gives a panorama from elsewhere, a
/// stitch from another program or a phone's sweep, its wide cell.
pub size: Option<(u32, u32)>,
}
impl MetadataFound {
/// The upright size a header describes.
pub fn upright_size(md: &dr_decode::Metadata) -> Option<(u32, u32)> {
let (w, h) = (md.width?, md.height?);
if w == 0 || h == 0 {
return None;
}
let turned = md.orientation.is_some_and(|o| o.quarter_turns % 2 == 1);
Some(if turned { (h, w) } else { (w, h) })
}
}
/// Write a batch of dates and tell the UI, draining `found`.
@@ -140,7 +157,9 @@ pub fn write_metadata(
camera = coalesce(?4, camera),
lens = coalesce(?5, lens),
iso = coalesce(?6, iso),
metadata_state = max(metadata_state, ?7)
metadata_state = max(metadata_state, ?7),
w = coalesce(?8, w),
h = coalesce(?9, h)
WHERE id = ?1",
rusqlite::params![
m.image_id,
@@ -150,6 +169,8 @@ pub fn write_metadata(
m.lens,
m.iso,
state,
m.size.map(|s| s.0),
m.size.map(|s| s.1),
],
)?;
if state == 2 {
@@ -404,6 +425,7 @@ pub fn spawn_sweep(conn: Connection, catalog_path: PathBuf) -> Receiver<SweepMes
camera: None,
lens: None,
iso: None,
size: None,
}),
);
@@ -874,6 +896,20 @@ pub(super) fn thumbnails_outstanding(
mod tests {
use super::*;
#[test]
fn a_header_gives_the_size_the_photograph_is_seen_at() {
let mut md = dr_decode::Metadata {
width: Some(9000),
height: Some(3000),
..Default::default()
};
assert_eq!(MetadataFound::upright_size(&md), Some((9000, 3000)));
md.orientation = Some(dr_types::Orientation::from_exif(6));
assert_eq!(MetadataFound::upright_size(&md), Some((3000, 9000)));
md.width = None;
assert_eq!(MetadataFound::upright_size(&md), None);
}
#[test]
fn join_all_preserves_order_regardless_of_completion() {
// The ordering guarantee is what lets a caller pair results back to