photocraft/crates/io/tests/raw.rs

91 lines
3.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Camera raw import: synthetic DNG / CR2 develop into a 16-bit ProPhoto
//! document; unsupported raw variants fall back to the embedded preview.
use photocraft_codecs::{ChannelLayout, EncodeOptions, Format, Image};
use photocraft_color::{ColorMode, SampleType};
use photocraft_io::{IoError, import};
use photocraft_raw::testgen::{Cr2Spec, DngSpec, TiffBuilder, Val, mosaic, scene};
#[test]
fn dng_opens_as_16_bit_prophoto() {
let (w, h) = (40, 24);
let mut spec = DngSpec::cfa(w, h, mosaic(&scene(w, h), w, [0, 1, 1, 2], 0, 65535));
spec.as_shot_neutral = Some([0.6, 1.0, 0.8]);
let r = import("shot.dng", &spec.build()).unwrap();
let d = &r.document;
assert_eq!((d.size.width, d.size.height), (40, 24));
assert_eq!(d.mode, ColorMode::Rgb);
assert_eq!(d.depth, SampleType::U16);
assert_eq!(d.layers.len(), 1);
let icc = d.icc_profile.as_ref().expect("profile");
assert_eq!(icc.as_slice(), &photocraft_cms::Builtin::ProPhotoCompat.profile().to_bytes()[..]);
assert!(r.warnings.iter().any(|w| w.contains("DNG") && w.contains("ProPhoto")), "{:?}", r.warnings);
}
#[test]
fn cr2_opens() {
let (w, h) = (48, 16);
let data = mosaic(&scene(w, h), w, [0, 1, 1, 2], 256, 12000);
let spec = Cr2Spec { width: w, height: h, data, precision: 14, components: 2, slices: vec![24, 24], borders: None, wb_rggb: None, orientation: 6 };
let r = import("IMG_0001.CR2", &spec.build()).unwrap();
// Orientation 6 rotates the 48×16 sensor image to 16×48.
assert_eq!((r.document.size.width, r.document.size.height), (16, 48));
assert_eq!(r.document.depth, SampleType::U16);
}
/// A NEF-like file with Nikon's (undocumented) compression and a full-size
/// baseline JPEG preview in IFD0.
fn nef_with_preview() -> Vec<u8> {
let img = Image::from_u8(32, 20, ChannelLayout::Rgb, vec![180; 32 * 20 * 3]).unwrap();
let jpeg = photocraft_codecs::encode(&img, Format::Jpeg, &EncodeOptions::default()).unwrap();
let mut t = TiffBuilder::default();
let strip = t.blob(vec![0; 64]);
let preview = t.blob(jpeg.clone());
let raw = t.ifd(vec![
(256, Val::Long(vec![8])),
(257, Val::Long(vec![8])),
(258, Val::Short(vec![12])),
(259, Val::Short(vec![34713])),
(262, Val::Short(vec![32803])),
(273, Val::Blobs(vec![strip])),
(279, Val::Long(vec![64])),
(33421, Val::Short(vec![2, 2])),
(33422, Val::Byte(vec![0, 1, 1, 2])),
]);
let ifd0 = t.ifd(vec![
(271, Val::Ascii("NIKON CORPORATION".into())),
(330, Val::Ifds(vec![raw])),
(513, Val::Blobs(vec![preview])),
(514, Val::Long(vec![jpeg.len() as u32])),
]);
t.chain = vec![ifd0];
t.build()
}
#[test]
fn unsupported_raw_falls_back_to_the_embedded_preview() {
let r = import("DSC_0001.NEF", &nef_with_preview()).unwrap();
assert_eq!((r.document.size.width, r.document.size.height), (32, 20));
assert!(r.warnings.first().is_some_and(|w| w.contains("Nikon compressed NEF") && w.contains("embedded")), "{:?}", r.warnings);
}
#[test]
fn unsupported_raw_without_preview_is_a_clear_error() {
let mut cr3 = vec![0, 0, 0, 24];
cr3.extend_from_slice(b"ftypcrx ");
cr3.extend_from_slice(&[0; 12]);
match import("IMG_0001.CR3", &cr3) {
Err(e @ IoError::Raw(_)) => assert!(e.to_string().contains("CR3"), "{e}"),
Err(e) => panic!("expected a raw error, got {e}"),
Ok(_) => panic!("CR3 must not decode yet"),
}
}
#[test]
fn truncated_raws_do_not_panic() {
let b = nef_with_preview();
for n in (0..b.len()).step_by(7) {
let _ = import("x.nef", &b[..n]);
}
}