diff --git a/crates/effects/src/group.rs b/crates/effects/src/group.rs index 4b08295d8..35ddf527b 100644 --- a/crates/effects/src/group.rs +++ b/crates/effects/src/group.rs @@ -13,13 +13,14 @@ use std::sync::Arc; +use serde_json::Value; use vectorcraft_doc::color::{Color, Paint}; use vectorcraft_doc::{Appearance, AppearanceItem, Node, NodeId, NodeKind, StrokeLayer}; use vectorcraft_geom::{FillRule, PathData, Rect}; use vectorcraft_pathops::{self as po, PathfinderOp}; /// Effect ids of the Pathfinder submenu with their operation, in Illustrator's menu order. -pub const PATHFINDER_EFFECTS: [(&str, &str, PathfinderOp); 11] = [ +pub const PATHFINDER_EFFECTS: [(&str, &str, PathfinderOp); 12] = [ ("pathfinder.add", "Add", PathfinderOp::Unite), ("pathfinder.intersect", "Intersect", PathfinderOp::Intersect), ("pathfinder.exclude", "Exclude", PathfinderOp::Exclude), @@ -31,6 +32,7 @@ pub const PATHFINDER_EFFECTS: [(&str, &str, PathfinderOp); 11] = [ ("pathfinder.crop", "Crop", PathfinderOp::Crop), ("pathfinder.outline", "Outline", PathfinderOp::Outline), ("pathfinder.hardMix", "Hard Mix", PathfinderOp::HardMix), + ("pathfinder.softMix", "Soft Mix", PathfinderOp::SoftMix), ]; /// Is `id` an Effect → Pathfinder effect? @@ -140,7 +142,14 @@ pub fn pathfinder_children(group: &Node, hook: Option) -> Option) -> Option f64 { + params.get("mixingRate").and_then(|v| v.as_f64()).filter(|r| r.is_finite() && *r > 0.0 && *r <= 100.0).map(|r| r / 100.0).unwrap_or(0.5) +} + +fn fill_cmyk(src: &Node) -> Option<[f32; 4]> { + let paint = src.appearance.fill_paint(); + let color = paint.color()?; + let tinted = match paint { + Paint::Solid { tint, .. } => color.tinted(tint), + _ => color, + }; + Some(tinted.to_cmyk()) +} + +/// One face of a Soft Mix: CMYK blended bottom to top at `rate`; no stroke. +fn soft_mix_face(path: PathData, covering: &[usize], rate: f64, shapes: &[po::Shape], sources: &[Node]) -> Node { + let rate = rate as f32; + let mut cmyk: Option<[f32; 4]> = None; + for &si in covering { + let Some(ch) = fill_cmyk(&sources[shapes[si].key as usize]) else { continue }; + cmyk = Some(match cmyk { + None => ch, + Some(acc) => { + let t = rate; + let u = 1.0 - t; + [acc[0] * u + ch[0] * t, acc[1] * u + ch[1] * t, acc[2] * u + ch[2] * t, acc[3] * u + ch[3] * t] + } + }); + } + let fill = cmyk.map(|c| Paint::solid(Color::cmyk(c[0], c[1], c[2], c[3]))).unwrap_or(Paint::None); + soft_mix_styled(path, covering, shapes, sources, fill) +} + /// One face of a Hard Mix: the max of each CMYK channel over every covering shape's fill; no stroke. fn hard_mix_face(path: PathData, covering: &[usize], shapes: &[po::Shape], sources: &[Node]) -> Node { let mut cmyk = [0.0f32; 4]; let mut painted = false; for &si in covering { - let src = &sources[shapes[si].key as usize]; - let paint = src.appearance.fill_paint(); - if let Some(color) = paint.color() { - let tinted = match paint { - Paint::Solid { tint, .. } => color.tinted(tint), - _ => color, - }; - let [c, m, y, k] = tinted.to_cmyk(); - for (out, v) in cmyk.iter_mut().zip([c, m, y, k]) { - *out = out.max(v); - } - painted = true; + let Some(ch) = fill_cmyk(&sources[shapes[si].key as usize]) else { continue }; + for (out, v) in cmyk.iter_mut().zip(ch) { + *out = out.max(v); } + painted = true; } let fill = if painted { Paint::solid(Color::cmyk(cmyk[0], cmyk[1], cmyk[2], cmyk[3])) } else { Paint::None }; + soft_mix_styled(path, covering, shapes, sources, fill) +} + +fn soft_mix_styled(path: PathData, covering: &[usize], shapes: &[po::Shape], sources: &[Node], fill: Paint) -> Node { let top = covering.last().and_then(|&si| sources.get(shapes[si].key as usize)); let mut n = Node::path(top.map_or(NodeId(0), |s| s.id), path, Appearance::basic(fill, Paint::None, 0.0)); if let Some(src) = top { @@ -359,19 +397,8 @@ mod tests { po::area(n.path_data().unwrap(), FillRule::NonZero).abs() } - #[test] - fn hard_mix_takes_the_highest_of_each_cmyk_channel_and_drops_strokes() { - let a = Appearance::basic(Paint::solid(Color::cmyk(0.2, 0.66, 0.4, 0.0)), Paint::solid(Color::BLACK), 2.0); - let b = Appearance::basic(Paint::solid(Color::cmyk(0.4, 0.2, 0.3, 0.1)), Paint::solid(Color::BLACK), 2.0); - let mut g = Node::group( - NodeId(10), - vec![ - Arc::new(Node::path(NodeId(1), shapes::rectangle(Rect::new(0.0, 0.0, 10.0, 10.0)), a)), - Arc::new(Node::path(NodeId(2), shapes::rectangle(Rect::new(5.0, 0.0, 15.0, 10.0)), b)), - ], - ); - g.appearance.effects.push(Effect { id: "pathfinder.hardMix".into(), params: serde_json::json!({}), visible: true }); - let faces = pathfinder_children(&g, None).unwrap(); + fn overlap_cmyk(g: &Node) -> [f32; 4] { + let faces = pathfinder_children(g, None).unwrap(); assert_eq!(faces.len(), 3); let overlap = faces .iter() @@ -381,10 +408,37 @@ mod tests { }) .expect("overlap face"); assert!(overlap.appearance.stroke_paint().is_none()); - let [c, m, y, k] = overlap.appearance.fill_paint().color().unwrap().to_cmyk(); + overlap.appearance.fill_paint().color().unwrap().to_cmyk() + } + + fn two_overlapping_cmyk_squares() -> Node { + let a = Appearance::basic(Paint::solid(Color::cmyk(0.2, 0.66, 0.4, 0.0)), Paint::solid(Color::BLACK), 2.0); + let b = Appearance::basic(Paint::solid(Color::cmyk(0.4, 0.2, 0.3, 0.1)), Paint::solid(Color::BLACK), 2.0); + Node::group( + NodeId(10), + vec![ + Arc::new(Node::path(NodeId(1), shapes::rectangle(Rect::new(0.0, 0.0, 10.0, 10.0)), a)), + Arc::new(Node::path(NodeId(2), shapes::rectangle(Rect::new(5.0, 0.0, 15.0, 10.0)), b)), + ], + ) + } + + #[test] + fn hard_mix_takes_the_highest_of_each_cmyk_channel_and_drops_strokes() { + let mut g = two_overlapping_cmyk_squares(); + g.appearance.effects.push(Effect { id: "pathfinder.hardMix".into(), params: serde_json::json!({}), visible: true }); + let [c, m, y, k] = overlap_cmyk(&g); assert!((c - 0.4).abs() < 0.02 && (m - 0.66).abs() < 0.02 && (y - 0.4).abs() < 0.02 && (k - 0.1).abs() < 0.02, "{c} {m} {y} {k}"); } + #[test] + fn soft_mix_blends_cmyk_bottom_to_top_and_drops_strokes() { + let mut g = two_overlapping_cmyk_squares(); + g.appearance.effects.push(Effect { id: "pathfinder.softMix".into(), params: serde_json::json!({"mixingRate": 50.0}), visible: true }); + let [c, m, y, k] = overlap_cmyk(&g); + assert!((c - 0.3).abs() < 0.02 && (m - 0.43).abs() < 0.02 && (y - 0.35).abs() < 0.02 && (k - 0.05).abs() < 0.02, "{c} {m} {y} {k}"); + } + #[test] fn shape_modes_follow_the_pathfinder_panel() { let add = pathfinder_children(&group_with("pathfinder.add"), None).unwrap(); diff --git a/crates/effects/src/lib.rs b/crates/effects/src/lib.rs index 691527682..7c2c9ac85 100644 --- a/crates/effects/src/lib.rs +++ b/crates/effects/src/lib.rs @@ -803,7 +803,17 @@ pub fn effect_catalog() -> Vec { v.push(g(id, label, WARP, WARP_DOC, json!({"bend": 50.0, "horizontal": 0.0, "vertical": 0.0, "orientation": "horizontal"}))); } for (id, label, _) in PATHFINDER_EFFECTS { - v.push(g(id, label, PATHFINDER, "{} (groups and layers: live Pathfinder over the members)", json!({}))); + if id == "pathfinder.softMix" { + v.push(g( + id, + label, + PATHFINDER, + "{mixingRate?: 1..100 % (50)} blend overlapping fills in CMYK bottom to top (groups and layers: live Pathfinder over the members)", + json!({"mixingRate": 50.0}), + )); + } else { + v.push(g(id, label, PATHFINDER, "{} (groups and layers: live Pathfinder over the members)", json!({}))); + } } v.push(g( CROP_MARKS, diff --git a/crates/engine/src/cmd/pathops.rs b/crates/engine/src/cmd/pathops.rs index cbed03515..c1f3399b0 100644 --- a/crates/engine/src/cmd/pathops.rs +++ b/crates/engine/src/cmd/pathops.rs @@ -382,6 +382,7 @@ fn pf_label(op: PathfinderOp) -> &'static str { PathfinderOp::Outline => "Outline", PathfinderOp::MinusBack => "Minus Back", PathfinderOp::HardMix => "Hard Mix", + PathfinderOp::SoftMix => "Soft Mix", } } diff --git a/crates/pathops/src/pathfinder.rs b/crates/pathops/src/pathfinder.rs index aa28d66d7..83ac9145f 100644 --- a/crates/pathops/src/pathfinder.rs +++ b/crates/pathops/src/pathfinder.rs @@ -26,7 +26,7 @@ impl Shape { } } -/// The ten Pathfinder panel operations. +/// Pathfinder panel and effect operations. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum PathfinderOp { /// Shape mode: union of everything; result keeps the front-most key. @@ -53,6 +53,9 @@ pub enum PathfinderOp { /// Effect only: split into faces like Divide; overlapping faces take the highest of each CMYK /// channel from every shape covering them (Illustrator Effect → Pathfinder → Hard Mix). HardMix, + /// Effect only: split into faces like Divide; overlapping faces blend fills in CMYK bottom to + /// top by a mixing rate (Illustrator Effect → Pathfinder → Soft Mix). + SoftMix, } /// One face of the planar arrangement of a set of shapes (Shape Builder / Live Paint face). @@ -175,7 +178,7 @@ pub fn pathfinder(op: PathfinderOp, shapes: &[Shape]) -> Vec { .collect() } PathfinderOp::Outline => outline_edges(&arr, shapes), - PathfinderOp::HardMix => regions_of(&arr) + PathfinderOp::HardMix | PathfinderOp::SoftMix => regions_of(&arr) .into_iter() .filter_map(|r| { let key = shapes.get(r.top()?)?.key; diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index ffd3cc038..7c6a80fef 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -3004,6 +3004,7 @@ Snapping Tolerance Толеранс на прилепване Social Square Post 1080×1080 Публикация за квадрат в социални мрежи 1080×1080 Soft Light Мека светлина + Soft Mix Мека смес Solid Плътен Sort by Kind Сортиране по вид Sort by Name Сортиране по име diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 3f23b24ce..c95a03812 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -2913,6 +2913,7 @@ lighting Light Světlo Luminosity Světlost Overlay Překrýt Soft Light Měkké světlo + Soft Mix Měkké míchání Crosshatch Křížové šrafování Fine Dots Jemné tečky diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index 6ddf99786..0a577bb9c 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -2686,6 +2686,7 @@ lighting Light Lys Luminosity Luminans Overlay Overlejring Soft Light Blødt lys + Soft Mix Blød blanding Crosshatch Krydsskravering Fine Dots Fine prikker diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index c36145fec..903701e7f 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -3040,6 +3040,7 @@ effect Points Punkte Snapping Tolerance Einrasttoleranz Social Square Post 1080×1080 Quadratischer Social-Media-Beitrag 1080×1080 Soft Light Weiches Licht + Soft Mix Weiche Mischung Solid Gefüllt Sort by Kind Nach Art sortieren Sort by Name Nach Name sortieren diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 8566e058e..7e6bc122a 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -1866,6 +1866,7 @@ Snap to Point Προσκόλληση σε σημείο Snap to Unit Προσκόλληση σε μονάδα Soft Light Απαλό φως + Soft Mix Απαλή ανάμειξη Solid Συνεχές Spacing: Απόσταση: Total: Σύνολο: diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 0d5ee1098..a111d1b82 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -3070,6 +3070,7 @@ Snapping Tolerance Tolerancia de ajuste Social Square Post 1080×1080 Publicación cuadrada para redes 1080×1080 Soft Light Luz suave + Soft Mix Mezcla suave Solid Sólido Sort by Kind Ordenar por tipo Sort by Name Ordenar por nombre diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 84af613c4..d77e194ec 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -2859,6 +2859,7 @@ lighting Light Valo Luminosity Luminanssi Overlay Sulautus Soft Light Pehmeä valo + Soft Mix Pehmeä sekoitus Crosshatch Ristiviivoitus Fine Dots Hienot pisteet diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index cc4af21e3..a0e8a04ca 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -3067,6 +3067,7 @@ Snapping Tolerance Tolérance du magnétisme Social Square Post 1080×1080 Publication carrée pour réseaux sociaux 1080×1080 Soft Light Lumière tamisée + Soft Mix Fusion douce Solid Plein Sort by Kind Trier par type Sort by Name Trier par nom diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 10adcbe9e..269d556a7 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -3702,6 +3702,7 @@ mark-style Japanese Japán Social Tall Post 1000×1500 Magas közösségimédia-bejegyzés 1000×1500 Soft Lágy Soft Light Lágy fény + Soft Mix Lágy keverés Solid Kitöltött Sort Rendezés Sort by Hue Rendezés színárnyalat szerint diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 9b65f48e0..13b7e6065 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -2686,6 +2686,7 @@ lighting Light Cahaya Luminosity Luminositas Overlay Menimpa Soft Light Cahaya lembut + Soft Mix Campuran lembut Crosshatch Arsir silang Fine Dots Titik halus diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 41df7fbc6..e5995fa59 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -3104,6 +3104,7 @@ mark-style Japanese Giapponese Snapping Tolerance Tolleranza di aggancio Social Square Post 1080×1080 Post quadrato per social 1080×1080 Soft Light Luce soffusa + Soft Mix Miscela soffice Solid Pieno Sort by Kind Ordina per tipo Sort by Name Ordina per nome diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 3c4904a66..4497638f8 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -2872,6 +2872,7 @@ mark-style Japanese 日本式 Snap to Unit 単位にスナップ Snapping Tolerance スナップ許容値 Soft Light ソフトライト + Soft Mix ソフトミックス Solid 実線 Sort by Kind 種類順に並べ替え Sort by Name 名前順に並べ替え diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 055096c7b..9e8c1055c 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -2498,6 +2498,7 @@ lighting Light სინათლე Luminosity ნათება Overlay გადაფარვა Soft Light რბილი სინათლე + Soft Mix რბილი შერევა Crosshatch ჯვარედინი დაშტრიხვა Fine Dots წვრილი წერტილები diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 800daeac1..c4eee9b0b 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -2866,6 +2866,7 @@ mark-style Japanese 일본식 Snap to Unit 단위에 스냅 Snapping Tolerance 스냅 허용 오차 Soft Light 소프트 라이트 + Soft Mix 소프트 혼합 Solid 단색 Sort by Kind 종류별 정렬 Sort by Name 이름별 정렬 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 38cd0a07a..22d89444a 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -2700,6 +2700,7 @@ lighting Light Licht Luminosity Luminositeit Overlay Bedekken Soft Light Zacht licht + Soft Mix Zachte menging Crosshatch Kruisarcering Fine Dots Fijne stippen diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index f4ab658c3..e2a767697 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -2791,6 +2791,7 @@ lighting Light Światło Luminosity Jasność Overlay Nakładka Soft Light Łagodne światło + Soft Mix Miękkie mieszanie Crosshatch Kreskowanie krzyżowe Fine Dots Drobne kropki diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 97f179076..5c50d24b8 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -2542,6 +2542,7 @@ Snap to Unit Ajustar à Unidade Snapping Tolerance Tolerância de Ajuste Soft Light Luz Suave + Soft Mix Mistura suave Solid Sólido Sort by Kind Ordenar por Tipo Sort by Name Ordenar por Nome diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 893f12ece..23dc4bd63 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -3100,6 +3100,7 @@ mark-style Japanese Японский Snapping Tolerance Допуск привязки Social Square Post 1080×1080 Квадратный пост для соцсетей 1080×1080 Soft Light Мягкий свет + Soft Mix Мягкое смешение Solid Сплошной Sort by Kind Сортировать по типу Sort by Name Сортировать по имени diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 4b7070d4f..3667e0434 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -3004,6 +3004,7 @@ Snapping Tolerance Fästtolerans Social Square Post 1080×1080 Kvadratiskt inlägg för sociala medier 1080×1080 Soft Light Mjukt ljus + Soft Mix Mjuk blandning Solid Enfärgad Sort by Kind Sortera efter typ Sort by Name Sortera efter namn diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 61dc3865e..78e65e0d9 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -3097,6 +3097,7 @@ effect Points Точки Snapping Tolerance Допуск прив’язки Social Square Post 1080×1080 Квадратний пост для соцмереж 1080×1080 Soft Light М’яке світло + Soft Mix М’яке змішування Solid Суцільний Sort by Kind Сортувати за типом Sort by Name Сортувати за назвою diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index d80001204..8e9c94239 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -3432,6 +3432,7 @@ mark-style Japanese Kiểu Nhật Social Square Post 1080×1080 Bài đăng vuông mạng xã hội 1080×1080 Soft Mềm Soft Light Ánh sáng mềm + Soft Mix Trộn mềm Solid Đặc Sort Sắp xếp Sort by Kind Sắp xếp theo loại diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 5ab3f370b..3b613f8f0 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -2938,6 +2938,7 @@ font-script Japanese 汉字 Snapping Tolerance 吸附容差 Social Square Post 1080×1080 社交方形帖子 1080×1080 Soft Light 柔光 + Soft Mix 柔和混合 Solid 实心 Sort by Kind 按类型排序 Sort by Name 按名称排序 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index dc853661e..9f56d96ae 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -3844,6 +3844,7 @@ font-script Japanese 漢字 Snapping Tolerance 靠齊容許度 Social Square Post 1080×1080 社群正方形貼文 1080×1080 Soft Light 柔光 + Soft Mix 柔和混合 Solid 實心 Sort by Kind 依類型排序 Sort by Name 依名稱排序 diff --git a/docs/effects-parity.md b/docs/effects-parity.md index 47c0851cd..53fbb0811 100644 --- a/docs/effects-parity.md +++ b/docs/effects-parity.md @@ -23,8 +23,8 @@ Part of [target-app-parity.md](target-app-parity.md); open work is in [gaps.md]( | Convert to Shape | Rectangle, Rounded Rectangle, Ellipse | 3/3 | — | | Crop Marks | Crop Marks | 1/1 | — | | Distort & Transform | Free Distort, Pucker & Bloat, Roughen, Transform, Tweak, Twist, Zig Zag | 7/7 | Free Distort's dialog has a handle on each corner of the object's bounds, moved by dragging or with the arrow keys; Transform's Transform Objects/Patterns and Scale Strokes & Effects options, invisible Reflect checkboxes (#885); Zig Zag's ridges are evenly spaced along each segment (#1558), and Smooth points make a continuous wave whose peaks and valleys have handles along the path (#2343); Roughen with Smooth keeps turn-backs smooth instead of cusps that draw as spikes (#1646) | -| Path | Offset Path, Outline Object, Outline Stroke | 3/3 | — | -| Pathfinder | Add, Intersect, Exclude, Subtract, Minus Back, Divide, Trim, Merge, Crop, Outline, Hard Mix, Soft Mix, Trap | 10/13 | Hard Mix, Soft Mix, Trap | +| Path | Offset Path, Outline Object, Outline Stroke | 3/3 | With Use Preview Bounds on, Align, Distribute and the Transform panel still measure type that carries Outline Object by its layout box (preview bounds leave out effects) | +| Pathfinder | Add, Intersect, Exclude, Subtract, Minus Back, Divide, Trim, Merge, Crop, Outline, Hard Mix, Soft Mix, Trap | 11/13 | Hard Mix, Trap | | Rasterize | Rasterize… (as a live effect) | 1/1 | — | | Stylize | Drop Shadow, Feather, Inner Glow, Outer Glow, Round Corners, Scribble | 6/6 | Scribble Options' Settings presets | | SVG Filters | Apply SVG Filter… and the filter list | 0/1 | the whole submenu (SVG filters on import round-trip already) |