mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-14 19:27:01 -04:00
Merge PR #1177
This commit is contained in:
commit
3e5439cc94
4 files changed
+28
-3
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 = 61;
|
||||
pub const RENDER_CACHE_VERSION: u64 = 62;
|
||||
|
||||
/// 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];
|
||||
|
||||
@@ -300,7 +300,9 @@ pub(crate) fn decode_as(bytes: &[u8], mode: Mode, format: RawFormat) -> Result<R
|
||||
if cpp != 1 {
|
||||
return Err(RawError::Unsupported("CFA data with several samples per pixel".into()));
|
||||
}
|
||||
Some(Cfa { width: cols, height: rows, pattern })
|
||||
// the tag is anchored at the top-left of the ActiveArea (DNG spec); `RawImage::cfa` is anchored at the
|
||||
// sensor origin (the crop to the active area shifts it back), so move the anchor out by the area's offset
|
||||
Some(Cfa { width: cols, height: rows, pattern }.shifted(cols - active_area.x % cols, rows - active_area.y % rows))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
@@ -125,7 +125,9 @@ pub fn write_dng(raw: &RawImage, opts: &DngWriteOptions) -> Result<Vec<u8>> {
|
||||
|
||||
if let Some(cfa) = &raw.cfa {
|
||||
ifd.set(t::CFA_REPEAT_PATTERN_DIM, Value::Short(vec![cfa.height as u16, cfa.width as u16]));
|
||||
ifd.set(t::CFA_PATTERN_EP, Value::Byte(cfa.pattern.clone()));
|
||||
// the tag is anchored at the ActiveArea's top-left, `raw.cfa` at the sensor origin
|
||||
let a = raw.active_area;
|
||||
ifd.set(t::CFA_PATTERN_EP, Value::Byte(cfa.shifted(a.x, a.y).pattern));
|
||||
ifd.set(t::CFA_PLANE_COLOR, Value::Byte(vec![0, 1, 2]));
|
||||
ifd.set(t::CFA_LAYOUT, Value::Short(vec![1]));
|
||||
}
|
||||
|
||||
@@ -1026,3 +1026,24 @@ fn baseline_sharpness_is_read_when_plausible() {
|
||||
assert_eq!(decode(&bytes).unwrap().color.baseline_sharpness, None);
|
||||
assert_eq!(decode(&profile_dng(ByteOrder::Big, |_| {})).unwrap().color.baseline_sharpness, None);
|
||||
}
|
||||
|
||||
/// The DNG CFAPattern is anchored at the top-left of the ActiveArea: a DNG whose area starts on an odd row or
|
||||
/// column still demosaics with the pattern the tag states (#1086), and the writer states it back the same way.
|
||||
#[test]
|
||||
fn cfa_pattern_is_relative_to_the_active_area() {
|
||||
let (w, h) = (20, 12);
|
||||
for (top, left, sensor_name) in [(0u32, 0u32, "GRBG"), (1, 0, "BGGR"), (0, 1, "RGGB"), (1, 1, "GBRG"), (3, 5, "GBRG"), (2, 4, "GRBG")] {
|
||||
let mut raw = base_ifd(w, h, 16, 1, true);
|
||||
raw.set_image(ImageData::Strips { rows_per_strip: h as u32, strips: vec![u16_bytes(&pattern(w, h, 1, 16), ByteOrder::Little)] });
|
||||
raw.set(t::WHITE_LEVEL, Value::Short(vec![65535]));
|
||||
raw.set(t::ACTIVE_AREA, Value::Long(vec![top, left, h as u32 - 1, w as u32 - 1]));
|
||||
let img = decode(&dng(raw, ByteOrder::Little)).unwrap();
|
||||
assert_eq!(img.cfa.as_ref().unwrap().name(), sensor_name, "sensor anchor for area at ({left}, {top})");
|
||||
assert_eq!(img.normalized().unwrap().cfa.unwrap().name(), "GRBG", "tag pattern for area at ({left}, {top})");
|
||||
let back =
|
||||
decode(&write_dng(&img, &DngWriteOptions { compression: DngCompression::Uncompressed, order: ByteOrder::Little, xmp: None }).unwrap())
|
||||
.unwrap();
|
||||
assert_eq!(back.cfa.as_ref().unwrap().name(), sensor_name);
|
||||
assert_eq!(back.normalized().unwrap().cfa.unwrap().name(), "GRBG");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user