C: Transparency Blend Space setting (+ IDML)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas
2026-10-02 23:28:43 -04:00
co-authored by Claude Opus 5.5
parent c9b969a60d
commit c2fbf1b0f6
8 changed files with 70 additions and 3 deletions
+1
View File
@@ -49,6 +49,7 @@ DesignCraft aims at full Adobe InDesign parity — and to be better: faster, ope
- Endnotes (`endnote.insert/edit/delete/list/options`, Type ▸ Insert Endnote): references number through the document, the endnote frame on a new last page lists them under a heading; IDML keeps the listed text only.
- Editorial notes (`note.new/edit/delete/convertToText/list`, Notes panel): anchored in text, flagged on screen, never printed or exported.
- File ▸ Print Booklet (`file.printBooklet`): saddle-stitch or 2-up consecutive printer spreads as PDF, padded with blanks, with a gap between pages.
- Edit ▸ Transparency Blend Space (`edit.transparencyBlendSpace`; RGB for web/mobile documents; IDML TransparencyPreference) — stored; compositing is still RGB on screen and in PDF.
- Drag and drop text editing: drag selected text to move it (Alt copies) with its formatting (`text.release`).
- Image Import Options: place any page of a multi-page PDF (`file.place {pdfPage}`; the app asks which page), shown on screen and embedded as that page in PDF export.
- Define Lists: named numbered lists that continue across stories in page order (`list.define`, paragraph `listName` / `startAt`), round-tripped through IDML; `null` in `type.para` / `type.char` now removes an override.
+1
View File
@@ -115,6 +115,7 @@ impl Document {
slug: nd.slug,
horizontal_units: nd.units,
vertical_units: nd.units,
blend_space: if nd.intent == Intent::Print { crate::BlendSpace::Cmyk } else { crate::BlendSpace::Rgb },
..Default::default()
};
let mut d = Document {
+13
View File
@@ -68,6 +68,16 @@ pub enum DocError {
pub type Result<T> = std::result::Result<T, DocError>;
/// Edit › Transparency Blend Space: the colour space transparency is flattened in (CMYK for
/// print documents, RGB for screen ones, as InDesign defaults).
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum BlendSpace {
#[default]
Cmyk,
Rgb,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum Intent {
@@ -210,6 +220,8 @@ pub struct DocSettings {
/// Preferences › Advanced Type: superscript and subscript size and position (percent of the
/// font size).
pub advanced_type: AdvancedType,
/// Edit › Transparency Blend Space.
pub blend_space: BlendSpace,
}
impl Default for DocSettings {
@@ -237,6 +249,7 @@ impl Default for DocSettings {
chapter_number: 1,
global_light: 120.0,
advanced_type: AdvancedType::default(),
blend_space: BlendSpace::Cmyk,
}
}
}
+36
View File
@@ -23,6 +23,24 @@ const DOC_KEYS: &[&str] = &[
pub fn specs() -> Vec<CommandSpec> {
vec![
cmd!(
"edit.transparencyBlendSpace",
"Transparency Blend Space",
["Edit", "Transparency Blend Space"],
None,
"{space: cmyk|rgb} — the colour space transparency is composited in for output",
has_doc,
|s, p| {
let space: designcraft_doc::BlendSpace = p
.get("space")
.and_then(|v| serde_json::from_value(v.clone()).ok())
.ok_or_else(|| bad("edit.transparencyBlendSpace", "`space`: cmyk or rgb"))?;
s.edit(|d, _| {
d.settings.blend_space = space;
Ok(serde_json::json!({"space": space}))
})
}
),
cmd!(
noundo "prefs.set",
"Preferences",
@@ -227,3 +245,21 @@ mod keep_highlight_tests {
assert!(flagged(&s), "too long to keep together in one column");
}
}
#[cfg(test)]
mod blend_space_tests {
use serde_json::json;
use crate::Session;
#[test]
fn blend_space_is_set_and_kept_in_idml() {
let mut s = Session::new();
s.execute("file.new", &json!({})).unwrap();
assert_eq!(s.doc().unwrap().doc.settings.blend_space, designcraft_doc::BlendSpace::Cmyk);
s.execute("edit.transparencyBlendSpace", &json!({"space": "rgb"})).unwrap();
let back = designcraft_idml::import_idml(&designcraft_idml::export_idml(&s.doc().unwrap().doc)).unwrap();
assert_eq!(back.settings.blend_space, designcraft_doc::BlendSpace::Rgb);
assert!(s.execute("edit.transparencyBlendSpace", &json!({"space": "lab"})).is_err());
}
}
+7
View File
@@ -704,6 +704,13 @@ impl<'a> Ex<'a> {
);
root.push(El::new("PasteboardPreference").attr("PasteboardMargins", pt(s.pasteboard.0, s.pasteboard.1)));
root.push(self.footnote_option_el());
root.push(El::new("TransparencyPreference").attr(
"BlendingSpace",
match s.blend_space {
designcraft_doc::BlendSpace::Cmyk => "CMYK",
designcraft_doc::BlendSpace::Rgb => "RGB",
},
));
let a = &s.advanced_type;
root.push(
El::new("TextPreference")
+5
View File
@@ -219,6 +219,11 @@ impl<'r> Importer<'r> {
for e in top {
match e.local() {
"DocumentPreference" => self.doc_prefs(e),
"TransparencyPreference" => {
if let Some(v) = e.get("BlendingSpace") {
self.settings.blend_space = if v == "RGB" { designcraft_doc::BlendSpace::Rgb } else { designcraft_doc::BlendSpace::Cmyk };
}
}
"TextPreference" => {
let a = &mut self.settings.advanced_type;
for (k, v) in [
+4
View File
@@ -146,6 +146,10 @@ pub const MENUS: &[(&str, &[&str])] = &[
"cmd:spelling.check",
"cmd:spelling.addWord",
"<",
">Transparency Blend Space",
"cmd:edit.transparencyBlendSpace|Document RGB|{\"space\": \"rgb\"}",
"cmd:edit.transparencyBlendSpace|Document CMYK|{\"space\": \"cmyk\"}",
"<",
"-",
"ui:app.palette",
"ui:app.keyboardShortcuts",
+3 -3
View File
@@ -10,7 +10,7 @@ Each row of the InDesign feature catalogue is scored **D** (done), **P** (partia
| Priority | Features | Done | Partial | Missing | Parity |
|---|---|---|---|---|---|
| P0 | 102 | 99 | 3 | 0 | 99% |
| P1 | 97 | 75 | 20 | 2 | 88% |
| P1 | 97 | 75 | 21 | 1 | 88% |
| P2 | 76 | 19 | 13 | 44 | 34% |
| Area | Parity |
@@ -21,7 +21,7 @@ Each row of the InDesign feature catalogue is scored **D** (done), **P** (partia
| Frames, shapes & paths | 93% |
| Transform | 100% |
| Fill, stroke, colour | 88% |
| Effects & transparency | 62% |
| Effects & transparency | 71% |
| Placing & links | 82% |
| Type & text frames | 92% |
| Typography | 88% |
@@ -164,7 +164,7 @@ Open P0 items: Preferences, Vector/page formats (PDF/AI/SVG/EPS place), Export t
| Effects & transparency | Inner Shadow, Outer Glow, Inner Glow, Bevel, Satin | P2 | P |
| Effects & transparency | Basic/Directional/Gradient Feather | P2 | P |
| Effects & transparency | Global Light | P2 | D |
| Effects & transparency | Transparency blend space | P1 | M |
| Effects & transparency | Transparency blend space | P1 | P |
| Effects & transparency | Transparency flattener | P2 | M |
| Placing & links | Place | P0 | D |
| Placing & links | Place into frame / by click or drag | P0 | D |