mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 01:15:25 +00:00
Export: symbol art dropped from the budget still counts toward it
An instance whose baked art passed the export's placed symbol art budget, or drew too deep, gave its count back, so any number of instances could each bake their art in full and be dropped without the work counting. - Art baked and then dropped is now counted with the placed art against the budget, both before more art is baked and when baked art is checked. - While an instance's art bakes, the art's objects before baking are held in the budget, so instances nested in it are placed only within what is left. Documents whose placed art fits the budget export as before.
This commit is contained in:
+29
-16
@@ -121,6 +121,10 @@ thread_local! {
|
||||
/// The objects in the baked art of the instances that [`bake_node`] has replaced by their
|
||||
/// placed art for one export ([`placed_symbol_art`]), counted against [`Placing::most_nodes`].
|
||||
static PLACED_NODES: std::cell::Cell<u64> = const { std::cell::Cell::new(0) };
|
||||
/// The objects in the baked art of the instances that [`bake_node`] baked for one export and
|
||||
/// then left as they are ([`placed_fits`] refused the art), counted with [`PLACED_NODES`]
|
||||
/// against [`Placing::most_nodes`] before more art is baked. Never given back.
|
||||
static DROPPED_NODES: std::cell::Cell<u64> = const { std::cell::Cell::new(0) };
|
||||
/// How deep the object [`bake_node`] is baking sits in the tree it returns: a top-level layer
|
||||
/// is 1 deep.
|
||||
static LEVEL: std::cell::Cell<usize> = const { std::cell::Cell::new(1) };
|
||||
@@ -179,17 +183,18 @@ fn unwritten(n: &Node) -> bool {
|
||||
}
|
||||
|
||||
/// Can `baked`, the baked art of a placed instance, take the instance's place [`LEVEL`] deep,
|
||||
/// when the art placed for the export so far holds `spent` objects? `Some` with the objects
|
||||
/// placed then, when its objects (opacity masks' art included) fit within
|
||||
/// when the art placed for the export so far holds `spent` objects and the art baked for
|
||||
/// instances left as they are holds `dropped` ([`DROPPED_NODES`])? `Some` with the
|
||||
/// objects placed then, when its objects (opacity masks' art included) fit with those within
|
||||
/// [`Placing::most_nodes`] and nothing in it, the symbols and patterns it uses included, draws
|
||||
/// deeper than [`vectorcraft_doc::depth::MAX_DRAWN_DEPTH`].
|
||||
fn placed_fits(baked: &Node, spent: u64) -> Option<u64> {
|
||||
fn placed_fits(baked: &Node, spent: u64, dropped: u64) -> Option<u64> {
|
||||
PLACING.with(|p| {
|
||||
let p = p.borrow();
|
||||
let p = p.as_ref()?;
|
||||
let spent = spent.saturating_add(baked.count_with_masks() as u64);
|
||||
let deepest = p.heights.deepest(baked, LEVEL.with(|c| c.get()));
|
||||
(spent <= p.most_nodes && deepest <= vectorcraft_doc::depth::MAX_DRAWN_DEPTH).then_some(spent)
|
||||
(spent.saturating_add(dropped) <= p.most_nodes && deepest <= vectorcraft_doc::depth::MAX_DRAWN_DEPTH).then_some(spent)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -246,10 +251,12 @@ fn holds_placed_symbol(n: &Node) -> bool {
|
||||
/// instance that scales its art does not scale what its effects do. `None` for other objects,
|
||||
/// for instances the export does not write ([`unwritten`], hidden or inside such an object), for
|
||||
/// instances nested [`vectorcraft_doc::depth::MAX_DEPTH`] deep in such art, and when the art
|
||||
/// as placed, before its effects are baked, would already take the art placed for the export
|
||||
/// past [`Placing::most_nodes`]; those instances stay as they are. [`bake_node`] checks the baked
|
||||
/// art with [`placed_fits`].
|
||||
fn placed_symbol_art(d: &Document, n: &Node) -> Option<Node> {
|
||||
/// as placed, before its effects are baked, would already take the art placed for the export,
|
||||
/// with the art baked for instances left as they are ([`DROPPED_NODES`]), past
|
||||
/// [`Placing::most_nodes`]; those instances stay as they are. `Some` with the objects in the art
|
||||
/// as placed, before its effects are baked. [`bake_node`] checks the baked art with
|
||||
/// [`placed_fits`].
|
||||
fn placed_symbol_art(d: &Document, n: &Node) -> Option<(Node, u64)> {
|
||||
let NodeKind::SymbolInstance { symbol, xf } = &n.kind else { return None };
|
||||
let (clip, most_nodes) = PLACING.with(|p| p.borrow().as_ref().filter(|p| p.symbols.contains(symbol)).map(|p| (p.clip_slices, p.most_nodes)))?;
|
||||
if INSTANCE_DEPTH.with(|c| c.get()) >= vectorcraft_doc::depth::MAX_DEPTH || UNWRITTEN.with(|c| c.get()) || unwritten(n) {
|
||||
@@ -262,13 +269,13 @@ fn placed_symbol_art(d: &Document, n: &Node) -> Option<Node> {
|
||||
Some(m) => m.most_placed_unclipped(&art, d),
|
||||
None => art.count_with_masks() as u64,
|
||||
};
|
||||
if PLACED_NODES.with(|c| c.get()).saturating_add(most) > most_nodes {
|
||||
if PLACED_NODES.with(|c| c.get()).saturating_add(DROPPED_NODES.with(|c| c.get())).saturating_add(most) > most_nodes {
|
||||
return None;
|
||||
}
|
||||
let placed = if clip { d.place_symbol_art(symbol, &art, *xf) } else { d.place_symbol_art_unclipped(symbol, &art, *xf) }?;
|
||||
let mut g = dressed(Node::group(n.id, vec![Arc::new(placed)]), n);
|
||||
g.extras_mut().attrs = n.extras().attrs.clone();
|
||||
Some(g)
|
||||
Some((g, most))
|
||||
}
|
||||
|
||||
/// `n` with its geometry effects evaluated (`None` = unchanged).
|
||||
@@ -346,18 +353,22 @@ fn bake_node(d: &mut Document, n: &Node) -> Option<Node> {
|
||||
// Symbol instances whose art draws live effects, when the caller asks for them: the art
|
||||
// placed, then baked. When the baked art passes the export's budget, or would draw too deep
|
||||
// where the instance is, it is dropped with the art placed for the instances inside it, and
|
||||
// the instance stays as it is.
|
||||
if let Some(m) = placed_symbol_art(d, n) {
|
||||
// the instance stays as it is. While the art bakes, its objects before baking are held in
|
||||
// the budget, so the instances inside it are placed only within what is left; art baked and
|
||||
// then dropped still counts against the budget for the instances after it.
|
||||
if let Some((m, most)) = placed_symbol_art(d, n) {
|
||||
let spent = PLACED_NODES.with(|c| c.get());
|
||||
PLACED_NODES.with(|c| c.set(spent.saturating_add(most)));
|
||||
INSTANCE_DEPTH.with(|c| c.set(c.get() + 1));
|
||||
let baked = bake_node(d, &m);
|
||||
INSTANCE_DEPTH.with(|c| c.set(c.get() - 1));
|
||||
let baked = baked.unwrap_or(m);
|
||||
if let Some(now) = placed_fits(&baked, spent) {
|
||||
if let Some(now) = placed_fits(&baked, spent, DROPPED_NODES.with(|c| c.get())) {
|
||||
PLACED_NODES.with(|c| c.set(now));
|
||||
return Some(baked);
|
||||
}
|
||||
PLACED_NODES.with(|c| c.set(spent));
|
||||
DROPPED_NODES.with(|c| c.set(c.get().saturating_add(baked.count_with_masks() as u64)));
|
||||
}
|
||||
// A path whose Transform effect copies it with a gradient, or scales its strokes or moves its
|
||||
// patterns: each copy an object of its own, so its gradient fits it rather than spanning
|
||||
@@ -895,14 +906,15 @@ pub fn bake_document_placing_symbols(doc: &Document, clip_slices: bool, layers:
|
||||
}
|
||||
|
||||
/// Restores what [`bake`] changes in the thread's baking state when it ends.
|
||||
struct Restore(Option<Rc<Placing>>, u64, usize, bool);
|
||||
struct Restore(Option<Rc<Placing>>, u64, u64, usize, bool);
|
||||
|
||||
impl Drop for Restore {
|
||||
fn drop(&mut self) {
|
||||
PLACING.with(|p| *p.borrow_mut() = self.0.take());
|
||||
PLACED_NODES.with(|c| c.set(self.1));
|
||||
LEVEL.with(|c| c.set(self.2));
|
||||
UNWRITTEN.with(|c| c.set(self.3));
|
||||
DROPPED_NODES.with(|c| c.set(self.2));
|
||||
LEVEL.with(|c| c.set(self.3));
|
||||
UNWRITTEN.with(|c| c.set(self.4));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -924,6 +936,7 @@ fn bake(doc: &Document, placing: Option<(bool, u64, WrittenLayers)>) -> Option<D
|
||||
let _restore = Restore(
|
||||
PLACING.with(|p| p.replace(placing.map(Rc::new))),
|
||||
PLACED_NODES.with(|c| c.replace(0)),
|
||||
DROPPED_NODES.with(|c| c.replace(0)),
|
||||
LEVEL.with(|c| c.replace(1)),
|
||||
UNWRITTEN.with(|c| c.replace(false)),
|
||||
);
|
||||
|
||||
@@ -1252,6 +1252,51 @@ fn placing_symbols_counts_nested_art_once() {
|
||||
assert!(is_instance(&short, 900), "the outer instance stays as it is");
|
||||
}
|
||||
|
||||
/// While an instance's art bakes, the art's own objects are held in the budget: an instance
|
||||
/// nested in it whose art does not fit in what is left stays as it is, and the outer instance is
|
||||
/// placed around it.
|
||||
#[test]
|
||||
fn placing_symbols_holds_the_outer_art_while_it_bakes() {
|
||||
use vectorcraft_geom::Affine;
|
||||
let mut d = doc_with(instance(900, "Outer", Affine::IDENTITY));
|
||||
add_symbol(&mut d, "Inner", Node::group(NodeId(803), vec![Arc::new(gradient_copies(800))]));
|
||||
let mut art: Vec<Arc<Node>> = (0..5)
|
||||
.map(|i| Arc::new(Node::path(NodeId(810 + i), shapes::rectangle(Rect::new(0.0, 0.0, 10.0, 10.0)), Appearance::default_art())))
|
||||
.collect();
|
||||
art.push(Arc::new(instance(802, "Inner", Affine::IDENTITY)));
|
||||
let outer = Node::group(NodeId(801), art);
|
||||
// The outer instance's group around its art, with the inner instance left as it is.
|
||||
let around = 1 + outer.count_with_masks() as u64;
|
||||
add_symbol(&mut d, "Outer", outer);
|
||||
let all = bake(&d, Some((true, u64::MAX, ALL))).unwrap();
|
||||
let inner = all.node(NodeId(802)).map_or(0, |n| n.count_with_masks() as u64);
|
||||
assert!(inner > 2 && inner <= around, "the inner art alone fits: {inner} <= {around}");
|
||||
let out = bake(&d, Some((true, around, ALL))).unwrap();
|
||||
assert!(!is_instance(&out, 900) && is_instance(&out, 802), "the outer instance is placed around the inner one");
|
||||
}
|
||||
|
||||
/// Art baked for an instance and then left out, because it passes the budget, still counts: an
|
||||
/// instance after it whose art would fit in the budget alone stays as it is, and a budget with
|
||||
/// room for both places both.
|
||||
#[test]
|
||||
fn placing_symbols_counts_the_art_it_drops() {
|
||||
use vectorcraft_geom::Affine;
|
||||
let mut d = doc_with(instance(901, "Small", Affine::IDENTITY));
|
||||
let layer = d.layers[0].id;
|
||||
d.insert(Some(layer), 0, instance(900, "Big", Affine::IDENTITY)).unwrap();
|
||||
add_symbol(&mut d, "Big", gradient_copies(800));
|
||||
add_symbol(&mut d, "Small", moved_square(810));
|
||||
let all = bake(&d, Some((true, u64::MAX, ALL))).unwrap();
|
||||
let count = |id: u64| all.node(NodeId(id)).map_or(0, |n| n.count_with_masks() as u64);
|
||||
let (big, small) = (count(900), count(901));
|
||||
assert!(small < big, "{small} < {big}");
|
||||
let short = bake(&d, Some((true, big - 1, ALL))).unwrap();
|
||||
assert!(is_instance(&short, 900), "the big art passes {}", big - 1);
|
||||
assert!(is_instance(&short, 901), "the big art's {big} objects count, so the small art does not fit");
|
||||
let both = bake(&d, Some((true, big + small, ALL))).unwrap();
|
||||
assert!(!is_instance(&both, 900) && !is_instance(&both, 901));
|
||||
}
|
||||
|
||||
/// Instances the export does not write are not placed and do not count against the budget: with
|
||||
/// room for one instance's baked art, hidden instances, an instance in a hidden group, one on a
|
||||
/// template layer, one on a layer that does not print and one on a hidden layer (when the export
|
||||
@@ -1329,3 +1374,36 @@ fn placing_symbols_keeps_the_baked_art_within_the_drawn_depth() {
|
||||
add_symbol(&mut shallow, "E", in_groups(5000, 1, gradient_copies(5100)));
|
||||
assert!(!is_instance(&bake_document_placing_symbols(&shallow, true, ALL).unwrap(), 900));
|
||||
}
|
||||
|
||||
/// Art baked for an instance and then left out because it draws too deep still counts when the
|
||||
/// baked art of a later instance is checked: that art fits before its effects add copies, but
|
||||
/// not once they do.
|
||||
#[test]
|
||||
fn placing_symbols_counts_art_dropped_for_depth_against_later_baked_art() {
|
||||
use vectorcraft_geom::Affine;
|
||||
// The chain of placing_symbols_keeps_the_baked_art_within_the_drawn_depth, then F, whose
|
||||
// square becomes a group of copies once baked.
|
||||
let mut d = doc_with(instance(900, "A", Affine::IDENTITY));
|
||||
for (i, (name, next)) in [("A", "B"), ("B", "C"), ("C", "D"), ("D", "E")].into_iter().enumerate() {
|
||||
let base = 1000 * (i as u64 + 1);
|
||||
add_symbol(&mut d, name, in_groups(base, 30, instance(base + 100, next, Affine::IDENTITY)));
|
||||
}
|
||||
add_symbol(&mut d, "E", in_groups(5000, 1, gradient_copies(5100)));
|
||||
add_symbol(&mut d, "F", gradient_copies(6000));
|
||||
let layer = d.layers[0].id;
|
||||
d.insert(Some(layer), 1, instance(901, "F", Affine::IDENTITY)).unwrap();
|
||||
let all = bake(&d, Some((true, u64::MAX, ALL))).unwrap();
|
||||
assert!(is_instance(&all, 4100) && !is_instance(&all, 900) && !is_instance(&all, 901));
|
||||
let count = |d: &Document, id: u64| d.node(NodeId(id)).map_or(0, |n| n.count_with_masks() as u64);
|
||||
let (a, f) = (count(&all, 900), count(&all, 901));
|
||||
// E's baked art, as placed where nothing above it draws deep.
|
||||
let mut shallow = doc_with(instance(4100, "E", Affine::IDENTITY));
|
||||
add_symbol(&mut shallow, "E", in_groups(5000, 1, gradient_copies(5100)));
|
||||
let e = count(&bake(&shallow, Some((true, u64::MAX, ALL))).unwrap(), 4100);
|
||||
assert!(f > 2, "F's copies are objects of their own: {f}");
|
||||
let short = bake(&d, Some((true, a + e + f - 1, ALL))).unwrap();
|
||||
assert!(!is_instance(&short, 900) && is_instance(&short, 4100), "A to D are placed, E is not");
|
||||
assert!(is_instance(&short, 901), "E's dropped {e} objects count, so F's baked {f} do not fit");
|
||||
let room = bake(&d, Some((true, a + e + f, ALL))).unwrap();
|
||||
assert!(!is_instance(&room, 900) && !is_instance(&room, 901));
|
||||
}
|
||||
|
||||
@@ -1575,7 +1575,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
Outline Object on an image's own fill or stroke follows the outline of the image's opaque area, and the image's frame when the image has no transparency. Path effects apply to a fill or stroke added to a bitmap object ([archived reference manual, page 561](https://web.archive.org/web/20210601162814/https://helpx.adobe.com/pdf/illustrator_reference.pdf#page=561)), and with Outline Object such a stroke follows the boundary of the art when the image has transparent areas and the image's frame when it has none ([CreativePro article on strokes for placed images](https://web.archive.org/web/20250815214529/https://creativepro.com/add-strokes-placed-images-illustrator/)). VectorCraft's own rules: the opaque area is the pixels at least 50% opaque, and its outline is traced as Image Trace's Black and White mode traces at threshold 128 and fitted with curves. Evidence: `tests::imageoutline` (vectorcraft-effects), `opaque::tests` (vectorcraft-trace), `tests::containers::an_images_stroke_with_outline_object_follows_its_opaque_area` and `tests::containers::an_images_outline_object_stroke_exports_selects_and_measures_along_its_opaque_area` (vectorcraft-engine), `tests::objectfx::an_images_outline_object_stroke_follows_new_pixels_under_the_same_key` (vectorcraft-render).
|
||||
A geometry effect on one of type's own fills or strokes reshapes the whole outline that the fill or stroke paints, on the canvas and in exports; PDF, SVG, EPS and the other vector exports write such type as paths. On type that holds inline graphics, those effects are drawn and exported only when the type has a geometry effect or perspective of its own.
|
||||
A geometry effect on a symbol instance's fill reshapes the filled shapes of the symbol's art and leaves their strokes as they are; one on the instance's stroke reshapes the stroked shapes and leaves their fills as they are. The shapes keep their colors. Only the instance's topmost fill and topmost stroke count, and only while they are visible with an opacity above 0. The canvas and Object › Expand Appearance use the same art, SVG and PDF export bake the same shapes, and Expand Appearance turns the instance into an editable group in one undo step. A group's own fills and strokes in the art take the effects too. An instance inside the art passes the effects on to its own art, and a dynamic symbol's instance reshapes the fills and strokes it paints on the art. How the effects map onto the symbol's art is VectorCraft's own rule. The help page <https://helpx.adobe.com/illustrator/desktop/special-effects-styles/apply-filter-effects/apply-and-modify-effects.html> describes effects on one fill or stroke, and the help page <https://helpx.adobe.com/illustrator/desktop/manage-objects/arrange-objects/expand-objects.html> describes Expand Appearance (engine `expand::a_symbol_instance_fill_effect_reshapes_its_filled_art_and_expands`, `a_symbol_instance_stroke_effect_reshapes_its_stroked_art_and_expands`, `a_stroke_effect_reshapes_a_stroke_a_dynamic_instance_adds`, `a_fill_effect_reshapes_the_fill_of_a_group_in_the_art`, `only_the_topmost_visible_instance_fill_reshapes_the_art`, `a_nested_symbol_instance_takes_the_outer_fill_effect`, `export_bakes_a_symbol_instance_fill_effect`, `a_fill_effect_on_an_instance_of_a_symbol_that_holds_itself_ends`). Existing documents with a geometry effect on a symbol instance's fill or stroke draw differently: before, the effect drew nothing.
|
||||
Live effects inside a symbol's art (geometry effects, color adjustments and the rest that export bakes) are written where each instance places the art in PDF, print, EPS and DXF, as the canvas draws them: the art is placed first and its effects are applied after, so an instance that scales its art does not scale the distance a Transform effect moves it. Symbols nested in the art, a dynamic symbol instance's own paint changes and the stain an instance's fill gives its art are kept, and the art is stained before its effects apply. A linked instance's PDF link covers its art where the effects draw it. A symbol whose art holds itself stops at the nesting limit, and the symbols' own art keeps its effects. An instance stays an instance in these exports when the objects its art makes once baked (the copies a Transform effect makes included) would take the export's placed symbol art past 16,000,000 objects, or when its baked art would draw deeper than the 128 levels a document may draw; these are VectorCraft's own limits. Instances the export leaves out (hidden ones, those in hidden groups, on template layers, and on hidden layers or layers that do not print when the export leaves those out) are not placed and do not count toward that limit. Before, these exports wrote the art without its effects (effects `bake::placing_symbols_bakes_their_art_where_each_instance_places_it`, `placing_symbols_reaches_the_art_of_nested_instances`, `placing_a_symbol_that_holds_itself_stops`, `placing_symbols_keeps_dynamic_instances_changes`, `placing_symbols_keeps_the_instances_stain`, `placing_symbols_counts_the_baked_art`, `placing_symbols_counts_nested_art_once`, `placing_symbols_keeps_the_baked_art_within_the_drawn_depth`, `placing_symbols_skips_instances_the_export_leaves_out`; doc `depth::tests::drawn_heights_measure_objects_outside_the_layers`; PDF, print, EPS and DXF `symbol_art_effects_are_written_where_they_draw`, `symbol_art_effects_print_where_they_draw`; PDF `a_stained_instance_keeps_its_stain_when_its_art_has_effects`, `a_linked_instance_keeps_its_link_when_its_art_has_effects`).
|
||||
Live effects inside a symbol's art (geometry effects, color adjustments and the rest that export bakes) are written where each instance places the art in PDF, print, EPS and DXF, as the canvas draws them: the art is placed first and its effects are applied after, so an instance that scales its art does not scale the distance a Transform effect moves it. Symbols nested in the art, a dynamic symbol instance's own paint changes and the stain an instance's fill gives its art are kept, and the art is stained before its effects apply. A linked instance's PDF link covers its art where the effects draw it. A symbol whose art holds itself stops at the nesting limit, and the symbols' own art keeps its effects. An instance stays an instance in these exports when the objects its art makes once baked (the copies a Transform effect makes included) would take the export's placed symbol art past 16,000,000 objects, or when its baked art would draw deeper than the 128 levels a document may draw; these are VectorCraft's own limits. Art baked for an instance that then stays an instance still counts toward that limit, and while an instance's art bakes, the art's own objects are held in the limit for the instances nested in it. Instances the export leaves out (hidden ones, those in hidden groups, on template layers, and on hidden layers or layers that do not print when the export leaves those out) are not placed and do not count toward that limit. Before, these exports wrote the art without its effects (effects `bake::placing_symbols_bakes_their_art_where_each_instance_places_it`, `placing_symbols_reaches_the_art_of_nested_instances`, `placing_a_symbol_that_holds_itself_stops`, `placing_symbols_keeps_dynamic_instances_changes`, `placing_symbols_keeps_the_instances_stain`, `placing_symbols_counts_the_baked_art`, `placing_symbols_counts_nested_art_once`, `placing_symbols_holds_the_outer_art_while_it_bakes`, `placing_symbols_counts_the_art_it_drops`, `placing_symbols_counts_art_dropped_for_depth_against_later_baked_art`, `placing_symbols_keeps_the_baked_art_within_the_drawn_depth`, `placing_symbols_skips_instances_the_export_leaves_out`; doc `depth::tests::drawn_heights_measure_objects_outside_the_layers`; PDF, print, EPS and DXF `symbol_art_effects_are_written_where_they_draw`, `symbol_art_effects_print_where_they_draw`; PDF `a_stained_instance_keeps_its_stain_when_its_art_has_effects`, `a_linked_instance_keeps_its_link_when_its_art_has_effects`).
|
||||
A raster effect (Drop Shadow, Outer Glow, Gaussian Blur and the other effects that paint pixels) on a symbol instance's topmost fill draws on each filled shape of the symbol's art, and one on its topmost stroke draws on each stroked shape, after any geometry effects listed before it, under the same rules as geometry effects: only a visible fill or stroke with an opacity above 0 counts, a group's own fills and strokes in the art take the effect, and an instance inside the art passes it on. Each shape gets its own shadow or glow, which is VectorCraft's own rule. The canvas, Use Preview Bounds and the drawn bounds, SVG and PDF export draw it, and Object › Expand Appearance is enabled for such an instance and makes the effect an image at the document's raster effects resolution, in one undo step (engine `expand::a_symbol_instance_fill_shadow_shadows_its_filled_art`, `a_symbol_instance_stroke_shadow_shadows_only_its_stroked_art`, `a_symbol_instance_fill_shadow_follows_the_fill_offset_before_it`, `a_nested_symbol_instance_takes_the_outer_fill_shadow`, `export_draws_a_symbol_instance_fill_shadow`). Existing documents with a raster effect on a symbol instance's fill or stroke draw differently: before, the effect drew nothing.
|
||||
The Appearance panel's inline effect editor labels each parameter as the effect dialogs' generic fields do, without the colon ("Max. Radius", "Channel 1", "Create New Fields by"). Roughen's and Zig Zag's Points, Offset Path's Joins, Inner Glow's Source and the menus of Radial Blur, Smart Blur, Sprayed Strokes, Glass, Mezzotint, Halftone Pattern, Grain, Texturizer and De-Interlace are dropdowns with the dialog's labels that send the dialog's values, and a plug-in's choice is a dropdown of the plug-in's values.
|
||||
Revolve's edge, Extrude & Bevel's bevel, every Warp style's orientation, Rasterize's Color Model, Background and Anti-aliasing and the channel of Levels and Curves are dropdowns too, with the labels their own dialogs show. `effect.apply` and `effect.setParams` refuse a Levels or Curves `channel` other than `rgb`, `red`, `green` or `blue` (or `r`, `g` and `b`, in any letter case).
|
||||
|
||||
Reference in New Issue
Block a user