Merge pull request #1613 from MarekSpodBiedry/issue-1551

IDML export: write the graphic placed in a table cell (#1551)
This commit is contained in:
Brandon Thomas
2026-10-23 17:26:55 -04:00
committed by GitHub
3 changed files with 68 additions and 2 deletions
+33 -1
View File
@@ -2797,7 +2797,25 @@ impl<'a> Ex<'a> {
ce.set(&format!("{side}StrokePriority"), priority);
}
}
for psr in self.story_paras(&cell.text) {
let mut paras = self.story_paras(&cell.text);
// A graphic cell holds its image as an inline object in the cell's first paragraph.
if let Some(g) = &cell.graphic
&& let Some(object) = self.cell_graphic_el(g)
{
// The cell clips its graphic on screen and in PDF; IDML does so only when asked.
ce.set("ClipContentToCell", bool_s(true));
let mut range = self.csr_el(&CharFormat::default());
range.push(object);
match paras.first_mut() {
Some(first) => first.push(range),
None => {
let mut psr = self.psr_el(&ParaFormat::default());
psr.push(range);
paras.push(psr);
}
}
}
for psr in paras {
ce.push(psr);
}
el.push(ce);
@@ -2806,6 +2824,20 @@ impl<'a> Ex<'a> {
el
}
/// The frame of a table cell's graphic: an inline `Rectangle` around the shown image, or `None`
/// when the graphic's asset is missing.
fn cell_graphic_el(&mut self, g: &designcraft_doc::Graphic) -> Option<El> {
self.d.assets.get(&g.asset)?;
let shown = g.xf.transform_rect_bbox(designcraft_geom::Rect::new(0.0, 0.0, g.size.0, g.size.1));
let layer = self.d.layers.first().map(|l| l.id).unwrap_or(designcraft_doc::ids::LayerId(0));
let mut item = Item::new(designcraft_doc::ids::ItemId(0), layer, Shape::Rectangle, designcraft_geom::shapes::rectangle(shown));
item.content = Content::Graphic(g.clone());
let mut el = self.item_el(&item, Affine::IDENTITY);
el.set("Self", self.fresh());
el.push(El::new("AnchoredObjectSetting").attr("AnchoredPosition", "InlinePosition").attr("AnchorYoffset", "0"));
Some(el)
}
fn psr_el(&mut self, pf: &ParaFormat) -> El {
let mut el = El::new("ParagraphStyleRange").attr("AppliedParagraphStyle", names::style_self("ParagraphStyle", PARA_BUILTINS, &pf.style));
let mut props = Vec::new();
+34
View File
@@ -4368,3 +4368,37 @@ fn cell_first_baseline_comes_from_cell_styles_table_regions_and_cells_and_round_
let s2 = back.styles.cell.iter().find(|c| c.name == "Cap").unwrap();
assert_eq!(s2.first_baseline, Some(FirstBaseline::CapHeight));
}
/// A graphic placed in a table cell is written into the cell, not dropped.
#[test]
fn exports_graphic_in_table_cell() {
let mut d = Document::new(&NewDocument::default());
let lid = d.default_layer();
let (_, sid) = d.add_text_frame(SpreadRef::Doc(0), Rect::new(40.0, 40.0, 400.0, 400.0), lid, "Intro", ParaFormat::default()).unwrap();
let asset = designcraft_doc::AssetId(d.alloc());
let id = d.add_asset(designcraft_doc::Asset {
id: asset,
name: "tick.png".into(),
mime: "image/png".into(),
data: std::sync::Arc::new(vec![1, 2, 3]),
..Default::default()
});
let mut t = designcraft_doc::Table::new(d.alloc(), 2, 2, 0, 0, 200.0);
t.cell_mut(1, 0).unwrap().graphic = Some(designcraft_doc::Graphic {
asset: id,
size: (24.0, 24.0),
xf: designcraft_geom::Affine::IDENTITY,
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
wrap: Default::default(),
fill: Default::default(),
});
d.story_mut(sid).unwrap().insert_table(5, t);
let story = zip_text(&export_idml(&d), "Stories/");
let cell = story.split("<Cell ").nth(3).unwrap_or_default();
let cell = cell.split("</Cell>").next().unwrap_or_default();
assert!(cell.contains("<Image "), "{story}");
assert!(cell.contains("ClipContentToCell=\"true\""), "{story}");
}
+1 -1
View File
@@ -368,7 +368,7 @@ It is evidence of breadth: each item exists. It is not a claim of InDesign-level
- Object States (`states.create/show/rename/release/list`, Object States panel): multi-state objects show one state on screen and in PDF.
- Buttons (`button.set/clear/list`, Buttons and Forms panel): go to page / next / previous / first / last / URL as PDF link annotations. Form fields too (`form.set/clear/list`: text fields, check boxes, combo and list boxes, signature fields; required, multiline, defaults) exported as AcroForm widgets through an incremental update (not in PDF/X or PDF/A).
- Power Zoom (Hand tool: press and hold still for half a second, or Alt-press): zoom out to the spread, aim the red view rectangle, release to zoom back in there.
- Graphic cells (`table.placeGraphic`, `table.textCell`, Table › Convert Cell Type, Table panel): images in table cells, fitted or filled, clipped to the cell on screen and in PDF.
- Graphic cells (`table.placeGraphic`, `table.textCell`, Table › Convert Cell Type, Table panel): images in table cells, fitted or filled, clipped to the cell on screen and in PDF; IDML export writes them as an inline graphic in the cell.
- Live Distribute (Space while dragging a selection handle; `transform.resize {distribute}`): objects keep their size and spread with the bounds.
- Flex Layout (InDesign 2026; `flex.add`, `flex.convert`, `flex.remove`, `flex.set`, `flex.reorder`, Window › Flex Layout and the Properties panel's Flex Layout section): a frame lays out its objects in rows or columns by direction, wrap, justification (Flex Start, Center, Flex End, Space Between, Space Around, Space Evenly), the alignment grid, Fixed/Auto width and height, padding and spacing; aligned objects are detected on Add (direction, Auto, Space Between); resizing a container reflows it; dragging an object in one reorders it. Not yet: item sizing (Fixed/Auto/Fill Space per object), object styles with Flex Layout settings, IDML (a container exports as a frame with pasted-in objects), nested selection cues on the canvas.
- Liquid Layout (`liquid.pageRule/object`, `guide.liquid`, `layout.createAlternate`, Liquid Layout panel): scale / re-center / guide-based / object-based page rules applied on page resize and Document Setup; dashed liquid guides; alternate layouts as resized page copies in a named section. Text in an alternate layout stays linked to the original stories (Links panel shows them out of date; `story.updateLink`).