diff --git a/crates/doc/src/links.rs b/crates/doc/src/links.rs index 2330e95ac..6e50a4f7f 100644 --- a/crates/doc/src/links.rs +++ b/crates/doc/src/links.rs @@ -166,6 +166,24 @@ impl ImageBlob { } } +/// The side of [`missing_placeholder`]'s image, in pixels. +pub const MISSING_SIDE: u32 = 64; + +/// What a linked image shows when an importer has no pixels for it (its file is missing or isn't +/// in the data): a light tile, crossed out, [`MISSING_SIDE`] pixels a side, as a PNG. `None` when +/// it can't be encoded. +pub fn missing_placeholder() -> Option> { + let last = MISSING_SIDE - 1; + let img = image::RgbaImage::from_fn(MISSING_SIDE, MISSING_SIDE, |x, y| { + let edge = x == 0 || y == 0 || x == last || y == last; + let cross = x.abs_diff(y) <= 1 || (x + y).abs_diff(last) <= 1; + image::Rgba(if edge || cross { [200, 60, 60, 255] } else { [236, 236, 236, 255] }) + }); + let mut png = Vec::new(); + img.write_to(&mut Cursor::new(&mut png), image::ImageFormat::Png).ok()?; + Some(png) +} + /// `bytes` decoded and shrunk to fit [`PROXY_SIZE`] as a PNG; `None` when small enough already or /// undecodable. fn proxy_png(bytes: &[u8]) -> Option> { @@ -445,6 +463,12 @@ mod tests { .unwrap() } + #[test] + fn the_placeholder_is_a_png() { + let png = missing_placeholder().unwrap(); + assert_eq!(image::load_from_memory(&png).unwrap().width(), MISSING_SIDE); + } + #[test] fn a_path_string_from_older_files_reads_as_a_link() { let old: ImageObject = serde_json::from_str(r#"{"key":"k","width":2,"height":1,"xf":[1,0,0,1,0,0],"link":"C:\\art\\photo.png"}"#).unwrap(); diff --git a/crates/engine/tests/import_fuzz.rs b/crates/engine/tests/import_fuzz.rs index 139268295..2ee24372a 100644 --- a/crates/engine/tests/import_fuzz.rs +++ b/crates/engine/tests/import_fuzz.rs @@ -3675,6 +3675,19 @@ proptest! { let text = mutate_text(&fixture, cut, &edits); survive("mutated PostScript-form .ai with placed files", || vectorcraft_engine::cmd::fileio::load("x.ai", text.as_bytes()).ok().map(|l| l.doc))?; } + + /// The same file with linked images in the version 7 form (`XG`, then `XF` with no samples), + /// one with an embedded image between its `XG` and `XF`, damaged. + #[test] + fn ps_form_ai_with_linked_images_never_panics(cut in 0usize..1_400, edits in prop::collection::vec((0usize..1_400, prop::sample::select(vec!['0', '9', '-', '.', ' ', '\n', '(', ')', '[', ']', '%', 'X', 'F', 'G'])), 0..12)) { + let linked = "%AI5_File:\n%AI5_BeginRaster\n(a.tif) 0 XG\n[ 2 0 0 3 10 80 ] 0 0 10 20 10 20 8 3 0 0 0 0 XF\n%AI5_EndRaster\n\ + %AI5_File:\n%AI5_BeginRaster\n(b.tif) 1 XG\n[ 1 0 0 1 0 100 ] 0 0 1 1 1 1 8 3 0 0 0 0 XI\n%FF0000\n%AI5_EndRaster\n\ + [ 0 1 -1 0 50 50 ] 0 0 4 4 4 4 8 3 0 0 0 0 XF\n"; + let fixture = NAMED_PROLOG_AI.replacen("0 Ap\nu\n", &format!("0 Ap\n{linked}u\n"), 1); + prop_assert!(fixture.contains("(a.tif)")); + let text = mutate_text(&fixture, cut, &edits); + survive("mutated PostScript-form .ai with linked images", || vectorcraft_engine::cmd::fileio::load("x.ai", text.as_bytes()).ok().map(|l| l.doc))?; + } } /// A `.ai` in the legacy format without layers (Illustrator 3) whose prolog is included: its @@ -3878,6 +3891,12 @@ fn arb_ai_token() -> impl Strategy { "[ 1 0 0 1 0 0 ] 0 0 2 2 2 2 8 3 1 0 1 0", "[ 1 0 0 1 0 0 ] 0 0 3 2 3 2 1 4 1 0 1 0", "[ 1 0 0 1 0 0 ] 0 0 99999 99999 99999 99999 1 1 0 0 0 0", + // A linked image in the version 7 form (§8.2, §8.3): `(path) modified XG`, then `XF`. + "XG", + "(a.tif) 0 XG", + "XF", + "[ 1 0 0 1 0 0 ] 0 0 2 2 2 2 8 3 0 0 0 0 XF", + "[ 1e308 0 0 1e308 0 0 ] 0 0 1e6 1e6 1e6 1e6 8 3 0 0 0 0 XF", "[", "]", "/Name", diff --git a/crates/eps/src/import/ai/read.rs b/crates/eps/src/import/ai/read.rs index 80b5396ee..12c8086df 100644 --- a/crates/eps/src/import/ai/read.rs +++ b/crates/eps/src/import/ai/read.rs @@ -35,6 +35,11 @@ //! and the samples after `XI`. 8-bit CMYK samples keep their ink amounts in a CMYK TIFF, and //! an alpha channel that hides part of such an image becomes its opacity mask; other samples //! become an RGBA PNG. +//! - Linked images in the version 7 form (§8.2, §8.3): `(path) modified XG`, then `XF` with the +//! operands `XI` takes and no samples. Each is a linked image of that file showing a placeholder +//! over the image's place until its file is found. An `XF` without a file name before it, or +//! with operands `XI` couldn't read, is left out with a warning. An `XI` after `XG` (newer files +//! write `() 1 XG` before their embedded images) stays an embedded image. //! - Placed (linked) files, as written in files users sent: `%AI5_BeginPlace`, `[matrix] llx lly urx //! ury … (path)` and the operator `` ` ``, the file's preview between `%AI26_BeginPlacedObjectPreview` //! and its end (`w h rowBytes 32 n `, then rows of premultiplied ARGB, the top one first), `~`. The @@ -124,7 +129,7 @@ pub(crate) use document::{slot_frame, slot_of}; pub use types::IMAGE_TOO_LARGE; use types::{BLEND_BUDGET, FLIP, Frame, GState, Graph, Kind, PatternHead, PendingEnvelope, Place, Raster}; #[cfg(test)] -pub use types::{GRAPH_PLAIN, GRAPH_UNENDED, NON_NATIVE_ART, NON_NATIVE_ART_UNREAD, VERSIONED_UNENDED}; +pub use types::{GRAPH_PLAIN, GRAPH_UNENDED, LINKED_PLACEHOLDERS, NON_NATIVE_ART, NON_NATIVE_ART_UNREAD, VERSIONED_UNENDED}; pub(super) use types::{blend_mode, blend_name}; #[path = "legacy_text.rs"] @@ -155,6 +160,10 @@ pub struct Structure { /// Where the drawn looks lay that objects read with their art style took the place of (the /// document's coordinates): the page draws Illustrator's rendering of those styles there. pub restyled: Vec, + /// Where linked images whose pixels the data doesn't keep (`XF`) show a placeholder (the + /// document's coordinates). A PostScript page doesn't draw them there; a PDF part draws the + /// image's pixels. + pub placeholders: Vec, /// Placed files whose pixels the file puts at another point too: their image's id and the /// move, in its pixels, that places them there (the corner of the box they are written with, /// in place of the canvas point of art space's origin). @@ -259,6 +268,8 @@ struct Reader<'a> { /// a global process colour, so these make swatches only for names no colour operator defines. stop_spots: Vec, raster: Option, + /// The file `XG` names for the image after it (`XF`), until an image is read. + image_link: Option, /// The placed file being read (`%AI5_BeginPlace` … `~`). place: Option, /// The last object read is the last child of the innermost frame, and nothing started since. @@ -343,6 +354,8 @@ struct Reader<'a> { palette: super::palette::Palette, /// See [`Structure::restyled`]. restyled: Vec, + /// See [`Structure::placeholders`]. + placeholders: Vec, /// See [`Structure::placed_elsewhere`]. placed_elsewhere: Vec<(NodeId, Affine)>, unread_elsewhere: Vec<(NodeId, Rect)>, @@ -443,6 +456,7 @@ impl<'a> Reader<'a> { spots: Vec::new(), stop_spots: Vec::new(), raster: None, + image_link: None, place: None, foreign_data: None, after_object: false, @@ -487,6 +501,7 @@ impl<'a> Reader<'a> { style_links: vec![], palette: super::palette::Palette::default(), restyled: vec![], + placeholders: vec![], placed_elsewhere: vec![], unread_elsewhere: vec![], mesh: None, diff --git a/crates/eps/src/import/ai/read/art.rs b/crates/eps/src/import/ai/read/art.rs index 1df1b2d9c..4d60ffc25 100644 --- a/crates/eps/src/import/ai/read/art.rs +++ b/crates/eps/src/import/ai/read/art.rs @@ -1,13 +1,14 @@ use super::containers::close; use super::document::TEXT_SLOT; use super::types::{ - FLIP, Frame, IMAGE_TOO_LARGE, Kind, LINKED_PREVIEWS, MAX_PIXELS, MAX_PLACED_ELSEWHERE, MAX_POINTS, MAX_SIDE, NON_NATIVE_ART, + FLIP, Frame, IMAGE_TOO_LARGE, Kind, LINKED_PLACEHOLDERS, LINKED_PREVIEWS, MAX_PIXELS, MAX_PLACED_ELSEWHERE, MAX_POINTS, MAX_SIDE, NON_NATIVE_ART, NON_NATIVE_ART_UNREAD, Place, }; use super::{ Affine, AnchorKind, Appearance, AppearanceItem, Arc, BezPath, CANVAS_CENTRE, FillLayer, ImageBlob, ImageObject, Inks, Instance, LinkInfo, Node, NodeId, NodeKind, Obj, OpacityMask, Paint, PathData, PathEl, Point, Reader, Rect, StrokeLayer, V, ps, }; +use vectorcraft_doc::links::missing_placeholder; impl<'a> Reader<'a> { /// A text object (`/AI11Text`): an empty group standing for it, named after its story. @@ -383,14 +384,46 @@ impl<'a> Reader<'a> { self.image_from(vals, data) } + /// The matrix and the numbers of an image's operands (`[a b c d tx ty] llx lly urx ury w h bits + /// ImageType AlphaChannelCount reserved bin-ascii ImageMask`, as `XI` and `XF` take them); `None` + /// without a matrix or with fewer numbers than up to the encoding (bin-ascii). + fn image_operands(vals: &[V]) -> Option<(Vec, Vec)> { + let m = vals.iter().find_map(|v| if let V::Arr(a) = v { Some(Self::nums(a)) } else { None })?; + let n = Self::nums(vals); + (n.len() >= 11).then_some((m, n)) + } + + /// `XG` (`w`, which names the file of the image after it) or `XF` (that image), with their + /// operands `vals`. Before the art, the setup's procedures run: there they do nothing. + pub(super) fn image_link_op(&mut self, w: &str, vals: Vec, hidden: bool) -> Result<(), String> { + if self.frames.is_empty() { + return Ok(()); + } + if w == "XG" { + self.image_link = Self::image_link(&vals); + return Ok(()); + } + self.linked_image(vals, hidden) + } + + /// The file `XG`'s operands (`(path) modified`) name; `None` for operands of another shape or + /// an empty path. + fn image_link(vals: &[V]) -> Option { + match vals { + [.., V::Str(path), V::Num(_)] if !path.is_empty() => Some(super::obj::text(path)), + _ => None, + } + } + /// An image of operands `vals` and samples `data`. pub(super) fn image_from(&mut self, vals: Vec, data: &[u8]) -> Result<(), String> { + // A file `XG` named before this image isn't the file of a later `XF`. + self.image_link = None; let space = self.raster.as_ref().and_then(|r| r.space.clone()).unwrap_or_default(); - let Some(m) = vals.iter().find_map(|v| if let V::Arr(a) = v { Some(Self::nums(a)) } else { None }) else { + let Some((m, n)) = Self::image_operands(&vals) else { self.warn("an image VectorCraft can't read was left out"); return Ok(()); }; - let n = Self::nums(&vals); let [_, _, _, _, w, h, bits, kind, alpha, _, binary, ..] = n.as_slice() else { self.warn("an image VectorCraft can't read was left out"); return Ok(()); @@ -476,6 +509,52 @@ impl<'a> Reader<'a> { self.add_raster(ImageBlob::new("image/png", png), None, &m, (w as u32, h as u32)) } + /// `XF` (§8.2): an image whose pixels are in the file the `XG` before it names becomes a linked + /// image of that file, of its `w` × `h` pixels placed as the matrix maps them, as `XI` places an + /// image. The data keeps no pixels or preview of it, so a placeholder is spread over those pixels + /// until its file is found. One without that file name, or whose operands `XI` couldn't read (no + /// matrix, too few numbers, no pixels, or samples of other than 1 or 8 bits), is left out with a + /// warning. No pixels are read, so its size isn't held to the limit on `XI`'s samples. + fn linked_image(&mut self, vals: Vec, hidden: bool) -> Result<(), String> { + let path = self.image_link.take(); + let operands = Self::image_operands(&vals); + let (Some(path), Some((m, n))) = (path, operands) else { + self.warn("an image VectorCraft can't read was left out"); + return Ok(()); + }; + let (&[a, b, c, d, tx, ty], &[_, _, _, _, w, h, bits, ..]) = (m.as_slice(), n.as_slice()) else { + self.warn("an image VectorCraft can't read was left out"); + return Ok(()); + }; + if !(1.0..=MAX_SIDE).contains(&w) || !(1.0..=MAX_SIDE).contains(&h) || ![1.0, 8.0].contains(&bits) { + self.warn("an image VectorCraft can't read was left out"); + return Ok(()); + } + let (w, h) = (w as u32, h as u32); + let xf = self.space() * Affine::new([a, b, c, d, tx, ty]) * FLIP; + if !xf.as_coeffs().iter().all(|v| v.is_finite()) || xf.determinant().abs() < 1e-12 { + self.warn("an image VectorCraft can't read was left out"); + return Ok(()); + } + let Some(png) = missing_placeholder() else { + self.warn("an image VectorCraft can't read was left out"); + return Ok(()); + }; + // The placeholder is all the document has of the file: what a missing link shows. + let bytes = Arc::new(png); + let blob = ImageBlob { mime: "image/png".into(), bytes: bytes.clone(), proxy: Some(bytes) }; + let key = linked_key(&blob, &path); + self.doc.images.entry(key.clone()).or_insert(blob); + self.warn(LINKED_PLACEHOLDERS); + // A PostScript page doesn't draw the placeholder: there its pixels are left out of the + // comparisons with the page. + if !hidden && !self.gs.hidden && self.shown() { + self.placeholders.push(xf.transform_rect_bbox(Rect::new(0.0, 0.0, f64::from(w), f64::from(h)))); + } + let im = ImageObject { key, width: w, height: h, xf, link: Some(LinkInfo::new(path)), placement: Default::default(), pixels: None }; + self.add_image(im, hidden) + } + /// Add the image `blob` (`w` × `h` pixels), which the matrix `m` maps into art space, with /// `alpha` (its alpha channel, one byte a pixel) as its opacity mask when it hides part of the /// image. @@ -597,7 +676,7 @@ impl<'a> Reader<'a> { // The preview is all the document has of the file: what a missing link shows. let bytes = Arc::new(png); let blob = ImageBlob { mime: "image/png".into(), bytes: bytes.clone(), proxy: Some(bytes) }; - let key = blob.content_key(); + let key = linked_key(&blob, &path); self.doc.images.entry(key.clone()).or_insert(blob); self.warn(LINKED_PREVIEWS); if let Some(shift) = elsewhere @@ -723,6 +802,13 @@ pub(super) fn relative_path(folder: &str, name: &str) -> Option { Some(format!("{}/{name}", folder.trim_end_matches('/'))) } +/// The image key of a linked image of the file at `path` that shows `blob` (its preview or a +/// placeholder): the blob's own key and the path's. Images of other files that show the same pixels +/// have keys of their own, and reading one file's pixels in changes that file's images only. +fn linked_key(blob: &ImageBlob, path: &str) -> String { + format!("{}-{}", blob.content_key(), vectorcraft_doc::links::hash_bytes(path.as_bytes())) +} + pub(super) fn sane(r: Rect) -> bool { [r.x0, r.y0, r.x1, r.y1].iter().all(|v| v.is_finite() && v.abs() <= MAX_SIDE) } diff --git a/crates/eps/src/import/ai/read/directives.rs b/crates/eps/src/import/ai/read/directives.rs index b1c9db39d..cb77f4427 100644 --- a/crates/eps/src/import/ai/read/directives.rs +++ b/crates/eps/src/import/ai/read/directives.rs @@ -160,8 +160,12 @@ impl<'a> Reader<'a> { return Ok(()); } if line.starts_with("AI5_BeginRaster") { + // An `XG` outside a raster object names no image in it. + self.image_link = None; self.raster = Some(Raster::default()); } else if line.starts_with("AI5_EndRaster") { + // A file `XG` named in this raster object is no later one's. + self.image_link = None; if let Some(Raster { operands: Some(vals), hex, .. }) = self.raster.take() { return self.image_from(vals, &hex); } diff --git a/crates/eps/src/import/ai/read/document.rs b/crates/eps/src/import/ai/read/document.rs index 6bb67851f..e07ab498d 100644 --- a/crates/eps/src/import/ai/read/document.rs +++ b/crates/eps/src/import/ai/read/document.rs @@ -894,6 +894,7 @@ impl<'a> Reader<'a> { unread_elsewhere: self.unread_elsewhere, slot_names: self.slot_names, restyled: self.restyled, + placeholders: self.placeholders, placed_elsewhere: self.placed_elsewhere, envelopes_drawn: self.envelopes_drawn, styles_read, diff --git a/crates/eps/src/import/ai/read/ops.rs b/crates/eps/src/import/ai/read/ops.rs index 38acc590e..3172b355d 100644 --- a/crates/eps/src/import/ai/read/ops.rs +++ b/crates/eps/src/import/ai/read/ops.rs @@ -371,6 +371,9 @@ impl<'a> Reader<'a> { r.operands = Some(vals); } } + // A linked image (§8.2, §8.3): `(path) modified XG` names the file of the `XF` image after + // it, which has `XI`'s operands and no samples. + "XG" | "XF" => self.image_link_op(w, vals, hidden)?, // A plugin group ends; a blend's record follows on `%` lines. "XP" => { let name = vals.iter().find_map(V::text).unwrap_or_default(); diff --git a/crates/eps/src/import/ai/read/types.rs b/crates/eps/src/import/ai/read/types.rs index 0d35458fc..078207318 100644 --- a/crates/eps/src/import/ai/read/types.rs +++ b/crates/eps/src/import/ai/read/types.rs @@ -269,6 +269,11 @@ pub(super) const MAX_PLACED_FOLDER: usize = 4096; pub(super) const LINKED_PREVIEWS: &str = "linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel"; +/// What the open result says of linked images the data keeps no pixels of (`XF`): they show a +/// placeholder. +pub const LINKED_PLACEHOLDERS: &str = + "linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel"; + /// Operators that change nothing the reader keeps. pub(super) const IGNORED: &[&str] = &[ "Ae", @@ -276,12 +281,10 @@ pub(super) const IGNORED: &[&str] = &[ "As", "Xd", "Xr", - "XG", // `/DeviceGray XC` after a linked image's file name (`XG`): its colour space. "XC", "Xh", "XH", - "XF", "Bc", "XP", "Np", diff --git a/crates/eps/src/import/ai/tests.rs b/crates/eps/src/import/ai/tests.rs index 7639cbe83..331e2b257 100644 --- a/crates/eps/src/import/ai/tests.rs +++ b/crates/eps/src/import/ai/tests.rs @@ -2112,6 +2112,90 @@ fn a_rotated_image_is_placed_as_its_matrix_maps_it() { } } +/// A raster object in the version 7 form (§8): `%AI5_BeginRaster`, `head` (a link's `XG`, or +/// nothing), the operands `[matrix] 0 0 w h w h 8 3 0 0 0 0`, the operator `op` and `tail` (an +/// `XI`'s samples on `%` lines), `%AI5_EndRaster`. +fn raster7(head: &str, matrix: &str, (w, h): (u32, u32), op: &str, tail: &str) -> String { + format!("%AI5_File:\n%AI5_BeginRaster\n{head}{matrix} 0 0 {w} {h} {w} {h} 8 3 0 0 0 0 {op}\n{tail}%AI5_EndRaster\n") +} + +/// A linked image in the version 7 form (§8.2, §8.3), `(path) modified XG` and then `XF` with no +/// samples, is a linked image of that file. The data keeps no pixels of it, so it shows a +/// placeholder over the place the matrix maps the image's pixels to, as an embedded image (`XI`) +/// of the same operands is placed. +#[test] +fn a_version_7_linked_image_shows_a_placeholder_where_the_image_is() { + let (s, c) = 30f64.to_radians().sin_cos(); + for m in [[2.0, 0.0, 0.0, 3.0, 100.0, 400.0], [3.0 * c, 3.0 * s, -2.0 * s, 2.0 * c, 40.0, 60.0]] { + let matrix = format!("[ {} ]", m.map(|v| v.to_string()).join(" ")); + let linked = raster7("(Macintosh HD:Images:photo.tif) 0 XG\n", &matrix, (10, 20), "XF", ""); + let embedded = raster7("", &matrix, (10, 20), "XI", &"%FF0000\n".repeat(200)); + let r = read(stream7(&layer7("L", &format!("{linked}{embedded}"))).as_bytes()).unwrap(); + let a = art(&r.doc); + assert_eq!(a.len(), 2, "{:?}", r.warnings); + let (NodeKind::Image(link), NodeKind::Image(emb)) = (&a[0].kind, &a[1].kind) else { panic!("{:?}", a) }; + assert_eq!(link.link.as_ref().map(|l| l.path.as_str()), Some("Macintosh HD:Images:photo.tif")); + assert_eq!(emb.link, None, "an image whose samples follow stays embedded"); + assert!(r.doc.images[&link.key].is_proxy(), "the placeholder is what a missing link shows"); + // The file's pixels, placed as the embedded image's are: relinking keeps that size. + assert_eq!((link.width, link.height, link.xf), (emb.width, emb.height, emb.xf)); + assert_eq!((link.width, link.height), (10, 20)); + assert_eq!(r.warnings.iter().filter(|w| *w == read::LINKED_PLACEHOLDERS).count(), 1, "{:?}", r.warnings); + assert!(!r.warnings.iter().any(|w| w.contains("left out")), "{:?}", r.warnings); + } + // Images of other files keep images of their own, though each shows the same placeholder; two + // of one file share theirs. + let m = "[ 1 0 0 1 0 100 ]"; + let three = ["(a.tif) 0 XG\n", "(b.tif) 0 XG\n", "(a.tif) 0 XG\n"].map(|xg| raster7(xg, m, (2, 2), "XF", "")).concat(); + let r = read(stream7(&layer7("L", &three)).as_bytes()).unwrap(); + let keys: Vec<_> = art(&r.doc).iter().filter_map(|n| if let NodeKind::Image(im) = &n.kind { Some(im.key.clone()) } else { None }).collect(); + assert!(matches!(&keys[..], [a, b, c] if a != b && a == c), "{keys:?}"); + assert_eq!(r.doc.images.len(), 2); +} + +/// `XG` names the file of the `XF` after it only: an `XF` without a file name before it, after an +/// `XG` with operands of another shape or an empty path, or after an image that took the name, +/// is left out with a warning, as is one whose operands `XI` couldn't read. Of two `XG`s, the +/// second names the file. +#[test] +fn a_version_7_linked_image_without_its_file_name_is_left_out_with_a_warning() { + let m = "[ 1 0 0 1 0 100 ]"; + let embedded = raster7("() 1 XG\n", m, (1, 1), "XI", "%FF0000\n"); + for (what, src) in [ + ("no XG", raster7("", m, (2, 2), "XF", "")), + ("a name, not a string", raster7("/photo 0 XG\n", m, (2, 2), "XF", "")), + ("no modified flag", raster7("(a.tif) XG\n", m, (2, 2), "XF", "")), + ("an empty path", raster7("() 0 XG\n", m, (2, 2), "XF", "")), + ("taken by an embedded image", format!("{}{}", raster7("(a.tif) 0 XG\n", m, (1, 1), "XI", "%FF0000\n"), raster7("", m, (2, 2), "XF", ""))), + ("named in an earlier raster object", format!("%AI5_BeginRaster\n(a.tif) 0 XG\n%AI5_EndRaster\n{}", raster7("", m, (2, 2), "XF", ""))), + ("named outside a raster object", format!("(a.tif) 0 XG\n{}", raster7("", m, (2, 2), "XF", ""))), + ("too few operands", raster7("(a.tif) 0 XG\n", m, (2, 2), "XF", "").replace(" 8 3 0 0 0 0 XF", " 8 3 0 XF")), + ("no matrix", raster7("(a.tif) 0 XG\n", "", (2, 2), "XF", "")), + ("a matrix with no area", raster7("(a.tif) 0 XG\n", "[ 0 0 0 0 0 0 ]", (2, 2), "XF", "")), + ("no pixels", raster7("(a.tif) 0 XG\n", m, (0, 2), "XF", "")), + ("a side past the largest", raster7("(a.tif) 0 XG\n", m, (2_000_000, 2), "XF", "")), + ("samples of 7 bits", raster7("(a.tif) 0 XG\n", m, (2, 2), "XF", "").replace(" 8 3 0 0 0 0 XF", " 7 3 0 0 0 0 XF")), + ] { + let body = format!("{embedded}{src}"); + let r = read(stream7(&layer7("L", &body)).as_bytes()).unwrap(); + let a = art(&r.doc); + assert_eq!(a.len(), body.matches(" XI\n").count(), "{what}: {:?}", r.warnings); + assert!(a.iter().all(|n| matches!(&n.kind, NodeKind::Image(im) if im.link.is_none())), "{what}: the embedded images only"); + let left_out = r.warnings.iter().filter(|w| *w == "an image VectorCraft can't read was left out").count(); + assert_eq!(left_out, 1, "{what}: {:?}", r.warnings); + assert!(!r.warnings.iter().any(|w| w == read::LINKED_PLACEHOLDERS), "{what}: {:?}", r.warnings); + } + // More pixels than an embedded image may have: no pixels are read, so the linked image comes in. + let r = read(stream7(&layer7("L", &raster7("(a.tif) 0 XG\n", m, (100_000, 100_000), "XF", ""))).as_bytes()).unwrap(); + let a = art(&r.doc); + assert!(matches!(&a[..], [n] if matches!(&n.kind, NodeKind::Image(im) if (im.width, im.height) == (100_000, 100_000))), "{a:?}"); + assert!(!r.warnings.iter().any(|w| w == read::IMAGE_TOO_LARGE), "{:?}", r.warnings); + let twice = raster7("(a.tif) 0 XG\n(b.tif) 0 XG\n", m, (2, 2), "XF", ""); + let r = read(stream7(&layer7("L", &twice)).as_bytes()).unwrap(); + let a = art(&r.doc); + assert!(matches!(&a[..], [n] if matches!(&n.kind, NodeKind::Image(im) if im.link.as_ref().is_some_and(|l| l.path == "b.tif"))), "{a:?}"); +} + /// CMYK images keep their ink amounts, as the file's PDF part keeps them, and an alpha channel /// becomes their opacity mask: a grayscale image over the image. #[test] @@ -2482,6 +2566,25 @@ fn xml_ids_stay_within_their_byte_budget() { assert_eq!(bytes, super::read::MAX_XML_ID_BYTES); } +/// Placed files of other paths keep images of their own though their previews are alike; two of +/// one path share theirs. +#[test] +fn placed_files_of_other_paths_keep_images_of_their_own() { + let preview = [&b"2 1 12 32 17 "[..], &[255, 255, 0, 0, 128, 0, 64, 0, 9, 9, 9, 9]].concat(); + let object = |path: &str| { + let data = placed(true, "[5 0 0 -5 0 200]", path, Some(&preview), ""); + let find = |s: &[u8]| data.windows(s.len()).position(|w| w == s).unwrap(); + data[find(b"%AI5_BeginPlace")..find(b"%AI5_EndPlace\r") + 14].to_vec() + }; + let mut data = placed(true, "[5 0 0 -5 0 200]", "a.png", Some(&preview), ""); + let end = data.windows(14).position(|w| w == b"%AI5_EndPlace\r").unwrap() + 14; + data.splice(end..end, [object("b.png"), object("a.png")].concat()); + let r = read(&data).unwrap(); + let keys: Vec<_> = art(&r.doc).iter().filter_map(|n| if let NodeKind::Image(im) = &n.kind { Some(im.key.clone()) } else { None }).collect(); + assert!(matches!(&keys[..], [a, b, c] if a != b && a == c), "{keys:?}"); + assert_eq!(r.doc.images.len(), 2); +} + #[test] fn placed_files_are_linked_images_showing_their_preview() { // A 2×1 preview (premultiplied ARGB, a padded row) of a file of 4×2 pixels. diff --git a/crates/eps/src/import/native/build.rs b/crates/eps/src/import/native/build.rs index 1498c730a..2da70d874 100644 --- a/crates/eps/src/import/native/build.rs +++ b/crates/eps/src/import/native/build.rs @@ -94,7 +94,7 @@ pub(super) type Built = Result<(Document, Vec), String>; /// `structure` (the editing copy `data` read) with nothing compared with the pages, when the file's /// text document makes the type of every text object (at least one shows, and none is type that a /// look draws), no object is unread or has another placement or drawn art that the page would -/// choose, and its artboards are the pages, one for one and of their size, in points or in the pages' +/// choose, no linked image shows a placeholder, and its artboards are the pages, one for one and of their size, in points or in the pages' /// units ([`page_scale_alone`]). The document is drawn at that scale. Else `Err(structure)`, for /// [`build_from`] with the page. pub(super) fn build_without_page(structure: Structure, data: &[u8], pages: &[(f64, f64)], unit: f64) -> Result> { @@ -116,9 +116,11 @@ pub(super) fn build_without_page(structure: Structure, data: &[u8], pages: &[(f6 /// Is nothing in `structure` waiting on the page: no object unread (the page's art takes its /// place), no placed file with another placement, no live envelope with the drawn art it replaced -/// (the comparison with the page chooses between them)? +/// (the comparison with the page chooses between them), no linked image showing a placeholder +/// where the page has its pixels? fn nothing_waits_on_page(structure: &Structure) -> bool { - structure.unread.is_empty() + structure.placeholders.is_empty() + && structure.unread.is_empty() && structure.unread_elsewhere.is_empty() && structure.placed_elsewhere.is_empty() && structure.envelopes_drawn.is_empty() @@ -168,6 +170,16 @@ fn page_scale_alone(structure: &Structure, pages: &[(f64, f64)], unit: f64) -> O [1.0, unit].into_iter().find(|&k| k.is_finite() && k >= 1.0 && fits(k)) } +/// The areas left out of the comparisons with `page`: the `restyled` looks', and on a PostScript +/// page, which draws nothing for them, the linked images' `placeholders`. A PDF part draws those +/// images' pixels, which the placeholders don't match. +fn left_out_of_comparisons(page: Page, mut restyled: Vec, placeholders: Vec) -> Vec { + if matches!(page, Page::Art) { + restyled.extend(placeholders); + } + restyled +} + /// [`build`] from `structure`, the editing copy `data` already read. pub(super) fn build_from( structure: Structure, @@ -189,6 +201,7 @@ pub(super) fn build_from( unread_elsewhere, slot_names, restyled, + placeholders, placed_elsewhere, envelopes_drawn, styles_read, @@ -198,6 +211,7 @@ pub(super) fn build_from( bindings_skipped, warnings, } = structure; + let restyled = left_out_of_comparisons(page, restyled, placeholders); // Editing data in the units of the page's user space ([`in_units`]), or at its declared large // canvas scale ([`page_scale`]), is compared with the page scaled down to those units, and the // document read from it is scaled up by `unit`. @@ -1600,6 +1614,19 @@ mod candidate_tests { assert_eq!(more_pages(Some(&tiny_boards), &tiny, 1).len() + 1, MAX_PAGES_COMPARED); } + /// A linked image showing a placeholder (`XF`) waits on the page, whose PDF part draws its + /// pixels: the layers aren't used without it. + #[test] + fn a_linked_image_placeholder_waits_on_the_page() { + let raster = "%AI5_File:\n%AI5_BeginRaster\n(photo.tif) 0 XG\n[ 1 0 0 1 0 4 ] 0 0 4 4 4 4 8 3 0 0 0 0 XF\n%AI5_EndRaster\n"; + let data = format!( + "%!PS-Adobe-3.0 \n%%BoundingBox: 0 0 100 100\n%AI3_Cropmarks: 0 0 100 100\n%AI5_BeginLayer\n1 1 1 1 0 0 1 0 79 128 255 0 50 0 Lb\n(L) Ln\n{raster}LB\n%AI5_EndLayer--\n%%Trailer\n" + ); + let structure = ai::read(data.as_bytes(), false).unwrap(); + assert_eq!(structure.placeholders.len(), 1); + assert!(!nothing_waits_on_page(&structure)); + } + /// The pages a box touches with a margin round it include those it only comes near. #[test] fn the_pages_within_reach_of_a_box_count_as_touched() { diff --git a/crates/eps/src/import/tests_illustrator.rs b/crates/eps/src/import/tests_illustrator.rs index 950c989f2..d921bccdb 100644 --- a/crates/eps/src/import/tests_illustrator.rs +++ b/crates/eps/src/import/tests_illustrator.rs @@ -350,6 +350,35 @@ fn a_legacy_file_with_a_placed_eps_comes_in_through_its_layers() { assert!(r.warnings.iter().any(|w| w.contains("placed files")), "{:?}", r.warnings); } +/// A legacy file with a linked image (version 7 specification §8.2, §8.3: `(path) modified XG`, then +/// `XF` with no samples) comes in through its layers, the image as a linked image of that file +/// showing a placeholder where the matrix puts the image. +#[test] +fn a_legacy_file_with_a_linked_image_comes_in_through_its_layers() { + let prolog = "/Lb {10 {pop} repeat} def /Ln {pop} def /LB {} def /A {pop} def /k {setcmykcolor} def\n\ + /XG {pop pop} def /XF {13 {pop} repeat} def"; + let raster = "%AI5_File:\n%AI5_BeginRaster\n(photo.tif) 0 XG\n[2 0 0 3 20 80] 0 0 10 20 10 20 8 3 0 0 0 0 XF\n%AI5_EndRaster\n"; + let body = format!("%AI5_BeginLayer\n1 1 1 1 0 0 0 79 128 255 Lb\n(Back) Ln\n0 A\n0 0 0 1 k\n{}\n{raster}LB\n%AI5_EndLayer--\n", tri(10)); + let file = String::from_utf8(ai(AI8, "", &body)).unwrap().replace("%%EndProlog", &format!("{prolog}\n%%EndProlog")); + let r = import(file.as_bytes()).unwrap(); + assert!(!r.preview); + let names: Vec<_> = r.document.layers.iter().map(|l| l.name.clone().unwrap_or_default()).collect(); + assert_eq!(names, ["Back"], "{:?}", r.warnings); + let art = r.document.layers[0].children().unwrap(); + assert_eq!(art.len(), 2, "{:?}", r.warnings); + let NodeKind::Image(im) = &art[1].kind else { panic!("{:?}", art[1].kind) }; + assert_eq!(im.link.as_ref().map(|l| l.path.as_str()), Some("photo.tif")); + // The image's 10 × 20 pixels from (20, 80) in art space, 2 and 3 points each: 20 20 40 80 on + // the page, y down. + assert_eq!((im.width, im.height), (10, 20)); + let (top_left, bottom_right) = (im.xf * Point::ZERO, im.xf * Point::new(10.0, 20.0)); + assert!( + (top_left - Point::new(20.0, 20.0)).hypot() < 0.01 && (bottom_right - Point::new(40.0, 80.0)).hypot() < 0.01, + "{top_left:?} {bottom_right:?}" + ); + assert!(r.warnings.iter().any(|w| w.contains("show a placeholder")), "{:?}", r.warnings); +} + /// A file in the legacy format without layers (Illustrator 3) whose prolog is included: its prolog, /// a setup, and `art`. fn layerless(art: &str) -> Vec { diff --git a/crates/eps/src/import/tests_native.rs b/crates/eps/src/import/tests_native.rs index cb1529edb..fef0c48f5 100644 --- a/crates/eps/src/import/tests_native.rs +++ b/crates/eps/src/import/tests_native.rs @@ -419,6 +419,18 @@ fn group_with_only_placed_file_without_preview_uses_page_art() { assert!(notes.iter().any(|n| n.contains("placed files (1)")), "{notes:?}"); } +/// A linked image whose pixels the editing data doesn't keep (`XF`) shows a placeholder where the +/// PDF part draws the image: the layers are compared with the PDF part there, and the file comes in +/// as its PDF part when they differ. +#[test] +fn a_linked_image_without_pixels_is_compared_with_the_pdf_part() { + let linked = "%AI5_File:\n%AI5_BeginRaster\n(photo.tif) 0 XG\n[ 10 0 0 10 50 54 ] 0 0 4 4 4 4 8 3 0 0 0 0 XF\n%AI5_EndRaster"; + let art = native(&(layer("Live", true, &square(10, 10)) + &layer("Linked", true, linked))); + let (doc, notes, read) = crate::layered_ai(&private(&art), pdf_two_squares(), vec![], false, false, 1.0); + assert!(!read, "{notes:?}"); + assert_eq!(names(&doc), ["Layer 1"]); +} + #[test] fn top_level_pattern_uses_page_art_beside_live_path() { let body = format!("(Absent) 0 0 1 1 0 0 0 0 0 [1 0 0 1 0 0] p\n{}\n{}", square_path(50, 10), square(70, 10)); diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index 5c297aeb2..3f641acdc 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -4524,6 +4524,7 @@ axis Both И двете @msg an image VectorCraft can't read was left out изображение, което VectorCraft не може да разчете, беше пропуснато @msg an image whose data is cut short was left out изображение с непълни данни беше пропуснато @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel свързаните картини показват записания във файла предварителен преглед с ниска резолюция, докато файловете им бъдат намерени: презакачете ги в панела „Връзки“ +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel свързаните картини без предварителен преглед във файла показват заместител, докато файловете им бъдат намерени: презакачете ги в панела „Връзки“ @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise текстовите рамки за област в редове, твърде къси за шрифта, в който се показват, получиха по-високи рамки ({_1}): текстът им иначе нямаше да се види @msg its editing data doesn't say where its art is данните му за редактиране не посочват къде се намира неговата графика @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) този файл е записан без съвместимост с PDF и данните му за редактиране не могат да бъдат прочетени ({why}) diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index 12b748971..6756a928e 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -4923,6 +4923,7 @@ imageTrace Outline Obris @msg an image VectorCraft can't read was left out izostavljena je slika koju VectorCraft ne može pročitati @msg an image whose data is cut short was left out izostavljena je slika čiji su podaci skraćeni @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel povezane slike prikazuju pregled niske rezolucije sačuvan u datoteci dok se njihove datoteke ne pronađu: ponovo ih povežite u panelu Veze +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel povezane slike bez pregleda u datoteci prikazuju čuvar mjesta dok se njihove datoteke ne pronađu: ponovo ih povežite u panelu Veze @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise tekst u području u okvirima prekratkim za red fonta u kojem se prikazuje dobio je više okvire ({_1}): inače se tekst ne bi prikazao @msg its editing data doesn't say where its art is njeni podaci za uređivanje ne govore gdje joj je crtež @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) ova datoteka je sačuvana bez PDF kompatibilnosti, a njeni podaci za uređivanje se ne mogu pročitati ({why}) diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index d68f2a5bc..adc70e662 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -5181,6 +5181,7 @@ digits Malayalam Malaiàlam @msg library panel `{given}` isn't missing its library al panell de biblioteca `{given}` no li falta la biblioteca @msg library panel `{given}` isn't open el panell de biblioteca `{given}` no està obert @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel les imatges enllaçades mostren la previsualització de baixa resolució desada al fitxer fins que es trobin els seus fitxers: torneu-les a enllaçar al panell Enllaços +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel les imatges enllaçades sense previsualització al fitxer mostren un marcador de posició fins que es trobin els seus fitxers: torneu-les a enllaçar al panell Enllaços @msg Live Paint Merge: select a Live Paint group and the paths to add Fusió de pintura interactiva: seleccioneu un grup de pintura interactiva i els traçats que voleu afegir @msg Live Paint takes paths and compound paths: convert type, images and other objects to paths first La pintura interactiva accepta traçats i traçats compostos: convertiu abans el text, les imatges i altres objectes a traçats @msg Live Paint: select paths or compound paths Pintura interactiva: seleccioneu traçats o traçats compostos diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 10a96a0e8..fe6a7fc9f 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -4981,6 +4981,7 @@ imageTrace Outline Obrys @msg graphs come in as plain art, without their data or settings grafy se načtou jako obyčejná grafika, bez svých dat a nastavení @msg an image whose data is cut short was left out obrázek s useknutými daty byl vynechán @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel propojené obrázky se zobrazují jako náhled v nízkém rozlišení uložený v souboru, dokud se nenajdou jejich soubory: znovu je propojte v panelu Propojení +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel propojené obrázky bez náhledu v souboru se zobrazují jako zástupný symbol, dokud se nenajdou jejich soubory: znovu je propojte v panelu Propojení @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise text v oblasti v rámcích příliš nízkých pro řádek písma, ve kterém se zde zobrazuje, dostal vyšší rámce ({_1}): jinak by nebyl vidět @msg its editing data doesn't say where its art is z jeho dat pro úpravy není zřejmé, kde je kresba @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) tento soubor byl uložen bez kompatibility s PDF a jeho data pro úpravy nelze přečíst ({why}) diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index ae8069ffa..b1b759159 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -4611,6 +4611,7 @@ imageTrace Outline Kontur @msg an image VectorCraft can't read was left out et billede, som VectorCraft ikke kan læse, blev udeladt @msg an image whose data is cut short was left out et billede, hvis data er afkortet, blev udeladt @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel linkede billeder viser den gemte forhåndsvisning i lav opløsning, indtil deres filer findes: link dem igen i Links-panelet +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel linkede billeder uden forhåndsvisning i filen viser en pladsholder, indtil deres filer findes: link dem igen i Links-panelet @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise rammetekst i rammer, der er for lave til en tekstlinje i den skrifttype, den viser i, fik højere rammer ({_1}): teksten ville ellers ikke blive vist @msg its editing data doesn't say where its art is dens redigeringsdata siger ikke, hvor dens grafik er @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) denne fil blev gemt uden PDF-kompatibilitet, og dens redigeringsdata kan ikke læses ({why}) diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index 436940908..0a79d70cf 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -4591,6 +4591,7 @@ theme Appearance Erscheinungsbild @msg graphs come in as plain art, without their data or settings Diagramme werden als einfache Grafik übernommen, ohne ihre Daten und Einstellungen @msg an image whose data is cut short was left out ein Bild mit abgeschnittenen Daten wurde ausgelassen @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel verknüpfte Bilder zeigen die in der Datei gespeicherte Vorschau in niedriger Auflösung, bis ihre Dateien gefunden werden: Verknüpfen Sie sie im Bedienfeld „Verknüpfungen“ neu +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel verknüpfte Bilder ohne Vorschau in der Datei zeigen einen Platzhalter, bis ihre Dateien gefunden werden: Verknüpfen Sie sie im Bedienfeld „Verknüpfungen“ neu @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise Flächentext in Rahmen, die für eine Zeile der Schrift, in der er hier erscheint, zu niedrig sind, hat höhere Rahmen bekommen ({_1}): Sonst wäre der Text nicht zu sehen @msg its editing data doesn't say where its art is seine Bearbeitungsdaten geben nicht an, wo seine Grafik liegt @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) diese Datei wurde ohne PDF-Kompatibilität gespeichert, und ihre Bearbeitungsdaten können nicht gelesen werden ({why}) diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 9dd19335d..10d3ce4a9 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -4624,6 +4624,7 @@ digits Malayalam Μαλαγιάλαμ @msg graphs come in as plain art, without their data or settings τα γραφήματα εισάγονται ως απλή γραφική, χωρίς τα δεδομένα και τις ρυθμίσεις τους @msg an image whose data is cut short was left out παραλείφθηκε εικόνα με περικομμένα δεδομένα @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel οι συνδεδεμένες εικόνες εμφανίζουν την προεπισκόπηση χαμηλής ανάλυσης που έχει αποθηκευτεί, μέχρι να βρεθούν τα αρχεία τους: επανασυνδέστε τις στον πίνακα Σύνδεσμοι +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel οι συνδεδεμένες εικόνες χωρίς προεπισκόπηση στο αρχείο εμφανίζουν ένα σύμβολο κράτησης θέσης, μέχρι να βρεθούν τα αρχεία τους: επανασυνδέστε τις στον πίνακα Σύνδεσμοι @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise οι περιοχές κειμένου με πλαίσια πολύ μικρά για μία γραμμή της γραμματοσειράς τους απέκτησαν μεγαλύτερο ύψος ({_1}), διαφορετικά το κείμενο δεν θα εμφανιζόταν @msg its editing data doesn't say where its art is τα δεδομένα επεξεργασίας του δεν προσδιορίζουν τη θέση του σχεδίου @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) το αρχείο αποθηκεύτηκε χωρίς συμβατότητα PDF και τα δεδομένα επεξεργασίας του δεν μπορούν να διαβαστούν ({why}) diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 46ed40b7d..8673be51b 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -4675,6 +4675,7 @@ axis Both Ambos @msg graphs come in as plain art, without their data or settings los gráficos se importan como ilustración normal, sin sus datos ni sus ajustes @msg an image whose data is cut short was left out se omitió una imagen con datos incompletos @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel las imágenes vinculadas muestran la vista previa de baja resolución guardada en el archivo hasta que se encuentren sus archivos: vuelva a vincularlas en el panel Vínculos +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel las imágenes vinculadas sin vista previa en el archivo muestran un marcador de posición hasta que se encuentren sus archivos: vuelva a vincularlas en el panel Vínculos @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise el texto de área en marcos demasiado bajos para una línea de la fuente en que se muestra recibió marcos más altos ({_1}): de otro modo no se vería @msg its editing data doesn't say where its art is sus datos de edición no dicen dónde está su ilustración @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) este archivo se guardó sin compatibilidad con PDF y sus datos de edición no se pueden leer ({why}) diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 16860a45f..44ac67011 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -4883,6 +4883,7 @@ imageTrace Outline Ääriviiva @msg graphs come in as plain art, without their data or settings kaaviot tuodaan tavallisena grafiikkana ilman niiden tietoja ja asetuksia @msg an image whose data is cut short was left out kuva, jonka data on katkennut, jätettiin pois @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel linkitetyt kuvat näyttävät tiedostoon tallennetun matalan tarkkuuden esikatselun, kunnes niiden tiedostot löytyvät: linkitä ne uudelleen Linkit-paneelissa +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel linkitetyt kuvat, joilla ei ole esikatselua tiedostossa, näkyvät paikkamerkkinä, kunnes niiden tiedostot löytyvät: linkitä ne uudelleen Linkit-paneelissa @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise aluetekstin kehykset, jotka olivat liian matalia yhdelle riville niiden fontilla, korotettiin ({_1}): muuten niiden teksti ei näkyisi @msg its editing data doesn't say where its art is sen muokkaustiedoista ei selviä kuvituksen sijainti @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) tämä tiedosto tallennettiin ilman PDF-yhteensopivuutta, eikä sen muokkaustietoja voi lukea ({why}) diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index c028d24c8..66568a930 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -4663,6 +4663,7 @@ axis Both Les deux @msg graphs come in as plain art, without their data or settings les graphes sont importés comme illustration ordinaire, sans leurs données ni leurs réglages @msg an image whose data is cut short was left out une image aux données tronquées a été ignorée @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel les images liées affichent l’aperçu basse résolution enregistré dans le fichier tant que leurs fichiers ne sont pas trouvés : liez-les à nouveau dans le panneau Liens +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel les images liées sans aperçu dans le fichier affichent un espace réservé tant que leurs fichiers ne sont pas trouvés : liez-les à nouveau dans le panneau Liens @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise le texte captif dans des cadres trop bas pour une ligne de la police dans laquelle il s’affiche a reçu des cadres plus hauts ({_1}) : il ne s’afficherait pas autrement @msg its editing data doesn't say where its art is ses données d’édition ne disent pas où se trouve son illustration @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) ce fichier a été enregistré sans compatibilité PDF et ses données d’édition sont illisibles ({why}) diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 3eb35419c..246834fbb 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -4689,6 +4689,7 @@ imageTrace Outline Körvonal @msg graphs come in as plain art, without their data or settings a diagramok egyszerű grafikaként kerülnek be, adataik és beállításaik nélkül @msg an image whose data is cut short was left out kimaradt egy csonka adatú kép @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel a csatolt képek a fájlban mentett kis felbontású előnézetet mutatják, amíg a fájljaik elő nem kerülnek: csatold őket újra a Csatolások panelen +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel a fájlban előnézet nélküli csatolt képek helyőrzőt mutatnak, amíg a fájljaik elő nem kerülnek: csatold őket újra a Csatolások panelen @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise a túl alacsony keretben lévő területszöveg, amelybe a megjelenítő betűtípus egy sora sem fér el, magasabb keretet kapott ({_1}): különben nem látszana @msg an object can't be read egy objektum nem olvasható @msg an object in perspective would leave the edited grid egy perspektivikus objektum kikerülne a szerkesztett rácsból diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 33c329600..403294bdb 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -4611,6 +4611,7 @@ imageTrace Outline Kontur @msg an image VectorCraft can't read was left out gambar yang tidak dapat dibaca VectorCraft tidak disertakan @msg an image whose data is cut short was left out gambar yang datanya terpotong tidak disertakan @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel gambar tertaut menampilkan pratinjau resolusi rendah yang tersimpan dalam berkas sampai berkasnya ditemukan: tautkan ulang di panel Tautan +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel gambar tertaut tanpa pratinjau dalam berkas menampilkan penanda tempat sampai berkasnya ditemukan: tautkan ulang di panel Tautan @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise teks area dalam bingkai yang terlalu pendek untuk satu baris font yang ditampilkannya mendapat bingkai yang lebih tinggi ({_1}): tanpa itu teksnya tidak akan tampil @msg its editing data doesn't say where its art is data pengeditannya tidak menyatakan di mana karya seninya berada @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) berkas ini disimpan tanpa kompatibilitas PDF, dan data pengeditannya tidak dapat dibaca ({why}) diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index e59c310d8..e28ce2e32 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -4717,6 +4717,7 @@ axis Both Entrambi @msg graphs come in as plain art, without their data or settings i grafici vengono importati come grafica semplice, senza i loro dati e le loro impostazioni @msg an image whose data is cut short was left out un'immagine con dati incompleti è stata omessa @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel le immagini collegate mostrano l'anteprima a bassa risoluzione salvata nel file finché i loro file non vengono trovati: ricollegale nel pannello Collegamenti +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel le immagini collegate senza anteprima nel file mostrano un segnaposto finché i loro file non vengono trovati: ricollegale nel pannello Collegamenti @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise il testo in area in cornici troppo basse per una riga del font in cui viene mostrato ha ricevuto cornici più alte ({_1}): altrimenti non sarebbe visibile @msg its editing data doesn't say where its art is i suoi dati di modifica non dicono dove si trova la grafica @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) questo file è stato salvato senza compatibilità PDF e i suoi dati di modifica non si possono leggere ({why}) diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index c0f05308c..d6627cee5 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -4404,6 +4404,7 @@ swatch Bright Violet ビビッドバイオレット @msg graphs come in as plain art, without their data or settings グラフは通常のアートとして読み込まれ、データと設定は保持されません @msg an image whose data is cut short was left out データが途中で切れている画像は除外されました @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel リンク画像は、元のファイルが見つかるまで、ファイルに保存された低解像度のプレビューで表示されます:リンクパネルで再リンクしてください +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel ファイルにプレビューのないリンク画像は、元のファイルが見つかるまでプレースホルダーで表示されます:リンクパネルで再リンクしてください @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise 表示に使われるフォントの 1 行に対して低すぎるフレーム内のエリア内文字は、フレームを高くしました ({_1}): そうしないと文字が表示されません @msg gradient “{name}” isn't defined in the file: a plain colour stands in for it グラデーション「{name}」はファイル内で定義されていません: 代わりに単色を使用しています @msg brushes VectorCraft can't read yet were left out of the Brushes panel ({_1}) VectorCraft がまだ読み込めないブラシ {_1} 個はブラシパネルに追加されませんでした diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 82127af21..c69fdd9ad 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -4779,6 +4779,7 @@ font-technology Variable ცვლადი Even თანაბრად Stacked დასტად @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel დაკავშირებული გამოსახულებები ფაილში შენახულ დაბალი გარჩევადობის მინიატურას აჩვენებს, სანამ მათი ფაილები არ მოიძებნება: დაუკავშირეთ ისინი ხელახლა ბმულების პანელში +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel დაკავშირებული გამოსახულებები, რომელთა მინიატურაც ფაილში არ არის, ადგილის შემნახველს აჩვენებს, სანამ მათი ფაილები არ მოიძებნება: დაუკავშირეთ ისინი ხელახლა ბმულების პანელში @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise არის ტექსტს ჩარჩოებში, რომლებიც მისი შრიფტის ერთი სტრიქონისთვის ზედმეტად დაბალი იყო, ჩარჩოები გაეზარდა ({_1}): სხვაგვარად ტექსტი არ გამოჩნდებოდა @msg the art on them differs from the page's in {_1}% of it: they come from its editing data all the same მათზე არსებული ნახატი გვერდისგან {_1}%-ით განსხვავდება: მიუხედავად ამისა, ისინი რედაქტირების მონაცემებიდან აიღება @msg every numbered name for {name} is taken in the document's folder დოკუმენტის საქაღალდეში {name}-ის ყველა დანომრილი სახელი დაკავებულია diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index adbf82710..203748a6e 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -4331,6 +4331,7 @@ theme Appearance 외관 @msg graphs come in as plain art, without their data or settings 그래프는 데이터와 설정 없이 일반 아트로 가져왔습니다 @msg an image whose data is cut short was left out 데이터가 잘린 이미지는 제외했습니다 @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel 연결된 그림은 해당 파일을 찾을 때까지 파일에 저장된 저해상도 미리 보기로 표시됩니다: 링크 패널에서 다시 연결하세요 +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel 파일에 미리 보기가 없는 연결된 그림은 해당 파일을 찾을 때까지 자리 표시자로 표시됩니다: 링크 패널에서 다시 연결하세요 @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise 표시되는 글꼴의 한 줄보다 낮은 프레임의 영역 문자는 프레임을 더 높였습니다({_1}). 그렇지 않으면 문자가 표시되지 않습니다 @msg gradient “{name}” isn't defined in the file: a plain colour stands in for it 그레이디언트 “{name}”이(가) 파일에 정의되어 있지 않아 단색으로 대체했습니다 @msg brushes VectorCraft can't read yet were left out of the Brushes panel ({_1}) VectorCraft에서 아직 읽을 수 없는 브러시는 브러시 패널에서 제외되었습니다({_1}) diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 5c00ac9f4..62a638596 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -4623,6 +4623,7 @@ imageTrace Outline Contour @msg an image VectorCraft can't read was left out een afbeelding die VectorCraft niet kan lezen, is weggelaten @msg an image whose data is cut short was left out een afbeelding waarvan de gegevens zijn afgekapt, is weggelaten @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel gekoppelde afbeeldingen tonen het in het bestand opgeslagen voorbeeld met lage resolutie totdat hun bestanden zijn gevonden: koppel ze opnieuw in het paneel Koppelingen +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel gekoppelde afbeeldingen zonder voorbeeld in het bestand tonen een tijdelijke aanduiding totdat hun bestanden zijn gevonden: koppel ze opnieuw in het paneel Koppelingen @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise vlaktekst in kaders die te kort zijn voor één regel van het lettertype waarin de tekst wordt weergegeven, heeft hogere kaders gekregen ({_1}): anders zou de tekst niet zichtbaar zijn @msg its editing data doesn't say where its art is zijn bewerkingsgegevens zeggen niet waar de illustratie zich bevindt @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) dit bestand is opgeslagen zonder PDF-compatibiliteit en de bewerkingsgegevens kunnen niet worden gelezen ({why}) diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 0754590d4..b77219534 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -4807,6 +4807,7 @@ imageTrace Outline Kontur @msg graphs come in as plain art, without their data or settings wykresy są wczytywane jako zwykła grafika, bez ich danych i ustawień @msg an image whose data is cut short was left out pominięto obraz z uciętymi danymi @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel połączone obrazy pokazują zapisany w pliku podgląd niskiej rozdzielczości, dopóki ich pliki nie zostaną znalezione: połącz je ponownie w panelu Łącza +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel połączone obrazy bez podglądu w pliku pokazują symbol zastępczy, dopóki ich pliki nie zostaną znalezione: połącz je ponownie w panelu Łącza @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise tekst akapitowy w ramkach niższych niż wiersz wyświetlanej czcionki otrzymał wyższe ramki ({_1}): inaczej tekst nie byłby widoczny @msg its editing data doesn't say where its art is jego dane edycyjne nie określają położenia kompozycji @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) ten plik zapisano bez zgodności z PDF, a jego danych edycyjnych nie można odczytać ({why}) diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 6ba1f7ff3..978570aa0 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -4901,6 +4901,7 @@ axis Both Ambos @msg object {id} is not a selected top-level object o objeto {id} não é um objeto selecionado de nível superior @msg {path}: not a file {path}: não é um arquivo @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel as imagens vinculadas mostram a visualização de baixa resolução salva no arquivo até que seus arquivos sejam encontrados: revincule-as no painel Links +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel as imagens vinculadas sem visualização no arquivo mostram um espaço reservado até que seus arquivos sejam encontrados: revincule-as no painel Links @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise o texto de área em molduras baixas demais para uma linha da fonte em que aparece recebeu molduras mais altas ({_1}): senão o texto não apareceria @msg every numbered name for {name} is taken in the document's folder todos os nomes numerados para {name} já existem na pasta do documento @msg No linked files to look for Nenhum arquivo vinculado para procurar diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 7be753b6f..6b73fd9ac 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -4712,6 +4712,7 @@ axis Both Оба @msg graphs come in as plain art, without their data or settings диаграммы импортируются как обычная графика, без их данных и настроек @msg an image whose data is cut short was left out изображение с обрезанными данными пропущено @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel связанные изображения показываются как сохранённый в файле просмотр низкого разрешения, пока их файлы не найдены: восстановите связи на панели «Связи» +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel связанные изображения без просмотра в файле показываются как заполнитель, пока их файлы не найдены: восстановите связи на панели «Связи» @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise текст в области в рамках, слишком низких для строки шрифта, которым он отображается, получил более высокие рамки ({_1}): иначе он не был бы виден @msg its editing data doesn't say where its art is в его данных редактирования не указано, где находится графика @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) этот файл сохранён без совместимости с PDF, и его данные редактирования не удаётся прочитать ({why}) diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 68eee3605..2289ac3ba 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -4574,6 +4574,7 @@ axis Both Båda @msg graphs come in as plain art, without their data or settings diagram läses in som vanlig grafik, utan sina data och inställningar @msg an image whose data is cut short was left out en bild med avkortade data utelämnades @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel länkade bilder visar förhandsgranskningen med låg upplösning som sparats i filen tills deras filer hittas: länka om dem i panelen Länkar +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel länkade bilder utan förhandsgranskning i filen visar en platshållare tills deras filer hittas: länka om dem i panelen Länkar @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise områdestext i ramar som var för låga för en rad i det typsnitt den visas med fick högre ramar ({_1}): annars skulle texten inte synas @msg its editing data doesn't say where its art is dess redigeringsdata anger inte var dess grafik finns @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) den här filen sparades utan PDF-kompatibilitet och dess redigeringsdata kan inte läsas ({why}) diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index 184bd0b46..9a42debc2 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -4411,6 +4411,7 @@ axis Both Her İkisi @msg graphs come in as plain art, without their data or settings grafikler, verileri ve ayarları olmadan düz çizim olarak içe aktarılır @msg an image whose data is cut short was left out verileri kısa kesilen bir resim dışarıda bırakıldı @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel bağlantılı resimler, dosyaları bulunana kadar dosyaya kaydedilen düşük çözünürlüklü önizlemeyi gösterir: bunları Bağlantılar panelinde yeniden bağlayın +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel dosyada önizlemesi olmayan bağlantılı resimler, dosyaları bulunana kadar bir yer tutucu gösterir: bunları Bağlantılar panelinde yeniden bağlayın @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise çerçevelerdeki alan türü, daha uzun çerçevelerde gösterdiği yazı tipinin bir satırı için çok kısa ({_1}): bunların türü aksi halde gösterilmez @msg its editing data doesn't say where its art is düzenleme verileri sanatın nerede olduğunu söylemiyor @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) bu dosya PDF uyumluluğu olmadan kaydedildi ve düzenleme verileri okunamıyor ({why}) diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index f89aa17e9..d95a9ae5c 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -4701,6 +4701,7 @@ axis Both Обидві @msg graphs come in as plain art, without their data or settings діаграми імпортуються як звичайна графіка, без їхніх даних і налаштувань @msg an image whose data is cut short was left out зображення з обрізаними даними пропущено @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel пов’язані зображення показуються як збережений у файлі перегляд низької роздільності, доки їхні файли не знайдено: відновіть зв’язки на панелі «Зв’язки» +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel пов’язані зображення без перегляду у файлі показуються як заповнювач, доки їхні файли не знайдено: відновіть зв’язки на панелі «Зв’язки» @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise текст в області в рамках, занизьких для рядка шрифту, яким він показується, отримав вищі рамки ({_1}): інакше його не було б видно @msg its editing data doesn't say where its art is у даних редагування не зазначено, де знаходиться графіка @msg this file was saved without PDF compatibility, and its editing data can't be read ({why}) цей файл збережений без сумісності з PDF, і його дані редагування не вдається прочитати ({why}) diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index a76ec9ebe..631443da9 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -4535,6 +4535,7 @@ theme Appearance Giao diện @msg line {line}: value for `{var}` must be true or false dòng {line}: giá trị của `{var}` phải là true hoặc false @msg line {line}: value for `{var}` is longer than {MAX_GRAPH_CSV} bytes dòng {line}: giá trị của `{var}` dài hơn {MAX_GRAPH_CSV} byte @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel ảnh liên kết hiển thị bản xem trước độ phân giải thấp đã lưu trong tệp cho đến khi tìm thấy tệp gốc: liên kết lại trong bảng Liên kết +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel ảnh liên kết không có bản xem trước trong tệp hiển thị ô giữ chỗ cho đến khi tìm thấy tệp gốc: liên kết lại trong bảng Liên kết @msg Live Paint Merge: select a Live Paint group and the paths to add Hợp nhất tô trực tiếp: chọn nhóm tô trực tiếp và các đường dẫn để thêm @msg Live Paint takes paths and compound paths: convert type, images and other objects to paths first Tô trực tiếp nhận đường dẫn và đường dẫn phức: hãy chuyển văn bản, hình ảnh và các đối tượng khác thành đường dẫn trước @msg Live Paint: select paths or compound paths Tô trực tiếp: chọn đường dẫn hoặc đường dẫn phức diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index c1945d726..fb2735e53 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -3464,6 +3464,7 @@ digits Malayalam 马拉雅拉姆数字 Update Changed Links 更新已更改的链接 @plural {n} linked image changed on disk. Show the new version?|{n} linked images changed on disk. Show the new versions? 有 {n} 个链接图像已在磁盘上更改。要显示新版本吗? @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel 链接的图片在找到其文件之前显示文件中存储的低分辨率预览:请在“链接”面板中重新链接 +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel 文件中没有预览的链接图片在找到其文件之前显示占位符:请在“链接”面板中重新链接 @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise 框架高度不足以容纳所显示字体一行的区域文字已加高框架 ({_1}):否则文字不会显示 Update Modified Links 更新已修改的链接 UPPERCASE 大写 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index d7347d174..23bf20637 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -4494,6 +4494,7 @@ digits Malayalam 馬來亞拉姆數字 Update Changed Links 更新已變更的連結 @plural {n} linked image changed on disk. Show the new version?|{n} linked images changed on disk. Show the new versions? 有 {n} 個連結影像已在磁碟上變更。要顯示新版本嗎? @msg linked pictures show the low-resolution preview saved in the file until their files are found: relink them in the Links panel 連結的圖片在找到其檔案之前顯示檔案中儲存的低解析度預覽:請在「連結」面板中重新連結 +@msg linked pictures with no preview in the file show a placeholder until their files are found: relink them in the Links panel 檔案中沒有預覽的連結圖片在找到其檔案之前顯示預留位置:請在「連結」面板中重新連結 @msg area type in frames too short for a line of the font it shows in got taller frames ({_1}): their type wouldn't show otherwise 框架高度不足以容納所顯示字體一行的區域文字已加高框架 ({_1}):否則文字不會顯示 Update Modified Links 更新已修改的連結 UPPERCASE 全部大寫 diff --git a/docs/file-format-parity.md b/docs/file-format-parity.md index 6689bf1b4..6191a52c5 100644 --- a/docs/file-format-parity.md +++ b/docs/file-format-parity.md @@ -120,7 +120,9 @@ private editing data. VectorCraft: without the prolog opens since #1027, its legacy type (`To` … `TO`) since #868, with its paragraphs' letter and word spacing (`TC`, `TW`), hanging punctuation (`Tq`) and hyphenation (`Th`). Its patterns in the version 7 form (a list of `@` and `&` layers, `_ &` for the tile's background) open as pattern swatches, - with a fill's offset, scale, rotation, reflection and shear applied before its matrix. + with a fill's offset, scale, rotation, reflection and shear applied before its matrix. Its linked images in + the version 7 form (`(path) modified XG`, then `XF` with no samples) come in as linked images of their files, + showing a placeholder where the image goes until the file is relinked in the Links panel. - Estimate: **~65%** for real exchange with Illustrator users (open: ~75%; save: PDF-compatible, or legacy version 7 with layers and groups; not yet tested by users who hand files back). Closing the open-side issues: 10–20 h with users' files.