From 2c5f3b9d20cddc5e75ac9427fe9cfa7736c38e0b Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sat, 14 Nov 2026 10:33:00 -0800 Subject: [PATCH] SVG import: refuse an SVG whose use copies and styles expand past the limits usvg copies the element a shows, and every copy gets its own copy of the declarations its style attribute and matching style sheet rules give it. A chain of s that doubles at each level made usvg build those copies before the import's object limit was checked: a 101 kB file whose rectangle has a 100 kB style took 4.7 GB at 14 levels, and one 100 kB style sheet rule on 16,000 groups took 1.5 GB without any . A plain chain stopped at usvg's own 1,000,000-node limit with a parse error. The import now measures, before usvg reads the SVG, how many elements it expands to and how many bytes of style values those elements copy, each element measured once and each counted as one addition. References follow usvg's rules: first element of an id, href before xlink:href, and the self and back references usvg leaves out. An SVG past 999,999 elements (500,000 on the web) is refused as too large, a loop of references usvg would copy without end is refused too, and one past 64 MB of copied style values is refused with the new SvgError::StylesTooLarge. SVG images count toward the same 64 MB as the SVG showing them, an image past either limit refuses the whole import, and an image that doesn't decode does not count. --- crates/svg/src/import.rs | 10 + crates/svg/src/import/budget.rs | 462 ++++++++++++++++++++++++++ crates/svg/src/import/files.rs | 42 ++- crates/svg/src/lib.rs | 4 + crates/svg/tests/it/import_details.rs | 60 ++++ crates/ui-egui/src/i18n/ca.tsv | 1 + crates/ui-egui/src/i18n/cs.tsv | 1 + crates/ui-egui/src/i18n/de.tsv | 1 + crates/ui-egui/src/i18n/el.tsv | 1 + crates/ui-egui/src/i18n/es.tsv | 1 + crates/ui-egui/src/i18n/fi.tsv | 1 + crates/ui-egui/src/i18n/fr.tsv | 1 + crates/ui-egui/src/i18n/hi.tsv | 1 + crates/ui-egui/src/i18n/hu.tsv | 1 + crates/ui-egui/src/i18n/it.tsv | 1 + crates/ui-egui/src/i18n/ja.tsv | 1 + crates/ui-egui/src/i18n/ka.tsv | 1 + crates/ui-egui/src/i18n/ko.tsv | 1 + crates/ui-egui/src/i18n/nl.tsv | 1 + crates/ui-egui/src/i18n/pl.tsv | 1 + crates/ui-egui/src/i18n/pt-br.tsv | 1 + crates/ui-egui/src/i18n/ru.tsv | 1 + crates/ui-egui/src/i18n/sv.tsv | 1 + crates/ui-egui/src/i18n/tr.tsv | 1 + crates/ui-egui/src/i18n/uk.tsv | 1 + crates/ui-egui/src/i18n/vi.tsv | 1 + crates/ui-egui/src/i18n/zh-hans.tsv | 1 + crates/ui-egui/src/i18n/zh-hant.tsv | 1 + docs/target-app-parity.md | 1 + 29 files changed, 600 insertions(+), 2 deletions(-) create mode 100644 crates/svg/src/import/budget.rs diff --git a/crates/svg/src/import.rs b/crates/svg/src/import.rs index 087512bf90..b583f3dc03 100644 --- a/crates/svg/src/import.rs +++ b/crates/svg/src/import.rs @@ -43,6 +43,7 @@ pub(super) use prepass::Edits; use prepass::{Extras, labels, prepass}; pub use prepass::{MAX_FOREIGN, MAX_FOREIGN_VALUE}; +mod budget; mod css; mod css_transform; mod depth; @@ -154,7 +155,13 @@ pub(crate) fn import_finding( let mut warnings = found.warnings; let text_xml = found.text_source.as_deref().map(parse).transpose()?; let (src, slots) = text::prepare(svg, &xml, text_xml.as_ref(), units.dpi, &mut warnings); + // Before usvg copies what ``s show and the style values of each copy: the text usvg reads. + let styles = match &src { + Cow::Borrowed(_) => budget::check(&xml, budget::MAX_COPIED_STYLES)?, + Cow::Owned(prepared) => budget::check(&parse(prepared)?, budget::MAX_COPIED_STYLES)?, + }; let files = found.files; + files.copied_styles(styles); let tree = { let opt = usvg::Options { dpi: units.dpi as f32, @@ -164,6 +171,9 @@ pub(crate) fn import_finding( }; usvg::Tree::from_str(&src, &opt).map_err(|e| SvgError::Parse(e.to_string()))? }; + if let Some(err) = files.refused() { + return Err(err); + } let size = tree.size(); let k = units.k; let mut doc = Document::new(size.width() as f64 * k, size.height() as f64 * k); diff --git a/crates/svg/src/import/budget.rs b/crates/svg/src/import/budget.rs new file mode 100644 index 0000000000..c2ff01a02f --- /dev/null +++ b/crates/svg/src/import/budget.rs @@ -0,0 +1,462 @@ +//! What usvg makes of an SVG, measured in the XML before usvg runs: how many elements it makes, +//! and how many bytes of style values it copies into them. +//! +//! usvg makes an element of each SVG element, and of each element a `` shows a copy of, by +//! copying what the `` refers to. Each copy gets its own copy of every declaration the style +//! sheets and the `style` attribute give the element, so a long style on an element that ``s +//! copy, again and again in a chain, or that a style sheet rule gives to many elements, takes more +//! memory than the file holds many times over. usvg stops past 1,000,000 elements, but only after +//! it has made them and copied their styles. An SVG past [`MAX_SVG_ELEMENTS`] elements or +//! [`MAX_COPIED_STYLES`] bytes of copied styles is refused here instead. +//! +//! The copies are counted, never made: each element's count is worked out once and added up, so a +//! `` of an element costs one addition, however many elements its copy holds. References +//! follow usvg 0.48.1 (`parser/svgtree/parse.rs`): an id names the first element that has it, an +//! unprefixed `href` wins over `xlink:href`, and a `` of itself, of the `` its own copy +//! starts from, or of an element holding a `` of the element or of the ``, is left out. +//! Any other loop of references makes usvg copy without end, so an SVG with one is refused. usvg +//! looks for those ``s inside an element only in the SVG namespace: in an SVG without one, a +//! `` that leads back to the `` its copy starts from is refused here too, though usvg +//! would leave it out. +//! +//! The style sheets' rules are matched against each element once, as usvg matches them against +//! each copy. + +use std::collections::{HashMap, HashSet}; + +use usvg::roxmltree; + +use super::{MAX_NODES, SVG_NS, XNode}; +use crate::SvgError; + +/// Most elements usvg may make of an SVG: [`MAX_NODES`], and below the 1,000,000 elements past +/// which usvg stops (its count includes a root of its own). +pub(crate) const MAX_SVG_ELEMENTS: usize = if MAX_NODES < 999_999 { MAX_NODES } else { 999_999 }; + +/// Most bytes of style values usvg may copy into the elements of an SVG and the SVG images it +/// shows, all together: VectorCraft's own limit. +pub(crate) const MAX_COPIED_STYLES: u64 = 64 << 20; + +/// What usvg keeps for each value it copies besides its bytes (the count and length of a shared +/// string). +const COPY: u64 = 16; + +/// The longhands a `font` shorthand resets before setting the ones it gives, and the most bytes of +/// each reset value (`normal`). +const FONT_RESETS: u64 = 12; +const RESET_VALUE: u64 = 6; + +/// The longhands a `font` shorthand sets from its own text. +const FONT_PARTS: u64 = 6; + +const XLINK_NS: &str = "http://www.w3.org/1999/xlink"; + +/// The elements usvg reads (`EId` in usvg's `parser/svgtree/names.rs`); it skips the others with +/// everything inside them. +const ELEMENTS: [&str; 53] = [ + "a", + "circle", + "clipPath", + "defs", + "ellipse", + "feBlend", + "feColorMatrix", + "feComponentTransfer", + "feComposite", + "feConvolveMatrix", + "feDiffuseLighting", + "feDisplacementMap", + "feDistantLight", + "feDropShadow", + "feFlood", + "feFuncA", + "feFuncB", + "feFuncG", + "feFuncR", + "feGaussianBlur", + "feImage", + "feMerge", + "feMergeNode", + "feMorphology", + "feOffset", + "fePointLight", + "feSpecularLighting", + "feSpotLight", + "feTile", + "feTurbulence", + "filter", + "g", + "image", + "line", + "linearGradient", + "marker", + "mask", + "path", + "pattern", + "polygon", + "polyline", + "radialGradient", + "rect", + "stop", + "style", + "svg", + "switch", + "symbol", + "text", + "textPath", + "tref", + "tspan", + "use", +]; + +/// The name of element `n` when usvg reads it: in the SVG namespace or none, and one of +/// [`ELEMENTS`]. +fn svg_name<'a>(n: XNode<'a, '_>) -> Option<&'a str> { + let name = n.tag_name(); + (n.is_element() && matches!(name.namespace(), None | Some(SVG_NS)) && ELEMENTS.contains(&name.name())).then(|| name.name()) +} + +/// An element as the style sheets' selectors see it, as usvg matches them. +struct Element<'a, 'i>(XNode<'a, 'i>); + +impl simplecss::Element for Element<'_, '_> { + fn parent_element(&self) -> Option { + self.0.parent_element().map(Self) + } + + fn prev_sibling_element(&self) -> Option { + self.0.prev_sibling_element().map(Self) + } + + fn has_local_name(&self, name: &str) -> bool { + self.0.tag_name().name() == name + } + + fn attribute_matches(&self, name: &str, operator: simplecss::AttributeOperator<'_>) -> bool { + self.0.attribute(name).is_some_and(|value| operator.matches(value)) + } + + fn pseudo_class_matches(&self, class: simplecss::PseudoClass<'_>) -> bool { + matches!(class, simplecss::PseudoClass::FirstChild) && self.0.prev_sibling_element().is_none() + } +} + +/// The bytes usvg copies for one declaration: three markers for `marker`, the resets and longhands +/// for `font`, its value for any other. Counted for every declaration, the ones usvg then drops (a +/// property it doesn't read, a value an earlier one overrides) too. +fn copied(declaration: &simplecss::Declaration) -> u64 { + let len = declaration.value.len() as u64; + match declaration.name { + "marker" => 3 * (COPY + len), + "font" => (FONT_RESETS + FONT_PARTS) * COPY + FONT_RESETS * RESET_VALUE + len, + _ => COPY + len, + } +} + +/// What usvg makes of one element: elements (text nodes included) and bytes of copied styles. +#[derive(Clone, Copy, Default)] +struct Cost { + elements: u64, + bytes: u64, +} + +impl Cost { + fn add(self, other: Cost) -> Cost { + Cost { elements: self.elements.saturating_add(other.elements), bytes: self.bytes.saturating_add(other.bytes) } + } +} + +/// What a `` shows: nothing, the element it refers to with all it holds, or only that +/// element (a `` whose own reference leads back to the `` showing it). +enum Shows<'a, 'i> { + Nothing, + All(XNode<'a, 'i>), + Bare(XNode<'a, 'i>), +} + +struct Measure<'a, 'i> { + /// The first element of each id. + ids: HashMap<&'a str, XNode<'a, 'i>>, + sheet: simplecss::StyleSheet<'a>, + /// The elements that hold a `` of themselves. + holds_use_of_itself: HashSet, + /// The ``s of each element, by the element. + used_by: HashMap>>, + /// The bytes of text in each element a `` shows. + tref_text: HashMap, +} + +impl<'a, 'i> Measure<'a, 'i> { + fn new(xml: &'a roxmltree::Document<'i>) -> Self { + let mut ids = HashMap::new(); + for n in xml.descendants() { + if let Some(id) = n.attribute("id") { + ids.entry(id).or_insert(n); + } + } + // The style sheets usvg reads: `{groups}"))); + assert_eq!(bytes, 4 * 19 + 20); + // A style sheet of another type is not read; the style element itself makes nothing. + assert_eq!(cost(&svg(&format!("{groups}"))), (5, 0)); + // `marker` sets three properties; `font` resets twelve and sets six from its text. + let (_, marker) = cost(&svg("")); + let (_, font) = cost(&svg("")); + assert_eq!((marker, font), (3 * (16 + 7), 18 * 16 + 12 * 6 + 6)); + } + + #[test] + fn references_usvg_leaves_out_copy_nothing() { + // A use of itself, of a group holding it, of what isn't there or isn't SVG. + let (n, _) = cost(&svg("")); + assert_eq!(n, 1 + 1 + 3 + 1 + 1); + // Two uses of each other: each shows the other alone. + assert_eq!(cost(&svg("")).0, 1 + 2 + 2); + // A group holding a use of the use that shows it: that use shows nothing, and the one the + // group holds shows it alone. + let back = svg(""); + assert_eq!(cost(&back).0, 1 + 3 + 1); + // The unprefixed href wins, and an id names its first element. + let first = svg(""); + assert_eq!(cost(&first).0, 1 + 3 + 1 + 1 + 2 + 4); + } + + #[test] + fn a_loop_usvg_copies_without_end_is_refused_as_usvg_refuses_it() { + let looped = svg(""); + assert_eq!(past(&looped, u64::MAX, u64::MAX), Some(Past::Elements)); + assert!(usvg::Tree::from_str(&looped, &usvg::Options::default()).is_err()); + // Without the loop, usvg reads it. + let open = svg(""); + assert!(past(&open, u64::MAX, u64::MAX).is_none() && usvg::Tree::from_str(&open, &usvg::Options::default()).is_ok()); + } + + #[test] + fn text_counts_its_runs_and_what_trefs_show() { + let (n, bytes) = cost(&svg("abcdxyz")); + // svg, g (its text is not counted outside a text), text, its runs "xy" and "z", tspan, tref and its text. + assert_eq!(n, 1 + 1 + 1 + 2 + 1 + 1 + 1); + assert_eq!(bytes, (16 + 2) + (16 + 1) + (16 + 4)); + } +} diff --git a/crates/svg/src/import/files.rs b/crates/svg/src/import/files.rs index d2b5504f9d..429c39c70f 100644 --- a/crates/svg/src/import/files.rs +++ b/crates/svg/src/import/files.rs @@ -21,7 +21,7 @@ use usvg::{ImageHrefResolver, ImageKind, roxmltree}; use vectorcraft_doc::LinkInfo; use vectorcraft_doc::links::missing_placeholder; -use super::{Edits, depth, href}; +use super::{Edits, budget, depth, href}; use crate::{ImportOptions, MAX_ELEMENT_DEPTH, MAX_SVGZ, SvgError}; /// Most nested SVG images an imported SVG may decode (#3564). @@ -74,6 +74,12 @@ pub(in crate::import) struct Files { /// The CMYK TIFF stored in place of a turned CMYK image, by the address of the PNG usvg got /// (kept here too, so the address stays its own). cmyk: Mutex>, + /// The bytes of style values usvg copies into the elements of the SVG and of the SVG images + /// read so far ([`budget`]). + styles: AtomicU64, + /// Why an SVG image refused the whole SVG: what usvg would make of it is past [`budget`]'s + /// limits. The first one. + refused: Mutex>, } /// Encoded image bytes, shared. @@ -479,6 +485,17 @@ impl Files { notes } + /// The SVG holding the images copies `bytes` of style values ([`budget::check`]): its images + /// copy at most what is left. + pub(in crate::import) fn copied_styles(&self, bytes: u64) { + self.styles.store(bytes, Ordering::Relaxed); + } + + /// The error of the first SVG image past [`budget`]'s limits, which refuses the SVG holding it. + pub(in crate::import) fn refused(&self) -> Option { + self.refused.lock().ok().and_then(|r| r.clone()) + } + fn note_text(&self, svg: &str) { if svg.contains(">, opts: &usvg::Options) -> Option { + // The SVG holding it is refused already: no more images are read. + if self.refused().is_some() { + return None; + } // Measured as the SVG holding it is (`import`): the text before the XML reader. let used = self.depth.load(Ordering::Relaxed); let left = MAX_ELEMENT_DEPTH.saturating_sub(used); @@ -569,6 +590,19 @@ impl Files { let Some(height) = depth::height(&xml, left) else { return leave_out(&self.too_deep, true) }; // usvg's parser would overflow on it, as on the SVG holding it (`import`). super::convolve_matrices_ok(&xml).ok()?; + // What usvg would make of it, measured as the SVG holding it is (`import`), its copied + // styles counted with theirs while usvg reads it, and kept only when it decodes: past the + // limits, the whole SVG is refused. + let spent = self.styles.load(Ordering::Relaxed); + match budget::check(&xml, budget::MAX_COPIED_STYLES.saturating_sub(spent)) { + Ok(bytes) => self.styles.store(spent.saturating_add(bytes), Ordering::Relaxed), + Err(e) => { + if let Ok(mut refused) = self.refused.lock() { + refused.get_or_insert(e); + } + return None; + } + } self.depth.store(used + height, Ordering::Relaxed); let within = self.within.lock().ok().map(|mut w| w.push(file)).is_some(); // usvg's `Tree::from_data_nested`, except that hrefs to files go to the resolver. @@ -592,7 +626,11 @@ impl Files { w.pop(); } self.depth.store(used, Ordering::Relaxed); - let tree = tree.ok()?; + let Ok(tree) = tree else { + // Left out: neither it nor the images inside it count. + self.styles.store(spent, Ordering::Relaxed); + return None; + }; self.note_text(text); Some(ImageKind::SVG(tree)) } diff --git a/crates/svg/src/lib.rs b/crates/svg/src/lib.rs index b035e6cd10..daf3288920 100644 --- a/crates/svg/src/lib.rs +++ b/crates/svg/src/lib.rs @@ -366,6 +366,10 @@ pub enum SvgError { /// nested-image expansion bombs, #3564). #[error("the SVG expands to more than {0} nested SVG images")] TooManyImages(usize), + /// The style values the reader would copy into the elements the SVG expands to, `` + /// copies and SVG images included, add up to more than this many megabytes. + #[error("the SVG's styles expand to more than {0} MB")] + StylesTooLarge(usize), } /// Export a document as an SVG string (linked images are not returned: see [`export_full`]). diff --git a/crates/svg/tests/it/import_details.rs b/crates/svg/tests/it/import_details.rs index 69e5cafa21..6276f5ee77 100644 --- a/crates/svg/tests/it/import_details.rs +++ b/crates/svg/tests/it/import_details.rs @@ -851,6 +851,66 @@ fn nested_image_within_budget_imports_and_use_fan_out_is_refused() { assert!(matches!(err, SvgError::TooLarge(15)), "{err:?}"); } +/// Groups `g0` to `g{levels}`: `g0` a rectangle styled `style`, each other two ``s of the +/// one before; one `` of the last shown. +fn use_chain(levels: usize, style: &str) -> String { + let links: String = (1..=levels).map(|i| format!(r##""##, i - 1)).collect(); + svg(&format!(r##"{links}"##)) +} + +/// A style value of 100,000 bytes. +fn long_style() -> String { + format!("font-family:{}", "a".repeat(100_000)) +} + +/// A long style that a chain of ``s copies, or that a style sheet rule gives to many +/// elements, is refused before usvg copies it; short styles import, a rule that matches nothing +/// costing nothing. +#[test] +fn styles_that_expand_past_the_limit_are_refused() { + let err = import_with(&use_chain(10, &long_style()), &ImportOptions::default()).unwrap_err(); + assert!(matches!(err, SvgError::StylesTooLarge(64)), "{err:?}"); + assert_eq!(err.to_string(), "the SVG's styles expand to more than 64 MB"); + // 1,000 groups that one rule gives the long style, without any ``. + let sheet = svg(&format!("{}", long_style(), "".repeat(1000))); + let err = import_with(&sheet, &ImportOptions::default()).unwrap_err(); + assert!(matches!(err, SvgError::StylesTooLarge(64)), "{err:?}"); + + // The chain with a short style shows its 1,024 rectangles. + let (d, _) = import_with(&use_chain(10, "fill:red"), &ImportOptions::default()).unwrap(); + assert_eq!(art(&d).iter().filter(|n| n.children().is_none()).count(), 1024); + // 5,000 rectangles of a class with short rules, beside a long rule that matches none of them. + let rules = format!(".a{{fill:#123456;stroke:#654321;stroke-width:2;opacity:.5}} .b{{{}}}", long_style()); + let classed = svg(&format!("{}", r#""#.repeat(5000))); + let (d, _) = import_with(&classed, &ImportOptions::default()).unwrap(); + assert_eq!(art(&d).len(), 5000); +} + +/// A chain of ``s that makes more elements than usvg reads is refused before usvg makes them. +#[test] +fn a_use_chain_past_the_elements_usvg_reads_is_refused() { + let err = import_with(&use_chain(20, ""), &ImportOptions::default()).unwrap_err(); + assert!(matches!(err, SvgError::TooLarge(n) if n == vectorcraft_svg::MAX_NODES.min(999_999)), "{err:?}"); +} + +/// An SVG image whose styles expand past the limit refuses the SVG showing it, and the SVG images +/// share the limit with the SVG showing them. +#[test] +fn svg_images_whose_styles_expand_past_the_limit_refuse_the_svg() { + let err = import_with(&svg(&image_of("image/svg+xml", &use_chain(10, &long_style()))), &ImportOptions::default()).unwrap_err(); + assert!(matches!(err, SvgError::StylesTooLarge(64)), "{err:?}"); + // Each image copies its long style 383 times (about 38 MB): one imports, two together don't. + let image = image_of("image/svg+xml", &use_chain(7, &long_style())); + let (d, _) = import_with(&svg(&image), &ImportOptions::default()).unwrap(); + assert!(!art(&d).is_empty()); + let err = import_with(&svg(&image.repeat(2)), &ImportOptions::default()).unwrap_err(); + assert!(matches!(err, SvgError::StylesTooLarge(64)), "{err:?}"); + // An image that doesn't decode (no size) is left out, and what it would copy doesn't count. + let sizeless = use_chain(7, &long_style()).replacen(r#"width="200" height="120""#, r#"width="0" height="0""#, 1); + let (d, _) = import_with(&svg(&format!("{}{image}", image_of("image/svg+xml", &sizeless).repeat(2))), &ImportOptions::default()).unwrap(); + assert!(!art(&d).is_empty()); +} + /// Nested SVG images exceeding `MAX_NESTED_SVG_IMAGES` are left out with a warning note (#3564). #[test] fn nested_svg_images_past_count_cap_are_left_out() { diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index 4ddd1d5605..3d07f33af2 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -6332,6 +6332,7 @@ digits Malayalam Malaiàlam @msg the spine has no segments l’espina no té segments @msg the stroke has no weight el traç no té gruix @msg the SVG's elements are nested more than {0} deep els elements de l’SVG estan imbricats a més de {0} nivells de profunditat +@msg the SVG's styles expand to more than {0} MB els estils de l’SVG s’expandeixen a més de {0} MB @msg the target layer is locked or hidden la capa de destinació està blocada o amagada @msg the thumbnail image is malformed la imatge de la miniatura està mal formada @msg the top object must be a path, compound path or text object to use as a clipping mask l’objecte superior ha de ser un traçat, un traçat compost o un objecte de text per fer-lo servir com a màscara de retall diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 211982f086..993ad41add 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -9008,6 +9008,7 @@ breakText Glyphs Glyfy @msg the RTF file is too large to place as type (at most {_1} MB) soubor RTF je příliš velký na umístění jako text (nejvýše {_1} MB) @msg the SVG expands to more than {0} nested SVG images SVG se rozvine na více než {0} vnořených obrázků SVG @msg the SVG expands to more than {0} objects SVG se rozvine na více než {0} objektů +@msg the SVG's styles expand to more than {0} MB styly SVG se rozvinou na více než {0} MB @msg the SVG file is larger than {MAX_IMPORT_BYTES} bytes soubor SVG je větší než {MAX_IMPORT_BYTES} bajtů @msg the SVG has no drawable objects SVG nemá žádné vykreslitelné objekty @msg the SVGZ file unpacks to more than {_1} MB soubor SVGZ se rozbalí na více než {_1} MB diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index d0610144ef..dd34c7fcc9 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -8576,6 +8576,7 @@ breakText Glyphs Glyphen @msg the RTF file is too large to place as type (at most {_1} MB) die RTF-Datei ist zu groß, um als Text platziert zu werden (höchstens {_1} MB) @msg the SVG expands to more than {0} nested SVG images das SVG wird zu mehr als {0} verschachtelten SVG-Bildern erweitert @msg the SVG expands to more than {0} objects das SVG wird zu mehr als {0} Objekten erweitert +@msg the SVG's styles expand to more than {0} MB die Stile des SVG werden auf mehr als {0} MB erweitert @msg the SVG has no drawable objects das SVG hat keine zeichenbaren Objekte @msg the SVGZ file unpacks to more than {_1} MB die SVGZ-Datei wird auf mehr als {_1} MB entpackt @msg the Word document has more than {MAX_PAGES} pages of properties, too many to place das Word-Dokument hat mehr als {MAX_PAGES} Seiten an Eigenschaften, zu viele zum Platzieren diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index d03f8c6958..4733e624b7 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -4802,6 +4802,7 @@ digits Malayalam Μαλαγιάλαμ @msg result would exceed the canvas (coordinates out of range) το αποτέλεσμα θα υπερέβαινε τον καμβά (συντεταγμένες εκτός εύρους) @msg objects can't be nested more than 32 deep τα αντικείμενα δεν μπορούν να έχουν ένθεση μεγαλύτερη των 32 επιπέδων @msg the SVG's elements are nested more than {0} deep τα στοιχεία SVG έχουν ένθεση μεγαλύτερη των {0} επιπέδων +@msg the SVG's styles expand to more than {0} MB τα στυλ του SVG επεκτείνονται σε περισσότερα από {0} MB @msg scale must be a number from {_1} to {_2}, not {_3} το scale πρέπει να είναι αριθμός από {_1} έως {_2}, όχι {_3} @msg scale must be a number from {_1} to {_2}, not {s} το scale πρέπει να είναι αριθμός από {_1} έως {_2}, όχι {s} @msg select (or target) objects whose appearance isn't basic επιλέξτε (ή στοχεύστε) αντικείμενα των οποίων η εμφάνιση δεν είναι βασική diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 3e8bd23752..ed8917e87d 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -4846,6 +4846,7 @@ axis Both Ambos @msg result would exceed the canvas (coordinates out of range) el resultado excedería el lienzo (coordenadas fuera de rango) @msg objects can't be nested more than 32 deep los objetos no pueden anidarse a más de 32 niveles @msg the SVG's elements are nested more than {0} deep los elementos del SVG están anidados a más de {0} niveles +@msg the SVG's styles expand to more than {0} MB los estilos del SVG se expanden a más de {0} MB @msg scale must be a number from {_1} to {_2}, not {_3} scale debe ser un número de {_1} a {_2}, no {_3} @msg scale must be a number from {_1} to {_2}, not {s} scale debe ser un número de {_1} a {_2}, no {s} @msg select (or target) objects whose appearance isn't basic selecciona (o apunta a) objetos cuya apariencia no sea básica diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index d408220f47..95a87bfa07 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -5061,6 +5061,7 @@ imageTrace Outline Ääriviiva @msg result would exceed the canvas (coordinates out of range) tulos ylittäisi kankaan (koordinaatit alueen ulkopuolella) @msg objects can't be nested more than 32 deep objekteja ei voi sisäkkäistää yli 32 tason syvyyteen @msg the SVG's elements are nested more than {0} deep elementit ovat SVG-tiedostossa sisäkkäin yli {0} tason syvyydessä +@msg the SVG's styles expand to more than {0} MB SVG-tiedoston tyylit laajenevat yli {0} megatavuksi @msg scale must be a number from {_1} to {_2}, not {_3} scale-arvon on oltava luku väliltä {_1}–{_2}, ei {_3} @msg scale must be a number from {_1} to {_2}, not {s} scale-arvon on oltava luku väliltä {_1}–{_2}, ei {s} @msg select (or target) objects whose appearance isn't basic valitse (tai kohdista) objektit, joiden ulkoasu ei ole perusulkoasu diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 318bbbeb44..e2ac12fd59 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -8872,6 +8872,7 @@ breakText Glyphs Glyphes @msg the RTF file is too large to place as type (at most {_1} MB) le fichier RTF est trop volumineux pour être importé comme texte (au plus {_1} Mo) @msg the SVG expands to more than {0} nested SVG images le SVG se développe en plus de {0} images SVG imbriquées @msg the SVG expands to more than {0} objects le SVG se développe en plus de {0} objets +@msg the SVG's styles expand to more than {0} MB les styles du SVG se développent en plus de {0} Mo @msg the SVG file is larger than {MAX_IMPORT_BYTES} bytes le fichier SVG dépasse {MAX_IMPORT_BYTES} octets @msg the SVG has no drawable objects le SVG n’a aucun objet dessinable @msg the SVGZ file unpacks to more than {_1} MB le fichier SVGZ se décompresse en plus de {_1} Mo diff --git a/crates/ui-egui/src/i18n/hi.tsv b/crates/ui-egui/src/i18n/hi.tsv index 78c0a9a7eb..afd8f1d754 100644 --- a/crates/ui-egui/src/i18n/hi.tsv +++ b/crates/ui-egui/src/i18n/hi.tsv @@ -8280,6 +8280,7 @@ antiAlias Sharp शार्प @msg the subpath is closed or too short to close सबपैथ बंद है या बंद करने के लिए बहुत कम है @msg the SVG expands to more than {0} nested SVG images SVG {0} नेस्टेड SVG इमेज से अधिक का विस्तार करता है @msg the SVG expands to more than {0} objects SVG {0} ऑब्जेक्ट्स से अधिक का विस्तार करता है +@msg the SVG's styles expand to more than {0} MB SVG की शैलियाँ {0} MB से अधिक तक विस्तारित होती हैं @msg the SVG has no drawable objects SVG में कोई आकर्षक ऑब्जेक्ट नहीं है @msg the SVG's elements are nested more than {0} deep SVG के तत्वों को {0} से अधिक गहरा घोंसला दिया जाता है @msg the SVGZ file unpacks to more than {_1} MB SVGZ फ़ाइल ने {_1} MB से अधिक के लिए अनपैक किया diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index a1f6100b2f..f29564ed97 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -8877,6 +8877,7 @@ breakText Glyphs Glifák @msg the RTF file is too large to place as type (at most {_1} MB) az RTF-fájl túl nagy ahhoz, hogy szövegként elhelyezhető legyen (legfeljebb {_1} MB) @msg the SVG expands to more than {0} nested SVG images az SVG kibontva több mint {0} beágyazott SVG-képet tartalmaz @msg the SVG expands to more than {0} objects az SVG kibontva több mint {0} objektumot tartalmaz +@msg the SVG's styles expand to more than {0} MB az SVG stílusai kibontva több mint {0} MB-ot foglalnak @msg the SVG file is larger than {MAX_IMPORT_BYTES} bytes az SVG-fájl nagyobb, mint {MAX_IMPORT_BYTES} bájt @msg the SVG has no drawable objects az SVG-ben nincsenek kirajzolható objektumok @msg the SVGZ file unpacks to more than {_1} MB az SVGZ-fájl kicsomagolva nagyobb, mint {_1} MB diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 6743704785..60ad4e99a6 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -8624,6 +8624,7 @@ breakText Glyphs Glifi @msg the RTF file is too large to place as type (at most {_1} MB) il file RTF è troppo grande per essere inserito come testo (al massimo {_1} MB) @msg the SVG expands to more than {0} nested SVG images l'SVG si espande in più di {0} immagini SVG annidate @msg the SVG expands to more than {0} objects l'SVG si espande in più di {0} oggetti +@msg the SVG's styles expand to more than {0} MB gli stili dell'SVG si espandono a oltre {0} MB @msg the SVG has no drawable objects l'SVG non ha oggetti disegnabili @msg the SVGZ file unpacks to more than {_1} MB il file SVGZ si decomprime in più di {_1} MB @msg the Word document has more than {MAX_PAGES} pages of properties, too many to place il documento Word ha più di {MAX_PAGES} pagine di proprietà, troppe per essere inserito diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index c9cdb8fcbe..f00bb9c388 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -7835,6 +7835,7 @@ axis Y Axis Y 軸 @msg the RTF file is too large to place as type (at most {_1} MB) RTF ファイルが大きすぎて、文字として配置できません (最大 {_1} MB) @msg the SVG expands to more than {0} nested SVG images SVG を展開すると、入れ子の SVG 画像が {0} 個を超えます @msg the SVG expands to more than {0} objects SVG を展開すると、オブジェクトが {0} 個を超えます +@msg the SVG's styles expand to more than {0} MB SVG のスタイルを展開すると {0} MB を超えます @msg the SVG has no drawable objects SVG に描画できるオブジェクトがありません @msg the SVGZ file unpacks to more than {_1} MB SVGZ ファイルを展開すると {_1} MB を超えます @msg the Word document has more than {MAX_PAGES} pages of properties, too many to place Word 文書のプロパティが {MAX_PAGES} ページを超えており、多すぎて配置できません diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 55f726dc38..8a155a1f76 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -5678,6 +5678,7 @@ imageTrace Outline კონტური @msg object has no weighted stroke ობიექტს ცვლადი სისქის კონტური არ აქვს @msg objects can't be nested more than 32 deep ობიექტების ჩადგმის სიღრმე 32-ს ვერ გადააჭარბებს @msg the SVG's elements are nested more than {0} deep SVG-ის ელემენტების ჩადგმის სიღრმე {0}-ს აჭარბებს +@msg the SVG's styles expand to more than {0} MB SVG-ის სტილები გაშლისას {0} MB-ს აჭარბებს @msg unknown control `{name}`: fillStroke, coloring, drawMode or screenMode უცნობი control `{name}`: fillStroke, coloring, drawMode ან screenMode @plural agrees with {n} default shortcut|agrees with {n} default shortcuts ემთხვევა ნაგულისხმევ მალსახმობებს: {n}|ემთხვევა ნაგულისხმევ მალსახმობებს: {n} @plural {n} part of the file wasn't read|{n} parts of the file weren't read ფაილის წაუკითხავი ნაწილები: {n}|ფაილის წაუკითხავი ნაწილები: {n} diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index abe2b4bc28..27dde64326 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -8605,6 +8605,7 @@ breakText Glyphs 글리프 @msg the RTF file is too large to place as type (at most {_1} MB) RTF 파일이 너무 커서 문자로 가져올 수 없습니다(최대 {_1} MB) @msg the SVG expands to more than {0} nested SVG images SVG를 확장하면 중첩된 SVG 이미지가 {0}개보다 많아집니다 @msg the SVG expands to more than {0} objects SVG를 확장하면 개체가 {0}개보다 많아집니다 +@msg the SVG's styles expand to more than {0} MB SVG의 스타일을 확장하면 {0}MB를 넘습니다 @msg the SVG file is larger than {MAX_IMPORT_BYTES} bytes SVG 파일이 {MAX_IMPORT_BYTES}바이트보다 큽니다 @msg the SVG has no drawable objects SVG에 그릴 수 있는 개체가 없습니다 @msg the SVGZ file unpacks to more than {_1} MB SVGZ 파일의 압축을 풀면 {_1} MB를 넘습니다 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index ed281382a4..2598123649 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -6957,6 +6957,7 @@ imageTrace Outline Contour @msg the RTF file is too large to place as type (at most {_1} MB) het RTF-bestand is te groot om als tekst te plaatsen (maximaal {_1} MB) @msg the SVG expands to more than {0} nested SVG images de SVG wordt uitgevouwen tot meer dan {0} geneste SVG-afbeeldingen @msg the SVG expands to more than {0} objects de SVG wordt uitgevouwen tot meer dan {0} objecten +@msg the SVG's styles expand to more than {0} MB de stijlen van de SVG worden uitgevouwen tot meer dan {0} MB @msg the SVG file is larger than {MAX_IMPORT_BYTES} bytes het SVG-bestand is groter dan {MAX_IMPORT_BYTES} bytes @msg the SVG has no drawable objects de SVG heeft geen tekenbare objecten @msg the SVGZ file unpacks to more than {_1} MB het SVGZ-bestand wordt uitgepakt tot meer dan {_1} MB diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 08e96e6a35..02f807a4b0 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -8862,6 +8862,7 @@ breakText Glyphs Glify @msg the RTF file is too large to place as type (at most {_1} MB) plik RTF jest zbyt duży, aby umieścić go jako tekst (najwyżej {_1} MB) @msg the SVG expands to more than {0} nested SVG images SVG rozwija się do ponad {0} zagnieżdżonych obrazów SVG @msg the SVG expands to more than {0} objects SVG rozwija się do ponad {0} obiektów +@msg the SVG's styles expand to more than {0} MB style SVG rozwijają się do ponad {0} MB @msg the SVG has no drawable objects SVG nie zawiera obiektów, które można narysować @msg the SVGZ file unpacks to more than {_1} MB plik SVGZ po rozpakowaniu ma ponad {_1} MB @msg the Word document has more than {MAX_PAGES} pages of properties, too many to place dokument Word ma ponad {MAX_PAGES} stron właściwości, zbyt wiele, aby go umieścić diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 79c4d9dc8e..6143ab85e3 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -9074,6 +9074,7 @@ swatch Yellow Green Verde-amarelado @msg the RTF file is too large to place as type (at most {_1} MB) o arquivo RTF é grande demais para ser colocado como texto (no máximo {_1} MB) @msg the SVG expands to more than {0} nested SVG images o SVG se expande em mais de {0} imagens SVG aninhadas @msg the SVG expands to more than {0} objects o SVG se expande em mais de {0} objetos +@msg the SVG's styles expand to more than {0} MB os estilos do SVG se expandem para mais de {0} MB @msg the SVG file is larger than {MAX_IMPORT_BYTES} bytes o arquivo SVG tem mais de {MAX_IMPORT_BYTES} bytes @msg the SVG has no drawable objects o SVG não tem objetos desenháveis @msg the SVGZ file unpacks to more than {_1} MB o arquivo SVGZ é descompactado em mais de {_1} MB diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 9f608618e7..2eb060d198 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -4883,6 +4883,7 @@ axis Both Оба @msg result would exceed the canvas (coordinates out of range) результат превысил бы холст (координаты вне диапазона) @msg objects can't be nested more than 32 deep объекты нельзя вкладывать глубже 32 уровней @msg the SVG's elements are nested more than {0} deep элементы SVG вложены глубже {0} уровней +@msg the SVG's styles expand to more than {0} MB после развёртывания стили SVG занимают более {0} МБ @msg scale must be a number from {_1} to {_2}, not {_3} scale должен быть числом от {_1} до {_2}, а не {_3} @msg scale must be a number from {_1} to {_2}, not {s} scale должен быть числом от {_1} до {_2}, а не {s} @msg select (or target) objects whose appearance isn't basic выделите (или укажите как объект) объекты, оформление которых не является основным diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 6156ca23d5..9d568f8984 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -8650,6 +8650,7 @@ digits Hindi Hindi @msg the subpath has no ends to extend (it is closed or a single point) delbanan har inga ändar att förlänga (den är stängd eller en enkel punkt) @msg the SVG expands to more than {0} nested SVG images SVG-filen expanderar till fler än {0} kapslade SVG-bilder @msg the SVG expands to more than {0} objects SVG-filen expanderar till fler än {0} objekt +@msg the SVG's styles expand to more than {0} MB SVG-filens stilar expanderar till mer än {0} MB @msg the SVG has no drawable objects SVG-filen har inga ritbara objekt @msg the SVGZ file unpacks to more than {_1} MB SVGZ-filen packas upp till mer än {_1} MB @msg the symbols are nested too deeply to expand their instances symbolerna är kapslade för djupt för att deras instanser ska kunna expanderas diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index 7120d44707..b39df911ec 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -4616,6 +4616,7 @@ axis Both Her İkisi @msg result would exceed the canvas (coordinates out of range) sonuç tuvali aşacaktır (koordinatlar aralık dışındadır) @msg objects can't be nested more than 32 deep nesneler 32'den fazla derinliğe yerleştirilemez @msg the SVG's elements are nested more than {0} deep SVG'nin öğeleri {0} derinliğinden daha fazla yuvalanmıştır +@msg the SVG's styles expand to more than {0} MB SVG'nin stilleri genişletildiğinde {0} MB'tan fazla yer kaplıyor @msg scale must be a number from {_1} to {_2}, not {_3} scale {_1} ile {_2} arasında bir sayı olmalıdır, {_3} değil @msg scale must be a number from {_1} to {_2}, not {s} scale {_1} ile {_2} arasında bir sayı olmalıdır, {s} değil @msg select (or target) objects whose appearance isn't basic Görünümü temel olmayan nesneleri seçin (veya hedefleyin) diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 84f296b0a6..dc94cc74b4 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -8490,6 +8490,7 @@ breakText Glyphs Гліфи @msg the RTF file is too large to place as type (at most {_1} MB) файл RTF завеликий, щоб помістити його як текст (не більше {_1} МБ) @msg the SVG expands to more than {0} nested SVG images SVG розгортається у понад {0} вкладених зображень SVG @msg the SVG expands to more than {0} objects SVG розгортається у понад {0} об’єктів +@msg the SVG's styles expand to more than {0} MB стилі SVG розгортаються у понад {0} МБ @msg the SVG file is larger than {MAX_IMPORT_BYTES} bytes файл SVG більший за {MAX_IMPORT_BYTES} байтів @msg the SVG has no drawable objects SVG не містить об’єктів, які можна намалювати @msg the SVGZ file unpacks to more than {_1} MB файл SVGZ розпаковується у понад {_1} МБ diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index e8b9e5758f..c5c38c0ddd 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -5257,6 +5257,7 @@ theme Appearance Giao diện @msg result would exceed the canvas (coordinates out of range) kết quả sẽ vượt quá vùng vẽ (tọa độ ngoài phạm vi) @msg objects can't be nested more than 32 deep không thể lồng các đối tượng sâu quá 32 cấp @msg the SVG's elements are nested more than {0} deep các phần tử SVG lồng nhau sâu quá {0} cấp +@msg the SVG's styles expand to more than {0} MB các kiểu của SVG khi mở rộng chiếm hơn {0} MB @msg Save for Web: the image is empty Lưu cho Web: ảnh trống @msg Save writes {_1}, not {_2}: use document.export for other formats Lưu ghi {_1}, không phải {_2}: dùng document.export cho các định dạng khác @msg Save writes {_1}, not {_2}: use file.saveAsTemplate to write it Lưu ghi {_1}, không phải {_2}: dùng file.saveAsTemplate để ghi định dạng này diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 719968086f..276c64f1b4 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -8848,6 +8848,7 @@ breakText Glyphs 字形 @msg the RTF file is too large to place as type (at most {_1} MB) RTF 文件过大,无法作为文字置入 (最多 {_1} MB) @msg the SVG expands to more than {0} nested SVG images SVG 展开后的嵌套 SVG 图像超过 {0} 个 @msg the SVG expands to more than {0} objects SVG 展开后的对象超过 {0} 个 +@msg the SVG's styles expand to more than {0} MB SVG 的样式展开后超过 {0} MB @msg the SVG has no drawable objects SVG 中没有可绘制的对象 @msg the SVGZ file unpacks to more than {_1} MB SVGZ 文件解压后超过 {_1} MB @msg the Word document has more than {MAX_PAGES} pages of properties, too many to place Word 文档的属性页超过 {MAX_PAGES} 页,过多而无法置入 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 121a8b8c02..f0fe72eda2 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -8773,6 +8773,7 @@ breakText Glyphs 字符 @msg the RTF file is too large to place as type (at most {_1} MB) RTF 檔案過大,無法置入為文字 (最多 {_1} MB) @msg the SVG expands to more than {0} nested SVG images SVG 展開後超過 {0} 個巢狀 SVG 影像 @msg the SVG expands to more than {0} objects SVG 展開後超過 {0} 個物件 +@msg the SVG's styles expand to more than {0} MB SVG 的樣式展開後超過 {0} MB @msg the SVG has no drawable objects SVG 中沒有可繪製的物件 @msg the SVGZ file unpacks to more than {_1} MB SVGZ 檔案解壓縮後超過 {_1} MB @msg the Word document has more than {MAX_PAGES} pages of properties, too many to place Word 文件的屬性超過 {MAX_PAGES} 頁,數量過多而無法置入 diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 8f5043993a..8b6136af58 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -1833,6 +1833,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - An image that Open and Place store again keeps the ICC profile its file embeds and its 16-bit samples. A turned PNG, JPEG, WebP or TIFF stored as PNG, and a TIFF the image decoder reads, keep their gray or RGB samples at 8 or 16 bits with their gray or RGB profile in the PNG's `iCCP` chunk ([PNG specification, iCCP](https://www.w3.org/TR/png-3/#11iCCP)). A CMYK TIFF stored with one plane per ink and a turned CMYK JPEG or TIFF keep their CMYK profile as TIFF tag 34675, a JPEG's put together from all its APP2 segments ([ICC image-format guide](https://github.com/InternationalColorConsortium/iccDEV/blob/master/iccdev-mcp/docs/icc-format-guide.md)). A profile whose color space differs from the stored samples' is left out. The profile is kept in the stored image; how CMYK inks are drawn and exported to PDF does not change (`crates/engine/src/cmd/fileio/tests.rs`). - SVG import shows a raster `` whose EXIF orientation or TIFF Orientation tag turns or flips it upright, linked or as a data URL, and inside an SVG shown as an image: the pixels are stored turned, the width and height swap, and the `` box fits the turned image under `preserveAspectRatio`, as CSS `image-orientation: from-image` describes (). A turned CMYK JPEG or TIFF keeps its inks as a CMYK TIFF, as does a CMYK TIFF that is not turned. TIFF data URLs (`image/tiff`, or untyped TIFF bytes) are read, and TIFFs with an alpha or other extra channel, CCITT Group 3 TIFFs and CMYK TIFFs stored one plane per ink are read as Open and Place read them. The pixels are decoded within the decode allowance, and a TIFF claiming more strips or tiles than the decoder can count is refused before it is decoded (`crates/svg/tests/it/image_orientation.rs`). - SVG import leaves out an SVG shown as an image that it can't read (text that isn't XML, an SVG without a size) and goes on with the images after it, as SVG 2's error processing describes (). Only images that decode count toward the 256 nested SVG images an SVG may show, so an image after many broken ones is imported. Every nested SVG image read, decoded or not, counts toward VectorCraft's own limits of 1,024 reads and 512 MB of text per import; past them, nested SVG images are left out with a warning (`crates/svg/tests/it/import_details.rs`). + - SVG import measures what an SVG expands to before the SVG reader builds it: every copy a `` shows (), chains of ``s included, and the style values each copy gets from its `style` attribute and from the style sheet rules that match it. An SVG that expands to more than 999,999 elements (500,000 on the web) or to more than 64 MB of copied style values is refused with an error, and so is a loop of `` references that would be copied without end; both limits are VectorCraft's own. An SVG shown as an image counts toward the same 64 MB as the SVG showing it, and one past either limit refuses the whole import (`crates/svg/src/import/budget.rs`, `crates/svg/tests/it/import_details.rs`). - SVG import reads the files that a linked SVG file's own `` elements link to, relative paths from that file's folder (), as it reads the imported SVG's links: a raster stays linked, an SVG file imports as vector art, and one that can't be read gets the placeholder, its link and a warning. SVG 2 tells a viewer not to load these links (); reading them is VectorCraft's own rule. The same href in SVG files of two folders names two files. A link that leads back to an SVG file showing it gets the placeholder and a warning, and reading the links of linked SVG files stops at the nesting depth cap and at 1,024 reads and 512 MB per import, the same limits decoded nested SVG images have, counted separately from them. The text of every linked SVG file read counts, and so does every file read for the links of a linked SVG file, raster or SVG; rasters the imported SVG links to don't. Once either limit is passed, no file linked from a linked SVG file is read and its image is left out with a warning, and an SVG file the imported SVG links to is still shown, without the files its own links name, with a warning. Another href to an SVG file already read, spelled differently or in another SVG file, does not read it again, unless a link back or the depth cap changes what it shows there (`crates/svg/tests/it/import_details.rs`, `crates/svg/src/import/files.rs`). - File › Place and a file dropped on the canvas refuse a PNG, JPEG, GIF or WebP file whose pixels can't be read, such as one cut short by a download or a sync still running, and the status bar shows "Couldn't place : the image's pixels can't be read". Paste and Relink refuse such an image too, and Update Links, or Open when it reads the file again, counts it as missing. A JPEG cut short still places when its pixels can be decoded (`file.place`, `crates/engine/src/tests_place.rs`). - On the desktop, Copy and Cut make the system clipboard's formats (text, SVG, PDF, PNG) from a copy of the clipboard on the thread that writes background saves and exports, and write them when they are ready; while that thread has a save, an export, a print or a recovery copy to finish, they are made and written at once. Until they are written, Paste in VectorCraft takes the internal clipboard, and while a text field or the Type tool has the keyboard the app waits for them. Another Copy or Cut, or a copy of text in VectorCraft, drops them.