mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Merge pull request #3063 from nrq6993-a11y/stream/vc-feat1-g2-pathfinder-soft-mix
G2: Effect › Pathfinder › Soft Mix blends overlapping CMYK fills
This commit is contained in:
+82
-28
@@ -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<OutlineHook>) -> Option<Ve
|
||||
if shapes.is_empty() {
|
||||
return Some(vec![]);
|
||||
}
|
||||
stack = if op == PathfinderOp::HardMix {
|
||||
stack = if op == PathfinderOp::SoftMix {
|
||||
let rate = mixing_rate(&e.params);
|
||||
po::regions(&shapes)
|
||||
.into_iter()
|
||||
.filter(|r| !r.path.is_empty())
|
||||
.map(|r| Arc::new(soft_mix_face(r.path, &r.sources, rate, &shapes, &sources)))
|
||||
.collect()
|
||||
} else if op == PathfinderOp::HardMix {
|
||||
po::regions(&shapes)
|
||||
.into_iter()
|
||||
.filter(|r| !r.path.is_empty())
|
||||
@@ -157,26 +166,55 @@ pub fn pathfinder_children(group: &Node, hook: Option<OutlineHook>) -> Option<Ve
|
||||
Some(stack)
|
||||
}
|
||||
|
||||
fn mixing_rate(params: &Value) -> 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();
|
||||
|
||||
@@ -803,7 +803,17 @@ pub fn effect_catalog() -> Vec<EffectInfo> {
|
||||
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,
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Shape> {
|
||||
.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;
|
||||
|
||||
@@ -3004,6 +3004,7 @@
|
||||
Snapping Tolerance Толеранс на прилепване
|
||||
Social Square Post 1080×1080 Публикация за квадрат в социални мрежи 1080×1080
|
||||
Soft Light Мека светлина
|
||||
Soft Mix Мека смес
|
||||
Solid Плътен
|
||||
Sort by Kind Сортиране по вид
|
||||
Sort by Name Сортиране по име
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -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
|
||||
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -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
|
||||
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -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
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1866,6 +1866,7 @@
|
||||
Snap to Point Προσκόλληση σε σημείο
|
||||
Snap to Unit Προσκόλληση σε μονάδα
|
||||
Soft Light Απαλό φως
|
||||
Soft Mix Απαλή ανάμειξη
|
||||
Solid Συνεχές
|
||||
Spacing: Απόσταση:
|
||||
Total: Σύνολο:
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -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
|
||||
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -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
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -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
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -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
|
||||
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2872,6 +2872,7 @@ mark-style Japanese 日本式
|
||||
Snap to Unit 単位にスナップ
|
||||
Snapping Tolerance スナップ許容値
|
||||
Soft Light ソフトライト
|
||||
Soft Mix ソフトミックス
|
||||
Solid 実線
|
||||
Sort by Kind 種類順に並べ替え
|
||||
Sort by Name 名前順に並べ替え
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2498,6 +2498,7 @@ lighting Light სინათლე
|
||||
Luminosity ნათება
|
||||
Overlay გადაფარვა
|
||||
Soft Light რბილი სინათლე
|
||||
Soft Mix რბილი შერევა
|
||||
Crosshatch ჯვარედინი დაშტრიხვა
|
||||
Fine Dots წვრილი წერტილები
|
||||
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2866,6 +2866,7 @@ mark-style Japanese 일본식
|
||||
Snap to Unit 단위에 스냅
|
||||
Snapping Tolerance 스냅 허용 오차
|
||||
Soft Light 소프트 라이트
|
||||
Soft Mix 소프트 혼합
|
||||
Solid 단색
|
||||
Sort by Kind 종류별 정렬
|
||||
Sort by Name 이름별 정렬
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -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
|
||||
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -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
|
||||
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -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
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -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 Сортировать по имени
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -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
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -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 Сортувати за назвою
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 733 and column 40.
|
@@ -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
|
||||
|
||||
|
@@ -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 按名称排序
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -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 依名稱排序
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -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) |
|
||||
|
||||
Reference in New Issue
Block a user