mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-09 23:31:23 +00:00
Merge pull request #3995 from dotCooCoo/feat/document-compare-image
Document: document.compare measures how far an artboard's render is from an image
This commit is contained in:
@@ -41,6 +41,15 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
cmd!(query "document.inspect", "Inspect Document", [], None, "{depth?, childLimit?, ids?: [id…] (list just these nodes, of any level, in this order, under `nodes` in place of `layers`; an unknown id is an error; at most 10000), kind?: panel label such as Layer; Group; Path; Type or Image (exact, ignoring case; list every such node under `nodes`, each with `path`, its ancestor ids with the layer first, searching the subtrees of `ids` when given), limit?: at most this many entries of the list, offset?: entries skipped first (default 0; with `ids`, `kind`, `limit` or `offset` the reply adds `total`, the entries before paging)} → layer tree (each node: id, name, kind, visible, locked, bounds, opacity (0–1) and opacityPct (0–100 %, the scale object.setProps takes) when below 1, blend when not Normal, fill, stroke and strokeWidth of objects and compound paths; a compound path's members have compoundMember: true instead of paint, which is the compound's), artboards, selection, history (a sliced tree reports childCount); without the scope options the reply is the whole layer tree", has_doc, doc_inspect),
|
||||
cmd!(query "document.node", "Inspect Object", [], None, "{id, summary?: compact summary, depth?: child levels in the summary (default all), childLimit?: children shown per node (default all; a level that shows fewer reports childCount)} → one object", has_doc, doc_node),
|
||||
cmd!(query "document.find", "Find Objects", [], None, "{name?: substring of the Layers panel name, kind?: panel label such as Group; Path; Type or Image (exact), text?: substring of type content, within?: [x, y, width, height] (an object's geometric bounds inside this rectangle, edges included; document points as document.inspect's bounds; layers never match this or the size filters), intersects?: [x, y, width, height] (bounds touching or overlapping it), minWidth?, maxWidth?, minHeight?, maxHeight?: pt (the bounds' size), minThickness?, maxThickness?: pt (the smaller of the bounds' width and height), minArea?, maxArea?: pt² (the bounds' width × height), minAnchors?, maxAnchors?: anchor points of a path (a compound path's members together; other objects never match), select?: bool (also select the matches, leaving out hidden and locked ones, those inside another match, and a compound path's members unless the compound path is isolated; Select > Reselect repeats it), limit?: max matches listed (default 100, 0 counts only)} → {matches: [{id, name, kind, path}], total, selected (with select: the count selected)}; at least one filter, all of them matching", has_doc, doc_find),
|
||||
cmd!(
|
||||
query "document.compare",
|
||||
"Compare with Image",
|
||||
[],
|
||||
None,
|
||||
"{path: an image file (PNG, JPEG, WebP, TIFF or BMP), artboard?: index=0, background?: \"#rrggbb\"=\"#ffffff\" (the render and the image are both flattened on it), threshold?: 0.08 (0–1), diffPath?: a PNG to write (each pixel's absolute R, G and B differences)} render the artboard at the image's size (the image's width in pixels over the artboard's width in points), drawn as document.export draws a PNG (linked images and placed documents from their files), and compare it with the image; an image whose height differs by more than a pixel from the artboard's height at that scale is refused (not in the browser) → {width, height, rmse: the root mean square of the R, G and B differences, 0–1 (6 decimals), over: the pixels with a channel that differs by more than threshold, total: the pixels, threshold, diffPath?, warnings?: as a PNG export's (type that doesn't fit its frame, an image that couldn't be decoded, type in a font or style that isn't available, previews drawn because a linked file can't be read)}",
|
||||
has_doc,
|
||||
doc_compare
|
||||
),
|
||||
cmd!(query "document.json", "Document JSON", [], None, "{} → complete document model", has_doc, |s, _| Ok(serde_json::to_value(&*s.doc()?.doc).unwrap_or(Value::Null))),
|
||||
cmd!(
|
||||
"document.setUnits",
|
||||
@@ -385,6 +394,155 @@ fn select_found(s: &mut Session, p: &Value, ids: &[NodeId]) -> Result<Value> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Render an artboard at an image's size, drawn as a PNG export draws it (linked images and placed
|
||||
/// documents from their files, with the export's warnings), and measure how far the
|
||||
/// two are apart: both flattened on `background`, the root mean square of the R, G and B
|
||||
/// differences (0–1), and the pixels with a channel that differs by more than `threshold`.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn doc_compare(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
use vectorcraft_render::encode::{RasterExportOptions, RasterFormat, png};
|
||||
const C: &str = "document.compare";
|
||||
let path = str_param(p, "path").ok_or_else(|| bad(C, "missing `path`"))?;
|
||||
let diff_path = match p.get("diffPath") {
|
||||
None | Some(Value::Null) => None,
|
||||
Some(Value::String(v)) => Some(v.as_str()),
|
||||
Some(_) => {
|
||||
let key = "diffPath";
|
||||
return Err(bad(C, format!("`{key}` must be a string")));
|
||||
}
|
||||
};
|
||||
let background = match p.get("background") {
|
||||
None | Some(Value::Null) => [255; 3],
|
||||
Some(v) => match super::fileio::background(v) {
|
||||
Ok(Some(rgb)) => rgb,
|
||||
_ => return Err(bad(C, format!("background {v}: a color such as \"#808080\""))),
|
||||
},
|
||||
};
|
||||
let threshold = match p.get("threshold") {
|
||||
None | Some(Value::Null) => 0.08,
|
||||
Some(v) => v.as_f64().filter(|t| (0.0..=1.0).contains(t)).ok_or_else(|| bad(C, "`threshold` must be a number from 0 to 1"))?,
|
||||
};
|
||||
let doc = &s.doc()?.doc;
|
||||
let count = doc.artboards.len();
|
||||
let i = opt_u64(p, C, "artboard")?.unwrap_or(0);
|
||||
let region = usize::try_from(i)
|
||||
.ok()
|
||||
.and_then(|i| doc.artboards.get(i))
|
||||
.map(|a| a.rect)
|
||||
.ok_or_else(|| bad(C, format!("no artboard {i} (0-based; the document has {count})")))?;
|
||||
if let Some(d) = diff_path {
|
||||
crate::file_access::check_write(d).map_err(EngineError::Other)?;
|
||||
}
|
||||
let image = compare_image(path)?;
|
||||
let (iw, ih) = image.dimensions();
|
||||
// The image's width sets the scale; its height may differ from the artboard's at that scale by
|
||||
// the pixel the rounding of a render takes.
|
||||
let scale = f64::from(iw) / region.width();
|
||||
let rendered_height = region.height() * scale;
|
||||
if iw == 0 || ih == 0 || !rendered_height.is_finite() || (rendered_height - f64::from(ih)).abs() > 1.0 {
|
||||
let (rw, rh) = (iw, rendered_height.round());
|
||||
return Err(bad(
|
||||
C,
|
||||
format!("the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ"),
|
||||
));
|
||||
}
|
||||
vectorcraft_render::raster_size(region, scale).map_err(|e| bad(C, e))?;
|
||||
vectorcraft_render::raster_size(vectorcraft_geom::Rect::new(0.0, 0.0, f64::from(iw), f64::from(ih)), 1.0).map_err(|e| bad(C, e))?;
|
||||
let view = Affine::scale(scale) * Affine::translate((-region.x0, -region.y0));
|
||||
let opts = RasterExportOptions { background: Some(background), ..Default::default() }.render_options(RasterFormat::Png);
|
||||
// As a PNG export: linked images and placed documents drawn from their files, not the
|
||||
// previews saved for them.
|
||||
let (full, linked) = super::place::document::full_documents(doc);
|
||||
let failed = vectorcraft_render::decode_failures();
|
||||
let rendered = vectorcraft_render::Renderer::new().render(&full, iw, ih, view, &opts);
|
||||
// A canceled render stops drawing: the picture is not whole.
|
||||
vectorcraft_doc::cancel::check()?;
|
||||
// As a PNG export says, in its order: type on the artboard that doesn't fit its frame, an image
|
||||
// the renderer couldn't decode (missing from the render), type in a missing font or style (drawn
|
||||
// in another one), and linked files drawn from their previews.
|
||||
let mut warnings: Vec<String> = super::fonts::export_overflow_warning(&full, &full.layers, Some(&[region])).into_iter().collect();
|
||||
if let Some(w) = super::rasterfx::undecoded_warning(failed) {
|
||||
warnings.push(w.into());
|
||||
}
|
||||
if let Some(w) = super::fonts::substitution_warning(&full) {
|
||||
warnings.push(w);
|
||||
}
|
||||
warnings.extend(linked);
|
||||
let rendered = rendered.to_straight();
|
||||
let flat = |px: &[u8; 4]| {
|
||||
let a = u32::from(px[3]);
|
||||
[0, 1, 2].map(|k| ((u32::from(px[k]) * a + u32::from(background[k]) * (255 - a) + 127) / 255) as u8)
|
||||
};
|
||||
let row = iw as usize * 4;
|
||||
let limit = threshold * 255.0;
|
||||
let (mut squares, mut over) = (0.0f64, 0u64);
|
||||
let mut diff = diff_path.map(|_| Vec::with_capacity(row * ih as usize));
|
||||
for (a, b) in rendered.chunks_exact(row).zip(image.as_raw().chunks_exact(row)) {
|
||||
vectorcraft_doc::cancel::check()?;
|
||||
for (pa, pb) in a.as_chunks::<4>().0.iter().zip(b.as_chunks::<4>().0) {
|
||||
let (fa, fb) = (flat(pa), flat(pb));
|
||||
let d = [0, 1, 2].map(|k| fa[k].abs_diff(fb[k]));
|
||||
squares += d.iter().map(|&x| f64::from(x) * f64::from(x)).sum::<f64>();
|
||||
if d.iter().any(|&x| f64::from(x) > limit) {
|
||||
over += 1;
|
||||
}
|
||||
if let Some(out) = &mut diff {
|
||||
out.extend_from_slice(&[d[0], d[1], d[2], 255]);
|
||||
}
|
||||
}
|
||||
}
|
||||
let total = u64::from(iw) * u64::from(ih);
|
||||
let rmse = (squares / (total as f64 * 3.0)).sqrt() / 255.0;
|
||||
let mut out = json!({
|
||||
"width": iw,
|
||||
"height": ih,
|
||||
"rmse": (rmse * 1e6).round() / 1e6,
|
||||
"over": over,
|
||||
"total": total,
|
||||
"threshold": threshold,
|
||||
});
|
||||
if let (Some(d), Some(pixels)) = (diff_path, diff) {
|
||||
let bytes = png::encode(&pixels, iw, ih, &png::PngOptions { ppi: None, interlaced: false }).map_err(EngineError::Other)?;
|
||||
super::fileio::write_file(d, &bytes)?;
|
||||
out["diffPath"] = json!(d);
|
||||
}
|
||||
if !warnings.is_empty() {
|
||||
out["warnings"] = json!(warnings);
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// The image `document.compare` reads from `path` (through the automation read root), as straight
|
||||
/// RGBA: a PNG, JPEG, WebP, TIFF or BMP within the allocation an opened image may take.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn compare_image(path: &str) -> Result<image::RgbaImage> {
|
||||
use image::ImageDecoder as _;
|
||||
const C: &str = "document.compare";
|
||||
let bytes = super::fileio::read_file(path)?;
|
||||
if let Some((w, h)) = vectorcraft_doc::cmyk::oversized_tiff(&bytes) {
|
||||
return Err(bad(C, format!("an image of {w} × {h} pixels is too large to draw")));
|
||||
}
|
||||
let mut reader = image::ImageReader::new(std::io::Cursor::new(bytes)).with_guessed_format().map_err(|e| bad(C, format!("{path}: {e}")))?;
|
||||
let readable = [image::ImageFormat::Png, image::ImageFormat::Jpeg, image::ImageFormat::WebP, image::ImageFormat::Tiff, image::ImageFormat::Bmp];
|
||||
if !reader.format().is_some_and(|f| readable.contains(&f)) {
|
||||
return Err(bad(C, format!("{path}: not a PNG, JPEG, WebP, TIFF or BMP image")));
|
||||
}
|
||||
let mut limits = image::Limits::default();
|
||||
limits.max_alloc = Some(vectorcraft_doc::MAX_RASTER_ALLOC);
|
||||
reader.limits(limits);
|
||||
let decoder = reader.into_decoder().map_err(|e| bad(C, format!("{path}: {e}")))?;
|
||||
let (w, h) = decoder.dimensions();
|
||||
if decoder.total_bytes() > vectorcraft_doc::MAX_RASTER_ALLOC || u64::from(w) * u64::from(h) * 4 > vectorcraft_doc::MAX_RASTER_ALLOC {
|
||||
return Err(bad(C, format!("an image of {w} × {h} pixels is too large to draw")));
|
||||
}
|
||||
Ok(image::DynamicImage::from_decoder(decoder).map_err(|e| bad(C, format!("{path}: {e}")))?.to_rgba8())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn doc_compare(_: &mut Session, _: &Value) -> Result<Value> {
|
||||
Err(bad("document.compare", "comparing with an image file isn't available in the browser"))
|
||||
}
|
||||
|
||||
/// Document Setup's units (also `document.setup {units}`).
|
||||
fn set_units(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let u = str_param(p, "units").and_then(Unit::named).ok_or_else(|| bad("document.setUnits", "unknown units"))?;
|
||||
|
||||
@@ -31,6 +31,7 @@ mod colorize;
|
||||
pub(super) mod colormgmt;
|
||||
mod colorthemes;
|
||||
mod colourfonts;
|
||||
mod compare;
|
||||
mod compound_shape;
|
||||
mod compoundpaint;
|
||||
mod constrain_new;
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
//! `document.compare`: an artboard rendered at an image's size, as a PNG export draws it, and
|
||||
//! measured against the image (RMSE, the pixels over a threshold, a difference image), with the
|
||||
//! image and the render flattened on one background; images of other proportions, files that
|
||||
//! can't be read and paths outside the automation roots are errors.
|
||||
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::Session;
|
||||
|
||||
/// A 40 × 20 pt document with a black 10 × 10 pt square at (10, 5), no stroke.
|
||||
fn session() -> (Session, Value) {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 40, "height": 20})).unwrap();
|
||||
s.execute("paint.setFill", &json!({"color": "#000000"})).unwrap();
|
||||
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
||||
let id = s.execute("shape.rectangle", &json!({"x": 10, "y": 5, "width": 10, "height": 10})).unwrap()["id"].clone();
|
||||
(s, id)
|
||||
}
|
||||
|
||||
fn path_in(dir: &std::path::Path, name: &str) -> String {
|
||||
dir.join(name).to_string_lossy().into_owned()
|
||||
}
|
||||
|
||||
/// The artboard exported as a PNG at 2 pixels a point on white.
|
||||
fn export(s: &mut Session, path: &str) {
|
||||
s.execute("document.export", &json!({"path": path, "format": "png", "scale": 2, "background": "white"})).unwrap();
|
||||
}
|
||||
|
||||
fn compare(s: &mut Session, p: Value) -> Value {
|
||||
s.execute("document.compare", &p).unwrap_or_else(|e| panic!("document.compare {p}: {e}"))
|
||||
}
|
||||
|
||||
fn error(s: &mut Session, p: Value) -> String {
|
||||
s.execute("document.compare", &p).map(|v| panic!("document.compare {p} answered {v}")).unwrap_err().to_string()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_export_compares_equal_and_a_moved_square_counts_the_pixels_it_changed() {
|
||||
let dir = vectorcraft_testkit::temp_dir("compare-moved");
|
||||
let png = path_in(&dir, "art.png");
|
||||
let (mut s, id) = session();
|
||||
export(&mut s, &png);
|
||||
let before = (s.doc().unwrap().revision, s.doc().unwrap().history.undo.len());
|
||||
let r = compare(&mut s, json!({"path": png}));
|
||||
assert_eq!(r, json!({"width": 80, "height": 40, "rmse": 0.0, "over": 0, "total": 3200, "threshold": 0.08}));
|
||||
assert_eq!((s.doc().unwrap().revision, s.doc().unwrap().history.undo.len()), before, "comparing doesn't edit the document");
|
||||
// 4 pt is 8 pixels: 8 columns of the square's 20 rows turn white and 8 turn black, every
|
||||
// channel by 255.
|
||||
s.execute("object.move", &json!({"ids": [id], "dx": 4, "dy": 0})).unwrap();
|
||||
let r = compare(&mut s, json!({"path": png}));
|
||||
let over = 2 * 8 * 20;
|
||||
assert_eq!((r["over"].as_u64(), r["total"].as_u64()), (Some(over), Some(3200)), "{r}");
|
||||
let rmse = ((over as f64 / 3200.0).sqrt() * 1e6).round() / 1e6;
|
||||
assert_eq!(r["rmse"].as_f64(), Some(rmse), "{r}");
|
||||
// Above every difference, nothing is over.
|
||||
assert_eq!(compare(&mut s, json!({"path": png, "threshold": 1}))["over"], json!(0));
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_image_and_the_render_are_flattened_on_the_background() {
|
||||
let dir = vectorcraft_testkit::temp_dir("compare-background");
|
||||
let png = path_in(&dir, "clear.png");
|
||||
// Transparent everywhere, with red in the color channels that the alpha hides.
|
||||
image::RgbaImage::from_pixel(80, 40, image::Rgba([255, 0, 0, 0])).save(&png).unwrap();
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 40, "height": 20})).unwrap();
|
||||
// Nothing drawn: both are the background alone.
|
||||
for background in ["#808080", "#ffffff"] {
|
||||
let r = compare(&mut s, json!({"path": png, "background": background}));
|
||||
assert_eq!((r["rmse"].as_f64(), r["over"].as_u64()), (Some(0.0), Some(0)), "{background}: {r}");
|
||||
}
|
||||
// A black left half: 128 from gray in every channel of half the pixels, 255 from white.
|
||||
s.execute("paint.setFill", &json!({"color": "#000000"})).unwrap();
|
||||
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
||||
s.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 20, "height": 20})).unwrap();
|
||||
let r = compare(&mut s, json!({"path": png, "background": "#808080"}));
|
||||
let rmse = |d: f64| ((0.5f64).sqrt() * d / 255.0 * 1e6).round() / 1e6;
|
||||
assert_eq!((r["rmse"].as_f64(), r["over"].as_u64()), (Some(rmse(128.0)), Some(1600)), "{r}");
|
||||
let r = compare(&mut s, json!({"path": png}));
|
||||
assert_eq!((r["rmse"].as_f64(), r["over"].as_u64()), (Some(rmse(255.0)), Some(1600)), "{r}");
|
||||
// A threshold just above 128/255 leaves the gray differences out.
|
||||
assert_eq!(compare(&mut s, json!({"path": png, "background": "#808080", "threshold": 0.51}))["over"], json!(0));
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_image_of_other_proportions_is_refused_and_one_pixel_is_allowed() {
|
||||
let dir = vectorcraft_testkit::temp_dir("compare-size");
|
||||
let (mut s, _) = session();
|
||||
let square = path_in(&dir, "square.png");
|
||||
image::RgbaImage::from_pixel(30, 30, image::Rgba([255; 4])).save(&square).unwrap();
|
||||
let e = error(&mut s, json!({"path": square}));
|
||||
assert!(e.contains("30 × 30 pixels") && e.contains("30 × 15 pixels"), "{e}");
|
||||
let taller = path_in(&dir, "taller.png");
|
||||
image::RgbaImage::from_pixel(80, 41, image::Rgba([255; 4])).save(&taller).unwrap();
|
||||
let r = compare(&mut s, json!({"path": taller}));
|
||||
assert_eq!((r["width"].as_u64(), r["height"].as_u64(), r["total"].as_u64()), (Some(80), Some(41), Some(3280)), "{r}");
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_export_whose_height_was_rounded_compares_equal() {
|
||||
let dir = vectorcraft_testkit::temp_dir("compare-rounded");
|
||||
let png = path_in(&dir, "art.png");
|
||||
// 20.25 pt at 2 pixels a point is 40.5 rows, which the export rounds to 41.
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 40, "height": 20.25})).unwrap();
|
||||
s.execute("paint.setFill", &json!({"color": "#000000"})).unwrap();
|
||||
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
||||
s.execute("shape.rectangle", &json!({"x": 10, "y": 5, "width": 10, "height": 10})).unwrap();
|
||||
export(&mut s, &png);
|
||||
let r = compare(&mut s, json!({"path": png}));
|
||||
assert_eq!(r, json!({"width": 80, "height": 41, "rmse": 0.0, "over": 0, "total": 3280, "threshold": 0.08}));
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_linked_image_is_drawn_from_its_file_as_a_png_export_draws_it() {
|
||||
use crate::tests_links::{BLUE, Folder, RED, open, place, png, save, session, write};
|
||||
let dir = Folder::new("compare-linked");
|
||||
let pic = dir.file("photo.png");
|
||||
write(&pic, &png(600, 300, RED));
|
||||
let mut s = session();
|
||||
place(&mut s, &pic);
|
||||
let doc_path = dir.file("poster.vectorcraft");
|
||||
save(&mut s, &doc_path);
|
||||
// The file changes after the save: the reopened document shows the red preview saved for it,
|
||||
// and a PNG export reads the blue file.
|
||||
write(&pic, &png(600, 300, BLUE));
|
||||
open(&mut s, &doc_path);
|
||||
let out = dir.file("export.png");
|
||||
s.execute("document.export", &json!({"path": out, "format": "png", "background": "white"})).unwrap();
|
||||
let r = compare(&mut s, json!({"path": out}));
|
||||
assert_eq!((r["rmse"].as_f64(), r["over"].as_u64(), r.get("warnings")), (Some(0.0), Some(0), None), "{r}");
|
||||
// Without the file the preview is drawn, and the reply says so.
|
||||
std::fs::remove_file(&pic).unwrap();
|
||||
let r = compare(&mut s, json!({"path": out}));
|
||||
assert_eq!(r["over"].as_u64(), r["total"].as_u64(), "{r}");
|
||||
let warnings = r["warnings"].as_array().unwrap();
|
||||
assert!(warnings.len() == 1 && warnings[0].as_str().unwrap().contains("1 linked image output as its preview"), "{r}");
|
||||
// With type that doesn't fit its frame as well, the warnings come in the export's order.
|
||||
let overset =
|
||||
s.execute("text.create", &json!({"x": 10, "y": 10, "text": "Ab\nCd\nEf\nGh", "size": 12, "area": {"width": 100, "height": 20}})).unwrap();
|
||||
assert_eq!(overset["overflow"], json!([overset["id"]]), "{overset}");
|
||||
let exported = s.execute("document.export", &json!({"path": dir.file("now.png"), "format": "png", "background": "white"})).unwrap();
|
||||
let r = compare(&mut s, json!({"path": out}));
|
||||
assert_eq!(r["warnings"].as_array().map(Vec::len), Some(2), "{r}");
|
||||
assert_eq!(r["warnings"], exported["warnings"], "{r}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_image_that_cannot_be_decoded_and_a_missing_font_warn_as_a_png_export_does() {
|
||||
let dir = vectorcraft_testkit::temp_dir("compare-warnings");
|
||||
let png = path_in(&dir, "art.png");
|
||||
let (mut s, _) = session();
|
||||
export(&mut s, &png);
|
||||
assert_eq!(compare(&mut s, json!({"path": png})).get("warnings"), None);
|
||||
crate::tests_menucmds::place_undecodable_png(&mut s);
|
||||
s.execute("text.create", &json!({"x": 2, "y": 18, "text": "Ab", "font": "Nonexistent Sans Probe"})).unwrap();
|
||||
let overset = s.execute("text.create", &json!({"x": 22, "y": 2, "text": "Ab\nCd\nEf", "size": 6, "area": {"width": 15, "height": 8}})).unwrap();
|
||||
assert_eq!(overset["overflow"], json!([overset["id"]]), "{overset}");
|
||||
let exported = s.execute("document.export", &json!({"path": path_in(&dir, "now.png"), "format": "png", "scale": 2})).unwrap();
|
||||
let r = compare(&mut s, json!({"path": png}));
|
||||
assert_eq!(r["warnings"], exported["warnings"], "{r}");
|
||||
let warnings = r["warnings"].as_array().unwrap();
|
||||
assert!(warnings.iter().any(|w| w == "an image couldn't be decoded and is missing from the picture"), "{r}");
|
||||
assert!(warnings.iter().any(|w| w.as_str().unwrap().contains("Nonexistent Sans Probe")), "{r}");
|
||||
assert!(warnings.iter().any(|w| w.as_str().unwrap().contains("doesn't fit its frame")), "{r}");
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diff_path_writes_each_pixels_differences() {
|
||||
let dir = vectorcraft_testkit::temp_dir("compare-diff");
|
||||
let png = path_in(&dir, "art.png");
|
||||
let diff = path_in(&dir, "diff.png");
|
||||
let (mut s, id) = session();
|
||||
export(&mut s, &png);
|
||||
s.execute("object.move", &json!({"ids": [id], "dx": 4, "dy": 0})).unwrap();
|
||||
let r = compare(&mut s, json!({"path": png, "diffPath": diff}));
|
||||
assert_eq!(r["diffPath"], json!(diff));
|
||||
let img = image::open(&diff).unwrap().to_rgba8();
|
||||
assert_eq!(img.dimensions(), (80, 40));
|
||||
// The square spanned pixels 20–39 and now spans 28–47, rows 10–29.
|
||||
for (x, y, want) in [(24, 20, 255), (44, 20, 255), (30, 20, 0), (24, 5, 0), (60, 20, 0)] {
|
||||
assert_eq!(img.get_pixel(x, y).0, [want, want, want, 255], "({x}, {y})");
|
||||
}
|
||||
let changed = img.pixels().filter(|p| p.0[0] != 0).count();
|
||||
assert_eq!(changed as u64, r["over"].as_u64().unwrap());
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_unreadable_and_malformed_inputs_are_errors() {
|
||||
let dir = vectorcraft_testkit::temp_dir("compare-errors");
|
||||
let (mut s, _) = session();
|
||||
let png = path_in(&dir, "art.png");
|
||||
export(&mut s, &png);
|
||||
let missing = path_in(&dir, "missing.png");
|
||||
assert!(error(&mut s, json!({"path": missing})).contains(&missing));
|
||||
let text = path_in(&dir, "notes.png");
|
||||
std::fs::write(&text, "not an image\n").unwrap();
|
||||
assert!(error(&mut s, json!({"path": text})).contains("not a PNG, JPEG, WebP, TIFF or BMP image"));
|
||||
let gif = path_in(&dir, "art.gif");
|
||||
image::RgbaImage::from_pixel(80, 40, image::Rgba([255; 4])).save(&gif).unwrap();
|
||||
assert!(error(&mut s, json!({"path": gif})).contains("not a PNG, JPEG, WebP, TIFF or BMP image"));
|
||||
for (p, want) in [
|
||||
(json!({}), "missing `path`"),
|
||||
(json!({"path": png, "artboard": 3}), "no artboard 3"),
|
||||
(json!({"path": png, "threshold": 2}), "`threshold` must be a number from 0 to 1"),
|
||||
(json!({"path": png, "threshold": "low"}), "`threshold` must be a number from 0 to 1"),
|
||||
(json!({"path": png, "background": "transparent"}), "a color such as"),
|
||||
(json!({"path": png, "diffPath": 5}), "`diffPath` must be a string"),
|
||||
] {
|
||||
let e = error(&mut s, p.clone());
|
||||
assert!(e.contains(want), "{p}: {e}");
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
/// A planar TIFF whose header claims more strips than the decoder can count (2^31 + 1 rows a strip
|
||||
/// each, times 5 planes) is refused as too large to draw, without a panic.
|
||||
#[test]
|
||||
fn a_tiff_with_more_strips_than_can_be_counted_is_too_large() {
|
||||
let dir = vectorcraft_testkit::temp_dir("compare-strips");
|
||||
let (mut s, _) = session();
|
||||
let plane = |v: u16| vec![v; 6];
|
||||
let channels = [plane(200), plane(40), plane(10), plane(0), plane(90)];
|
||||
let t = vectorcraft_testkit::tiff::Tiff {
|
||||
width: 3,
|
||||
height: 2,
|
||||
photometric: 5,
|
||||
bits: 8,
|
||||
extra: &[0],
|
||||
planar: true,
|
||||
ppi: Some(150),
|
||||
channels: &channels,
|
||||
};
|
||||
let mut file = vectorcraft_testkit::tiff::tiff(&t);
|
||||
// ImageLength (the directory's second entry, its value at offset 30) and RowsPerStrip (the
|
||||
// eighth, at offset 102).
|
||||
file[30..34].copy_from_slice(&(1u32 << 31 | 1).to_le_bytes());
|
||||
file[102..106].copy_from_slice(&1u32.to_le_bytes());
|
||||
assert_eq!(vectorcraft_doc::cmyk::oversized_tiff(&file), Some((3, 1 << 31 | 1)));
|
||||
let tif = path_in(&dir, "strips.tif");
|
||||
std::fs::write(&tif, &file).unwrap();
|
||||
let e = error(&mut s, json!({"path": tif}));
|
||||
assert_eq!(e, "invalid parameters for `document.compare`: an image of 3 × 2147483649 pixels is too large to draw");
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_image_and_the_difference_image_stay_inside_the_automation_roots() {
|
||||
let dir = vectorcraft_testkit::temp_dir("compare-roots");
|
||||
for d in ["in", "out", "elsewhere"] {
|
||||
std::fs::create_dir_all(dir.join(d)).unwrap();
|
||||
}
|
||||
let (mut s, _) = session();
|
||||
let inside = path_in(&dir.join("in"), "art.png");
|
||||
let outside = path_in(&dir.join("elsewhere"), "art.png");
|
||||
export(&mut s, &inside);
|
||||
export(&mut s, &outside);
|
||||
let roots = crate::file_access::AutomationRoots::new(&[&dir.join("in")], &[&dir.join("out")]).unwrap().unwrap();
|
||||
let mut run = |p: Value| crate::file_access::confine(Some(&roots), || s.execute("document.compare", &p));
|
||||
assert!(run(json!({"path": inside})).is_ok());
|
||||
let e = run(json!({"path": outside})).unwrap_err().to_string();
|
||||
assert!(e.contains("outside the read root"), "{e}");
|
||||
let stray = path_in(&dir.join("elsewhere"), "diff.png");
|
||||
let e = run(json!({"path": inside, "diffPath": stray})).unwrap_err().to_string();
|
||||
assert!(e.contains("outside the write root"), "{e}");
|
||||
assert!(!std::path::Path::new(&stray).exists());
|
||||
let kept = path_in(&dir.join("out"), "diff.png");
|
||||
assert_eq!(run(json!({"path": inside, "diffPath": kept})).unwrap()["diffPath"], json!(kept));
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
@@ -1140,6 +1140,7 @@ font-technology Variable Променливи
|
||||
Find Font… Търсене на шрифт…
|
||||
Find Next Търсене на следващ
|
||||
Find Objects Търсене на обекти
|
||||
Compare with Image Сравняване с изображение
|
||||
First Page Първа страница
|
||||
First-line Left Indent Ляв отстъп на първи ред
|
||||
Fisheye… Рибено око…
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1580,6 +1580,7 @@ digits Malayalam Malaiàlam
|
||||
Find Linked Files in Folder… Cerca fitxers enllaçats en una carpeta…
|
||||
Find Next Cerca el següent
|
||||
Find Objects Cerca objectes
|
||||
Compare with Image Compara amb una imatge
|
||||
Fine Dots Punts fins
|
||||
Fine noise hides banding in the gradient fill El soroll fi amaga l’efecte de bandes del farciment de degradat
|
||||
First Primer
|
||||
@@ -5006,6 +5007,11 @@ digits Malayalam Malaiàlam
|
||||
@msg an image has no pixels and was left out una imatge no té píxels i s’ha omès
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size una imatge de {w} × {h} píxels es mostra a mida reduïda
|
||||
@msg an image of {w} × {h} pixels is too large to draw una imatge de {w} × {h} píxels és massa gran per dibuixar-la
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: no és una imatge PNG, JPEG, WebP, TIFF ni BMP
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ la imatge fa {iw} × {ih} píxels i el tauler a aquesta amplada fa {rw} × {rh} píxels: les proporcions són diferents
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` ha de ser un nombre de 0 a 1
|
||||
@msg background {v}: a color such as "#808080" fons {v}: un color com "#808080"
|
||||
@msg comparing with an image file isn't available in the browser la comparació amb un fitxer d’imatge no està disponible al navegador
|
||||
@msg an image VectorCraft can't read was left out s’ha omès una imatge que VectorCraft no pot llegir
|
||||
@msg graphs come in as plain art, without their data or settings els gràfics s’importen com a il·lustració normal, sense les seves dades ni la seva configuració
|
||||
@msg an image whose data is cut short was left out s’ha omès una imatge les dades de la qual estan tallades
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3316,6 +3316,7 @@ theme Appearance Motiv
|
||||
Document JSON JSON dokumentu
|
||||
Duplicate Duplikovat
|
||||
Find Objects Najít objekty
|
||||
Compare with Image Porovnat s obrazem
|
||||
Inspect Document Prozkoumat dokument
|
||||
Inspect Object Prozkoumat objekt
|
||||
Begin Undo Group Zahájit skupinu kroků zpět
|
||||
@@ -5512,6 +5513,11 @@ mark-style Japanese Japonské
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} neznámý parametr `{key}`; příkaz přijímá: {keys}
|
||||
Load EPS into Clipboard Načíst EPS do schránky
|
||||
@msg an image of {w} × {h} pixels is too large to draw obraz o velikosti {w} × {h} obrazových bodů je příliš velký na vykreslení
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: není obraz PNG, JPEG, WebP, TIFF ani BMP
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ obraz má {iw} × {ih} obrazových bodů a pracovní plocha v této šířce má {rw} × {rh} obrazových bodů: jejich proporce se liší
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` musí být číslo od 0 do 1
|
||||
@msg background {v}: a color such as "#808080" pozadí {v}: barva jako "#808080"
|
||||
@msg comparing with an image file isn't available in the browser porovnání se souborem obrazu není v prohlížeči k dispozici
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size obraz o velikosti {w} × {h} obrazových bodů se zobrazuje ve zmenšené velikosti
|
||||
@msg the image can't be read as a texture obraz nelze načíst jako texturu
|
||||
Fill and Stroke Controls Ovládací prvky výplně a tahu
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3058,6 +3058,7 @@ theme Appearance Udseende
|
||||
Document JSON Dokument-JSON
|
||||
Duplicate Duplikér
|
||||
Find Objects Find objekter
|
||||
Compare with Image Sammenlign med billede
|
||||
Inspect Document Inspicér dokument
|
||||
Inspect Object Inspicér objekt
|
||||
Begin Undo Group Start fortrydelsesgruppe
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1155,6 +1155,7 @@ font-technology Variable Variabel
|
||||
Find Font… Schrift suchen…
|
||||
Find Next Weitersuchen
|
||||
Find Objects Objekte suchen
|
||||
Compare with Image Mit Bild vergleichen
|
||||
First Page Erste Seite
|
||||
First-line Left Indent Einzug links in erster Zeile
|
||||
Fisheye… Fischauge…
|
||||
@@ -5078,6 +5079,11 @@ lighting Light Licht
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} unbekannter Parameter `{key}`; der Befehl akzeptiert: {keys}
|
||||
Load EPS into Clipboard EPS in die Zwischenablage laden
|
||||
@msg an image of {w} × {h} pixels is too large to draw ein Bild mit {w} × {h} Pixeln ist zu groß, um gezeichnet zu werden
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: kein PNG-, JPEG-, WebP-, TIFF- oder BMP-Bild
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ das Bild hat {iw} × {ih} Pixel und die Zeichenfläche in dieser Breite {rw} × {rh} Pixel: ihre Proportionen unterscheiden sich
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` muss eine Zahl von 0 bis 1 sein
|
||||
@msg background {v}: a color such as "#808080" background {v}: eine Farbe wie "#808080"
|
||||
@msg comparing with an image file isn't available in the browser der Vergleich mit einer Bilddatei ist im Browser nicht verfügbar
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size ein Bild mit {w} × {h} Pixeln wird verkleinert angezeigt
|
||||
@msg the image can't be read as a texture das Bild kann nicht als Struktur gelesen werden
|
||||
Basic Basis
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1113,6 +1113,7 @@ font-technology Variable Μεταβλητές
|
||||
Find Font… Εύρεση γραμματοσειράς…
|
||||
Find Next Εύρεση επόμενου
|
||||
Find Objects Εύρεση αντικειμένων
|
||||
Compare with Image Σύγκριση με εικόνα
|
||||
First Page Πρώτη σελίδα
|
||||
First-line Left Indent Αριστερή εσοχή πρώτης γραμμής
|
||||
Fisheye… Εφέ ματιού ψαριού…
|
||||
@@ -5256,6 +5257,11 @@ effect Points Σημεία
|
||||
Load EPS into Clipboard Φόρτωση EPS στο πρόχειρο
|
||||
@msg unknown control `{name}`: fillStroke, coloring, drawMode or screenMode Άγνωστο στοιχείο ελέγχου `{name}`: fillStroke, coloring, drawMode ή screenMode
|
||||
@msg an image of {w} × {h} pixels is too large to draw Η εικόνα {w} × {h} εικονοστοιχείων είναι υπερβολικά μεγάλη για σχεδίαση
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: δεν είναι εικόνα PNG, JPEG, WebP, TIFF ή BMP
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ η εικόνα είναι {iw} × {ih} εικονοστοιχεία και ο πίνακας σχεδίασης σε αυτό το πλάτος είναι {rw} × {rh} εικονοστοιχεία: οι αναλογίες τους διαφέρουν
|
||||
@msg `threshold` must be a number from 0 to 1 Το `threshold` πρέπει να είναι αριθμός από 0 έως 1
|
||||
@msg background {v}: a color such as "#808080" φόντο {v}: χρώμα όπως "#808080"
|
||||
@msg comparing with an image file isn't available in the browser η σύγκριση με αρχείο εικόνας δεν είναι διαθέσιμη στο πρόγραμμα περιήγησης
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size Η εικόνα {w} × {h} εικονοστοιχείων εμφανίζεται σε μειωμένο μέγεθος
|
||||
Open Recent File 1 Άνοιγμα πρόσφατου αρχείου 1
|
||||
Open Recent File 2 Άνοιγμα πρόσφατου αρχείου 2
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 168 and column 5.
|
@@ -1184,6 +1184,7 @@ font-technology Variable Variables
|
||||
Find Font… Buscar fuente…
|
||||
Find Next Buscar siguiente
|
||||
Find Objects Buscar objetos
|
||||
Compare with Image Comparar con imagen
|
||||
First Page Primera página
|
||||
First-line Left Indent Sangría izquierda en primera línea
|
||||
Fisheye… Ojo de pez…
|
||||
@@ -5452,6 +5453,11 @@ mark-style Japanese Japonesas
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} parámetro desconocido `{key}`; el comando acepta: {keys}
|
||||
Load EPS into Clipboard Cargar EPS en el portapapeles
|
||||
@msg an image of {w} × {h} pixels is too large to draw una imagen de {w} × {h} píxeles es demasiado grande para dibujarse
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: no es una imagen PNG, JPEG, WebP, TIFF ni BMP
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ la imagen mide {iw} × {ih} píxeles y la mesa de trabajo a ese ancho mide {rw} × {rh} píxeles: sus proporciones difieren
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` debe ser un número de 0 a 1
|
||||
@msg background {v}: a color such as "#808080" fondo {v}: un color como "#808080"
|
||||
@msg comparing with an image file isn't available in the browser la comparación con un archivo de imagen no está disponible en el navegador
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size una imagen de {w} × {h} píxeles se muestra a tamaño reducido
|
||||
@msg the image can't be read as a texture la imagen no se puede leer como textura
|
||||
Fill and Stroke Controls Controles de relleno y trazo
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3254,6 +3254,7 @@ theme Appearance Ulkoasu
|
||||
Document JSON Asiakirjan JSON
|
||||
Duplicate Monista
|
||||
Find Objects Etsi objekteja
|
||||
Compare with Image Vertaa kuvaan
|
||||
Inspect Document Tarkastele asiakirjaa
|
||||
Inspect Object Tarkastele objektia
|
||||
Begin Undo Group Aloita kumoamisryhmä
|
||||
@@ -5396,6 +5397,11 @@ mark-style Japanese Japanilainen
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} tuntematon parametri `{key}`; komennon parametrit: {keys}
|
||||
Load EPS into Clipboard Lataa EPS leikepöydälle
|
||||
@msg an image of {w} × {h} pixels is too large to draw kuva, jonka koko on {w} × {h} pikseliä, on liian suuri piirrettäväksi
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: ei ole PNG-, JPEG-, WebP-, TIFF- tai BMP-kuva
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ kuva on {iw} × {ih} pikseliä ja piirtoalusta tällä leveydellä {rw} × {rh} pikseliä: niiden mittasuhteet eroavat
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` on oltava luku väliltä 0–1
|
||||
@msg background {v}: a color such as "#808080" tausta {v}: väri, kuten "#808080"
|
||||
@msg comparing with an image file isn't available in the browser vertailu kuvatiedostoon ei ole käytettävissä selaimessa
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size kuva, jonka koko on {w} × {h} pikseliä, näytetään pienennettynä
|
||||
Fill and Stroke Controls Täytön ja viivan säätimet
|
||||
Coloring Controls Värityksen säätimet
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1178,6 +1178,7 @@ font-technology Variable Variables
|
||||
Find Font… Rechercher une police…
|
||||
Find Next Rechercher le suivant
|
||||
Find Objects Rechercher des objets
|
||||
Compare with Image Comparer à une image
|
||||
First Page Première page
|
||||
First-line Left Indent Retrait gauche de première ligne
|
||||
Fisheye… Fish-eye…
|
||||
@@ -5508,6 +5509,11 @@ mark-style Japanese Japonais
|
||||
theme Appearance Apparence
|
||||
Load EPS into Clipboard Charger un EPS dans le presse-papiers
|
||||
@msg an image of {w} × {h} pixels is too large to draw une image de {w} × {h} pixels est trop grande pour être dessinée
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path} : ce n’est pas une image PNG, JPEG, WebP, TIFF ou BMP
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ l’image fait {iw} × {ih} pixels et le plan de travail à cette largeur fait {rw} × {rh} pixels : leurs proportions diffèrent
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` doit être un nombre de 0 à 1
|
||||
@msg background {v}: a color such as "#808080" arrière-plan {v} : une couleur comme "#808080"
|
||||
@msg comparing with an image file isn't available in the browser la comparaison avec un fichier image n’est pas disponible dans le navigateur
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size une image de {w} × {h} pixels est affichée en taille réduite
|
||||
@msg the image can't be read as a texture l'image ne peut pas être lue comme texture
|
||||
Fill and Stroke Controls Commandes de fond et de contour
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1484,6 +1484,7 @@ digits Malayalam Malajálam
|
||||
Find in Folder… Keresés mappában…
|
||||
Find Next Következő keresése
|
||||
Find Objects Objektumok keresése
|
||||
Compare with Image Összehasonlítás képpel
|
||||
Fine Dots Finom pontok
|
||||
|
||||
Simple Egyszerű
|
||||
@@ -5495,6 +5496,11 @@ imageTrace Outline Körvonal
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} ismeretlen paraméter: `{key}`; a parancs ezeket fogadja el: {keys}
|
||||
Load EPS into Clipboard EPS betöltése a vágólapra
|
||||
@msg an image of {w} × {h} pixels is too large to draw egy {w} × {h} pixeles kép túl nagy a kirajzoláshoz
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: nem PNG, JPEG, WebP, TIFF vagy BMP kép
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ a kép {iw} × {ih} pixeles, a rajztábla ilyen szélességben {rw} × {rh} pixeles: az arányaik eltérnek
|
||||
@msg `threshold` must be a number from 0 to 1 a `threshold` értéke 0 és 1 közötti szám lehet
|
||||
@msg background {v}: a color such as "#808080" background {v}: egy szín, például "#808080"
|
||||
@msg comparing with an image file isn't available in the browser a képfájllal való összehasonlítás a böngészőben nem érhető el
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size egy {w} × {h} pixeles kép csökkentett méretben jelenik meg
|
||||
@msg the image can't be read as a texture a kép nem olvasható be textúraként
|
||||
Fill and Stroke Controls Kitöltés és körvonal vezérlői
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3058,6 +3058,7 @@ theme Appearance Tampilan
|
||||
Document JSON JSON dokumen
|
||||
Duplicate Duplikatkan
|
||||
Find Objects Cari objek
|
||||
Compare with Image Bandingkan dengan gambar
|
||||
Inspect Document Periksa dokumen
|
||||
Inspect Object Periksa objek
|
||||
Begin Undo Group Mulai grup urungkan
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2260 and column 5.
|
@@ -1185,6 +1185,7 @@ font-technology Variable Variabili
|
||||
Find Font… Trova font…
|
||||
Find Next Trova successivo
|
||||
Find Objects Trova oggetti
|
||||
Compare with Image Confronta con immagine
|
||||
First Page Prima pagina
|
||||
First-line Left Indent Rientro sinistro prima riga
|
||||
Fisheye… Occhio di pesce…
|
||||
@@ -5120,6 +5121,11 @@ lighting Light Luce
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} parametro sconosciuto `{key}`; il comando accetta: {keys}
|
||||
Load EPS into Clipboard Carica EPS negli appunti
|
||||
@msg an image of {w} × {h} pixels is too large to draw un'immagine di {w} × {h} pixel è troppo grande per essere disegnata
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: non è un'immagine PNG, JPEG, WebP, TIFF o BMP
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ l'immagine è di {iw} × {ih} pixel e la tavola da disegno a quella larghezza è di {rw} × {rh} pixel: le proporzioni sono diverse
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` deve essere un numero da 0 a 1
|
||||
@msg background {v}: a color such as "#808080" sfondo {v}: un colore come "#808080"
|
||||
@msg comparing with an image file isn't available in the browser il confronto con un file immagine non è disponibile nel browser
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size un'immagine di {w} × {h} pixel viene mostrata a dimensioni ridotte
|
||||
@msg the image can't be read as a texture l'immagine non può essere letta come texture
|
||||
Basic Base
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -154,6 +154,7 @@ digits Malayalam マラヤーラム数字
|
||||
Find and Replace… 検索と置換…
|
||||
Find Next 次を検索
|
||||
Find Objects オブジェクトを検索
|
||||
Compare with Image 画像と比較
|
||||
Spelling スペルチェック
|
||||
Auto Spell Check 自動スペルチェック
|
||||
Check Spelling… スペルチェック…
|
||||
@@ -5162,6 +5163,11 @@ lighting Light ライト
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} `{key}` は不明なパラメーターです。このコマンドで使えるパラメーター: {keys}
|
||||
Load EPS into Clipboard EPS をクリップボードに読み込む
|
||||
@msg an image of {w} × {h} pixels is too large to draw {w} × {h} ピクセルの画像は大きすぎて描画できません
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: PNG、JPEG、WebP、TIFF、BMP のいずれの画像でもありません
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ 画像は {iw} × {ih} ピクセルで、その幅でのアートボードは {rw} × {rh} ピクセルです: 縦横比が異なります
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` には 0 から 1 までの数値を指定してください
|
||||
@msg background {v}: a color such as "#808080" 背景に {v} は指定できません: 「#808080」のようなカラーを指定してください
|
||||
@msg comparing with an image file isn't available in the browser 画像ファイルとの比較はブラウザーでは使用できません
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size {w} × {h} ピクセルの画像は縮小して表示されます
|
||||
@msg the image can't be read as a texture この画像はテクスチャとして読み込めません
|
||||
Basic 基本
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2876,6 +2876,7 @@ theme Appearance იერსახე
|
||||
Document JSON დოკუმენტის JSON
|
||||
Duplicate დუბლირება
|
||||
Find Objects ობიექტების ძებნა
|
||||
Compare with Image გამოსახულებასთან შედარება
|
||||
Inspect Document დოკუმენტის შემოწმება
|
||||
Inspect Object ობიექტის შემოწმება
|
||||
Begin Undo Group დაბრუნების ჯგუფის დაწყება
|
||||
@@ -5049,6 +5050,11 @@ imageTrace Outline კონტური
|
||||
@msg {path}: not a file {path}: ფაილი არ არის
|
||||
Load EPS into Clipboard EPS-ის ბუფერში ჩატვირთვა
|
||||
@msg an image of {w} × {h} pixels is too large to draw {w} × {h} პიქსელის გამოსახულება დასახატად ზედმეტად დიდია
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: არ არის PNG, JPEG, WebP, TIFF ან BMP გამოსახულება
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ გამოსახულება არის {iw} × {ih} პიქსელი, ხოლო სამუშაო დაფა ამ სიგანეზე არის {rw} × {rh} პიქსელი: მათი პროპორციები განსხვავდება
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` უნდა იყოს რიცხვი 0-დან 1-მდე
|
||||
@msg background {v}: a color such as "#808080" ფონი {v}: ფერი, მაგალითად "#808080"
|
||||
@msg comparing with an image file isn't available in the browser გამოსახულების ფაილთან შედარება ბრაუზერში მიუწვდომელია
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size {w} × {h} პიქსელის გამოსახულება შემცირებული ზომით ჩანს
|
||||
A later row takes this shortcut ამ მალსახმობს ქვემოთა სტრიქონი იყენებს
|
||||
Add to the Current Shortcuts მიმდინარე მალსახმობებზე დამატება
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -147,6 +147,7 @@ digits Malayalam 말라얄람어
|
||||
Find and Replace… 찾기 및 바꾸기…
|
||||
Find Next 다음 찾기
|
||||
Find Objects 개체 찾기
|
||||
Compare with Image 이미지와 비교
|
||||
Spelling 맞춤법
|
||||
Auto Spell Check 자동 맞춤법 검사
|
||||
Check Spelling… 맞춤법 검사…
|
||||
@@ -5081,6 +5082,11 @@ lighting Light 광원
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} 알 수 없는 매개변수 `{key}`: 이 명령이 받는 매개변수: {keys}
|
||||
Load EPS into Clipboard EPS를 클립보드로 불러오기
|
||||
@msg an image of {w} × {h} pixels is too large to draw {w} × {h}픽셀 이미지는 너무 커서 그릴 수 없습니다
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: PNG, JPEG, WebP, TIFF 또는 BMP 이미지가 아닙니다
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ 이미지는 {iw} × {ih}픽셀이고 그 너비에서 아트보드는 {rw} × {rh}픽셀입니다: 비율이 다릅니다
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold`은(는) 0에서 1 사이의 숫자여야 합니다
|
||||
@msg background {v}: a color such as "#808080" 배경 {v}: "#808080" 같은 색상이어야 합니다
|
||||
@msg comparing with an image file isn't available in the browser 이미지 파일과 비교하는 기능은 브라우저에서 사용할 수 없습니다
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size {w} × {h}픽셀 이미지는 축소된 크기로 표시됩니다
|
||||
@msg the image can't be read as a texture 이미지를 텍스처로 읽을 수 없습니다
|
||||
Basic 기본
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3072,6 +3072,7 @@ theme Appearance Vormgeving
|
||||
Document JSON Document-JSON
|
||||
Duplicate Dupliceren
|
||||
Find Objects Objecten zoeken
|
||||
Compare with Image Vergelijken met afbeelding
|
||||
Inspect Document Document inspecteren
|
||||
Inspect Object Object inspecteren
|
||||
Begin Undo Group Groep voor ongedaan maken beginnen
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3195,6 +3195,7 @@ theme Appearance Wygląd
|
||||
Document JSON JSON dokumentu
|
||||
Duplicate Powiel
|
||||
Find Objects Znajdź obiekty
|
||||
Compare with Image Porównaj z obrazem
|
||||
Inspect Document Zbadaj dokument
|
||||
Inspect Object Zbadaj obiekt
|
||||
Begin Undo Group Rozpocznij grupę cofania
|
||||
@@ -5350,6 +5351,11 @@ mark-style Japanese Japońskie
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} nieznany parametr `{key}`; polecenie przyjmuje: {keys}
|
||||
Load EPS into Clipboard Wczytaj EPS do schowka
|
||||
@msg an image of {w} × {h} pixels is too large to draw obraz o wymiarach {w} × {h} pikseli jest zbyt duży, aby go narysować
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: to nie jest obraz PNG, JPEG, WebP, TIFF ani BMP
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ obraz ma {iw} × {ih} pikseli, a obszar kompozycji przy tej szerokości ma {rw} × {rh} pikseli: ich proporcje się różnią
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` musi być liczbą od 0 do 1
|
||||
@msg background {v}: a color such as "#808080" tło {v}: kolor, np. "#808080"
|
||||
@msg comparing with an image file isn't available in the browser porównywanie z plikiem obrazu nie jest dostępne w przeglądarce
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size obraz o wymiarach {w} × {h} pikseli jest wyświetlany w zmniejszonym rozmiarze
|
||||
Basic Podstawowy
|
||||
Fill and Stroke Controls Elementy sterujące wypełnieniem i obrysem
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3343,6 +3343,7 @@ font-technology Variable Variáveis
|
||||
Favorites Favoritos
|
||||
Fill (X), double-click for the Color Picker Preenchimento (X), clique duas vezes para o seletor de cores
|
||||
Find Objects Localizar objetos
|
||||
Compare with Image Comparar com imagem
|
||||
Flare Tool Options Opções da ferramenta Reflexo
|
||||
Halo Halo
|
||||
Rays Raios
|
||||
@@ -5447,6 +5448,11 @@ mark-style Japanese Japonesas
|
||||
@msg The shape is too complex for a 3D effect A forma é complexa demais para um efeito 3D
|
||||
@msg The 3D surface is too complex; simplify the shape A superfície 3D é complexa demais; simplifique a forma
|
||||
@msg an image of {w} × {h} pixels is too large to draw uma imagem de {w} × {h} pixels é grande demais para ser desenhada
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: não é uma imagem PNG, JPEG, WebP, TIFF ou BMP
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ a imagem tem {iw} × {ih} pixels e a prancheta nessa largura tem {rw} × {rh} pixels: as proporções são diferentes
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` deve ser um número de 0 a 1
|
||||
@msg background {v}: a color such as "#808080" plano de fundo {v}: uma cor como "#808080"
|
||||
@msg comparing with an image file isn't available in the browser a comparação com um arquivo de imagem não está disponível no navegador
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size uma imagem de {w} × {h} pixels é exibida em tamanho reduzido
|
||||
Fill and Stroke Controls Controles de Preenchimento e Traçado
|
||||
Coloring Controls Controles de Coloração
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -1182,6 +1182,7 @@ font-technology Variable Вариативные
|
||||
Find Font… Найти шрифт…
|
||||
Find Next Найти далее
|
||||
Find Objects Найти объекты
|
||||
Compare with Image Сравнить с изображением
|
||||
First Page Первая страница
|
||||
First-line Left Indent Отступ слева в первой строке
|
||||
Fisheye… Рыбий глаз…
|
||||
@@ -5115,6 +5116,11 @@ lighting Light Свет
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} неизвестный параметр `{key}`; команда принимает: {keys}
|
||||
Load EPS into Clipboard Загрузить EPS в буфер обмена
|
||||
@msg an image of {w} × {h} pixels is too large to draw изображение размером {w} × {h} пикселей слишком велико для отрисовки
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: это не изображение PNG, JPEG, WebP, TIFF или BMP
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ размер изображения {iw} × {ih} пикселей, а монтажной области при этой ширине {rw} × {rh} пикселей: их пропорции различаются
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` должно быть числом от 0 до 1
|
||||
@msg background {v}: a color such as "#808080" фон {v}: цвет, например "#808080"
|
||||
@msg comparing with an image file isn't available in the browser сравнение с файлом изображения недоступно в браузере
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size изображение размером {w} × {h} пикселей показано в уменьшенном размере
|
||||
@msg the image can't be read as a texture изображение не удаётся прочитать как текстуру
|
||||
Basic Базовый
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1148,6 +1148,7 @@ font-technology Variable Variabla
|
||||
Find Font… Sök typsnitt…
|
||||
Find Next Sök nästa
|
||||
Find Objects Sök objekt
|
||||
Compare with Image Jämför med bild
|
||||
First Page Första sidan
|
||||
First-line Left Indent Vänsterindrag för första raden
|
||||
Fisheye… Fisköga…
|
||||
@@ -5412,6 +5413,11 @@ mark-style Japanese Japanska
|
||||
theme Appearance Utseende
|
||||
Load EPS into Clipboard Läs in EPS till urklipp
|
||||
@msg an image of {w} × {h} pixels is too large to draw en bild på {w} × {h} pixlar är för stor för att ritas
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: inte en PNG-, JPEG-, WebP-, TIFF- eller BMP-bild
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ bilden är {iw} × {ih} pixlar och ritytan i den bredden är {rw} × {rh} pixlar: proportionerna skiljer sig åt
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` måste vara ett tal från 0 till 1
|
||||
@msg background {v}: a color such as "#808080" background {v}: en färg som "#808080"
|
||||
@msg comparing with an image file isn't available in the browser jämförelse med en bildfil är inte tillgänglig i webbläsaren
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size en bild på {w} × {h} pixlar visas i förminskad storlek
|
||||
Fill and Stroke Controls Kontroller för fyllning och kontur
|
||||
Coloring Controls Kontroller för färgläggning
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -1137,6 +1137,7 @@ font-technology Variable Değişken
|
||||
Find Font… Yazı Tipi Bul…
|
||||
Find Next Sonrakini Bul
|
||||
Find Objects Nesneleri Bul
|
||||
Compare with Image Görüntüyle Karşılaştır
|
||||
First Page İlk Sayfa
|
||||
First-line Left Indent Birinci Satırda Sol Girinti
|
||||
Fisheye… Balıkgözü…
|
||||
@@ -4017,6 +4018,11 @@ axis Both Her İkisi
|
||||
@msg invalid image data for `{0}` `{0}` için geçersiz resim verileri
|
||||
@msg invalid parameters for `{cmd}`: {msg} `{cmd}` için geçersiz parametreler: {msg}
|
||||
@msg is not an image VectorCraft reads VectorCraft'ın okuduğu bir resim değil
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: PNG, JPEG, WebP, TIFF veya BMP resmi değil
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ resim {iw} × {ih} piksel, çalışma yüzeyi bu genişlikte {rw} × {rh} piksel: oranları farklı
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` 0 ile 1 arasında bir sayı olmalıdır
|
||||
@msg background {v}: a color such as "#808080" background {v}: "#808080" gibi bir renk
|
||||
@msg comparing with an image file isn't available in the browser bir resim dosyasıyla karşılaştırma tarayıcıda kullanılamaz
|
||||
@msg it uses `{at}`, which VectorCraft's PostScript reader doesn't know VectorCraft'ın PostScript okuyucusunun bilmediği `{at}`yi kullanıyor
|
||||
@msg it uses `{at}`, which VectorCraft's PostScript reader doesn't know, in {procs} {procs}'de VectorCraft'ın PostScript okuyucusunun bilmediği `{at}`yi kullanıyor
|
||||
@msg its Windows metafile preview was opened instead, which may simplify the art bunun yerine Windows meta dosyası önizlemesi açıldı, bu da işi basitleştirebilir
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -1179,6 +1179,7 @@ font-technology Variable Варіативні
|
||||
Find Font… Знайти шрифт…
|
||||
Find Next Знайти далі
|
||||
Find Objects Знайти об’єкти
|
||||
Compare with Image Порівняти із зображенням
|
||||
First Page Перша сторінка
|
||||
First-line Left Indent Відступ ліворуч у першому рядку
|
||||
Fisheye… Риб’яче око…
|
||||
@@ -5100,6 +5101,11 @@ lighting Light Світло
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} невідомий параметр `{key}`; команда приймає: {keys}
|
||||
Load EPS into Clipboard Завантажити EPS у буфер обміну
|
||||
@msg an image of {w} × {h} pixels is too large to draw зображення розміром {w} × {h} пікселів завелике для відображення
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: це не зображення PNG, JPEG, WebP, TIFF чи BMP
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ розмір зображення {iw} × {ih} пікселів, а монтажної області за цієї ширини {rw} × {rh} пікселів: їхні пропорції відрізняються
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` має бути числом від 0 до 1
|
||||
@msg background {v}: a color such as "#808080" фон {v}: колір, наприклад "#808080"
|
||||
@msg comparing with an image file isn't available in the browser порівняння з файлом зображення недоступне в браузері
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size зображення розміром {w} × {h} пікселів показано в зменшеному розмірі
|
||||
@msg the image can't be read as a texture зображення не вдається прочитати як текстуру
|
||||
Basic Базовий
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 182 and column 5.
|
@@ -1389,6 +1389,7 @@ digits Malayalam Malayalam
|
||||
Find Linked Files in Folder… Tìm tệp liên kết trong thư mục…
|
||||
Find Next Tìm tiếp
|
||||
Find Objects Tìm đối tượng
|
||||
Compare with Image So sánh với ảnh
|
||||
Fine Dots Chấm mịn
|
||||
|
||||
Simple Đơn giản
|
||||
@@ -5104,6 +5105,11 @@ theme Appearance Giao diện
|
||||
@msg {tool} isn't in a toolbar group of several tools {tool} không nằm trong nhóm thanh công cụ có nhiều công cụ
|
||||
Load EPS into Clipboard Tải EPS vào bảng tạm
|
||||
@msg an image of {w} × {h} pixels is too large to draw ảnh {w} × {h} điểm ảnh quá lớn nên không thể vẽ
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}: không phải ảnh PNG, JPEG, WebP, TIFF hay BMP
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ ảnh có kích thước {iw} × {ih} điểm ảnh, còn bảng vẽ ở chiều rộng đó có kích thước {rw} × {rh} điểm ảnh: tỉ lệ của chúng khác nhau
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` phải là một số từ 0 đến 1
|
||||
@msg background {v}: a color such as "#808080" background {v}: màu như "#808080"
|
||||
@msg comparing with an image file isn't available in the browser không thể so sánh với tệp ảnh trong trình duyệt
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size ảnh {w} × {h} điểm ảnh được hiển thị ở kích thước thu nhỏ
|
||||
Basic Cơ bản
|
||||
Fill and Stroke Controls Điều khiển tô và nét
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 204 and column 5.
|
@@ -1125,6 +1125,7 @@
|
||||
Find Font… 查找字体…
|
||||
Find Next 查找下一个
|
||||
Find Objects 查找对象
|
||||
Compare with Image 与图像比较
|
||||
First Page 第一页
|
||||
First-line Left Indent 首行左缩进
|
||||
Fisheye… 鱼眼…
|
||||
@@ -5386,6 +5387,11 @@ lighting Light 光源
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} 未知参数 `{key}`;该命令接受:{keys}
|
||||
Load EPS into Clipboard 将 EPS 载入剪贴板
|
||||
@msg an image of {w} × {h} pixels is too large to draw {w} × {h} 像素的图像过大,无法绘制
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}:不是 PNG、JPEG、WebP、TIFF 或 BMP 图像
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ 图像为 {iw} × {ih} 像素,而画板在该宽度下为 {rw} × {rh} 像素:两者的比例不同
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` 必须是 0 到 1 之间的数字
|
||||
@msg background {v}: a color such as "#808080" background {v}:颜色,例如 "#808080"
|
||||
@msg comparing with an image file isn't available in the browser 浏览器中无法与图像文件进行比较
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size {w} × {h} 像素的图像以缩小的尺寸显示
|
||||
Fill and Stroke Controls 填色和描边控件
|
||||
Coloring Controls 颜色控件
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1150,6 +1150,7 @@ font-technology Variable 可變
|
||||
Find Font… 尋找字體…
|
||||
Find Next 尋找下一個
|
||||
Find Objects 尋找物件
|
||||
Compare with Image 與影像比較
|
||||
First Page 第一頁
|
||||
First-line Left Indent 首行左縮排
|
||||
Fisheye… 魚眼…
|
||||
@@ -5200,6 +5201,11 @@ lighting Light 光源
|
||||
@msg unknown parameter `{key}`; the command takes: {keys} 未知的參數 `{key}`;此指令接受:{keys}
|
||||
Load EPS into Clipboard 將 EPS 載入剪貼簿
|
||||
@msg an image of {w} × {h} pixels is too large to draw {w} × {h} 像素的影像過大,無法繪製
|
||||
@msg {path}: not a PNG, JPEG, WebP, TIFF or BMP image {path}:不是 PNG、JPEG、WebP、TIFF 或 BMP 影像
|
||||
@msg the image is {iw} × {ih} pixels and the artboard at that width is {rw} × {rh} pixels: their proportions differ 影像為 {iw} × {ih} 像素,而工作區域在該寬度下為 {rw} × {rh} 像素:兩者的比例不同
|
||||
@msg `threshold` must be a number from 0 to 1 `threshold` 必須是 0 到 1 之間的數字
|
||||
@msg background {v}: a color such as "#808080" background {v}:顏色,例如 "#808080"
|
||||
@msg comparing with an image file isn't available in the browser 瀏覽器中無法與影像檔案進行比較
|
||||
@msg an image of {w} × {h} pixels is shown at reduced size {w} × {h} 像素的影像以縮小的尺寸顯示
|
||||
Basic 基本
|
||||
Fill and Stroke Controls 填色和筆畫控制項
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
+16
@@ -269,6 +269,22 @@ chain (layer first) and `limit` caps `matches` (default 100; `0` only counts); w
|
||||
`selected`, the number of objects selected. `document.json` stays whole: it is the fidelity path, not the way to
|
||||
look around.
|
||||
|
||||
`run_command document.compare {path, artboard?, background?, threshold?, diffPath?}` measures how far an
|
||||
artboard is from an image file (PNG, JPEG, WebP, TIFF or BMP). It renders the
|
||||
artboard (default 0) at the image's size, as `export` draws a PNG: the scale is the image's width in pixels over
|
||||
the artboard's width in points, and an image whose height differs from the artboard's height at that scale by
|
||||
more than one pixel is an error that names both sizes. The render and the image are both flattened on
|
||||
`background` (`"#rrggbb"`, default `"#ffffff"`). The reply is `{width, height, rmse, over, total, threshold}`:
|
||||
`rmse` is the root mean square of the R, G and B differences on a 0 to 1 scale, rounded to 6 decimals, and
|
||||
`over` counts the pixels with a channel that differs by more than `threshold` (0 to 1, default 0.08) of the
|
||||
total `total`. `diffPath` writes a PNG of each pixel's absolute R, G and B differences (black where the two
|
||||
match) and adds `diffPath` to the reply. As in a PNG export, linked images and placed documents are drawn
|
||||
from their files rather than from the previews saved for them. The reply's `warnings` are a PNG export's, in
|
||||
the same order: type on the artboard that doesn't fit its frame, an embedded image that couldn't be decoded (it
|
||||
is missing from the render), type in a font or style that isn't available, and a linked file that can't be read
|
||||
(its preview is drawn). `path` is read through the automation read root, and `diffPath` is written through the
|
||||
write root. The command does not change the document, and it is not available in the web app.
|
||||
|
||||
### Completions
|
||||
|
||||
`completion/complete` answers for a prompt argument (`ref/prompt`) or a template variable
|
||||
|
||||
Reference in New Issue
Block a user