mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-14 19:27:01 -04:00
LR-IMP-FORMATS: EOS R5 Mark II crop-mode CR3s develop without a black band
The R5 Mark II's APS-C crop-mode files (5376 x 3574) state an IAD1 active area of x 132..5243, but columns 132..~256 sit at the black level and the image runs to the right edge (measured on raw.pixls.us 7883/7884), while their recommended crop, x 272..5359 (5088 x 3392, the camera JPEG's size), lies on the image. The recommended crop didn't fit inside the stated active area, so the whole active area was kept: a black band down the left and ~130 image columns lost. When the recommended crop doesn't fit inside the stated active area, it is now the valid area. On 7883 the render's high-pass correlation with the camera JPEG goes from -0.13 to 0.99. The active area and crop of the other 108 decodable CC0 CR3s on raw.pixls.us are unchanged. RENDER_CACHE_VERSION 49.
This commit is contained in:
1 parent
b70ae1741e
commit
e7f8faf77d
3 files changed
+29
-9
No files matched your search
@@ -62,7 +62,7 @@ impl SettingsHashes {
|
||||
}
|
||||
|
||||
/// Bump when the pipeline's output changes, to invalidate cached thumbnails.
|
||||
pub const RENDER_CACHE_VERSION: u64 = 42;
|
||||
pub const RENDER_CACHE_VERSION: u64 = 49;
|
||||
|
||||
/// Thumbnails render at one of these long edges (so window/cell size changes reuse the cache).
|
||||
pub const THUMB_SIZES: [usize; 4] = [128, 256, 384, 512];
|
||||
|
||||
Vendored
+22
-8
@@ -108,10 +108,20 @@ fn aspect_crop(maker: Option<&Ifd>, image: Rect) -> Option<Rect> {
|
||||
fn geometry(area: Option<&Cr3ImageArea>, maker: Option<&Ifd>, width: usize, height: usize) -> (Rect, Rect) {
|
||||
let area = area.filter(|a| usize::from(a.width) == width && usize::from(a.height) == height);
|
||||
let sensor = sensor_crop(maker, width, height);
|
||||
let active = area.and_then(|a| a.active).and_then(|b| inclusive_rect(b, width, height)).or(sensor).unwrap_or(Rect::new(0, 0, width, height));
|
||||
// The recommended crop, when the file gives a consistent one. `AspectInfo` is measured from its origin, so it
|
||||
// is only applied on top of that; without it (the crop doesn't fit the valid area) the whole active area stays.
|
||||
let recommended = area.and_then(|a| inclusive_rect(a.crop, width, height)).or(sensor).and_then(|c| relative_crop(c, active));
|
||||
let mut active = area.and_then(|a| a.active).and_then(|b| inclusive_rect(b, width, height)).or(sensor).unwrap_or(Rect::new(0, 0, width, height));
|
||||
// The recommended crop. `AspectInfo` is measured from its origin, so it is applied on top of it.
|
||||
let stated = area.and_then(|a| inclusive_rect(a.crop, width, height)).or(sensor);
|
||||
let mut recommended = stated.and_then(|c| relative_crop(c, active));
|
||||
// Some crop-mode files (EOS R5 Mark II APS-C, 5376 x 3574) state an active area that starts in the dark
|
||||
// columns and stops short of the image, while their recommended crop lies on the image (measured: columns
|
||||
// 132..~256 sit at the black level, the image runs to the right edge). The recommended crop is then the
|
||||
// valid area.
|
||||
if recommended.is_none()
|
||||
&& let Some(c) = stated.filter(|c| c.width >= 2 && c.height >= 2)
|
||||
{
|
||||
active = c;
|
||||
recommended = Some(Rect::new(0, 0, c.width, c.height));
|
||||
}
|
||||
let crop = recommended.map(|c| aspect_crop(maker, c).unwrap_or(c)).unwrap_or(Rect::new(0, 0, active.width, active.height));
|
||||
(active, crop)
|
||||
}
|
||||
@@ -424,8 +434,9 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// Some crop-mode files (EOS R5 Mark II 7883) record a recommended crop that reaches past their valid area. The
|
||||
/// whole active area stays then, and `AspectInfo`, which is measured from the recommended crop, is not applied.
|
||||
/// Some crop-mode files (EOS R5 Mark II 7883) record a recommended crop that reaches past their stated active
|
||||
/// area, which starts in dark columns. The recommended crop is then the valid area (no black band on the left),
|
||||
/// and `AspectInfo` applies from its origin.
|
||||
#[test]
|
||||
fn aspect_info_needs_a_consistent_recommended_crop() {
|
||||
let aspect = lightcraft_tiff::IfdBuilder::new().with(ASPECT_INFO, Value::Long(vec![13, 5088, 3392, 0, 0]));
|
||||
@@ -433,8 +444,11 @@ mod tests {
|
||||
let maker = Tiff::parse(&bytes).unwrap().ifds.remove(0);
|
||||
let area =
|
||||
|crop| Cr3ImageArea { width: 5376, height: 3574, crop, active: Some([132, 160, 5243, 3567]), masked_left: [0; 4], masked_top: None };
|
||||
// crop right edge 5359 > active right edge 5243: not a crop of the active area
|
||||
assert_eq!(geometry(Some(&area([272, 172, 5359, 3563])), Some(&maker), 5376, 3574).1, Rect::new(0, 0, 5112, 3408));
|
||||
// crop right edge 5359 > active right edge 5243: the recommended crop becomes the valid area
|
||||
assert_eq!(
|
||||
geometry(Some(&area([272, 172, 5359, 3563])), Some(&maker), 5376, 3574),
|
||||
(Rect::new(272, 172, 5088, 3392), Rect::new(0, 0, 5088, 3392))
|
||||
);
|
||||
// consistent crop: AspectInfo applies from its origin
|
||||
assert_eq!(geometry(Some(&area([140, 172, 5227, 3563])), Some(&maker), 5376, 3574).1, Rect::new(8, 12, 5088, 3392));
|
||||
}
|
||||
|
||||
@@ -11,6 +11,12 @@ recommended crop, and the decoder uses it as the default crop, so the developed
|
||||
framed (PowerShot SX70 HS, EOS 250D, PowerShot G5 X Mark II, EOS M6 Mark II and EOS M50 samples). A rectangle that
|
||||
is missing or does not fit inside the crop is ignored. The embedded JPEG still shows the whole frame.
|
||||
|
||||
The EOS R5 Mark II's APS-C crop-mode files (5376 x 3574) state an active area that starts in dark columns
|
||||
(132..~256 sit at the black level) and stops ~130 columns short of the image, while their recommended crop
|
||||
(5088 x 3392, the camera JPEG's size) lies on the image. When the recommended crop doesn't fit inside the stated
|
||||
active area, it is used as the valid area: on raw.pixls.us 7883/7884 the render matches the camera JPEG
|
||||
(high-pass correlation 0.99, was -0.13 with a black band on the left). No other of the 110 CC0 CR3s changes.
|
||||
|
||||
The decoder is independent Rust code shared by desktop, CLI and WebAssembly;
|
||||
it has no operating-system imaging dependency or external decoder. Its sources
|
||||
are the public prose descriptions and patents cited in
|
||||
|
||||
Reference in new issue
Block a user