Files
photocraft/crates/io/tests/it/xmp_export.rs
T
David MannandClaude Opus 5.5 cab3ef6191 Merge PR #5815: perf(doc): share the XMP packet, Duotone PSD data and unsupported adjustment bytes between snapshots
- crates/engine/src/tests.rs: kept both tests (main's restore_layer_selection test and the PR's history_states_share_large_document_payloads).
- crates/io/src/psd_import.rs: kept main's parsed Duotone inks (duotone_map) with the PR's Arc<[u8]> psd_raw; also main's unknown-adjustment-key import (#6575) now builds Arc<[u8]> raw.
- crates/io/tests/adjust_warnings.rs: moved to tests/it/adjust_warnings.rs on main; PR's .into() edits applied there, plus #6322's Color Lookup test (raw.as_slice().into()).
- docs/architecture.md: union; status line names both changes, both revision-history rows kept.
- Adapted main-new sites to the PR's types: psd_export.rs (Duotone write-back via as_deref/to_vec, Unsupported block compare by slice), inspect.rs and ui-egui unsupported_marker_tests.rs (raw .into()), io tests/it/psd_unknown_adjustment.rs (slice compare).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:38:56 +02:00

57 lines
2.6 KiB
Rust

//! #647: Export As's Metadata: None (`XmpEmbed::None`) embeds none of the document's XMP (the
//! packet lists the text of every type layer and one id per placed document); the default,
//! `XmpEmbed::All`, keeps it as Save As does, and layered saves (PSD, `.pcraft`) always keep it.
use photocraft_color::{ColorMode, SampleType};
use photocraft_doc::{Document, Layer, LayerContent, Size};
use photocraft_io::{ExportOptions, XmpEmbed, export};
use photocraft_raster::Surface;
const XMP: &str = "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"><rdf:RDF>\
<photoshop:DocumentAncestors><rdf:Bag><rdf:li>xmp.did:11111111-2222-3333-4444-555555555555</rdf:li></rdf:Bag></photoshop:DocumentAncestors>\
<photoshop:TextLayers><rdf:Bag><rdf:li>Secret campaign copy</rdf:li></rdf:Bag></photoshop:TextLayers>\
</rdf:RDF></x:xmpmeta>";
fn doc_with_xmp() -> Document {
let mut d = Document::new("x", Size::new(8, 6), ColorMode::Rgb, SampleType::U8);
let mut s = Surface::new(d.pixel_format());
s.fill_rect(photocraft_geom::Rect::new(0, 0, 8, 6), &[0.5, 0.4, 0.3, 1.0]);
d.layers.push(Layer::new("flat", LayerContent::Raster(s)));
d.metadata.xmp = Some(XMP.into());
d
}
fn leaks_xmp(bytes: &[u8]) -> bool {
let s = String::from_utf8_lossy(bytes);
s.contains("x:xmpmeta") || s.contains("DocumentAncestors") || s.contains("Secret campaign copy")
}
#[test]
fn metadata_none_embeds_no_xmp() {
let opts = ExportOptions { xmp: XmpEmbed::None, ..ExportOptions::default() };
for ext in ["png", "jpg", "webp", "tif"] {
let r = export(&doc_with_xmp(), &format!("out.{ext}"), &opts).expect(ext);
assert!(!leaks_xmp(&r.bytes), "{ext}: the document XMP leaked into the export");
}
}
#[test]
fn all_embeds_the_whole_packet_and_is_the_default() {
assert_eq!(ExportOptions::default().xmp, XmpEmbed::All);
let opts = ExportOptions { xmp: XmpEmbed::All, ..ExportOptions::default() };
for ext in ["png", "jpg", "webp"] {
let r = export(&doc_with_xmp(), &format!("out.{ext}"), &opts).expect(ext);
assert!(leaks_xmp(&r.bytes), "{ext}: XmpEmbed::All must embed the packet");
}
}
#[test]
fn layered_saves_keep_the_xmp_whatever_the_option() {
for opts in [ExportOptions::default(), ExportOptions { xmp: XmpEmbed::None, ..ExportOptions::default() }] {
let psd = export(&doc_with_xmp(), "out.psd", &opts).expect("psd");
assert!(leaks_xmp(&psd.bytes), "PSD always keeps the document XMP");
let pcraft = export(&doc_with_xmp(), "out.pcraft", &opts).expect("pcraft");
assert!(leaks_xmp(&pcraft.bytes), ".pcraft always keeps the document XMP");
}
}