Smart Objects > Export Contents: another extension exports the contents in that format (#4847)
Export Contents wrote the smart object's file as it was whatever the
path, so out.png held .pcraft or .psb data. With the contents' own
extension (or none) it still copies the file; with another one it opens
the contents and exports them in that format, as File > Export does
("converted": true, with the export's warnings). jpg/jpeg and tif/tiff
count as the same; an unknown extension is an error.
Fixes #4846
This commit is contained in:
parent
0df333f623
commit
663863e62b
|
|
@ -862,12 +862,28 @@ pub fn contents_of(doc: &Document, id: LayerId) -> Result<(String, Arc<Vec<u8>>)
|
|||
source_bytes(&doc.metadata, &smart(doc, id)?.source).ok_or_else(|| other("the smart object's contents are unavailable"))
|
||||
}
|
||||
|
||||
/// Writes the smart object's file as it is. To a path with another extension (a `.png` for
|
||||
/// `.psb` or `.pcraft` contents) the contents are opened and exported in that format instead.
|
||||
fn export_contents(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let path = path_param("layer.smartObjects.exportContents", p)?;
|
||||
let id = layer_param(s, p)?;
|
||||
let (name, bytes) = contents_of(&s.active().ok_or(EngineError::NoDocument)?.doc, id)?;
|
||||
crate::file_cmds::write_file(path, &bytes)?;
|
||||
Ok(json!({"path": path, "fileName": name, "bytes": bytes.len()}))
|
||||
let ext = |f: &str| {
|
||||
let e = std::path::Path::new(f).extension().and_then(|e| e.to_str()).map(str::to_ascii_lowercase);
|
||||
e.map(|e| match e.as_str() {
|
||||
"jpeg" => "jpg".to_string(),
|
||||
"tiff" => "tif".to_string(),
|
||||
_ => e,
|
||||
})
|
||||
};
|
||||
if ext(path).is_none() || ext(path) == ext(&name) {
|
||||
crate::file_cmds::write_file(path, &bytes)?;
|
||||
return Ok(json!({"path": path, "fileName": name, "bytes": bytes.len(), "converted": false}));
|
||||
}
|
||||
let contents = decode_source(&name, &bytes)?;
|
||||
let r = photocraft_io::export(&contents, path, &Default::default()).map_err(|e| other(format!("can't export the contents as {}: {e}", base_name(path))))?;
|
||||
crate::file_cmds::write_file(path, &r.bytes)?;
|
||||
Ok(json!({"path": path, "fileName": name, "bytes": r.bytes.len(), "converted": true, "warnings": r.warnings}))
|
||||
}
|
||||
|
||||
fn edit_contents(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
|
|
@ -1216,7 +1232,14 @@ pub fn specs() -> Vec<CommandSpec> {
|
|||
Ok(json!({"updated": commit_child(s, i)?}))
|
||||
}),
|
||||
spec!("layer.smartObjects.replaceContents", "Replace Contents…", SO, r##"{"layer":id?,"path":str}"##, has_smart, replace_contents),
|
||||
spec!("layer.smartObjects.exportContents", "Export Contents…", SO, r##"{"layer":id?,"path":str}"##, has_smart, export_contents),
|
||||
spec!(
|
||||
"layer.smartObjects.exportContents",
|
||||
"Export Contents…",
|
||||
SO,
|
||||
r##"{"layer":id?,"path":str (another extension than the contents' own exports them in that format)}"##,
|
||||
has_smart,
|
||||
export_contents
|
||||
),
|
||||
spec!("layer.smartObjects.relinkToFile", "Relink to File…", SO, r##"{"layer":id?,"path":str}"##, has_smart, |s, p| {
|
||||
let path = path_param("layer.smartObjects.relinkToFile", p)?.to_string();
|
||||
set_source(s, p, "Relink to File", false, |_, _| Ok(SmartSource::Linked { path }))
|
||||
|
|
|
|||
|
|
@ -529,8 +529,18 @@ fn export_replace_and_linked_contents() {
|
|||
paint(&mut s);
|
||||
convert(&mut s);
|
||||
let out = dir.join("contents.pcraft");
|
||||
s.execute("layer.smartObjects.exportContents", json!({"path": out.to_str().unwrap()})).unwrap();
|
||||
let r = s.execute("layer.smartObjects.exportContents", json!({"path": out.to_str().unwrap()})).unwrap();
|
||||
assert!(photocraft_format::is_pcraft(&std::fs::read(&out).unwrap()));
|
||||
assert_eq!(r["converted"], false);
|
||||
// Another extension exports the contents in that format.
|
||||
for (ext, magic) in [("png", &b"\x89PNG"[..]), ("jpeg", &b"\xFF\xD8\xFF"[..]), ("psd", &b"8BPS"[..])] {
|
||||
let other = dir.join(format!("contents.{ext}"));
|
||||
let r = s.execute("layer.smartObjects.exportContents", json!({"path": other.to_str().unwrap()})).unwrap();
|
||||
assert_eq!(r["converted"], true, "{ext}");
|
||||
assert!(std::fs::read(&other).unwrap().starts_with(magic), "{ext}");
|
||||
}
|
||||
let bad = dir.join("contents.nope");
|
||||
assert!(s.execute("layer.smartObjects.exportContents", json!({"path": bad.to_str().unwrap()})).is_err());
|
||||
// Replace with a flat PNG.
|
||||
let png_doc = Document::with_background(
|
||||
"p",
|
||||
|
|
|
|||
Loading…
Reference in New Issue