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:
@@ -28,6 +28,23 @@ pub struct MetadataFound {
|
|||||||
pub camera: Option<String>,
|
pub camera: Option<String>,
|
||||||
pub lens: Option<String>,
|
pub lens: Option<String>,
|
||||||
pub iso: Option<u32>,
|
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`.
|
/// Write a batch of dates and tell the UI, draining `found`.
|
||||||
@@ -140,7 +157,9 @@ pub fn write_metadata(
|
|||||||
camera = coalesce(?4, camera),
|
camera = coalesce(?4, camera),
|
||||||
lens = coalesce(?5, lens),
|
lens = coalesce(?5, lens),
|
||||||
iso = coalesce(?6, iso),
|
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",
|
WHERE id = ?1",
|
||||||
rusqlite::params![
|
rusqlite::params![
|
||||||
m.image_id,
|
m.image_id,
|
||||||
@@ -150,6 +169,8 @@ pub fn write_metadata(
|
|||||||
m.lens,
|
m.lens,
|
||||||
m.iso,
|
m.iso,
|
||||||
state,
|
state,
|
||||||
|
m.size.map(|s| s.0),
|
||||||
|
m.size.map(|s| s.1),
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
if state == 2 {
|
if state == 2 {
|
||||||
@@ -404,6 +425,7 @@ pub fn spawn_sweep(conn: Connection, catalog_path: PathBuf) -> Receiver<SweepMes
|
|||||||
camera: None,
|
camera: None,
|
||||||
lens: None,
|
lens: None,
|
||||||
iso: None,
|
iso: None,
|
||||||
|
size: None,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -874,6 +896,20 @@ pub(super) fn thumbnails_outstanding(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
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]
|
#[test]
|
||||||
fn join_all_preserves_order_regardless_of_completion() {
|
fn join_all_preserves_order_regardless_of_completion() {
|
||||||
// The ordering guarantee is what lets a caller pair results back to
|
// The ordering guarantee is what lets a caller pair results back to
|
||||||
|
|||||||
@@ -517,6 +517,7 @@ pub(super) async fn collect_metadata(
|
|||||||
captured_at: md.captured_at,
|
captured_at: md.captured_at,
|
||||||
captured_offset: md.captured_offset,
|
captured_offset: md.captured_offset,
|
||||||
camera: camera_label(md.make.as_deref(), md.model.as_deref()),
|
camera: camera_label(md.make.as_deref(), md.model.as_deref()),
|
||||||
|
size: MetadataFound::upright_size(&md),
|
||||||
lens: md.lens.map(|l| l.trim().to_string()),
|
lens: md.lens.map(|l| l.trim().to_string()),
|
||||||
iso: md.iso,
|
iso: md.iso,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -712,6 +712,7 @@ fn metadata(
|
|||||||
captured_at: md.captured_at,
|
captured_at: md.captured_at,
|
||||||
captured_offset: md.captured_offset,
|
captured_offset: md.captured_offset,
|
||||||
camera: crate::library::camera_label(md.make.as_deref(), md.model.as_deref()),
|
camera: crate::library::camera_label(md.make.as_deref(), md.model.as_deref()),
|
||||||
|
size: MetadataFound::upright_size(&md),
|
||||||
lens: md.lens.map(|l| l.trim().to_string()),
|
lens: md.lens.map(|l| l.trim().to_string()),
|
||||||
iso: md.iso,
|
iso: md.iso,
|
||||||
},
|
},
|
||||||
@@ -724,6 +725,7 @@ fn metadata(
|
|||||||
camera: None,
|
camera: None,
|
||||||
lens: None,
|
lens: None,
|
||||||
iso: None,
|
iso: None,
|
||||||
|
size: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user