.ai import: multi-layer masks open as a clipping group in each layer

Squashed from #5117 onto main.
This commit is contained in:
dotCooCoo
2026-11-02 12:04:26 +07:00
committed by bflatastic
parent f6e262c92e
commit ccc7e44078
30 changed files with 597 additions and 2 deletions
+49
View File
@@ -3322,6 +3322,48 @@ proptest! {
let text = mutate_text(NAMED_PROLOG_AI, cut, &edits);
survive("mutated PostScript-form .ai", || vectorcraft_engine::cmd::fileio::load("x.ai", text.as_bytes()).ok().map(|l| l.doc))?;
}
/// Multi-layer masks (`Mb` <path> `W n` `Md` … `MB`) over any number of layers, with tokens
/// dropped or put anywhere (the mask operators, layer ends, groups, clipping paths) and the
/// data cut short.
#[test]
fn ai_multi_layer_masks_never_panic(
layers in 1usize..5,
aliases in any::<bool>(),
edits in prop::collection::vec((0usize..64, prop::sample::select(vec!["", "Mb", "Md", "MB", "Mi", "LB", "u", "U", "q", "Q", "W n", "h W n"])), 0..4),
cut in prop::option::of(0usize..64),
) {
use vectorcraft_testkit::ai;
let (begin, define) = if aliases { ("Mv", "ME") } else { ("Mb", "Md") };
let mut tokens: Vec<String> = vec![];
for i in 0..layers {
if i > 0 {
tokens.push(format!("LB\n%AI5_EndLayer--\n%AI5_BeginLayer\n1 1 1 1 0 1 1 79 128 255 Lb\n(L{i}) Ln\n"));
} else {
tokens.extend([begin.to_string(), "40 40 m 120 40 L 120 120 L 40 120 L h W n".into(), define.to_string()]);
}
let x = 10 * i;
tokens.push(format!("0.5 0 0 0 k {x} {x} m {} {x} L {} {} L f", x + 140, x + 140, x + 140));
}
tokens.extend(["MB".to_string(), "150 150 m 190 150 L 190 190 L f".into()]);
for (at, with) in &edits {
let at = at % (tokens.len() + 1);
if with.is_empty() {
if at < tokens.len() {
tokens.remove(at);
}
} else {
tokens.insert(at, with.to_string());
}
}
if let Some(cut) = cut {
tokens.truncate(cut);
}
let data = ai::editing_data(200.0, 100.0, &format!("%AI5_BeginLayer\n1 1 1 1 0 1 1 79 128 255 Lb\n(L0) Ln\n{}\nLB\n", tokens.join("\n")));
survive("multi-layer masks", || Some(vectorcraft_eps::layered_ai(data.as_bytes(), Document::new(200.0, 100.0), vec![], false, false, 1.0).0))?;
let eps = ai::eps(data.as_bytes(), ai::page_ps());
survive("multi-layer masks in an EPS", || vectorcraft_engine::cmd::fileio::load("x.eps", &eps).ok().map(|l| l.doc))?;
}
}
/// An operand of a layer's options (`Lb`): a flag, a colour index or component, a percentage, or
@@ -3390,6 +3432,13 @@ fn arb_ai_token() -> impl Strategy<Value = String> {
"Lb",
"Ln",
"(name) Ln",
"\n%AI5_BeginLayer\n1 1 1 1 0 1 1 79 128 255 Lb\n",
"Mb",
"Mv",
"Md",
"ME",
"Mi",
"MB",
"g",
"G",
"k",
+9
View File
@@ -4,6 +4,8 @@
//! - Layers: `%AI5_BeginLayer`, `visible preview unlocked printing dimmed … colorIndex r g b
//! template dimPercent … Lb` (ten operands in the legacy format, without the one before the
//! colour index; see `Reader::layer_attrs`), `(name) Ln`, its art, `LB`.
//! - Multi-layer masks `Mb` <path> `W n` `Md` … `MB`, whose objects can go on past `LB` into the
//! next layers: a clipping group in each layer, read by [`masks`].
//! - Ruler guides: a straight `(N) *` guide path, directly on a layer, that runs across the whole
//! canvas (16,383 points around the template box's centre) or from edge to edge of one artboard
//! is a ruler guide on that layer ([`Document::guides`]); other guide paths stay paths.
@@ -87,6 +89,7 @@ mod art;
mod containers;
mod directives;
mod document;
mod masks;
mod on_path;
mod ops;
mod types;
@@ -308,6 +311,8 @@ struct Reader<'a> {
type_state: legacy_text::TypeState,
/// The graph being read (see [`Reader::graph_record`]).
graph: Option<Graph>,
/// The multi-layer mask being read (`Mb` … `MB`), which goes on past a layer's end.
multi_mask: Option<masks::MultiMask>,
}
/// A section comment's marker without its `AI<version>_` prefix and value (`AI14_BeginSymbol` →
@@ -406,6 +411,7 @@ impl<'a> Reader<'a> {
text: None,
type_state: legacy_text::TypeState::default(),
graph: None,
multi_mask: None,
}
}
@@ -436,6 +442,9 @@ impl<'a> Reader<'a> {
if self.frames.iter().any(|f| matches!(f.kind, Kind::Layer(_))) {
return Err("it ends inside a layer".into());
}
if self.multi_mask.is_some() {
return Err("it ends inside a multi-layer mask".into());
}
Ok(())
}
}
@@ -75,6 +75,7 @@ impl<'a> Reader<'a> {
}
pub(super) fn end_container(&mut self, what: &str, hidden: bool) -> Result<(), String> {
self.multi_mask_container_ends()?;
let f = match what {
"U" => self.close(what, |k| matches!(k, Kind::Group))?,
"*U" => self.close(what, |k| matches!(k, Kind::Compound))?,
+4 -1
View File
@@ -130,7 +130,10 @@ impl<'a> Reader<'a> {
_ => {}
}
if line.starts_with("AI5_BeginLayer") {
return self.open(Kind::Layer(Box::default()), false);
self.multi_mask_layer_starts()?;
self.open(Kind::Layer(Box::default()), false)?;
self.multi_mask_go_on();
return Ok(());
}
if line.starts_with("AI5_BeginRaster") {
self.raster = Some(Raster::default());
+185
View File
@@ -0,0 +1,185 @@
//! Multi-layer masks in the legacy format (version 7 specification §10): `Mb`, the mask's path
//! painted with `W`, `Md`, the masked objects (in that layer and, past its `LB`, in the layers
//! after it), `MB`. The objects of each layer the mask covers become one clipping group in that
//! layer, its clipping path a copy of the mask's.
use super::types::{Frame, Kind, MAX_NODES};
use super::{Arc, Node, NodeKind, Reader};
/// The note for a file with a multi-layer mask.
pub(crate) const PER_LAYER: &str = "a mask that covers several layers comes in as a clipping group in each layer it covers";
/// A multi-layer mask being read.
#[derive(Debug)]
pub(super) struct MultiMask {
/// The mask's clipping path, once `Md` has defined it.
mask: Option<Node>,
/// What each copy of the mask adds to the objects read: its objects and their points.
weight: usize,
/// How many frames were open when the masked objects started in the frame they go in; 0
/// outside the layers, until a layer starts.
depth: usize,
/// Where the masked objects start among that frame's children.
start: usize,
}
impl Reader<'_> {
/// A multi-layer mask's operator `w`: `Mb` (or `Mv`) starts the mask, `Md` (or `ME`) defines
/// it, `MB` ends it, and `Mi` changes nothing here.
pub(super) fn multi_mask_op(&mut self, w: &str) -> Result<(), String> {
match w {
"Mb" | "Mv" => self.begin_multi_mask(),
"Md" | "ME" => self.define_multi_mask(),
"MB" => self.end_multi_mask(),
_ => Ok(()),
}
}
/// `LB`: the layer ends, and a multi-layer mask goes on in the frame around it.
pub(super) fn end_layer_in_mask(&mut self) -> Result<(), String> {
self.multi_mask_layer_ends()?;
self.end_layer()?;
self.multi_mask_go_on();
Ok(())
}
/// `Mb`: a multi-layer mask starts.
fn begin_multi_mask(&mut self) -> Result<(), String> {
if self.multi_mask.is_some() {
return Err("a multi-layer mask's operators are out of order".into());
}
self.end_path_quietly();
let start = self.frames.last().map_or(0, |f| f.children.len());
self.multi_mask = Some(MultiMask { mask: None, weight: 0, depth: self.frames.len(), start });
Ok(())
}
/// `Md`: the clipping path painted last since `Mb`, in the same group or layer, is the mask.
fn define_multi_mask(&mut self) -> Result<(), String> {
let depth = self.frames.len();
let Some(m) = self.multi_mask.as_mut() else { return Err("a multi-layer mask's operators are out of order".into()) };
if m.mask.is_some() || depth == 0 {
return Err("a multi-layer mask's operators are out of order".into());
}
if m.depth != depth {
return Err("a group crosses a multi-layer mask".into());
}
let Some(f) = self.frames.last_mut() else { return Err("a multi-layer mask's operators are out of order".into()) };
let Some(at) = f.clips.iter().copied().filter(|i| *i >= m.start && *i < f.children.len()).max() else {
return Err("a multi-layer mask needs one clipping path".into());
};
let mask = f.children.remove(at);
f.clips.retain(|i| *i != at);
for i in &mut f.clips {
if *i > at {
*i -= 1;
}
}
let mut weight = mask.count_with_masks();
mask.walk(&mut |n| {
if let NodeKind::Path { path, .. } = &n.kind {
weight = weight.saturating_add(path.anchor_count());
}
});
m.weight = weight;
m.mask = Some(mask);
self.after_object = false;
Ok(())
}
/// `MB`: the masked objects end.
fn end_multi_mask(&mut self) -> Result<(), String> {
if !self.multi_mask.as_ref().is_some_and(|m| m.mask.is_some()) {
return Err("a multi-layer mask's operators are out of order".into());
}
self.wrap_masked()?;
self.multi_mask = None;
Ok(())
}
/// `%AI5_BeginLayer` in a multi-layer mask, before the layer opens: the objects masked so far
/// in the frame around it are grouped, and the mask goes on in the new layer.
pub(super) fn multi_mask_layer_starts(&mut self) -> Result<(), String> {
let Some(m) = self.multi_mask.as_ref() else { return Ok(()) };
if m.depth != 0 {
if m.mask.is_none() {
return Err("a multi-layer mask's operators are out of order".into());
}
self.wrap_masked()?;
}
Ok(())
}
/// A layer opened or closed in a multi-layer mask: the masked objects go on in the frame now
/// innermost.
pub(super) fn multi_mask_go_on(&mut self) {
let (depth, start) = (self.frames.len(), self.frames.last().map_or(0, |f| f.children.len()));
if let Some(m) = self.multi_mask.as_mut() {
(m.depth, m.start) = (depth, start);
}
}
/// `LB` in a multi-layer mask, before the layer closes: its masked objects are grouped.
fn multi_mask_layer_ends(&mut self) -> Result<(), String> {
let Some(m) = self.multi_mask.as_ref() else { return Ok(()) };
if m.mask.is_none() {
return Err("a multi-layer mask's operators are out of order".into());
}
if !matches!(self.frames.last(), Some(Frame { kind: Kind::Layer(_), .. })) {
return Err("a group crosses a multi-layer mask".into());
}
self.wrap_masked()
}
/// A group, compound path or clipping group closing: it must have opened inside the mask.
pub(super) fn multi_mask_container_ends(&self) -> Result<(), String> {
match &self.multi_mask {
Some(m) if m.depth == self.frames.len() => Err("a group crosses a multi-layer mask".into()),
_ => Ok(()),
}
}
/// The masked objects in the innermost frame become a clipping group, a copy of the mask first.
fn wrap_masked(&mut self) -> Result<(), String> {
let Some(m) = self.multi_mask.as_ref() else { return Ok(()) };
if m.depth == 0 {
return Ok(());
}
if m.depth != self.frames.len() {
return Err("a group crosses a multi-layer mask".into());
}
let Some(mut mask) = m.mask.clone() else { return Err("a multi-layer mask's operators are out of order".into()) };
let (start, weight) = (m.start, m.weight);
let Some(f) = self.frames.last_mut() else { return Ok(()) };
if start >= f.children.len() {
return Ok(());
}
// A clipping path painted among the masked objects clips the whole layer or group, as
// outside a mask: it stays in the frame, outside the masked objects' group.
let painted: std::collections::HashSet<usize> = f.clips.iter().filter_map(|i| i.checked_sub(start)).collect();
let (clips, kids): (Vec<_>, Vec<_>) = f.children.split_off(start).into_iter().enumerate().partition(|(i, _)| painted.contains(i));
let (clips, kids): (Vec<Node>, Vec<Node>) = (clips.into_iter().map(|(_, k)| k).collect(), kids.into_iter().map(|(_, k)| k).collect());
f.clips.retain(|i| *i < start);
if !kids.is_empty() {
self.nodes = self.nodes.saturating_add(weight).saturating_add(1);
if self.nodes > MAX_NODES {
return Err(format!("it has more than {MAX_NODES} objects"));
}
self.reid(&mut mask);
let children = std::iter::once(mask).chain(kids).map(Arc::new).collect();
let group = Node::new(self.doc.alloc_id(), NodeKind::Group { children, clip: true });
if let Some(f) = self.frames.last_mut() {
f.children.push(group);
}
self.warn(PER_LAYER);
}
if let Some(f) = self.frames.last_mut() {
for c in clips {
f.clips.push(f.children.len());
f.children.push(c);
}
}
self.after_object = false;
Ok(())
}
}
+2 -1
View File
@@ -154,7 +154,7 @@ impl<'a> Reader<'a> {
self.graph = None;
self.warn(GRAPH_UNENDED);
}
self.end_layer()?
self.end_layer_in_mask()?
}
// Paths.
"m" | "l" | "L" | "c" | "C" | "v" | "V" | "y" | "Y" => self.path_op(w, &vals)?,
@@ -162,6 +162,7 @@ impl<'a> Reader<'a> {
// Ends a path that stays open.
"H" => {}
"W" => self.clip_next = true,
"Mb" | "Mv" | "Md" | "ME" | "MB" | "Mi" => self.multi_mask_op(w)?,
// A text object's frame or path.
"N" | "n" | "F" | "f" | "S" | "s" | "B" | "b" if self.in_text_path() => self.text_path(),
"N" | "n" | "F" | "f" | "S" | "s" | "B" | "b" => self.paint(w, hidden, false)?,
+221
View File
@@ -3953,3 +3953,224 @@ fn a_graphs_records_take_their_operands() {
assert_eq!(paths(&a[0]), 1, "the empty groups hold no art");
assert_eq!(r.warnings, [GRAPH_PLAIN]);
}
/// Editing data in the legacy format (`%AI5_FileFormat 2.0`, ten `Lb` operands), then `body`.
fn mask_stream7(body: &str) -> String {
format!(
"%!PS-Adobe-3.0\n%%Creator: test\n%%BoundingBox: 0 0 200 200\n%AI5_FileFormat 2.0\n%AI5_ArtSize: 200 200\n\
%AI3_TemplateBox: 100 100 100 100\n%%EndComments\n%%BeginProlog\n%%EndProlog\n%%BeginSetup\n%%EndSetup\n{body}\n\
%%PageTrailer\ngsave annotatepage grestore showpage\n%%Trailer\n%%EOF\n"
)
}
/// The start of a legacy layer named `name`, `masks` its multi-layer mask flag (`Lb`'s sixth operand).
fn begin7(name: &str, masks: u8) -> String {
format!("%AI5_BeginLayer\n1 1 1 1 0 {masks} 1 79 128 255 Lb\n({name}) Ln\n")
}
const END7: &str = "LB\n%AI5_EndLayer--\n";
/// `Mb`, an 80 by 80 point mask path painted `W n`, `Md` (the version 7 specification's §10.4 order).
fn mask_start() -> String {
format!("Mb\n{}h\nW\nn\nMd\n", rect_path(40.0, 40.0, 120.0, 120.0))
}
/// A filled square at `x`.
fn masked(x: f64) -> String {
format!("0.5 0 0 0 k\n{}f\n", rect_path(x, x, x + 140.0, x + 140.0))
}
/// A layer's objects as a tree: `p` a path, `c` a clipping path, `o` a compound path, `g[…]` a
/// group, `k[…]` a clipping group, `l[…]` a sublayer.
fn mask_tree(nodes: &[Arc<Node>]) -> String {
let one = |n: &Arc<Node>| match &n.kind {
NodeKind::Layer { children, .. } => format!("l[{}]", mask_tree(children)),
NodeKind::Group { children, clip: false } => format!("g[{}]", mask_tree(children)),
NodeKind::Group { children, clip: true } => format!("k[{}]", mask_tree(children)),
NodeKind::Path { clipping: true, .. } => "c".into(),
NodeKind::Path { .. } => "p".into(),
NodeKind::Compound { .. } => "o".into(),
k => format!("{k:?}"),
};
nodes.iter().map(one).collect::<Vec<_>>().join(" ")
}
fn read7(body: &str) -> Structure {
match read(mask_stream7(body).as_bytes()) {
Ok(r) => r,
Err(e) => panic!("{e}"),
}
}
/// Each layer's tree, and whether the layer itself clips.
fn layer_trees(doc: &Document) -> Vec<(String, String, bool)> {
doc.layers
.iter()
.map(|l| {
let NodeKind::Layer { children, clip, .. } = &l.kind else { panic!("a layer") };
(l.name.clone().unwrap_or_default(), mask_tree(children), *clip)
})
.collect()
}
/// A multi-layer mask (version 7 specification §10.4: `Mb`, the mask path, `Md`, objects in two
/// layers, `MB`) comes in as a clipping group in each layer it covers, each clipped by a copy of
/// the mask's path; what follows `MB` isn't clipped.
#[test]
fn a_multi_layer_mask_clips_each_layer_it_covers() {
let body = format!("{}{}{}{END7}{}{}MB\n{}{END7}", begin7("A", 1), mask_start(), masked(15.0), begin7("B", 1), masked(30.0), masked(150.0));
let r = read7(&body);
assert_eq!(layer_trees(&r.doc), [("A".to_string(), "k[c p]".to_string(), false), ("B".to_string(), "k[c p] p".to_string(), false)]);
let mask = |l: usize| r.doc.layers[l].children().unwrap()[0].children().unwrap()[0].clone();
let (a, b) = (mask(0), mask(1));
assert_ne!(a.id, b.id, "each layer has a copy of its own");
assert_eq!(a.geometric_bounds(), b.geometric_bounds());
let bounds = a.geometric_bounds().unwrap();
assert_eq!((bounds.width(), bounds.height()), (80.0, 80.0));
assert!(r.warnings.iter().any(|w| w.contains("clipping group in each layer")), "{:?}", r.warnings);
// The layers' flag saying they have multi-layer masks changes nothing.
let unflagged = read7(&body.replace(&begin7("A", 1), &begin7("A", 0)).replace(&begin7("B", 1), &begin7("B", 0)));
assert_eq!(format!("{:?}", unflagged.doc.layers), format!("{:?}", r.doc.layers));
}
#[test]
fn a_multi_layer_mask_in_one_layer_or_over_three() {
let one = format!("{}{}{}MB\n{}{END7}", begin7("A", 1), mask_start(), masked(15.0), masked(150.0));
assert_eq!(layer_trees(&read7(&one).doc), [("A".to_string(), "k[c p] p".to_string(), false)]);
let three = format!(
"{}{}{}{END7}{}{}{END7}{}{}MB\n{END7}",
begin7("A", 1),
mask_start(),
masked(15.0),
begin7("B", 1),
masked(30.0),
begin7("C", 1),
masked(45.0)
);
let trees: Vec<_> = layer_trees(&read7(&three).doc).into_iter().map(|(_, t, clip)| (t, clip)).collect();
assert_eq!(trees, vec![("k[c p]".to_string(), false); 3]);
// Objects before the mask's path are masked too; a layer between with nothing in it stays empty.
let before = format!(
"{}Mb\n{}{}h\nW\nn\nMd\n{END7}{}{END7}{}{}MB\n{END7}",
begin7("A", 1),
masked(15.0),
rect_path(40.0, 40.0, 120.0, 120.0),
begin7("B", 1),
begin7("C", 1),
masked(45.0)
);
let trees: Vec<_> = layer_trees(&read7(&before).doc).into_iter().map(|(_, t, _)| t).collect();
assert_eq!(trees, ["k[c p]", "", "k[c p]"]);
}
#[test]
fn a_multi_layer_mask_in_a_group_or_sublayer() {
// Begun and ended in a group of one layer.
let grouped = format!("{}u\n{}{}MB\n{}U\n{END7}", begin7("A", 1), mask_start(), masked(15.0), masked(150.0));
assert_eq!(layer_trees(&read7(&grouped).doc)[0].1, "g[k[c p] p]");
// A sublayer in the mask: what the mask covers in the layer around it and in the sublayer.
let nested = format!("{}{}{}{}{}{END7}{}MB\n{END7}", begin7("A", 1), mask_start(), masked(15.0), begin7("S", 1), masked(30.0), masked(45.0));
assert_eq!(layer_trees(&read7(&nested).doc)[0].1, "k[c p] l[k[c p]] k[c p]");
}
#[test]
fn a_multi_layer_masks_path_can_be_painted_or_compound() {
// `W f`: the path also paints, under what the mask covers.
let painted = format!("{}Mb\n0 0 0 1 k\n{}h\nW\nf\nMd\n{}MB\n{END7}", begin7("A", 1), rect_path(40.0, 40.0, 120.0, 120.0), masked(15.0));
let doc = read7(&painted).doc;
assert_eq!(layer_trees(&doc)[0].1, "k[c p p]");
let group = doc.layers[0].children().unwrap()[0].clone();
let kids = group.children().unwrap();
assert_eq!(fill(&kids[1]).color(), Some(Color::cmyk(0.0, 0.0, 0.0, 1.0)), "the painted path first");
// A compound path of clipping paths.
let compound = format!(
"{}Mb\n*u\n{}h\nW\nn\n{}h\nW\nn\n*U\nMd\n{}MB\n{END7}",
begin7("A", 1),
rect_path(40.0, 40.0, 80.0, 80.0),
rect_path(90.0, 90.0, 120.0, 120.0),
masked(15.0)
);
assert_eq!(layer_trees(&read7(&compound).doc)[0].1, "k[o p]");
}
/// `Mv` starts a mask as `Mb` does, `ME` defines one as `Md` does, and `Mi` changes nothing.
#[test]
fn other_multi_layer_mask_operators() {
let body = format!("{}{}{}{END7}{}{}MB\n{}{END7}", begin7("A", 1), mask_start(), masked(15.0), begin7("B", 1), masked(30.0), masked(150.0));
let plain = format!("{:?}", read7(&body).doc.layers);
let aliases = body.replace("Mb\n", "Mv\n").replace("Md\n", "ME\n");
assert_eq!(format!("{:?}", read7(&aliases).doc.layers), plain);
let with_mi = body.replace("Md\n", "Md\nMi\n").replace("MB\n", "Mi\nMB\n");
assert_eq!(format!("{:?}", read7(&with_mi).doc.layers), plain);
}
#[test]
fn a_malformed_multi_layer_mask_is_an_error() {
let path = format!("{}h\nW\nn\n", rect_path(40.0, 40.0, 120.0, 120.0));
let sq = masked(15.0);
let cases = [
("an end without a start", format!("{sq}MB\n")),
("a definition without a start", format!("{path}Md\n{sq}")),
("no mask path", format!("Mb\n{sq}Md\n{sq}MB\n")),
("a start inside another", format!("Mb\nMb\n{path}Md\n{sq}MB\n")),
("an end before the definition", format!("Mb\n{path}MB\n")),
("a definition in another group", format!("Mb\nu\n{path}Md\n{sq}MB\nU\n")),
("a group crossing the end", format!("{}u\n{sq}MB\nU\n", mask_start())),
("a group crossing the start", format!("u\n{}{sq}U\nMB\n", mask_start())),
];
for (why, art) in cases {
let body = format!("{}{art}{END7}", begin7("A", 1));
let e = read(mask_stream7(&body).as_bytes()).unwrap_err();
assert!(e.contains("mask"), "{why}: {e}");
}
let layered = [
("a layer ends before the definition", format!("{}Mb\n{sq}{END7}{}{path}Md\nMB\n{END7}", begin7("A", 1), begin7("B", 1))),
("a group open at the layer's end", format!("{}{}u\n{sq}{END7}{}U\nMB\n{END7}", begin7("A", 1), mask_start(), begin7("B", 1))),
("the end of the file inside the mask", format!("{}{}{sq}{END7}", begin7("A", 1), mask_start())),
];
for (why, body) in layered {
let e = read(mask_stream7(&body).as_bytes()).unwrap_err();
assert!(e.contains("mask"), "{why}: {e}");
}
// Outside the layers, `Md` has nowhere to take its path from.
let outside = format!("Mb\nMd\n{}{path}{sq}MB\n{END7}", begin7("A", 1));
let e = read(mask_stream7(&outside).as_bytes()).unwrap_err();
assert!(e.contains("mask"), "{e}");
}
/// A clipping path painted among the masked objects clips its whole layer, as outside a mask.
#[test]
fn a_layers_clipping_path_in_a_multi_layer_mask_clips_the_layer() {
let path = format!("{}h\nW\nn\n", rect_path(10.0, 10.0, 190.0, 190.0));
let body = format!("{}{}{}{path}{}MB\n{END7}", begin7("A", 1), mask_start(), masked(15.0), masked(30.0));
assert_eq!(layer_trees(&read7(&body).doc), [("A".to_string(), "c k[c p p]".to_string(), true)]);
}
/// `Mb` before the first layer it covers and `MB` after the last one's `LB`.
#[test]
fn a_multi_layer_mask_begun_or_ended_between_layers() {
let body = format!(
"Mb\n{}{}h\nW\nn\nMd\n{}{END7}{}{}{END7}MB\n{}{}{END7}",
begin7("A", 1),
rect_path(40.0, 40.0, 120.0, 120.0),
masked(15.0),
begin7("B", 1),
masked(30.0),
begin7("C", 1),
masked(150.0)
);
let trees: Vec<_> = layer_trees(&read7(&body).doc).into_iter().map(|(_, t, _)| t).collect();
assert_eq!(trees, ["k[c p]", "k[c p]", "p"]);
}
/// Each copy of the mask counts toward the most objects read, with its points.
#[test]
fn copies_of_a_multi_layer_mask_count_toward_the_limit() {
let points: String = (0..2_000_001).map(|i| format!("{} 40 L\n", 40 + i % 80)).collect();
let mask = format!("Mb\n40 40 m\n{points}h\nW\nn\nMd\n");
let one = format!("{}{mask}{}MB\n{END7}", begin7("A", 1), masked(15.0));
assert_eq!(layer_trees(&read7(&one).doc)[0].1, "k[c p]");
let two = format!("{}{mask}{}{END7}{}{}MB\n{END7}", begin7("A", 1), masked(15.0), begin7("B", 1), masked(30.0));
let e = read(mask_stream7(&two).as_bytes()).unwrap_err();
assert!(e.contains("objects"), "{e}");
}
@@ -163,6 +163,25 @@ fn a_postscript_ai_whose_layers_cant_be_read_says_why() {
assert!(e.contains("`Adobe_packedarray`") && e.contains("its layers couldn't be read either") && e.contains("`frobnicate`"), "{e}");
}
/// A `.ai` in PostScript form with a multi-layer mask (`Mb`, its path, `Md`, objects in both
/// layers, `MB`) opens through its layers: a clipping group in each, and what follows `MB` unclipped.
#[test]
fn a_postscript_ai_with_a_multi_layer_mask_opens_with_its_layers() {
let src = NAMED_PROLOG
.replace("0 D\n10 10 m", "0 D\nMb\n20 20 m\n180 20 L\n180 80 L\n20 80 L\nh\nW\nn\nMd\n10 10 m")
.replace("190 90 L\nS\nLB", "190 90 L\nS\nMB\n150 50 m\n195 95 L\nS\nLB");
let r = import(src.as_bytes()).unwrap();
assert!(!r.preview, "read through the layers, not a fallback preview");
let d = &r.document;
let names: Vec<_> = d.layers.iter().map(|l| l.name.clone().unwrap_or_default()).collect();
assert_eq!(names, ["SECTION::Cut", "SECTION::Hatch"]);
assert_eq!(tree(d.layers[0].children().unwrap()), "k[c p]");
assert_eq!(tree(d.layers[1].children().unwrap()), "k[c p] p");
let mask = d.layers[1].children().unwrap()[0].children().unwrap()[0].clone();
assert_eq!(mask.geometric_bounds(), Some(Rect::new(20.0, 20.0, 180.0, 80.0)));
assert!(r.warnings.iter().any(|w| w.contains("clipping group in each layer")), "{:?}", r.warnings);
}
/// A `.ai` in PostScript form (read through its layers) whose text carries hyphenation and
/// tab-ruler attributes: `XL` (hyphenation language), `Xb`/`XB` (a tab definition) and `Th`
/// (hyphen control). These keep no geometry, so the reader drops them rather than failing the
+5
View File
@@ -4814,6 +4814,7 @@ digits Malayalam Malaiàlam
@msg `{to}` is not an available name `{to}` no és un nom disponible
@msg `{what}` closes nothing `{what}` no tanca res
@msg `{what}` closes something it didn't open `{what}` tanca una cosa que no havia obert
@msg a mask that covers several layers comes in as a clipping group in each layer it covers una màscara que cobreix diverses capes entra com un grup de retall a cada capa que cobreix
@msg a graph's records don't end where they should: its art was read as it is els registres d’un gràfic no acaben on haurien: la seva il·lustració s’ha llegit tal com és
@msg `{w}` takes no operands `{w}` no admet operands
@msg a wraparound group is inside a compound path un grup d’ajustament del text és dins d’un traçat compost
@@ -5050,6 +5051,10 @@ digits Malayalam Malaiàlam
@msg is not an image VectorCraft reads no és una imatge que VectorCraft pugui llegir
@msg it decompresses to more than {_1} MB es descomprimeix fins a més de {_1} MB
@msg it ends inside a layer acaba dins d’una capa
@msg it ends inside a multi-layer mask acaba dins d’una màscara multicapa
@msg a multi-layer mask's operators are out of order els operadors d’una màscara multicapa estan desordenats
@msg a multi-layer mask needs one clipping path una màscara multicapa necessita un traçat de retall
@msg a group crosses a multi-layer mask un grup travessa una màscara multicapa
@msg it has art outside its layers té art fora de les seves capes
@msg it has more than one artboard té més d’un tauler
@msg it has more than {MAX_NODES} objects té més de {MAX_NODES} objectes
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -4872,11 +4872,16 @@ imageTrace Outline Obrys
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead nejde o logo s plnými barvami ({_1} % jeho plných ploch odpovídá několika plným barvám), takže režim Ploché logo by z jeho přechodů udělal skvrny: použijte místo toho režim Barva
@msg `{what}` closes nothing `{what}` nic neuzavírá
@msg `{what}` closes something it didn't open `{what}` uzavírá něco, co neotevřel
@msg a mask that covers several layers comes in as a clipping group in each layer it covers maska, která pokrývá několik vrstev, se načte jako ořezová skupina v každé vrstvě, kterou pokrývá
@msg a graph's records don't end where they should: its art was read as it is záznamy grafu nekončí tam, kde mají: jeho kresba byla načtena tak, jak je
@msg `{w}` takes no operands `{w}` nepřijímá žádné operandy
@msg a wraparound group is inside a compound path skupina obtékání textu je uvnitř složené cesty
@msg a path has too many points cesta má příliš mnoho bodů
@msg it ends inside a layer končí uvnitř vrstvy
@msg it ends inside a multi-layer mask končí uvnitř masky přes více vrstev
@msg a multi-layer mask's operators are out of order operátory masky přes více vrstev jsou ve špatném pořadí
@msg a multi-layer mask needs one clipping path maska přes více vrstev potřebuje jednu ořezovou cestu
@msg a group crosses a multi-layer mask skupina přesahuje masku přes více vrstev
@msg it has art outside its layers má kresbu mimo své vrstvy
@msg it has more than {MAX_NODES} objects má více než {MAX_NODES} objektů
@msg it has no layers nemá žádné vrstvy
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -4481,11 +4481,16 @@ theme Appearance Erscheinungsbild
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead dies ist kein Logo aus flächigen Farben ({_1} % seiner einfarbigen Bereiche entsprechen wenigen flächigen Farben), daher würde der Modus „Flaches Logo“ seine Verläufe in Flecken zerlegen: Verwenden Sie stattdessen den Modus „Farbe“
@msg `{what}` closes nothing `{what}` schließt nichts
@msg `{what}` closes something it didn't open `{what}` schließt etwas, das es nicht geöffnet hat
@msg a mask that covers several layers comes in as a clipping group in each layer it covers eine Maske über mehrere Ebenen wird in jeder Ebene, die sie abdeckt, zu einer Schnittgruppe
@msg a graph's records don't end where they should: its art was read as it is die Datensätze eines Diagramms enden nicht dort, wo sie sollten: seine Grafik wurde so gelesen, wie sie ist
@msg `{w}` takes no operands `{w}` nimmt keine Operanden
@msg a wraparound group is inside a compound path eine Textumfluss-Gruppe liegt in einem zusammengesetzten Pfad
@msg a path has too many points ein Pfad hat zu viele Punkte
@msg it ends inside a layer es endet innerhalb einer Ebene
@msg it ends inside a multi-layer mask es endet innerhalb einer ebenenübergreifenden Maske
@msg a multi-layer mask's operators are out of order die Operatoren einer ebenenübergreifenden Maske stehen in falscher Reihenfolge
@msg a multi-layer mask needs one clipping path eine ebenenübergreifende Maske braucht genau einen Schnittpfad
@msg a group crosses a multi-layer mask eine Gruppe überschneidet eine ebenenübergreifende Maske
@msg it has art outside its layers es enthält Grafik außerhalb seiner Ebenen
@msg it has more than {MAX_NODES} objects es enthält mehr als {MAX_NODES} Objekte
@msg it has no layers es enthält keine Ebenen
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -4514,11 +4514,16 @@ digits Malayalam Μαλαγιάλαμ
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead αυτό δεν είναι λογότυπο επίπεδων χρωμάτων ({_1}% των συμπαγών περιοχών του αντιστοιχούν σε λίγα χρώματα), επομένως η λειτουργία Επίπεδο λογότυπο θα μετατρέψει τα ντεγκραντέ σε κηλίδες: χρησιμοποιήστε τη λειτουργία Χρώμα
@msg `{what}` closes nothing το `{what}` δεν κλείνει κανένα στοιχείο
@msg `{what}` closes something it didn't open το `{what}` κλείνει στοιχείο που δεν άνοιξε
@msg a mask that covers several layers comes in as a clipping group in each layer it covers μια μάσκα που καλύπτει πολλά επίπεδα εισάγεται ως ομάδα αποκοπής σε κάθε επίπεδο που καλύπτει
@msg a graph's records don't end where they should: its art was read as it is οι εγγραφές ενός γραφήματος δεν τελειώνουν εκεί που πρέπει: το έργο του διαβάστηκε όπως είναι
@msg `{w}` takes no operands το `{w}` δεν δέχεται τελεστέους
@msg a wraparound group is inside a compound path μια ομάδα αναδίπλωσης κειμένου βρίσκεται μέσα σε σύνθετη διαδρομή
@msg a path has too many points η διαδρομή έχει υπερβολικά πολλά σημεία
@msg it ends inside a layer τερματίζει μέσα σε επίπεδο
@msg it ends inside a multi-layer mask τερματίζει μέσα σε μάσκα πολλών επιπέδων
@msg a multi-layer mask's operators are out of order οι τελεστές μιας μάσκας πολλών επιπέδων είναι σε λάθος σειρά
@msg a multi-layer mask needs one clipping path μια μάσκα πολλών επιπέδων χρειάζεται μία διαδρομή αποκοπής
@msg a group crosses a multi-layer mask μια ομάδα διασχίζει μια μάσκα πολλών επιπέδων
@msg it has art outside its layers περιέχει σχέδιο εκτός των επιπέδων του
@msg it has more than {MAX_NODES} objects περιέχει περισσότερα από {MAX_NODES} αντικείμενα
@msg it has no layers δεν περιέχει επίπεδα
Can't render this file because it contains an unexpected character in line 164 and column 5.
+5
View File
@@ -4566,11 +4566,16 @@ axis Both Ambos
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead esto no es un logotipo de colores planos ({_1}% de sus zonas sólidas coinciden con unos pocos colores planos), así que el modo Logotipo plano convertiría sus degradados en manchas: usa el modo Color
@msg `{what}` closes nothing `{what}` no cierra nada
@msg `{what}` closes something it didn't open `{what}` cierra algo que no abrió
@msg a mask that covers several layers comes in as a clipping group in each layer it covers una máscara que cubre varias capas entra como un grupo de recorte en cada capa que cubre
@msg a graph's records don't end where they should: its art was read as it is los registros de un gráfico no terminan donde deberían: su ilustración se leyó tal cual
@msg `{w}` takes no operands `{w}` no admite operandos
@msg a wraparound group is inside a compound path un grupo de ceñir texto está dentro de un trazado compuesto
@msg a path has too many points un trazado tiene demasiados puntos
@msg it ends inside a layer terminan dentro de una capa
@msg it ends inside a multi-layer mask terminan dentro de una máscara de varias capas
@msg a multi-layer mask's operators are out of order los operadores de una máscara de varias capas están desordenados
@msg a multi-layer mask needs one clipping path una máscara de varias capas necesita un trazado de recorte
@msg a group crosses a multi-layer mask un grupo atraviesa una máscara de varias capas
@msg it has art outside its layers tienen ilustraciones fuera de sus capas
@msg it has more than {MAX_NODES} objects tienen más de {MAX_NODES} objetos
@msg it has no layers no tienen capas
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -4774,11 +4774,16 @@ imageTrace Outline Ääriviiva
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead tämä ei ole tasavärinen logo ({_1} % sen yhtenäisistä alueista vastaa muutamaa tasaväriä), joten Tasavärilogo-tila muuttaisi sen liukuvärit laikuiksi: käytä sen sijaan Väri-tilaa
@msg `{what}` closes nothing `{what}` ei sulje mitään
@msg `{what}` closes something it didn't open `{what}` sulkee jotain, mitä se ei avannut
@msg a mask that covers several layers comes in as a clipping group in each layer it covers useita tasoja peittävä maski tuodaan leikkausryhmänä jokaiseen tasoon, jonka se peittää
@msg a graph's records don't end where they should: its art was read as it is kaavion tietueet eivät pääty siihen, mihin niiden pitäisi: sen piirros luettiin sellaisenaan
@msg `{w}` takes no operands `{w}` ei ota operandeja
@msg a wraparound group is inside a compound path tekstin rivitysryhmä on yhdistelmäpolun sisällä
@msg a path has too many points polulla on liian monta pistettä
@msg it ends inside a layer se päättyy tason sisään
@msg it ends inside a multi-layer mask se päättyy monitasoisen maskin sisään
@msg a multi-layer mask's operators are out of order monitasoisen maskin operaattorit ovat väärässä järjestyksessä
@msg a multi-layer mask needs one clipping path monitasoinen maski tarvitsee yhden leikkauspolun
@msg a group crosses a multi-layer mask ryhmä ylittää monitasoisen maskin rajan
@msg it has art outside its layers siinä on kuvitusta tasojensa ulkopuolella
@msg it has more than {MAX_NODES} objects siinä on yli {MAX_NODES} objektia
@msg it has no layers siinä ei ole tasoja
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -4556,11 +4556,16 @@ axis Both Les deux
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead ce n’est pas un logo en aplats ({_1} % de ses zones pleines correspondent à quelques couleurs unies), donc le mode Logo en aplats transformerait ses dégradés en taches : utilisez le mode Couleur
@msg `{what}` closes nothing `{what}` ne ferme rien
@msg `{what}` closes something it didn't open `{what}` ferme quelque chose qu’il n’a pas ouvert
@msg a mask that covers several layers comes in as a clipping group in each layer it covers un masque qui couvre plusieurs calques est importé comme un groupe de découpe dans chaque calque qu’il couvre
@msg a graph's records don't end where they should: its art was read as it is les enregistrements d’un graphe ne se terminent pas là où ils le devraient : son illustration a été lue telle quelle
@msg `{w}` takes no operands `{w}` n’accepte aucun opérande
@msg a wraparound group is inside a compound path un groupe d’habillage de texte se trouve dans un tracé transparent
@msg a path has too many points un tracé a trop de points
@msg it ends inside a layer elles se terminent à l’intérieur d’un calque
@msg it ends inside a multi-layer mask elles se terminent à l’intérieur d’un masque multicalque
@msg a multi-layer mask's operators are out of order les opérateurs d’un masque multicalque sont dans le désordre
@msg a multi-layer mask needs one clipping path un masque multicalque nécessite un seul tracé d’écrêtage
@msg a group crosses a multi-layer mask un groupe chevauche un masque multicalque
@msg it has art outside its layers elles contiennent des illustrations hors de leurs calques
@msg it has more than {MAX_NODES} objects elles contiennent plus de {MAX_NODES} objets
@msg it has no layers elles n’ont aucun calque
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -4557,6 +4557,7 @@ imageTrace Outline Körvonal
@msg `{to}` is not an available name ez a név nem használható: `{to}`
@msg `{what}` closes nothing `{what}` semmit sem zár le
@msg `{what}` closes something it didn't open `{what}` olyat zár le, amit nem nyitott meg
@msg a mask that covers several layers comes in as a clipping group in each layer it covers a több réteget lefedő maszk minden általa lefedett rétegben vágócsoportként jön be
@msg a graph's records don't end where they should: its art was read as it is egy grafikon rekordjai nem ott érnek véget, ahol kellene: a grafikája úgy lett beolvasva, ahogy van
@msg `{w}` takes no operands `{w}` nem fogad operandusokat
@msg a wraparound group is inside a compound path egy szövegkörbefuttatási csoport összetett útvonalon belül van
@@ -4772,6 +4773,10 @@ imageTrace Outline Körvonal
@msg invalid restored panel group érvénytelen visszaállított panelcsoport
@msg is not an image VectorCraft reads nem olyan kép, amelyet a VectorCraft olvas
@msg it ends inside a layer egy rétegen belül ér véget
@msg it ends inside a multi-layer mask egy többrétegű maszkon belül ér véget
@msg a multi-layer mask's operators are out of order egy többrétegű maszk operátorai rossz sorrendben vannak
@msg a multi-layer mask needs one clipping path egy többrétegű maszkhoz egy vágóútvonal kell
@msg a group crosses a multi-layer mask egy csoport átnyúlik egy többrétegű maszkon
@msg it has art outside its layers a rétegein kívül is van grafikája
@msg it has more than one artboard egynél több rajztáblája van
@msg it has more than {MAX_NODES} objects túl sok objektumot tartalmaz (legfeljebb {MAX_NODES})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -4607,11 +4607,16 @@ axis Both Entrambi
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead questo non è un logo a colori piatti ({_1}% delle sue aree piene corrisponde a pochi colori piatti), quindi la modalità Logo piatto trasformerebbe i suoi sfumati in macchie: usa la modalità Colore
@msg `{what}` closes nothing `{what}` non chiude nulla
@msg `{what}` closes something it didn't open `{what}` chiude qualcosa che non ha aperto
@msg a mask that covers several layers comes in as a clipping group in each layer it covers una maschera che copre più livelli viene importata come gruppo di ritaglio in ogni livello che copre
@msg a graph's records don't end where they should: its art was read as it is i record di un grafico non finiscono dove dovrebbero: la sua grafica è stata letta così com’è
@msg `{w}` takes no operands `{w}` non accetta operandi
@msg a wraparound group is inside a compound path un gruppo di testo attorno si trova in un tracciato composto
@msg a path has too many points un tracciato ha troppi punti
@msg it ends inside a layer terminano all'interno di un livello
@msg it ends inside a multi-layer mask terminano all'interno di una maschera multilivello
@msg a multi-layer mask's operators are out of order gli operatori di una maschera multilivello non sono in ordine
@msg a multi-layer mask needs one clipping path una maschera multilivello richiede un solo tracciato di ritaglio
@msg a group crosses a multi-layer mask un gruppo attraversa una maschera multilivello
@msg it has art outside its layers contengono grafica al di fuori dei loro livelli
@msg it has more than {MAX_NODES} objects contengono più di {MAX_NODES} oggetti
@msg it has no layers non hanno livelli
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -4311,11 +4311,16 @@ swatch Bright Violet ビビッドバイオレット
@msg unknown command `{0}`; did you mean `{1}`? `{0}` は不明なコマンドです。`{1}` のことですか?
@msg `{what}` closes nothing `{what}` に対応する開始部分がありません
@msg `{what}` closes something it didn't open `{what}` が対応しない開始部分を閉じています
@msg a mask that covers several layers comes in as a clipping group in each layer it covers 複数のレイヤーにまたがるマスクは、覆う各レイヤーでクリップグループとして読み込まれます
@msg a graph's records don't end where they should: its art was read as it is グラフのレコードが正しい位置で終わっていません: アートはそのまま読み込まれました
@msg `{w}` takes no operands `{w}` はオペランドを取りません
@msg a wraparound group is inside a compound path テキストの回り込みグループが複合パスの中にあります
@msg a path has too many points ポイントが多すぎるパスがあります
@msg it ends inside a layer レイヤーの途中で終わっています
@msg it ends inside a multi-layer mask 複数レイヤーにまたがるマスクの途中で終わっています
@msg a multi-layer mask's operators are out of order 複数レイヤーにまたがるマスクの演算子の順序が正しくありません
@msg a multi-layer mask needs one clipping path 複数レイヤーにまたがるマスクにはクリッピングパスが 1 つ必要です
@msg a group crosses a multi-layer mask グループが複数レイヤーにまたがるマスクと交差しています
@msg it has art outside its layers レイヤーの外にアートがあります
@msg it has more than {MAX_NODES} objects オブジェクトが {MAX_NODES} 個を超えています
@msg it has no layers レイヤーがありません
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -4305,11 +4305,16 @@ font-technology Variable ცვლადი
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead ეს ერთფეროვანი ლოგო არ არის (მისი მყარი არეების {_1}% რამდენიმე ერთგვაროვან ფერს ემთხვევა), ამიტომ Flat Logo რეჟიმი მის გრადიენტებს ლაქებად აქცევდა: გამოიყენეთ Color რეჟიმი
@msg `{what}` closes nothing `{what}` არაფერს ხურავს
@msg `{what}` closes something it didn't open `{what}` ხურავს იმას, რაც არ გაუხსნია
@msg a mask that covers several layers comes in as a clipping group in each layer it covers რამდენიმე ფენის დამფარავი ნიღაბი შემოდის როგორც ჩამოჭრის ჯგუფი თითოეულ ფენაში, რომელსაც ფარავს
@msg a graph's records don't end where they should: its art was read as it is დიაგრამის ჩანაწერები იქ არ მთავრდება, სადაც უნდა: მისი გრაფიკა წაკითხულია ისე, როგორც არის
@msg `{w}` takes no operands `{w}` ოპერანდებს არ იღებს
@msg a wraparound group is inside a compound path ტექსტის გარსშემოვლების ჯგუფი შედგენილი ტრაექტორიის შიგნითაა
@msg a path has too many points ტრაექტორიას ზედმეტად ბევრი წერტილი აქვს
@msg it ends inside a layer ის შრის შიგნით მთავრდება
@msg it ends inside a multi-layer mask ის მრავალშრიანი ნიღბის შიგნით მთავრდება
@msg a multi-layer mask's operators are out of order მრავალშრიანი ნიღბის ოპერატორები არასწორი თანმიმდევრობითაა
@msg a multi-layer mask needs one clipping path მრავალშრიან ნიღაბს ერთი მომჭრელი ტრაექტორია სჭირდება
@msg a group crosses a multi-layer mask ჯგუფი მრავალშრიან ნიღაბს კვეთს
@msg it has art outside its layers მას შრეების გარეთ ნახატი აქვს
@msg it has more than {MAX_NODES} objects მას {MAX_NODES}-ზე მეტი ობიექტი აქვს
@msg it has no layers მას შრეები არ აქვს
Can't render this file because it is too large.
+5
View File
@@ -4238,11 +4238,16 @@ theme Appearance 외관
@msg unknown command `{0}`; did you mean `{1}`? 알 수 없는 명령 `{0}`: `{1}`을(를) 의미하셨습니까?
@msg `{what}` closes nothing `{what}`이(가) 닫는 항목이 없습니다
@msg `{what}` closes something it didn't open `{what}`이(가) 열지 않은 항목을 닫습니다
@msg a mask that covers several layers comes in as a clipping group in each layer it covers 여러 레이어에 걸친 마스크는 덮는 각 레이어에서 클리핑 그룹으로 들어옵니다
@msg a graph's records don't end where they should: its art was read as it is 그래프의 레코드가 끝나야 할 곳에서 끝나지 않습니다: 아트는 있는 그대로 읽었습니다
@msg `{w}` takes no operands `{w}`은(는) 피연산자를 받지 않습니다
@msg a wraparound group is inside a compound path 문자 감싸기 그룹이 컴파운드 패스 안에 있습니다
@msg a path has too many points 패스의 점이 너무 많습니다
@msg it ends inside a layer 레이어 안에서 끝납니다
@msg it ends inside a multi-layer mask 여러 레이어 마스크 안에서 끝납니다
@msg a multi-layer mask's operators are out of order 여러 레이어 마스크의 연산자 순서가 잘못되었습니다
@msg a multi-layer mask needs one clipping path 여러 레이어 마스크에는 클리핑 패스가 하나 필요합니다
@msg a group crosses a multi-layer mask 그룹이 여러 레이어 마스크에 걸쳐 있습니다
@msg it has art outside its layers 레이어 밖에 아트웍이 있습니다
@msg it has more than {MAX_NODES} objects 개체가 {MAX_NODES}개를 넘습니다
@msg it has no layers 레이어가 없습니다
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -4698,11 +4698,16 @@ imageTrace Outline Kontur
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead to nie jest logo z płaskimi kolorami ({_1}% jego jednolitych obszarów pasuje do kilku płaskich kolorów), więc tryb Płaskie logo zamieniłby jego gradienty w plamy: użyj trybu Kolor
@msg `{what}` closes nothing `{what}` niczego nie zamyka
@msg `{what}` closes something it didn't open `{what}` zamyka coś, czego nie otworzył
@msg a mask that covers several layers comes in as a clipping group in each layer it covers maska obejmująca kilka warstw jest wczytywana jako grupa przycinająca w każdej obejmowanej warstwie
@msg a graph's records don't end where they should: its art was read as it is rekordy wykresu nie kończą się tam, gdzie powinny: jego grafika została wczytana tak, jak jest
@msg `{w}` takes no operands `{w}` nie przyjmuje operandów
@msg a wraparound group is inside a compound path grupa oblewania tekstem jest wewnątrz ścieżki złożonej
@msg a path has too many points ścieżka ma zbyt wiele punktów
@msg it ends inside a layer kończy się wewnątrz warstwy
@msg it ends inside a multi-layer mask kończy się wewnątrz maski wielowarstwowej
@msg a multi-layer mask's operators are out of order operatory maski wielowarstwowej są w złej kolejności
@msg a multi-layer mask needs one clipping path maska wielowarstwowa wymaga jednej ścieżki przycinającej
@msg a group crosses a multi-layer mask grupa przecina maskę wielowarstwową
@msg it has art outside its layers ma kompozycję poza warstwami
@msg it has more than {MAX_NODES} objects ma ponad {MAX_NODES} obiektów
@msg it has no layers nie ma warstw
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -4148,11 +4148,16 @@ axis Both Ambos
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead este não é um logotipo de cores chapadas ({_1}% de suas áreas sólidas correspondem a poucas cores chapadas), então o modo Logotipo plano transformaria seus gradientes em manchas: use o modo Cor
@msg `{what}` closes nothing `{what}` não fecha nada
@msg `{what}` closes something it didn't open `{what}` fecha algo que não abriu
@msg a mask that covers several layers comes in as a clipping group in each layer it covers uma máscara que cobre várias camadas entra como um grupo de recorte em cada camada que cobre
@msg a graph's records don't end where they should: its art was read as it is os registros de um gráfico não terminam onde deveriam: sua arte foi lida como está
@msg `{w}` takes no operands `{w}` não aceita operandos
@msg a wraparound group is inside a compound path um grupo de quebra de texto está dentro de um traçado composto
@msg a path has too many points um traçado tem pontos demais
@msg it ends inside a layer termina dentro de uma camada
@msg it ends inside a multi-layer mask termina dentro de uma máscara de várias camadas
@msg a multi-layer mask's operators are out of order os operadores de uma máscara de várias camadas estão fora de ordem
@msg a multi-layer mask needs one clipping path uma máscara de várias camadas precisa de um caminho de recorte
@msg a group crosses a multi-layer mask um grupo atravessa uma máscara de várias camadas
@msg it has art outside its layers tem arte fora de suas camadas
@msg it has more than {MAX_NODES} objects tem mais de {MAX_NODES} objetos
@msg it has no layers não tem camadas
Can't render this file because it contains an unexpected character in line 6 and column 47.
+5
View File
@@ -4602,11 +4602,16 @@ axis Both Оба
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead это не логотип из плоских цветов ({_1}% его сплошных областей совпадает с несколькими плоскими цветами), поэтому режим «Плоский логотип» превратил бы градиенты в пятна: используйте режим «Цвет»
@msg `{what}` closes nothing `{what}` ничего не закрывает
@msg `{what}` closes something it didn't open `{what}` закрывает то, что не открывал
@msg a mask that covers several layers comes in as a clipping group in each layer it covers маска, охватывающая несколько слоёв, переносится как обтравочная группа в каждый слой, который она охватывает
@msg a graph's records don't end where they should: its art was read as it is записи диаграммы не заканчиваются там, где должны: её графика прочитана как есть
@msg `{w}` takes no operands `{w}` не принимает операндов
@msg a wraparound group is inside a compound path группа обтекания текстом находится внутри составного контура
@msg a path has too many points в контуре слишком много точек
@msg it ends inside a layer они заканчиваются внутри слоя
@msg it ends inside a multi-layer mask они заканчиваются внутри многослойной маски
@msg a multi-layer mask's operators are out of order операторы многослойной маски идут в неправильном порядке
@msg a multi-layer mask needs one clipping path многослойной маске нужен один контур обрезки
@msg a group crosses a multi-layer mask группа пересекает многослойную маску
@msg it has art outside its layers в них есть графика вне слоёв
@msg it has more than {MAX_NODES} objects в них больше {MAX_NODES} объектов
@msg it has no layers в них нет слоёв
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -4465,11 +4465,16 @@ axis Both Båda
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead det här är ingen logotyp i platta färger ({_1} % av dess enfärgade ytor matchar några få platta färger), så läget Platt logotyp skulle göra om dess gradienter till fläckar: använd läget Färg i stället
@msg `{what}` closes nothing `{what}` stänger ingenting
@msg `{what}` closes something it didn't open `{what}` stänger något som den inte öppnade
@msg a mask that covers several layers comes in as a clipping group in each layer it covers en mask som täcker flera lager kommer in som en urklippsgrupp i varje lager den täcker
@msg a graph's records don't end where they should: its art was read as it is ett diagrams poster slutar inte där de ska: dess grafik lästes som den är
@msg `{w}` takes no operands `{w}` tar inga operander
@msg a wraparound group is inside a compound path en textombrytningsgrupp ligger inuti en sammansatt bana
@msg a path has too many points en bana har för många punkter
@msg it ends inside a layer den slutar inuti ett lager
@msg it ends inside a multi-layer mask den slutar inuti en flerlagersmask
@msg a multi-layer mask's operators are out of order operatorerna för en flerlagersmask står i fel ordning
@msg a multi-layer mask needs one clipping path en flerlagersmask behöver en klippbana
@msg a group crosses a multi-layer mask en grupp korsar en flerlagersmask
@msg it has art outside its layers den har grafik utanför sina lager
@msg it has more than {MAX_NODES} objects den har fler än {MAX_NODES} objekt
@msg it has no layers den har inga lager
Can't render this file because it contains an unexpected character in line 5 and column 25.
+5
View File
@@ -4303,11 +4303,16 @@ axis Both Her İkisi
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead bu düz renkli bir logo değildir (düz alanların %{_1}'si birkaç düz renkle eşleşir), dolayısıyla Düz Logo modu degradelerini yamalara dönüştürür: bunun yerine Renk modunu kullanın
@msg `{what}` closes nothing `{what}` hiçbir şeyi kapatmaz
@msg `{what}` closes something it didn't open `{what}` açmadığı bir şeyi kapatıyor
@msg a mask that covers several layers comes in as a clipping group in each layer it covers birkaç katmanı kaplayan bir maske, kapladığı her katmana bir kırpma grubu olarak gelir
@msg a graph's records don't end where they should: its art was read as it is bir grafiğin kayıtları bitmesi gereken yerde bitmiyor: resmi olduğu gibi okundu
@msg `{w}` takes no operands `{w}` işlenen almaz
@msg a wraparound group is inside a compound path bir metin kaydırma grubu bileşik bir yolun içinde
@msg a path has too many points bir yolun çok fazla noktası var
@msg it ends inside a layer bir katmanın içinde bitiyor
@msg it ends inside a multi-layer mask çok katmanlı bir maskenin içinde bitiyor
@msg a multi-layer mask's operators are out of order çok katmanlı bir maskenin işleçleri yanlış sırada
@msg a multi-layer mask needs one clipping path çok katmanlı bir maskenin bir kırpma yoluna ihtiyacı var
@msg a group crosses a multi-layer mask bir grup çok katmanlı bir maskeyi kesiyor
@msg it has art outside its layers katmanlarının dışında sanat var
@msg it has more than {MAX_NODES} objects {MAX_NODES}'den daha fazla nesneye sahip
@msg it has no layers katmanı yok
Can't render this file because it contains an unexpected character in line 5 and column 25.
+5
View File
@@ -4591,11 +4591,16 @@ axis Both Обидві
@msg this isn't a flat-colour logo ({_1}% of its solid areas match a few flat colours), so Flat Logo mode would turn its gradients into patches: use Color mode instead це не логотип із плоских кольорів ({_1}% його суцільних областей збігається з кількома плоскими кольорами), тому режим «Плоский логотип» перетворив би градієнти на плями: використовуйте режим «Колір»
@msg `{what}` closes nothing `{what}` нічого не закриває
@msg `{what}` closes something it didn't open `{what}` закриває те, що не відкривав
@msg a mask that covers several layers comes in as a clipping group in each layer it covers маску, що охоплює кілька шарів, перенесено як групу відсікання в кожен шар, який вона охоплює
@msg a graph's records don't end where they should: its art was read as it is записи діаграми не закінчуються там, де мають: її графіку прочитано як є
@msg `{w}` takes no operands `{w}` не приймає операндів
@msg a wraparound group is inside a compound path група обтікання текстом розташована всередині складеного контуру
@msg a path has too many points у контурі занадто багато точок
@msg it ends inside a layer вони закінчуються всередині шару
@msg it ends inside a multi-layer mask вони закінчуються всередині багатошарової маски
@msg a multi-layer mask's operators are out of order оператори багатошарової маски йдуть у неправильному порядку
@msg a multi-layer mask needs one clipping path багатошаровій масці потрібен один відсічний контур
@msg a group crosses a multi-layer mask група перетинає багатошарову маску
@msg it has art outside its layers у них є графіка поза шарами
@msg it has more than {MAX_NODES} objects в них більше {MAX_NODES} об’єктів
@msg it has no layers у них немає шарів
Can't render this file because it contains an unexpected character in line 178 and column 5.
+5
View File
@@ -4209,6 +4209,7 @@ theme Appearance Giao diện
@msg `{to}` is not an available name `{to}` không phải là tên khả dụng
@msg `{what}` closes nothing `{what}` không đóng gì
@msg `{what}` closes something it didn't open `{what}` đóng thứ nó chưa mở
@msg a mask that covers several layers comes in as a clipping group in each layer it covers một mặt nạ phủ nhiều lớp được nhập thành một nhóm cắt xén trong mỗi lớp mà nó phủ
@msg a graph's records don't end where they should: its art was read as it is các bản ghi của một biểu đồ không kết thúc đúng chỗ: hình vẽ của nó được đọc nguyên trạng
@msg `{w}` takes no operands `{w}` không nhận toán hạng
@msg a wraparound group is inside a compound path một nhóm bao văn bản nằm trong một đường dẫn phức
@@ -4422,6 +4423,10 @@ theme Appearance Giao diện
@msg invalid restored panel group nhóm bảng được phục hồi không hợp lệ
@msg is not an image VectorCraft reads không phải ảnh mà VectorCraft đọc được
@msg it ends inside a layer nó kết thúc bên trong một lớp
@msg it ends inside a multi-layer mask nó kết thúc bên trong một mặt nạ nhiều lớp
@msg a multi-layer mask's operators are out of order các toán tử của mặt nạ nhiều lớp không đúng thứ tự
@msg a multi-layer mask needs one clipping path mặt nạ nhiều lớp cần một đường dẫn cắt
@msg a group crosses a multi-layer mask một nhóm vắt ngang mặt nạ nhiều lớp
@msg it has art outside its layers nó có tác phẩm ngoài các lớp
@msg it has more than one artboard nó có nhiều hơn một bảng vẽ
@msg it has more than {MAX_NODES} objects nó có hơn {MAX_NODES} đối tượng
Can't render this file because it contains an unexpected character in line 200 and column 5.
+5
View File
@@ -4036,11 +4036,16 @@ imageTrace Outline 轮廓
@msg unknown command `{0}`; did you mean `{1}`? 未知命令 `{0}`;您是否想输入 `{1}`?
@msg `{what}` closes nothing `{what}` 没有可结束的内容
@msg `{what}` closes something it didn't open `{what}` 结束了并非由它开始的内容
@msg a mask that covers several layers comes in as a clipping group in each layer it covers 覆盖多个图层的蒙版会在其覆盖的每个图层中作为剪切组导入
@msg a graph's records don't end where they should: its art was read as it is 图表的记录没有在应有的位置结束:其图稿按原样读取
@msg `{w}` takes no operands `{w}` 不接受操作数
@msg a wraparound group is inside a compound path 文本绕排组位于复合路径内
@msg a path has too many points 某条路径的点过多
@msg it ends inside a layer 它在图层内部结束
@msg it ends inside a multi-layer mask 它在跨图层蒙版内部结束
@msg a multi-layer mask's operators are out of order 跨图层蒙版的运算符顺序错误
@msg a multi-layer mask needs one clipping path 跨图层蒙版需要一条剪切路径
@msg a group crosses a multi-layer mask 编组跨越了跨图层蒙版
@msg it has art outside its layers 它有位于图层之外的图稿
@msg it has more than {MAX_NODES} objects 它包含超过 {MAX_NODES} 个对象
@msg it has no layers 它没有图层
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5
View File
@@ -1958,11 +1958,16 @@ file-filter Templates 範本
@msg unknown command `{0}`; did you mean `{1}`? 未知的指令 `{0}`;您是指 `{1}` 嗎?
@msg `{what}` closes nothing `{what}` 沒有可結束的內容
@msg `{what}` closes something it didn't open `{what}` 結束了並非由它開始的內容
@msg a mask that covers several layers comes in as a clipping group in each layer it covers 覆蓋多個圖層的遮色片會在其覆蓋的每個圖層中作為剪裁群組匯入
@msg a graph's records don't end where they should: its art was read as it is 圖表的記錄沒有在應有的位置結束:其圖稿按原樣讀取
@msg `{w}` takes no operands `{w}` 不接受運算元
@msg a wraparound group is inside a compound path 文字繞圖群組位於複合路徑內
@msg a path has too many points 有一條路徑的點過多
@msg it ends inside a layer 它在圖層內部結束
@msg it ends inside a multi-layer mask 它在跨圖層遮色片內部結束
@msg a multi-layer mask's operators are out of order 跨圖層遮色片的運算子順序錯誤
@msg a multi-layer mask needs one clipping path 跨圖層遮色片需要一條剪裁路徑
@msg a group crosses a multi-layer mask 群組跨越了跨圖層遮色片
@msg it has art outside its layers 它有位於圖層之外的圖稿
@msg it has more than {MAX_NODES} objects 它有超過 {MAX_NODES} 個物件
@msg it has no layers 它沒有圖層
Can't render this file because it contains an unexpected character in line 6 and column 47.
+2
View File
@@ -43,6 +43,8 @@ private editing data. VectorCraft:
write) is its own editing data: it opens through the layers its program has, compared with its page
when the program runs, from the layers alone when it names its prolog without including it (#1027), and with its art on one
layer when it has no layers (Illustrator 3, and image editors' exported paths: storytold/photocraft#6036).
A multi-layer mask (`Mb` … `Md` … `MB`) comes in as a clipping group in each layer it covers, each
clipped by a copy of the mask's path.
RGB in the PDF page's `ICCBased` spaces keeps the file's numbers in a `.ai` (the `uncalibrated_rgb`
import option, on for editor documents, off for PDFs), so `.ai` files tagged with a non-sRGB RGB profile
open with different, unconverted RGB colours than before.