Images: declare a graphic's clipping path beside its transform

This commit is contained in:
aiongg
2026-10-12 05:32:11 +00:00
parent 8125f2490b
commit e111bb74f7
17 changed files with 25 additions and 25 deletions
+1 -1
View File
@@ -243,10 +243,10 @@ pub fn synthetic(spec: &Spec) -> Result<Document, String> {
asset,
size: (nw, nh),
xf: Affine::translate((r.x0 + (r.width() - nw * s) / 2.0, r.y0 + (r.height() - nh * s) / 2.0)) * Affine::scale(s),
clip: None,
auto_fit: designcraft_doc::Fitting::FillProportionally,
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
if k == 0 && pi == 0 {
it.effects.drop_shadow.on = true;
+1 -1
View File
@@ -286,10 +286,10 @@ mod tests {
asset: AssetId(asset),
size: (10.0, 10.0),
xf: Affine::translate((crop, 0.0)),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [crop; 4],
clip: None,
});
it
}
+4 -4
View File
@@ -447,6 +447,9 @@ pub struct Graphic {
pub size: (f64, f64),
/// Graphic space (0,0)-(w,h) → frame inner space.
pub xf: Affine,
/// Clipping path: only the part of the graphic inside it shows.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub clip: Option<Arc<ClippingPath>>,
#[serde(default)]
pub auto_fit: Fitting,
/// Frame Fitting Options › Align From: the reference point (0–8, row-major; 4 = centre).
@@ -455,9 +458,6 @@ pub struct Graphic {
/// Frame Fitting Options › Crop Amount: top, left, bottom, right (negative adds space).
#[serde(default)]
pub crop: [f64; 4],
/// Clipping path: only the part of the graphic inside it shows.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub clip: Option<Arc<ClippingPath>>,
}
fn center_ref() -> u8 {
@@ -1305,10 +1305,10 @@ mod tests {
asset: AssetId(3),
size: (40.0, 30.0),
xf: Affine::translate((5.0, 5.0)),
clip: None,
auto_fit: Fitting::None,
fit_align: 4,
crop: [0.0; 4],
clip: None,
};
let v = serde_json::to_value(&g).unwrap();
assert!(v.get("clip").is_none(), "{v}");
+2 -2
View File
@@ -264,10 +264,10 @@ fn flatten(d: &designcraft_doc::Document, cache: &designcraft_compose::Cache, pp
size: (w as f64, h as f64),
xf: designcraft_geom::Affine::translate((r.x0, r.y0))
* designcraft_geom::Affine::scale_non_uniform(r.width() / w as f64, r.height() / h as f64),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
it.stroke.weight = 0.0;
it
@@ -430,10 +430,10 @@ fn rasterize_where(
asset: aid,
size: (w as f64, h as f64),
xf: designcraft_geom::Affine::translate((reach.x0, reach.y0)) * designcraft_geom::Affine::scale(1.0 / k),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
img_item.stroke.weight = 0.0;
img_item.alt_text = it.alt_text.clone();
+4 -4
View File
@@ -358,10 +358,10 @@ fn file_place(s: &mut Session, p: &Value) -> Result<Value> {
asset: aid,
size: (nw, nh),
xf: Affine::translate((r.x0 + (r.width() - gw) / 2.0, r.y0 + (r.height() - gh) / 2.0)) * Affine::scale(k),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
fid
} else {
@@ -377,10 +377,10 @@ fn file_place(s: &mut Session, p: &Value) -> Result<Value> {
asset: aid,
size: (nw, nh),
xf: Affine::translate((x - bx * k, y - by * k)) * Affine::scale(k),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
d.insert_item(spread, it, None)?;
id
@@ -471,10 +471,10 @@ fn place_drop(s: &mut Session, p: &Value) -> Result<Value> {
asset: aid,
size: (nw, nh),
xf: Affine::translate((r.x0 + (r.width() - nw * k) / 2.0, r.y0 + (r.height() - nh * k) / 2.0)) * Affine::scale(k),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
fid
}
@@ -494,10 +494,10 @@ fn place_drop(s: &mut Session, p: &Value) -> Result<Value> {
asset: aid,
size: (nw, nh),
xf: Affine::translate((frame_r.x0, frame_r.y0)) * Affine::scale(k),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
d.insert_item(sr, it, None)?;
id
+1 -1
View File
@@ -417,10 +417,10 @@ mod shared_asset_tests {
asset: sid,
size: (4.0, 4.0),
xf: designcraft_geom::Affine::IDENTITY,
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [1.0; 4],
clip: None,
});
src.insert_item(SpreadRef::Doc(0), it, None).unwrap();
let ids = super::super::object::duplicate_from(&mut dst, &src, &[iid], SpreadRef::Doc(0), designcraft_geom::Vec2::ZERO).unwrap();
+1 -1
View File
@@ -30,10 +30,10 @@ fn math_item(d: &mut designcraft_doc::Document, latex: &str, size: f64, lid: des
asset: aid,
size: (w, h),
xf: Affine::translate(at),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
it.alt_text = latex.to_string();
it.name = "Math".into();
+2 -2
View File
@@ -35,10 +35,10 @@ pub(crate) fn place_media(s: &mut Session, p: &Value, name: String, mime: &str,
asset: aid,
size: (r.width(), r.height()),
xf: Affine::translate((r.x0, r.y0)),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
it.media = Some(MediaOptions { controls: true, ..Default::default() });
fid
@@ -52,10 +52,10 @@ pub(crate) fn place_media(s: &mut Session, p: &Value, name: String, mime: &str,
asset: aid,
size: (w, h),
xf: Affine::translate((x, y)),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
it.media = Some(MediaOptions { controls: true, ..Default::default() });
d.insert_item(spread, it, None)?;
+1 -1
View File
@@ -1423,10 +1423,10 @@ fn place_graphic(s: &mut Session, p: &Value) -> Result<Value> {
asset: aid,
size: (nw, nh),
xf,
clip: None,
auto_fit: if fill { designcraft_doc::Fitting::FillProportionally } else { designcraft_doc::Fitting::FitProportionally },
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
clamp_selection(d, sel);
Ok(json!({"asset": aid.0, "row": r, "col": c}))
+1 -1
View File
@@ -82,10 +82,10 @@ fn graphic_frame(d: &mut Document, sr: SpreadRef, r: Rect, asset: AssetId, px: (
asset,
size: (nw, nh),
xf: Affine::translate((r.x0 + (r.width() - nw * k) / 2.0, r.y0 + (r.height() - nh * k) / 2.0)) * Affine::scale(k),
clip: None,
auto_fit: designcraft_doc::Fitting::FillProportionally,
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
it.object_style = designcraft_doc::BASIC_GRAPHICS_FRAME.into();
d.insert_item(sr, it, None)?;
+1 -1
View File
@@ -847,10 +847,10 @@ mod tests {
asset: aid,
size: (1.0, 1.0),
xf: Affine::IDENTITY,
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
d.insert_item(SpreadRef::Doc(0), item, None).unwrap();
+1 -1
View File
@@ -248,10 +248,10 @@ mod tests {
asset,
size: (1.0, 1.0),
xf: Affine::translate((crop, crop)),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [crop; 4],
clip: None,
});
d.insert_item(SpreadRef::Doc(0), it, None).unwrap();
id
+1 -1
View File
@@ -2276,10 +2276,10 @@ impl<'r> Importer<'r> {
asset,
size,
xf: gxf * Affine::translate((l, t)),
clip: clip.clone(),
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: clip.clone(),
})
};
let mut data = g.prop_el("Contents").map(|c| base64_decode(&c.text_content())).unwrap_or_default();
+1 -1
View File
@@ -477,10 +477,10 @@ mod tests {
asset,
size,
xf: Affine::translate(at) * Affine::scale(100.0 / size.0),
clip: None,
auto_fit: Fitting::FillProportionally,
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
d.insert_item(SpreadRef::Doc(0), it, None).unwrap();
}
+1 -1
View File
@@ -233,10 +233,10 @@ fn place(d: &mut Document, data: Vec<u8>, px: (u32, u32)) {
asset,
size: (px.0 as f64, px.1 as f64),
xf: designcraft_geom::Affine::translate((72.0, 72.0)) * designcraft_geom::Affine::scale(50.0),
clip: None,
auto_fit: designcraft_doc::Fitting::FillProportionally,
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
d.insert_item(SpreadRef::Doc(0), it, None).unwrap();
}
@@ -31,10 +31,10 @@ fn place_named(d: &mut Document, data: Vec<u8>, x: f64, name: &str, mime: &str,
asset: aid,
size: (20.0, 20.0),
xf: Affine::translate((x, 36.0)),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
d.insert_item(SpreadRef::Doc(0), item, None).unwrap();
}
+1 -1
View File
@@ -1469,10 +1469,10 @@ mod tests {
asset: aid,
size: (100.0, 100.0),
xf: Affine::translate((100.0, 100.0)),
clip: None,
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
clip: None,
});
d.insert_item(SpreadRef::Doc(0), it, None).unwrap();
let cache = Cache::new();