mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-14 06:12:28 +00:00
M6: the .fig export writes sanitized image adjustments (#2297)
A document can hold image adjustments outside -1..=1 or not a number (a saved file, or a fills property); the renderer and the importer clamp them, but the export wrote the raw values for other readers. The export now writes the sanitized values, and a paint whose adjustments are all neutral after sanitizing writes no `paintFilter`. The round-trip test pins both cases and that all seven fields are written on a partly neutral paint. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Model-Effort: Opus 5.5 drove; Fable 5.2 briefed; Sonnet 5.5 wrote at medium
This commit is contained in:
1 parent
b54df860de
commit
501df23499
2 files changed
+22
-3
No files matched your search
@@ -76,8 +76,8 @@ impl<'d> Exporter<'d> {
|
||||
if let (ImageScaleMode::Crop, Some(c)) = (img.scale_mode, img.crop) {
|
||||
f.push(("transform", matrix(Affine::new(c))));
|
||||
}
|
||||
if !img.filters.is_identity() {
|
||||
let x = &img.filters;
|
||||
let x = img.filters.sanitized();
|
||||
if !x.is_identity() {
|
||||
// The file's tint is positive towards magenta, ours towards green; `0.0 -` keeps zero positive.
|
||||
f.push((
|
||||
"paintFilter",
|
||||
|
||||
@@ -110,12 +110,24 @@ fn warnings_naming_unknown_filter_fields_are_capped() {
|
||||
|
||||
#[test]
|
||||
fn image_adjustments_survive_a_fig_export() {
|
||||
let (doc, _) = import(&image_filter_fixture(), "ImageFilters.fig").unwrap();
|
||||
let (mut doc, _) = import(&image_filter_fixture(), "ImageFilters.fig").unwrap();
|
||||
let filters_of = |doc: &figcraft_doc::Document, name: &str| {
|
||||
let node = doc.nodes().find(|node| node.name == name).unwrap();
|
||||
let figcraft_doc::color::PaintKind::Image(image) = &node.fills[0].kind else { panic!("{name} is not an image fill") };
|
||||
image.filters
|
||||
};
|
||||
// Values a document can hold and the file can't: out of range, and not a number.
|
||||
let ids: Vec<figcraft_doc::NodeId> = doc.ids().collect();
|
||||
for id in ids {
|
||||
let Some(node) = doc.node_mut(id) else { continue };
|
||||
let name = node.name.clone();
|
||||
let Some(figcraft_doc::color::PaintKind::Image(image)) = node.fills.first_mut().map(|p| &mut p.kind) else { continue };
|
||||
match name.as_str() {
|
||||
"Legacy" => image.filters.exposure = 5.0,
|
||||
"Explicit neutral" => image.filters.contrast = f32::NAN,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let (bytes, warnings) = export::export(&doc, None).unwrap();
|
||||
assert!(!warnings.iter().any(|w| w.contains("image adjustments")), "{warnings:?}");
|
||||
let (back, _) = import(&bytes, "Back.fig").unwrap();
|
||||
@@ -150,6 +162,13 @@ fn image_adjustments_survive_a_fig_export() {
|
||||
assert!((written(¤t, "tint").unwrap() - 1.0).abs() < 1e-6);
|
||||
assert!((written(¤t, "shadows").unwrap() - 0.7).abs() < 1e-6);
|
||||
assert!(fill_of("Neutral").get("paintFilter").is_none());
|
||||
assert!((written(&fill_of("Legacy"), "exposure").unwrap() - 1.0).abs() < 1e-6, "written within the file's range");
|
||||
assert!(fill_of("Explicit neutral").get("paintFilter").is_none(), "not a number is no adjustment");
|
||||
let partly = fill_of("Negative tint");
|
||||
for field in ["exposure", "contrast", "vibrance", "temperature", "tint", "highlights", "shadows"] {
|
||||
assert!(written(&partly, field).is_some(), "{field} is written");
|
||||
}
|
||||
assert!((written(&partly, "tint").unwrap() + 1.0).abs() < 1e-6);
|
||||
|
||||
// The numbers the format uses.
|
||||
let s = Schema::parse(export::SCHEMA).unwrap();
|
||||
|
||||
Reference in new issue
Block a user