mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-20 22:24:16 -04:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c10da25ce4 | ||
|
|
8ab574b7de |
No files matched your search
@@ -214,6 +214,7 @@ pub fn import(bytes: &[u8], o: &ImportOptions) -> Result<Imported, String> {
|
||||
let (mut document, mut warnings) = build::Build::new(&d, o).run(layout, natural, ratio)?;
|
||||
document.units = if o.fit { unit } else { o.unit.unwrap_or(unit) };
|
||||
warnings.extend(damaged);
|
||||
document.limit_depth_noting(&mut warnings);
|
||||
Ok(Imported { document, warnings })
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,10 @@ pub struct Clip {
|
||||
}
|
||||
|
||||
/// Deepest nesting of clips, and of groups, an importer records ([`nest`] goes one level deeper
|
||||
/// for each): deeper ones are left out.
|
||||
pub const MAX_NEST: usize = 128;
|
||||
/// for each): deeper ones are left out. As deep as a document's objects may nest
|
||||
/// ([`crate::MAX_DEPTH`]) under a layer, around the art; clips in groups that deep together are
|
||||
/// merged by [`Document::limit_depth`].
|
||||
pub const MAX_NEST: usize = crate::MAX_DEPTH - 2;
|
||||
|
||||
/// The warning for clips left out for nesting deeper than [`MAX_NEST`].
|
||||
pub fn deep_clips() -> String {
|
||||
|
||||
@@ -0,0 +1,588 @@
|
||||
//! How deep objects may nest.
|
||||
//!
|
||||
//! The tree is walked by recursion everywhere (drawing, bounds, hit tests, saving, exporting), so
|
||||
//! a tree of unbounded depth overflows the stack: an abort no guard catches. No document deeper
|
||||
//! than [`MAX_DEPTH`] is ever kept, nor one whose symbols and patterns draw deeper than
|
||||
//! [`MAX_DRAWN_DEPTH`] (a symbol holding an instance of itself, or a pattern painting its own
|
||||
//! tile, draws without end): importers and the native reader merge deeper objects into the group
|
||||
//! around them and leave such instances and paints out
|
||||
//! ([`Document::limit_depth`], with [`merged_note`] and [`symbols_note`] as their warnings), and
|
||||
//! the engine refuses an edit that would nest deeper ([`Document::too_deep`]).
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use vectorcraft_color::Paint;
|
||||
|
||||
use crate::{Document, Node, NodeKind};
|
||||
|
||||
/// The deepest an object may be: a top-level layer is 1 deep, what it holds 2, and so on (the art
|
||||
/// of an opacity mask is one deeper than the object it masks). A symbol's or pattern's art counts
|
||||
/// from 1 again.
|
||||
///
|
||||
/// A native file writes three levels of JSON for each level of objects, and its reader stops at
|
||||
/// 128 levels: 32 leaves the deepest object 29 of them for its own data, so every document that
|
||||
/// can be made can be saved and opened again.
|
||||
pub const MAX_DEPTH: usize = 32;
|
||||
|
||||
/// The deepest an object may be drawn: as [`MAX_DEPTH`], the art of a symbol counted under its
|
||||
/// instance and a pattern's tile under the object it paints (and what those use, under them).
|
||||
/// Symbols a few objects deep nest in one another dozens deep within it.
|
||||
pub const MAX_DRAWN_DEPTH: usize = 4 * MAX_DEPTH;
|
||||
|
||||
/// The warning of a file whose objects were nested deeper than [`MAX_DEPTH`].
|
||||
pub fn merged_note() -> String {
|
||||
format!("objects nested more than {MAX_DEPTH} deep were merged into the group around them")
|
||||
}
|
||||
|
||||
/// The warning of a file with symbols or patterns that use themselves or are drawn deeper than
|
||||
/// [`MAX_DRAWN_DEPTH`].
|
||||
pub fn symbols_note() -> String {
|
||||
format!(
|
||||
"symbol instances and pattern paints inside their own symbol or pattern, or drawn more than {MAX_DRAWN_DEPTH} objects deep, were left out"
|
||||
)
|
||||
}
|
||||
|
||||
/// Run `f` where recursion has room: on a thread of its own with a 16 MB stack (the main thread
|
||||
/// has 1 MB on Windows), or here where there are no threads (the web) or none can be started. For
|
||||
/// readers whose recursion is capped but heavy; a panic in `f` goes on to the caller.
|
||||
pub fn with_deep_stack<T: Send>(f: impl Fn() -> T + Sync) -> T {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let threaded = std::thread::scope(|s| {
|
||||
let thread = std::thread::Builder::new().stack_size(16 << 20).spawn_scoped(s, &f).ok()?;
|
||||
Some(thread.join().unwrap_or_else(|panic| std::panic::resume_unwind(panic)))
|
||||
});
|
||||
if let Some(done) = threaded {
|
||||
return done;
|
||||
}
|
||||
}
|
||||
f()
|
||||
}
|
||||
|
||||
/// Is anything in `now` (each `depth` deep) deeper than [`MAX_DEPTH`], or `over` (given its
|
||||
/// depth)? Without recursion: the trees may be of any depth. With `before` (the same list before
|
||||
/// an edit, within the caps), only what the edit changed is looked at: a subtree still shared with
|
||||
/// it, in the same place, is as it was.
|
||||
fn deeper(now: &[Arc<Node>], before: Option<&[Arc<Node>]>, depth: usize, over: &dyn Fn(&Node, usize) -> bool) -> bool {
|
||||
type Pending<'a> = Vec<(&'a Node, Option<&'a Node>, usize)>;
|
||||
fn push<'a>(stack: &mut Pending<'a>, now: &'a [Arc<Node>], before: Option<&'a [Arc<Node>]>, depth: usize) {
|
||||
for (i, n) in now.iter().enumerate() {
|
||||
let was = before.and_then(|b| b.get(i));
|
||||
if !was.is_some_and(|w| Arc::ptr_eq(w, n)) {
|
||||
stack.push((n, was.map(|w| &**w), depth));
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut stack = vec![];
|
||||
push(&mut stack, now, before, depth);
|
||||
while let Some((n, was, d)) = stack.pop() {
|
||||
if d > MAX_DEPTH || over(n, d) {
|
||||
return true;
|
||||
}
|
||||
if let Some(ch) = n.children() {
|
||||
push(&mut stack, ch, was.and_then(Node::children).map(Vec::as_slice), d + 1);
|
||||
}
|
||||
if let Some(m) = &n.extras().mask {
|
||||
let was = was.and_then(|w| w.extras().mask.as_ref()).map(|m| std::slice::from_ref(&m.art));
|
||||
push(&mut stack, std::slice::from_ref(&m.art), was, d + 1);
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// [`deeper`] for the nesting alone.
|
||||
fn nested_deeper(now: &[Arc<Node>], depth: usize) -> bool {
|
||||
deeper(now, None, depth, &|_, _| false)
|
||||
}
|
||||
|
||||
/// Merge what is deeper than [`MAX_DEPTH`] in `nodes` (each `depth` deep) into the group around
|
||||
/// it: a container at the cap is replaced by what it holds (a clipping group's clipping path and
|
||||
/// an opacity mask too deep are left out); what it held stays hidden or locked as it was. Returns
|
||||
/// whether anything changed. Recurses no deeper than the cap.
|
||||
fn limit(nodes: &mut Vec<Arc<Node>>, depth: usize) -> bool {
|
||||
let mut changed = false;
|
||||
let mut i = 0;
|
||||
while let Some(n) = nodes.get_mut(i) {
|
||||
if !nested_deeper(std::slice::from_ref(n), depth) {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
changed = true;
|
||||
let n = Arc::make_mut(n);
|
||||
if n.extras().mask.as_ref().is_some_and(|m| nested_deeper(std::slice::from_ref(&m.art), depth + 1)) {
|
||||
n.extras_mut().mask = None;
|
||||
}
|
||||
if depth < MAX_DEPTH {
|
||||
if let Some(ch) = n.children_mut() {
|
||||
limit(ch, depth + 1);
|
||||
}
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
let clip = matches!(n.kind, NodeKind::Group { clip: true, .. } | NodeKind::Layer { clip: true, .. });
|
||||
let (visible, locked) = (n.visible, n.locked);
|
||||
let mut held = n.children_mut().map(std::mem::take).unwrap_or_default();
|
||||
if clip && !held.is_empty() {
|
||||
held.remove(0);
|
||||
}
|
||||
for c in &mut held {
|
||||
if (!visible && c.visible) || (locked && !c.locked) {
|
||||
let c = Arc::make_mut(c);
|
||||
c.visible &= visible;
|
||||
c.locked |= locked;
|
||||
}
|
||||
}
|
||||
// What it held takes its place, and is looked at in its turn.
|
||||
nodes.splice(i..=i, held);
|
||||
}
|
||||
changed
|
||||
}
|
||||
|
||||
/// A symbol (`false`) or a pattern (`true`) of the document, by name: what art draws by name, an
|
||||
/// instance its symbol's art and a pattern paint its tile's.
|
||||
type Def<'a> = (bool, &'a str);
|
||||
|
||||
/// How deep each symbol's and pattern's art is drawn, the art of the symbols and patterns it uses
|
||||
/// included (drawn under the object that uses them): `None` for one that uses itself, in its art
|
||||
/// or through what that uses, or is drawn deeper than [`MAX_DRAWN_DEPTH`].
|
||||
type Heights<'a> = HashMap<Def<'a>, Option<usize>>;
|
||||
|
||||
/// What `n` itself draws by name: the symbol it is an instance of, the patterns that paint it.
|
||||
fn uses(n: &Node) -> impl Iterator<Item = Def<'_>> {
|
||||
let symbol = match &n.kind {
|
||||
NodeKind::SymbolInstance { symbol, .. } => Some((false, symbol.as_str())),
|
||||
_ => None,
|
||||
};
|
||||
let patterns = crate::swatches::node_paints(n).filter_map(|p| match p {
|
||||
Paint::Pattern { pattern, .. } => Some((true, pattern.as_str())),
|
||||
_ => None,
|
||||
});
|
||||
symbol.into_iter().chain(patterns)
|
||||
}
|
||||
|
||||
/// [`Heights`] of the document's symbols and patterns. Without recursion: they may use one
|
||||
/// another in a chain of any length. Their own art is within [`MAX_DEPTH`].
|
||||
fn heights(doc: &Document) -> Heights<'_> {
|
||||
// Each one's own depth, and what its art uses with the deepest use of each.
|
||||
type Own<'a> = (usize, Vec<(Def<'a>, usize)>);
|
||||
let arts = (doc.symbols.iter().map(|s| ((false, s.name.as_str()), std::slice::from_ref(&s.art))))
|
||||
.chain(doc.patterns.iter().map(|p| ((true, p.name.as_str()), &p.art[..])));
|
||||
let mut own: HashMap<Def, Own> = HashMap::new();
|
||||
for (def, art) in arts {
|
||||
let (mut deepest, mut used) = (0, HashMap::<Def, usize>::new());
|
||||
let mut stack: Vec<(&Node, usize)> = art.iter().map(|n| (&**n, 1)).collect();
|
||||
while let Some((n, d)) = stack.pop() {
|
||||
deepest = deepest.max(d);
|
||||
for u in uses(n) {
|
||||
let at = used.entry(u).or_default();
|
||||
*at = (*at).max(d);
|
||||
}
|
||||
stack.extend(n.children().into_iter().flatten().chain(n.extras().mask.as_ref().map(|m| &m.art)).map(|c| (&**c, d + 1)));
|
||||
}
|
||||
// (The first of two of one name is the one drawn.)
|
||||
own.entry(def).or_insert((deepest, used.into_iter().collect()));
|
||||
}
|
||||
// Depth first over what uses what. One met again while it is being worked out (`None` in its
|
||||
// entry) uses itself.
|
||||
let mut found: HashMap<Def, Option<Option<usize>>> = HashMap::new();
|
||||
let starts: Vec<Def> = own.keys().copied().collect();
|
||||
for start in starts {
|
||||
if found.contains_key(&start) {
|
||||
continue;
|
||||
}
|
||||
// (which, the next of its uses to look at, the deepest found so far: `None` once it can't be drawn)
|
||||
let mut path: Vec<(Def, usize, Option<usize>)> = vec![(start, 0, own.get(&start).map(|o| o.0))];
|
||||
found.insert(start, None);
|
||||
while let Some(&(def, next, deepest)) = path.last() {
|
||||
let used = own.get(&def).map_or(&[][..], |o| &o.1);
|
||||
let Some(&(other, at)) = used.get(next) else {
|
||||
// Everything it uses is worked out.
|
||||
let deepest = deepest.filter(|d| *d <= MAX_DRAWN_DEPTH);
|
||||
found.insert(def, Some(deepest));
|
||||
path.pop();
|
||||
if let Some((user, next, held)) = path.last_mut() {
|
||||
let at = own.get(user).and_then(|o| o.1.get(next.wrapping_sub(1))).map_or(1, |u| u.1);
|
||||
*held = held.zip(deepest).map(|(h, d)| h.max(at + d));
|
||||
}
|
||||
continue;
|
||||
};
|
||||
let known = found.get(&other).copied();
|
||||
if known.is_none() && own.contains_key(&other) {
|
||||
found.insert(other, None);
|
||||
}
|
||||
let Some((_, next, deepest)) = path.last_mut() else { break };
|
||||
*next += 1;
|
||||
match known {
|
||||
// Not in the document: it draws nothing.
|
||||
None if !own.contains_key(&other) => {}
|
||||
None => path.push((other, 0, own.get(&other).map(|o| o.0))),
|
||||
Some(Some(Some(d))) => *deepest = deepest.map(|h| h.max(at + d)),
|
||||
// It uses itself (it is on the way down here), or can't be drawn.
|
||||
Some(None | Some(None)) => *deepest = None,
|
||||
}
|
||||
}
|
||||
}
|
||||
found.into_iter().map(|(def, h)| (def, h.flatten())).collect()
|
||||
}
|
||||
|
||||
/// Can't `used`, by an object `depth` deep, be drawn there?
|
||||
fn undrawable(heights: &Heights, used: Def, depth: usize) -> bool {
|
||||
heights.get(&used).is_some_and(|h| h.is_none_or(|h| depth + h > MAX_DRAWN_DEPTH))
|
||||
}
|
||||
|
||||
/// Take out of `nodes` (each `depth` deep) the uses `bad` picks (given the depth of the object):
|
||||
/// an instance goes, a pattern paint becomes no paint. Returns whether anything changed. For trees
|
||||
/// within [`MAX_DEPTH`].
|
||||
fn strip(nodes: &mut Vec<Arc<Node>>, depth: usize, bad: &dyn Fn(Def, usize) -> bool) -> bool {
|
||||
let any = |n: &Node, d: usize| uses(n).any(|u| bad(u, d));
|
||||
let before = nodes.len();
|
||||
nodes.retain(|n| !matches!(&n.kind, NodeKind::SymbolInstance { symbol, .. } if bad((false, symbol.as_str()), depth)));
|
||||
let mut changed = nodes.len() != before;
|
||||
for n in nodes.iter_mut() {
|
||||
if !deeper(std::slice::from_ref(n), None, depth, &any) {
|
||||
continue;
|
||||
}
|
||||
changed = true;
|
||||
let n = Arc::make_mut(n);
|
||||
if uses(n).any(|u| bad(u, depth)) {
|
||||
for p in crate::swatches::node_paints_mut(n) {
|
||||
if matches!(p, Paint::Pattern { pattern, .. } if bad((true, pattern.as_str()), depth)) {
|
||||
*p = Paint::None;
|
||||
}
|
||||
}
|
||||
}
|
||||
// An opacity mask whose art is such an instance goes with it.
|
||||
let mut mask = n.extras().mask.as_ref().map(|m| vec![m.art.clone()]);
|
||||
if let Some(art) = &mut mask
|
||||
&& strip(art, depth + 1, bad)
|
||||
{
|
||||
match art.pop() {
|
||||
Some(art) => {
|
||||
if let Some(m) = n.extras_mut().mask.as_mut() {
|
||||
m.art = art;
|
||||
}
|
||||
}
|
||||
None => n.extras_mut().mask = None,
|
||||
}
|
||||
}
|
||||
if let Some(ch) = n.children_mut() {
|
||||
strip(ch, depth + 1, bad);
|
||||
}
|
||||
}
|
||||
changed
|
||||
}
|
||||
|
||||
impl Document {
|
||||
/// Is anything nested deeper than [`MAX_DEPTH`], or drawn deeper than [`MAX_DRAWN_DEPTH`]
|
||||
/// (a symbol or pattern that uses itself is)? With `before` (this document before an edit,
|
||||
/// itself within the caps), only what the edit changed is looked at.
|
||||
pub fn too_deep(&self, before: Option<&Document>) -> bool {
|
||||
fn symbol(d: &Document, i: usize) -> Option<&[Arc<Node>]> {
|
||||
d.symbols.get(i).map(|s| std::slice::from_ref(&s.art))
|
||||
}
|
||||
fn pattern(d: &Document, i: usize) -> Option<&[Arc<Node>]> {
|
||||
d.patterns.get(i).map(|p| &p.art[..])
|
||||
}
|
||||
let nested = |_: &Node, _: usize| false;
|
||||
if (0..self.symbols.len()).any(|i| symbol(self, i).is_some_and(|art| deeper(art, before.and_then(|b| symbol(b, i)), 1, &nested)))
|
||||
|| (0..self.patterns.len()).any(|i| pattern(self, i).is_some_and(|art| deeper(art, before.and_then(|b| pattern(b, i)), 1, &nested)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if self.symbols.is_empty() && self.patterns.is_empty() {
|
||||
return deeper(&self.layers, before.map(|b| &b.layers[..]), 1, &nested);
|
||||
}
|
||||
let heights = heights(self);
|
||||
if heights.values().any(Option::is_none) {
|
||||
return true;
|
||||
}
|
||||
// Symbols and patterns draw as deep as before when none changed; else every use of them
|
||||
// is looked at again.
|
||||
let same = |x: &[Arc<Node>], y: &[Arc<Node>]| x.len() == y.len() && x.iter().zip(y).all(|(x, y)| Arc::ptr_eq(x, y));
|
||||
let before = before.filter(|b| {
|
||||
b.symbols.len() == self.symbols.len()
|
||||
&& b.patterns.len() == self.patterns.len()
|
||||
&& b.symbols.iter().zip(&self.symbols).all(|(x, y)| x.name == y.name && Arc::ptr_eq(&x.art, &y.art))
|
||||
&& b.patterns.iter().zip(&self.patterns).all(|(x, y)| x.name == y.name && same(&x.art, &y.art))
|
||||
});
|
||||
let over = |n: &Node, d: usize| uses(n).any(|u| undrawable(&heights, u, d));
|
||||
deeper(&self.layers, before.map(|b| &b.layers[..]), 1, &over)
|
||||
}
|
||||
|
||||
/// [`Self::limit_depth`] → whether objects were merged, and whether uses of symbols and
|
||||
/// patterns were left out.
|
||||
fn limit_depths(&mut self) -> (bool, bool) {
|
||||
let mut merged = limit(&mut self.layers, 1);
|
||||
for s in &mut self.symbols {
|
||||
// The art itself is 1 deep, so it stays the one object it is.
|
||||
let mut art = vec![s.art.clone()];
|
||||
if limit(&mut art, 1)
|
||||
&& let Some(one) = art.pop()
|
||||
{
|
||||
s.art = one;
|
||||
merged = true;
|
||||
}
|
||||
}
|
||||
for p in &mut self.patterns {
|
||||
merged |= limit(&mut p.art, 1);
|
||||
}
|
||||
if self.symbols.is_empty() && self.patterns.is_empty() {
|
||||
return (merged, false);
|
||||
}
|
||||
// The symbols and patterns that can't be drawn lose what their art uses: each is then as
|
||||
// deep as its own art, and what uses it can be drawn.
|
||||
let (symbols, patterns): (Vec<usize>, Vec<usize>) = {
|
||||
let heights = heights(self);
|
||||
let bad = |def: Def| heights.get(&def).is_some_and(Option::is_none);
|
||||
(
|
||||
(0..self.symbols.len()).filter(|i| self.symbols.get(*i).is_some_and(|s| bad((false, s.name.as_str())))).collect(),
|
||||
(0..self.patterns.len()).filter(|i| self.patterns.get(*i).is_some_and(|p| bad((true, p.name.as_str())))).collect(),
|
||||
)
|
||||
};
|
||||
let mut left_out = !(symbols.is_empty() && patterns.is_empty());
|
||||
let all = |_: Def, _: usize| true;
|
||||
for i in symbols {
|
||||
let Some(s) = self.symbols.get_mut(i) else { continue };
|
||||
let mut art = vec![s.art.clone()];
|
||||
strip(&mut art, 1, &all);
|
||||
// (An instance alone was the whole art: an empty group stands in.)
|
||||
s.art = art.pop().unwrap_or_else(|| Arc::new(Node::group(s.art.id, vec![])));
|
||||
}
|
||||
for i in patterns {
|
||||
if let Some(p) = self.patterns.get_mut(i) {
|
||||
strip(&mut p.art, 1, &all);
|
||||
}
|
||||
}
|
||||
// Then the uses drawn too deep where they are.
|
||||
let mut layers = self.layers.clone();
|
||||
left_out |= {
|
||||
let heights = heights(self);
|
||||
strip(&mut layers, 1, &|used, depth| undrawable(&heights, used, depth))
|
||||
};
|
||||
self.layers = layers;
|
||||
(merged, left_out)
|
||||
}
|
||||
|
||||
/// Bring the document within the caps: merge the objects nested deeper than [`MAX_DEPTH`]
|
||||
/// into the group around them, and leave out the uses of symbols and patterns that can't be
|
||||
/// drawn (inside their own symbol or pattern, or deeper than [`MAX_DRAWN_DEPTH`]). What an
|
||||
/// importer does to what it read. Returns whether anything changed.
|
||||
pub fn limit_depth(&mut self) -> bool {
|
||||
let (merged, left_out) = self.limit_depths();
|
||||
merged || left_out
|
||||
}
|
||||
|
||||
/// [`Self::limit_depth`], adding [`merged_note`] and [`symbols_note`] to an importer's
|
||||
/// `warnings` for what it did.
|
||||
pub fn limit_depth_noting(&mut self, warnings: &mut Vec<String>) {
|
||||
let (merged, left_out) = self.limit_depths();
|
||||
warnings.extend(merged.then(merged_note));
|
||||
warnings.extend(left_out.then(symbols_note));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{NodeId, OpacityMask};
|
||||
|
||||
/// One path in `levels` groups, each holding a second path beside the next group.
|
||||
fn nested(levels: usize) -> Arc<Node> {
|
||||
let mut id = 0;
|
||||
let mut next = || {
|
||||
id += 1;
|
||||
NodeId(id)
|
||||
};
|
||||
let path = |id| Arc::new(Node::path(id, Default::default(), Default::default()));
|
||||
let mut inner = path(next());
|
||||
for _ in 0..levels {
|
||||
inner = Arc::new(Node::group(next(), vec![inner, path(next())]));
|
||||
}
|
||||
inner
|
||||
}
|
||||
|
||||
fn doc(art: Arc<Node>) -> Document {
|
||||
let mut d = Document::new(100.0, 100.0);
|
||||
if let Some(ch) = d.layers.first_mut().and_then(|l| Arc::make_mut(l).children_mut()) {
|
||||
ch.push(art);
|
||||
}
|
||||
d
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_document_at_the_cap_is_left_alone() {
|
||||
// The layer, the groups and the path in them: MAX_DEPTH deep.
|
||||
let mut d = doc(nested(MAX_DEPTH - 2));
|
||||
let before = d.clone();
|
||||
assert!(!d.too_deep(None));
|
||||
assert!(!d.limit_depth());
|
||||
assert_eq!(d, before);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deeper_objects_are_merged_into_the_group_around_them() {
|
||||
for levels in [MAX_DEPTH - 1, MAX_DEPTH + 5, 100_000] {
|
||||
let mut d = doc(nested(levels));
|
||||
assert!(d.too_deep(None), "{levels}");
|
||||
assert!(d.limit_depth(), "{levels}");
|
||||
assert!(!d.too_deep(None), "{levels}");
|
||||
// Every path is kept, under the layer and the groups down to the cap.
|
||||
assert_eq!(d.node_count(), 1 + (MAX_DEPTH - 2) + (levels + 1), "{levels}");
|
||||
assert!(!d.limit_depth(), "nothing more to merge");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_clipping_path_and_a_mask_too_deep_are_left_out_and_hidden_art_stays_hidden() {
|
||||
let mut inner = Node::new(NodeId(9000), NodeKind::Group { children: vec![nested(0), nested(0)], clip: true });
|
||||
inner.visible = false;
|
||||
let mut art = Arc::new(inner);
|
||||
for i in 0..MAX_DEPTH {
|
||||
art = Arc::new(Node::group(NodeId(9001 + i as u64), vec![art]));
|
||||
}
|
||||
let mut masked = Node::group(NodeId(8000), vec![]);
|
||||
masked.extras_mut().mask = Some(Box::new(OpacityMask::new((*nested(MAX_DEPTH)).clone(), true)));
|
||||
let mut d = doc(art);
|
||||
if let Some(ch) = d.layers.first_mut().and_then(|l| Arc::make_mut(l).children_mut()) {
|
||||
ch.push(Arc::new(masked));
|
||||
}
|
||||
assert!(d.limit_depth());
|
||||
assert!(!d.too_deep(None));
|
||||
let mut leaves = vec![];
|
||||
d.walk(|n| {
|
||||
if n.children().is_none() {
|
||||
leaves.push(n.visible);
|
||||
}
|
||||
});
|
||||
assert_eq!(leaves, [false], "the clipping path is gone, what it clipped is still hidden");
|
||||
assert!(d.node(NodeId(8000)).is_some_and(|n| n.extras().mask.is_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_edit_is_checked_by_what_it_changed() {
|
||||
let before = doc(nested(MAX_DEPTH - 2));
|
||||
let mut wrapped = before.clone();
|
||||
if let Some(ch) = wrapped.layers.first_mut().and_then(|l| Arc::make_mut(l).children_mut()) {
|
||||
let all = std::mem::take(ch);
|
||||
ch.push(Arc::new(Node::group(NodeId(7000), all)));
|
||||
}
|
||||
assert!(wrapped.too_deep(Some(&before)), "the same art, one deeper");
|
||||
let mut beside = before.clone();
|
||||
if let Some(ch) = beside.layers.first_mut().and_then(|l| Arc::make_mut(l).children_mut()) {
|
||||
ch.push(nested(3));
|
||||
}
|
||||
assert!(!beside.too_deep(Some(&before)));
|
||||
assert!(!before.too_deep(Some(&before)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn symbols_and_patterns_are_limited_too() {
|
||||
let mut d = Document::new(10.0, 10.0);
|
||||
d.symbols.push(crate::Symbol { name: "s".into(), art: nested(MAX_DEPTH + 3) });
|
||||
assert!(d.too_deep(None));
|
||||
assert!(d.limit_depth());
|
||||
assert!(!d.too_deep(None));
|
||||
assert!(d.symbols.first().is_some_and(|s| s.art.children().is_some()), "still one object");
|
||||
}
|
||||
|
||||
fn instance(id: u64, of: &str) -> Arc<Node> {
|
||||
Arc::new(Node::new(NodeId(id), NodeKind::SymbolInstance { symbol: of.into(), xf: Default::default() }))
|
||||
}
|
||||
|
||||
/// `count` symbols, each `levels` groups around an instance of the next; the last one's of `last`.
|
||||
fn symbols(count: usize, levels: usize, last: &str) -> Document {
|
||||
let mut d = doc(instance(1, "s0"));
|
||||
for i in 0..count {
|
||||
let mut art = instance(2, &if i + 1 < count { format!("s{}", i + 1) } else { last.to_string() });
|
||||
for _ in 0..levels {
|
||||
art = Arc::new(Node::group(NodeId(3), vec![art]));
|
||||
}
|
||||
d.symbols.push(crate::Symbol { name: format!("s{i}"), art });
|
||||
}
|
||||
d
|
||||
}
|
||||
|
||||
fn instances(d: &Document) -> usize {
|
||||
let mut n = 0;
|
||||
let mut count = |x: &Node| n += usize::from(matches!(x.kind, NodeKind::SymbolInstance { .. }));
|
||||
d.walk(&mut count);
|
||||
d.symbols.iter().for_each(|s| s.art.walk(&mut count));
|
||||
n
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn symbols_in_symbols_are_drawn_only_so_deep() {
|
||||
// Three objects deep each (two groups and the instance), under the instance on the layer.
|
||||
let fits = MAX_DRAWN_DEPTH / 3 - 1;
|
||||
let mut d = symbols(fits, 2, "none");
|
||||
assert!(!d.too_deep(None) && !d.limit_depth());
|
||||
let mut d = symbols(fits + 2, 2, "none");
|
||||
assert!(d.too_deep(None));
|
||||
let before = instances(&d);
|
||||
assert!(d.limit_depth() && !d.too_deep(None));
|
||||
assert!(instances(&d) < before && instances(&d) > 0, "only the instances drawn too deep go");
|
||||
// A chain of any length is measured, not walked by recursion.
|
||||
let mut d = symbols(100_000, 0, "none");
|
||||
assert!(d.too_deep(None) && d.limit_depth() && !d.too_deep(None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_symbol_holding_itself_loses_the_instance() {
|
||||
for (count, last) in [(1, "s0"), (3, "s0"), (3, "s1")] {
|
||||
let mut d = symbols(count, 1, last);
|
||||
assert!(d.too_deep(None), "{count} {last}");
|
||||
let mut warnings = vec![];
|
||||
d.limit_depth_noting(&mut warnings);
|
||||
assert_eq!(warnings, [symbols_note()]);
|
||||
assert!(!d.too_deep(None), "{count} {last}");
|
||||
assert!(d.symbols.iter().all(|s| s.art.children().is_some()), "the art is still a group");
|
||||
}
|
||||
// An edit that makes one hold itself is seen, whatever else stayed as it was.
|
||||
let before = symbols(2, 1, "none");
|
||||
let mut after = before.clone();
|
||||
after.symbols[1].art = Arc::new(Node::group(NodeId(9), vec![instance(8, "s0")]));
|
||||
assert!(!before.too_deep(None) && after.too_deep(Some(&before)));
|
||||
}
|
||||
|
||||
/// A path painted with the pattern named `with`.
|
||||
fn painted(id: u64, with: &str) -> Arc<Node> {
|
||||
let fill = Paint::Pattern { pattern: with.into(), xf: Default::default() };
|
||||
Arc::new(Node::path(NodeId(id), Default::default(), crate::Appearance::basic(fill, Paint::None, 0.0)))
|
||||
}
|
||||
|
||||
fn pattern_fills(d: &Document) -> usize {
|
||||
let mut n = 0;
|
||||
d.visit_paints(&mut |p| n += usize::from(matches!(p, Paint::Pattern { .. })));
|
||||
n
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_pattern_painting_its_own_tile_loses_the_paint() {
|
||||
// One that paints its own tile; two that paint each other's; one in a symbol it holds.
|
||||
let itself = |d: &mut Document| d.patterns.push(crate::PatternDef::new("p", vec![painted(2, "p")]));
|
||||
let each_other = |d: &mut Document| {
|
||||
d.patterns.push(crate::PatternDef::new("p", vec![painted(2, "q")]));
|
||||
d.patterns.push(crate::PatternDef::new("q", vec![painted(3, "p")]));
|
||||
};
|
||||
let through_a_symbol = |d: &mut Document| {
|
||||
d.patterns.push(crate::PatternDef::new("p", vec![instance(2, "s")]));
|
||||
d.symbols.push(crate::Symbol { name: "s".into(), art: painted(3, "p") });
|
||||
};
|
||||
for make in [&itself as &dyn Fn(&mut Document), &each_other, &through_a_symbol] {
|
||||
let mut d = doc(painted(1, "p"));
|
||||
make(&mut d);
|
||||
assert!(d.too_deep(None));
|
||||
let mut warnings = vec![];
|
||||
d.limit_depth_noting(&mut warnings);
|
||||
assert_eq!(warnings, [symbols_note()]);
|
||||
assert!(!d.too_deep(None));
|
||||
assert_eq!(pattern_fills(&d), 1, "the object on the layer keeps its pattern");
|
||||
}
|
||||
// A pattern whose tile is painted with another is fine.
|
||||
let mut d = doc(painted(1, "p"));
|
||||
d.patterns.push(crate::PatternDef::new("p", vec![painted(2, "q")]));
|
||||
d.patterns.push(crate::PatternDef::new("q", vec![painted(3, "none")]));
|
||||
assert!(!d.too_deep(None) && !d.limit_depth());
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ pub mod blend;
|
||||
pub mod clipnest;
|
||||
pub mod cmyk;
|
||||
pub mod corners;
|
||||
pub mod depth;
|
||||
pub mod graph;
|
||||
pub mod hit;
|
||||
mod id_index;
|
||||
@@ -79,6 +80,7 @@ pub use appearance::{
|
||||
};
|
||||
pub use assets::ExportAsset;
|
||||
pub use corners::LiveCorners;
|
||||
pub use depth::MAX_DEPTH;
|
||||
pub use graph::{
|
||||
GraphDesign, GraphKind, GraphSpec, LabelStyles, MAX_GRAPH_CATEGORIES, MAX_GRAPH_SERIES, PiePosition, PieSort, SeriesPaint, TickLength,
|
||||
ValueAxisSide,
|
||||
|
||||
@@ -224,7 +224,7 @@ fn item_paint_mut(it: &mut AppearanceItem) -> &mut Paint {
|
||||
}
|
||||
|
||||
/// The paints a node holds itself (not its children): appearance items, then text runs.
|
||||
fn node_paints(n: &Node) -> impl Iterator<Item = &Paint> {
|
||||
pub(crate) fn node_paints(n: &Node) -> impl Iterator<Item = &Paint> {
|
||||
let runs = match &n.kind {
|
||||
NodeKind::Text(t) => t.runs.as_slice(),
|
||||
_ => &[],
|
||||
@@ -233,7 +233,7 @@ fn node_paints(n: &Node) -> impl Iterator<Item = &Paint> {
|
||||
}
|
||||
|
||||
/// Mutable [`node_paints`], in the same order.
|
||||
fn node_paints_mut(n: &mut Node) -> impl Iterator<Item = &mut Paint> {
|
||||
pub(crate) fn node_paints_mut(n: &mut Node) -> impl Iterator<Item = &mut Paint> {
|
||||
let runs = match &mut n.kind {
|
||||
NodeKind::Text(t) => t.runs.as_mut_slice(),
|
||||
_ => &mut [],
|
||||
|
||||
@@ -120,7 +120,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Make",
|
||||
["Object", "Image Trace"],
|
||||
None,
|
||||
"{id?: image or Image Trace group (default: selection), preset?: name (imageTrace.presets), enhanced?: false (the preset's enhanced version: with Auto Grouping, and with Shapes in all but High Fidelity Photo; Flat Logo has none and is traced as it is), params?: {mode: \"blackAndWhite\"|\"grayscale\"|\"color\"|\"logo\", threshold: 0-255, palette: \"limited\"|\"fullTone\"|\"automatic\"|\"documentLibrary\" (color mode; limited: the `colors` best colours, fullTone: as many as the tones need, more with colorDetail, automatic: flat art with its own colours, else fullTone, documentLibrary: at most `colors` of the library's colours, as they are), colors: 2-256, colorDetail: 0-100 (fullTone, automatic), library: \"document\" (the document's swatches) or a swatch library id or name (swatch.library.list; documentLibrary), paths: 0-100, corners: 0-100, noise: px, method: \"abutting\"|\"overlapping\", ignoreWhite (leave out white areas), ignoreColor?: \"#rrggbb\" (with ignoreWhite: the colour left out instead of white), snapCurvesToLines, shapes: false (filled outlines that are a circle, an ellipse, a rectangle or a regular polygon come out as that live shape), autoGrouping: false (each path that has others inside it is grouped with them), gradients: false (grayscale and color: an area whose colour changes evenly along one direction, or outwards from a point, is one path with a linear or radial gradient fill), fills: true, strokes: false (Create: lines up to strokeWidth wide become stroked centre lines; without fills, wider areas become stroked outlines), strokeWidth: px (10), logoColors?: [\"#rrggbb\"…] (mode logo: flat-colour logos only; colours found automatically or named here, white is always its own colour, at most ten; noise = areas under noise/10 px ignored; edges to a fraction of a pixel, sharp corners restored, lines and circles snapped; enclosed transparent areas are painted white unless ignoreWhite makes them holes; fills/strokes are ignored; gradients and photos are refused)}, view?: as imageTrace.setView (default: the traced object's own, else tracingResult), ids?: [id…] (instead of id)} → {id, paths, anchors, colors}",
|
||||
"{id?: image or Image Trace group (default: selection), preset?: name (imageTrace.presets), enhanced?: false (the preset's enhanced version: with Auto Grouping, and with Shapes in all but High Fidelity Photo; Flat Logo has none and is traced as it is), params?: {mode: \"blackAndWhite\"|\"grayscale\"|\"color\"|\"logo\", threshold: 0-255, palette: \"limited\"|\"fullTone\"|\"automatic\"|\"documentLibrary\" (color mode; limited: the `colors` best colours, fullTone: as many as the tones need, more with colorDetail, automatic: flat art with its own colours, else fullTone, documentLibrary: at most `colors` of the library's colours, as they are), colors: 2-256, colorDetail: 0-100 (fullTone, automatic), library: \"document\" (the document's swatches) or a swatch library id or name (swatch.library.list; documentLibrary), paths: 0-100, corners: 0-100, noise: px, method: \"abutting\"|\"overlapping\", ignoreWhite (leave out white areas), ignoreColor?: \"#rrggbb\" (with ignoreWhite: the colour left out instead of white), snapCurvesToLines, shapes: false (filled outlines that are a circle, an ellipse, a rectangle or a regular polygon come out as that live shape), autoGrouping: false (each path that has others inside it is grouped with them), gradients: false (grayscale and color: an area whose colour changes evenly along one direction is one path with a linear gradient fill), fills: true, strokes: false (Create: lines up to strokeWidth wide become stroked centre lines; without fills, wider areas become stroked outlines), strokeWidth: px (10), logoColors?: [\"#rrggbb\"…] (mode logo: flat-colour logos only; colours found automatically or named here, white is always its own colour, at most ten; noise = areas under noise/10 px ignored; edges to a fraction of a pixel, sharp corners restored, lines and circles snapped; enclosed transparent areas are painted white unless ignoreWhite makes them holes; fills/strokes are ignored; gradients and photos are refused)}, view?: as imageTrace.setView (default: the traced object's own, else tracingResult), ids?: [id…] (instead of id)} → {id, paths, anchors, colors}",
|
||||
has_selection_or_ids,
|
||||
|s, p| trace_make(s, p, false)
|
||||
),
|
||||
@@ -730,14 +730,12 @@ fn traced_shape(shape: tr::TracedShape, xf: vectorcraft_geom::Affine) -> LiveSha
|
||||
live
|
||||
}
|
||||
|
||||
/// The gradient fill for a gradient the tracer found (in the image's pixels), placed in the
|
||||
/// document by `xf` (a radial one: its middle and a point on its outermost circle; a circle
|
||||
/// still where the image is scaled evenly).
|
||||
/// The gradient fill for a linear gradient the tracer found (in the image's pixels), placed in the
|
||||
/// document by `xf`.
|
||||
fn traced_gradient(g: &tr::TracedGradient, xf: vectorcraft_geom::Affine) -> Paint {
|
||||
use vectorcraft_color::{Gradient, GradientGeom, GradientKind, GradientPaint, GradientStop};
|
||||
let stops = g.stops.iter().map(|&(at, c)| GradientStop::new(at as f32, Color::rgb8(c[0], c[1], c[2]))).collect();
|
||||
let kind = if g.radial { GradientKind::Radial } else { GradientKind::Linear };
|
||||
let mut paint = GradientPaint::new(Gradient { kind, stops });
|
||||
let mut paint = GradientPaint::new(Gradient { kind: GradientKind::Linear, stops });
|
||||
paint.geom = Some(GradientGeom { start: xf * g.start, end: xf * g.end, aspect: 1.0, focal: None });
|
||||
Paint::Gradient(Box::new(paint))
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ pub(super) fn import(name: &str, bytes: &[u8]) -> Result<Imported> {
|
||||
Ok(d) => {
|
||||
let mut b = Builder { doc: Document::new(0.0, 0.0), warnings: Vec::new(), k: 72.0 / d.dpi, layer: 0 };
|
||||
b.document(&d)?;
|
||||
b.doc.limit_depth_noting(&mut b.warnings);
|
||||
let mut warnings = d.warnings.iter().map(|w| format!("Affinity: not imported or approximated: {w}.")).collect::<Vec<_>>();
|
||||
warnings.extend(b.warnings.iter().map(|w| format!("Affinity: {w}.")));
|
||||
Ok(Imported { doc: b.doc, warnings, preview_only: false })
|
||||
|
||||
@@ -139,7 +139,8 @@ fn restore_or_import(
|
||||
/// (with a warning for each that can't be used).
|
||||
pub(crate) fn native_file(bytes: &[u8]) -> Result<(Document, vectorcraft_format::FileInfo, Vec<String>)> {
|
||||
let f = vectorcraft_format::load_file(bytes).map_err(err)?;
|
||||
let warnings = super::native::install_profiles(f.profiles);
|
||||
let mut warnings = super::native::install_profiles(f.profiles);
|
||||
warnings.extend(f.depth_notes);
|
||||
Ok((f.doc, f.info, warnings))
|
||||
}
|
||||
|
||||
|
||||
@@ -583,6 +583,10 @@ pub(crate) fn is_guide_path(d: &Document, id: NodeId) -> bool {
|
||||
d.node(id).is_some_and(|n| matches!(n.kind, NodeKind::Path { guide: true, .. }))
|
||||
}
|
||||
|
||||
/// The error of an edit that would nest objects deeper than [`vectorcraft_doc::MAX_DEPTH`].
|
||||
pub const TOO_DEEP: &str = "objects can't be nested more than 32 deep";
|
||||
const _: () = assert!(vectorcraft_doc::MAX_DEPTH == 32, "TOO_DEEP (and its catalog rows) names the cap");
|
||||
|
||||
/// Cheap sanity check after an edit: artboards and the objects just touched (the selection) must
|
||||
/// have finite, in-range geometry, so saved files always reload and renderers never see NaN/∞.
|
||||
fn doc_sane(d: &Document, sel: &Selection) -> bool {
|
||||
@@ -1245,6 +1249,9 @@ impl Session {
|
||||
}
|
||||
/// Add a document and make it active.
|
||||
pub fn add_document(&mut self, mut doc: Document, path: Option<String>) -> usize {
|
||||
// Every edit is checked against the document before it, so the first one is within the cap
|
||||
// (importers and the native reader have seen to theirs already, with a warning).
|
||||
doc.limit_depth();
|
||||
Self::refresh_text_bounds(&mut doc);
|
||||
// Guides from files saved before guides had layers go on a layer.
|
||||
doc.adopt_guides();
|
||||
@@ -1262,6 +1269,7 @@ impl Session {
|
||||
if index >= self.docs.len() {
|
||||
return false;
|
||||
}
|
||||
doc.limit_depth();
|
||||
Self::refresh_text_bounds(&mut doc);
|
||||
doc.adopt_guides();
|
||||
if self.active == Some(index) {
|
||||
@@ -1476,7 +1484,10 @@ impl Session {
|
||||
if !st.doc.variables.bindings.is_empty() {
|
||||
Arc::make_mut(&mut st.doc).prune_variable_bindings();
|
||||
}
|
||||
if doc_sane(&st.doc, &st.selection) {
|
||||
if st.doc.too_deep(Some(&before)) {
|
||||
// Deeper trees overflow the stack of what walks them.
|
||||
Err(EngineError::Other(TOO_DEEP.into()))
|
||||
} else if doc_sane(&st.doc, &st.selection) {
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(EngineError::Other("result would exceed the canvas (coordinates out of range)".into()))
|
||||
|
||||
@@ -783,19 +783,6 @@ fn image_trace_gradients_fills_with_a_gradient() {
|
||||
assert!((a.x - 50.0).abs() < 3.0 && (b.x - 250.0).abs() < 3.0 && (a.y - b.y).abs() < 2.0, "{geom:?}");
|
||||
let flat = make(false);
|
||||
assert!(flat.len() > 1 && flat.iter().all(|n| matches!(n.appearance.fill_paint(), Paint::Solid { .. })));
|
||||
// Colours going out from a point: a radial gradient, its middle where the image has it.
|
||||
let round = vectorcraft_trace::Raster::from_fn(120, 100, |x, y| {
|
||||
let t = ((f64::from(x) + 0.5 - 50.0).hypot(f64::from(y) + 0.5 - 40.0) / 90.0).min(1.0);
|
||||
[(250.0 - 200.0 * t) as u8, (230.0 - 150.0 * t) as u8, 90, 255]
|
||||
});
|
||||
let mut s = session();
|
||||
add_image(&mut s, &round, Affine::translate((10.0, 20.0)));
|
||||
let r = s.execute("imageTrace.make", &json!({"preset": "6 Colors", "params": {"gradients": true}})).unwrap();
|
||||
let paths = traced_paths(&node(&s, NodeId(r["id"].as_u64().unwrap())));
|
||||
let Paint::Gradient(g) = paths[0].appearance.fill_paint() else { panic!("{:?}", paths[0].appearance.fill_paint()) };
|
||||
assert_eq!((paths.len(), g.gradient.kind), (1, vectorcraft_color::GradientKind::Radial));
|
||||
let middle = g.geom.as_ref().unwrap().start;
|
||||
assert!((middle.x - 60.0).abs() < 1.5 && (middle.y - 60.0).abs() < 1.5, "{middle:?}");
|
||||
}
|
||||
|
||||
/// A preset's enhanced version: the preset with Auto Grouping and Shapes, under the preset's name.
|
||||
|
||||
@@ -2440,3 +2440,345 @@ proptest! {
|
||||
checked("mutated script", json!({"dataBase64": vectorcraft_format::base64_encode(&bytes), "name": "sample.jsx"}))?;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- deep nesting ----------
|
||||
//
|
||||
// The tree is walked by recursion, so a file nested deeply enough overflowed the stack: an abort,
|
||||
// which nothing catches. Every reader caps what it reads, and no document is deeper than
|
||||
// `MAX_DEPTH`. These run on a thread with the stack of a Windows main thread (1 MB), where an
|
||||
// overflow ends the test run.
|
||||
|
||||
use vectorcraft_doc::MAX_DEPTH;
|
||||
|
||||
/// `f` on a thread with a 1 MB stack.
|
||||
fn on_a_small_stack(f: impl FnOnce() + Send + 'static) {
|
||||
std::thread::Builder::new().stack_size(1 << 20).spawn(f).unwrap().join().unwrap();
|
||||
}
|
||||
|
||||
/// Open `bytes` as the file `name`: an error, or a document within the cap that renders and
|
||||
/// exports. Returns the document and the import's warnings.
|
||||
fn open_deep(name: &str, bytes: &[u8]) -> Option<(Document, Vec<String>)> {
|
||||
let loaded = vectorcraft_engine::cmd::fileio::load(name, bytes).ok()?;
|
||||
assert!(!loaded.doc.too_deep(None), "{name}: deeper than the cap");
|
||||
let doc = loaded.doc.clone();
|
||||
survive(name, move || Some(doc)).unwrap();
|
||||
Some((loaded.doc, loaded.warnings))
|
||||
}
|
||||
|
||||
fn merged(warnings: &[String]) -> bool {
|
||||
warnings.iter().any(|w| w.contains("nested more than"))
|
||||
}
|
||||
|
||||
fn paths_in(doc: &Document) -> usize {
|
||||
let mut paths = 0;
|
||||
doc.walk(|n| paths += usize::from(n.path_data().is_some()));
|
||||
paths
|
||||
}
|
||||
|
||||
const SVG_NS: &str = "xmlns=\"http://www.w3.org/2000/svg\"";
|
||||
|
||||
/// `n` groups in one another, each named (so it is kept) and with a rectangle beside the next.
|
||||
fn nested_svg(n: usize) -> String {
|
||||
let open: String = (0..n).map(|i| format!("<g id=\"g{i}\"><rect width=\"5\" height=\"5\"/>")).collect();
|
||||
format!("<svg {SVG_NS} width=\"100\" height=\"100\">{open}<rect width=\"10\" height=\"10\"/>{}</svg>", "</g>".repeat(n))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deeply_nested_svg_is_refused_or_merged() {
|
||||
on_a_small_stack(|| {
|
||||
// Within what the reader takes: opened, the groups past the cap merged into the last.
|
||||
let (doc, warnings) = open_deep("deep.svg", nested_svg(40).as_bytes()).expect("40 groups open");
|
||||
assert!(merged(&warnings), "{warnings:?}");
|
||||
assert_eq!(paths_in(&doc), 41, "no art is lost");
|
||||
let (_, warnings) = open_deep("shallow.svg", nested_svg(20).as_bytes()).expect("20 groups open");
|
||||
assert!(!merged(&warnings), "{warnings:?}");
|
||||
// As deep as the reader goes (on a stack of its own): opened and merged the same.
|
||||
let most = vectorcraft_svg::MAX_ELEMENT_DEPTH;
|
||||
let (doc, warnings) = open_deep("deepest.svg", nested_svg(most - 2).as_bytes()).expect("opens at the reader's cap");
|
||||
assert!(merged(&warnings), "{warnings:?}");
|
||||
assert_eq!(paths_in(&doc), most - 1, "no art is lost");
|
||||
// Past it: an error that says why, whatever the depth.
|
||||
for n in [most, 2 * most, 200_000] {
|
||||
let e = vectorcraft_engine::cmd::fileio::load("deep.svg", nested_svg(n).as_bytes()).err().expect("refused").to_string();
|
||||
assert!(e.contains(&format!("nested more than {most} deep")), "{n}: {e}");
|
||||
}
|
||||
// Unnamed groups of one object aren't kept, but usvg walks them all the same.
|
||||
let plain = format!(
|
||||
"<svg {SVG_NS} width=\"9\" height=\"9\">{}<rect width=\"1\" height=\"1\"/>{}</svg>",
|
||||
"<g>".repeat(2 * most),
|
||||
"</g>".repeat(2 * most)
|
||||
);
|
||||
assert!(open_deep("plain.svg", plain.as_bytes()).is_none());
|
||||
// A chain of `<use>`: shallow XML, a deep tree.
|
||||
let links: String = (0..3000).map(|i| format!("<g id=\"u{i}\"><use href=\"#u{}\"/></g>", i + 1)).collect();
|
||||
let chain = format!(
|
||||
"<svg {SVG_NS} width=\"9\" height=\"9\"><defs>{links}<rect id=\"u3000\" width=\"1\" height=\"1\"/></defs><use href=\"#u0\"/></svg>"
|
||||
);
|
||||
assert!(open_deep("chain.svg", chain.as_bytes()).is_none());
|
||||
// Placed and pasted, as opened.
|
||||
let mut s = vectorcraft_engine::Session::new();
|
||||
s.execute("file.new", &json!({"width": 300, "height": 200})).unwrap();
|
||||
for n in [40, 2 * most] {
|
||||
let p = json!({"name": "deep.svg", "dataBase64": vectorcraft_format::base64_encode(nested_svg(n).as_bytes())});
|
||||
let _ = no_panic(s.execute("file.place", &p));
|
||||
let _ = no_panic(s.execute("clipboard.importSvg", &json!({"svg": nested_svg(n)})));
|
||||
let _ = no_panic(s.execute("edit.paste", &json!({})));
|
||||
assert!(!s.doc().unwrap().doc.too_deep(None));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// A page whose content is `content`, with `resources`.
|
||||
fn deep_pdf(content: &str, resources: &str) -> Vec<u8> {
|
||||
handmade_pdf(content, resources, "[0 0 100 100]")
|
||||
}
|
||||
|
||||
/// An EPS whose program is `body`.
|
||||
fn deep_eps(body: &str) -> Vec<u8> {
|
||||
format!("%!PS-Adobe-3.0 EPSF-3.0\n%%BoundingBox: 0 0 100 100\n%%EndComments\n{body}\nshowpage\n%%EOF\n").into_bytes()
|
||||
}
|
||||
|
||||
/// A test for each file: it opens as an error or as a document within the cap, on a small stack.
|
||||
macro_rules! deep_files {
|
||||
($($test:ident: $name:literal, $bytes:expr;)*) => {$(
|
||||
#[test]
|
||||
fn $test() {
|
||||
on_a_small_stack(|| {
|
||||
open_deep($name, &$bytes);
|
||||
});
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
deep_files! {
|
||||
// PDF: clips inside clips (saved states never restored); arrays in arrays as an operand and as
|
||||
// an object; dictionaries in dictionaries as a resource and inline; marked content never ended.
|
||||
pdf_clips_in_clips: "clips.pdf", deep_pdf(&format!("{} 0 0 5 5 re f", "q 0 0 50 50 re W n ".repeat(20_000)), "<< >>");
|
||||
pdf_arrays_in_an_operand: "arrays.pdf", deep_pdf(&format!("BT {}{} TJ ET 0 0 5 5 re f", "[".repeat(100_000), "]".repeat(100_000)), "<< >>");
|
||||
pdf_arrays_in_an_object: "boxes.pdf", handmade_pdf("0 0 5 5 re f", "<< >>", &format!("{}0 0 100 100{}", "[".repeat(100_000), "]".repeat(100_000)));
|
||||
pdf_dictionaries_in_resources: "dicts.pdf", deep_pdf("0 0 5 5 re f", &format!("{}{}", "<< /A ".repeat(50_000), ">> ".repeat(50_000)));
|
||||
pdf_dictionaries_in_content: "inline.pdf", deep_pdf(&format!("/P {}{} DP 0 0 5 5 re f", "<< /A ".repeat(50_000), ">> ".repeat(50_000)), "<< >>");
|
||||
pdf_marked_content_never_ended: "marked.pdf", deep_pdf(&format!("{} 0 0 5 5 re f", "/Span << /MCID 0 >> BDC ".repeat(50_000)), "<< >>");
|
||||
// PostScript: clips inside clips; procedures in procedures; arrays in arrays; a procedure that
|
||||
// calls itself; dictionaries never ended.
|
||||
eps_clips_in_clips: "clips.eps", deep_eps(&format!("{} 0 0 5 5 rectfill", "gsave 0 0 50 50 rectclip ".repeat(20_000)));
|
||||
eps_procedures_in_procedures: "procs.eps", deep_eps(&format!("{}{} 0 0 5 5 rectfill", "{".repeat(100_000), "}".repeat(100_000)));
|
||||
eps_arrays_in_arrays: "arrays.eps", deep_eps(&format!("{}{} pop 0 0 5 5 rectfill", "[".repeat(100_000), "]".repeat(100_000)));
|
||||
eps_a_procedure_calling_itself: "runaway.eps", deep_eps("/f { 0 0 5 5 rectfill f } def f");
|
||||
eps_dictionaries_never_ended: "dicts.eps", deep_eps(&format!("{} 0 0 5 5 rectfill", "1 dict begin ".repeat(100_000)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deeply_nested_dxf_blocks_are_read_within_the_cap() {
|
||||
on_a_small_stack(|| {
|
||||
// Block `B0` inserts `B1`, which inserts `B2`, and so on; the last one holds a line.
|
||||
let pair = |c: i32, v: &str| (c, v.to_string());
|
||||
let mut pairs = vec![pair(0, "SECTION"), pair(2, "BLOCKS")];
|
||||
for i in 0..2_000 {
|
||||
pairs.extend([pair(0, "BLOCK"), pair(2, &format!("B{i}")), pair(10, "0"), pair(20, "0")]);
|
||||
if i + 1 < 2_000 {
|
||||
pairs.extend([pair(0, "INSERT"), pair(2, &format!("B{}", i + 1)), pair(10, "1"), pair(20, "1")]);
|
||||
} else {
|
||||
pairs.extend([pair(0, "LINE"), pair(10, "0"), pair(20, "0"), pair(11, "5"), pair(21, "5")]);
|
||||
}
|
||||
pairs.push(pair(0, "ENDBLK"));
|
||||
}
|
||||
pairs.extend([pair(0, "ENDSEC"), pair(0, "SECTION"), pair(2, "ENTITIES"), pair(0, "INSERT"), pair(2, "B0"), pair(10, "0"), pair(20, "0")]);
|
||||
pairs.extend([pair(0, "LINE"), pair(10, "0"), pair(20, "0"), pair(11, "9"), pair(21, "9"), pair(0, "ENDSEC"), pair(0, "EOF")]);
|
||||
open_deep("blocks.dxf", dxf_text(&pairs).as_bytes()).expect("opens");
|
||||
});
|
||||
}
|
||||
|
||||
/// A layer holding `levels` groups in one another around a rectangle, each with a second
|
||||
/// rectangle beside the next: `levels + 2` deep.
|
||||
fn nested_document(levels: usize) -> Document {
|
||||
use vectorcraft_doc::Node;
|
||||
use vectorcraft_testkit::fixtures::DocBuilder;
|
||||
let mut b = DocBuilder::new(100.0, 100.0);
|
||||
let rect =
|
||||
|b: &mut DocBuilder, x: f64| b.rect_node(vectorcraft_geom::Rect::new(x, 0.0, x + 10.0, 10.0), vectorcraft_color::Color::rgb8(200, 0, 0));
|
||||
let mut inner = rect(&mut b, 0.0);
|
||||
for _ in 0..levels {
|
||||
let beside = rect(&mut b, 20.0);
|
||||
inner = Node::group(b.alloc(), vec![std::sync::Arc::new(inner), std::sync::Arc::new(beside)]);
|
||||
inner.opacity = 0.9;
|
||||
}
|
||||
b.add(inner);
|
||||
b.build()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_document_at_the_cap_saves_opens_and_exports() {
|
||||
on_a_small_stack(|| {
|
||||
let doc = nested_document(MAX_DEPTH - 2);
|
||||
assert!(!doc.too_deep(None));
|
||||
let back = vectorcraft_format::load_file(&vectorcraft_format::save_file(&doc)).expect("what can be made opens again");
|
||||
assert!(back.depth_notes.is_empty());
|
||||
assert_eq!(back.doc.layers, doc.layers);
|
||||
survive("at the cap", || Some(doc.clone())).unwrap();
|
||||
// Every format that keeps the nesting reads its own file back within the cap.
|
||||
let mut s = vectorcraft_engine::Session::new();
|
||||
s.add_document(doc, None);
|
||||
for format in ["svg", "pdf", "eps", "ai"] {
|
||||
let r = s.execute("document.export", &json!({"format": format})).unwrap();
|
||||
let bytes = vectorcraft_format::base64_decode(r["dataBase64"].as_str().unwrap()).unwrap();
|
||||
open_deep(&format!("cap.{format}"), &bytes).unwrap_or_else(|| panic!("{format} opens"));
|
||||
}
|
||||
for cmd in ["select.all", "document.inspect", "document.info", "edit.copy", "edit.paste", "object.ungroup", "edit.undo"] {
|
||||
no_panic(s.execute(cmd, &json!({}))).unwrap_or_else(|e| panic!("{cmd}: {e}"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_native_file_nested_too_deep_is_merged_or_refused() {
|
||||
on_a_small_stack(|| {
|
||||
// Saved before the cap by a version that could still open it: opened, the deepest merged.
|
||||
let old = vectorcraft_format::save_file(&nested_document(MAX_DEPTH + 2));
|
||||
let (doc, warnings) = open_deep("old.vectorcraft", &old).expect("opens");
|
||||
assert!(merged(&warnings), "{warnings:?}");
|
||||
assert_eq!(paths_in(&doc), MAX_DEPTH + 3, "no art is lost");
|
||||
// Deeper than any version could open, and a hostile file: an error that says why. Written
|
||||
// by hand: a tree this deep can't be built and saved.
|
||||
let text = String::from_utf8(vectorcraft_format::save(&nested_document(0), false)).unwrap();
|
||||
let (open, close) = ("{\"id\":900000,\"kind\":{\"type\":\"group\",\"children\":[", "]}}");
|
||||
let at = text.find("\"children\":[").expect("the layer's children") + "\"children\":[".len();
|
||||
for levels in [100, 50_000] {
|
||||
let deep = format!("{}{}{},{}", &text[..at], open.repeat(levels), close.repeat(levels), &text[at..]);
|
||||
let e = vectorcraft_engine::cmd::fileio::load("deep.vectorcraft", deep.as_bytes()).err().expect("refused").to_string();
|
||||
assert!(e.contains("nested too deep"), "{levels}: {e}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn commands_cannot_nest_deeper_than_the_cap() {
|
||||
on_a_small_stack(|| {
|
||||
let mut s = vectorcraft_engine::Session::new();
|
||||
s.execute("file.new", &json!({"width": 200, "height": 200})).unwrap();
|
||||
s.execute("shape.rectangle", &json!({"x": 10, "y": 10, "width": 50, "height": 50})).unwrap();
|
||||
s.execute("select.all", &json!({})).unwrap();
|
||||
let mut grouped = 0;
|
||||
for _ in 0..10_000 {
|
||||
match no_panic(s.execute("object.group", &json!({}))) {
|
||||
Ok(_) => grouped += 1,
|
||||
Err(e) => assert!(e.to_string().contains(vectorcraft_engine::TOO_DEEP), "after {grouped} groups: {e}"),
|
||||
}
|
||||
}
|
||||
// The layer, the groups and the rectangle.
|
||||
assert_eq!(grouped, MAX_DEPTH - 2);
|
||||
assert!(!s.doc().unwrap().doc.too_deep(None));
|
||||
// Other ways down: a clipping mask, a copy pasted, a symbol made of it.
|
||||
for (cmd, p) in [
|
||||
("object.clippingMask.make", json!({})),
|
||||
("edit.copy", json!({})),
|
||||
("edit.pasteInFront", json!({})),
|
||||
("symbol.new", json!({"name": "deep"})),
|
||||
] {
|
||||
let _ = no_panic(s.execute(cmd, &p));
|
||||
assert!(!s.doc().unwrap().doc.too_deep(None), "{cmd}");
|
||||
}
|
||||
survive("grouped to the cap", || Some((*s.doc().unwrap().doc).clone())).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
/// A document whose one object is an instance of the first of `count` symbols: each symbol's art
|
||||
/// is `levels` groups around an instance of the next symbol, the last one of `last`.
|
||||
fn symbols_document(count: usize, levels: usize, last: &str) -> Document {
|
||||
use vectorcraft_doc::{Node, NodeKind, Symbol};
|
||||
let instance =
|
||||
|doc: &mut Document, of: String| Node::new(doc.alloc_id(), NodeKind::SymbolInstance { symbol: of, xf: vectorcraft_geom::Affine::IDENTITY });
|
||||
let mut doc = nested_document(1);
|
||||
for i in 0..count {
|
||||
let mut art = instance(&mut doc, if i + 1 < count { format!("s{}", i + 1) } else { last.to_string() });
|
||||
for _ in 0..levels {
|
||||
art = Node::group(doc.alloc_id(), vec![std::sync::Arc::new(art)]);
|
||||
}
|
||||
doc.symbols.push(Symbol { name: format!("s{i}"), art: std::sync::Arc::new(art) });
|
||||
}
|
||||
let first = instance(&mut doc, "s0".into());
|
||||
let layer = doc.layers[0].id;
|
||||
doc.insert(Some(layer), usize::MAX, first).unwrap();
|
||||
doc
|
||||
}
|
||||
|
||||
/// `doc` saved (as an older version, or a hostile file, could have) and opened again: within the
|
||||
/// caps (`kept`: as it was), drawn, exported and edited.
|
||||
fn symbols_survive(what: &str, doc: Document, kept: bool) {
|
||||
let (back, warnings) = open_deep("symbols.vectorcraft", &vectorcraft_format::save_file(&doc)).expect("opens");
|
||||
assert_eq!(!warnings.iter().any(|w| w.contains("symbol instances")), kept, "{what}: {warnings:?}");
|
||||
let mut s = vectorcraft_engine::Session::new();
|
||||
s.add_document(back, None);
|
||||
for cmd in [
|
||||
"select.all",
|
||||
"document.inspect",
|
||||
"document.info",
|
||||
"object.expand",
|
||||
"symbol.breakLink",
|
||||
"object.flattenTransparency",
|
||||
"edit.copy",
|
||||
"edit.paste",
|
||||
] {
|
||||
let _ = no_panic(s.execute(cmd, &json!({})));
|
||||
assert!(!s.doc().unwrap().doc.too_deep(None), "{what}: {cmd}");
|
||||
}
|
||||
for format in ["svg", "pdf", "eps", "png"] {
|
||||
let _ = no_panic(s.execute("document.export", &json!({"format": format})));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_symbol_holding_itself_opens_without_the_instance() {
|
||||
on_a_small_stack(|| {
|
||||
symbols_survive("a symbol holding itself", symbols_document(1, 1, "s0"), false);
|
||||
symbols_survive("symbols holding one another", symbols_document(3, 2, "s0"), false);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn symbols_in_symbols_are_drawn_only_so_deep() {
|
||||
on_a_small_stack(|| {
|
||||
// As deep as symbols draw: each one's art as deep as art goes.
|
||||
symbols_survive("symbols at the cap", symbols_document(3, MAX_DEPTH - 2, "none"), true);
|
||||
symbols_survive("symbols in symbols", symbols_document(40, MAX_DEPTH - 1, "none"), false);
|
||||
// A symbol can't be made to hold itself, or one that holds it, by editing either.
|
||||
let mut s = vectorcraft_engine::Session::new();
|
||||
s.add_document(symbols_document(2, 1, "none"), None);
|
||||
s.execute("select.all", &json!({})).unwrap();
|
||||
for (cmd, p) in [
|
||||
("symbol.new", json!({"name": "s1"})),
|
||||
("symbol.update", json!({"name": "s1"})),
|
||||
("symbol.update", json!({"name": "s0"})),
|
||||
("symbol.replace", json!({"name": "s1"})),
|
||||
] {
|
||||
let _ = no_panic(s.execute(cmd, &p));
|
||||
assert!(!s.doc().unwrap().doc.too_deep(None), "{cmd} {p}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_pattern_painting_its_own_tile_opens_without_the_paint() {
|
||||
on_a_small_stack(|| {
|
||||
use vectorcraft_color::Paint;
|
||||
use vectorcraft_doc::{Appearance, PatternDef};
|
||||
let painted = |doc: &mut Document, with: &str| {
|
||||
let fill = Paint::Pattern { pattern: with.into(), xf: vectorcraft_geom::Affine::IDENTITY };
|
||||
let square = vectorcraft_geom::shapes::rectangle(vectorcraft_geom::Rect::new(0.0, 0.0, 20.0, 20.0));
|
||||
vectorcraft_doc::Node::path(doc.alloc_id(), square, Appearance::basic(fill, Paint::None, 0.0))
|
||||
};
|
||||
// One pattern painting its own tile, and two painting each other's.
|
||||
for names in [["p", "p"], ["p", "q"]] {
|
||||
let mut doc = nested_document(1);
|
||||
let (first, second) = (painted(&mut doc, names[1]), painted(&mut doc, names[0]));
|
||||
doc.patterns.push(PatternDef::new(names[0], vec![std::sync::Arc::new(first)]));
|
||||
if names[0] != names[1] {
|
||||
doc.patterns.push(PatternDef::new(names[1], vec![std::sync::Arc::new(second)]));
|
||||
}
|
||||
let on_layer = painted(&mut doc, "p");
|
||||
let layer = doc.layers[0].id;
|
||||
doc.insert(Some(layer), usize::MAX, on_layer).unwrap();
|
||||
symbols_survive("a pattern painting its own tile", doc, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
//! Every operation counts against a budget and procedures nest only so deep, so a looping or
|
||||
//! recursing program ends with [`PsError::Limit`] instead of hanging.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use vectorcraft_geom::Affine;
|
||||
@@ -86,7 +85,7 @@ struct SaveMark {
|
||||
}
|
||||
|
||||
fn new_dict() -> DictRef {
|
||||
Rc::new(RefCell::new(Dict::new()))
|
||||
DictRef::new(Dict::new())
|
||||
}
|
||||
|
||||
/// An encoding vector: 256 `/.notdef` names (type is read as Latin-1 whatever the encoding).
|
||||
|
||||
@@ -268,5 +268,7 @@ fn finish_with(out: Out, layers: Vec<Arc<Node>>) -> Imported {
|
||||
}
|
||||
}
|
||||
doc.layers = layers;
|
||||
Imported { document: doc, warnings: out.warnings, preview: false }
|
||||
let mut warnings = out.warnings;
|
||||
doc.limit_depth_noting(&mut warnings);
|
||||
Imported { document: doc, warnings, preview: false }
|
||||
}
|
||||
@@ -993,6 +993,7 @@ fn build(data: &[u8], visible: Option<&Document>, page: Page, outlined: bool, tr
|
||||
}
|
||||
None => unmark(&mut doc.layers, true, &mut vec![]),
|
||||
}
|
||||
doc.limit_depth_noting(&mut notes);
|
||||
Ok((doc, notes))
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,73 @@ use super::graphics::GState;
|
||||
pub(crate) type Dict = HashMap<Key, Obj>;
|
||||
|
||||
/// A shared, mutable dictionary.
|
||||
pub(crate) type DictRef = Rc<RefCell<Dict>>;
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct DictRef(Rc<RefCell<Dict>>);
|
||||
|
||||
impl DictRef {
|
||||
pub fn new(d: Dict) -> Self {
|
||||
Self(Rc::new(RefCell::new(d)))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for DictRef {
|
||||
type Target = Rc<RefCell<Dict>>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DictRef {
|
||||
fn drop(&mut self) {
|
||||
if Rc::strong_count(&self.0) == 1
|
||||
&& let Ok(mut d) = self.0.try_borrow_mut()
|
||||
{
|
||||
drop_held(d.drain().map(|(_, v)| v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
/// What the composite objects being dropped held, waiting for their turn (while any is).
|
||||
static HELD: RefCell<Option<Vec<Obj>>> = const { RefCell::new(None) };
|
||||
}
|
||||
|
||||
/// Drop what a composite object held, now that nothing else refers to it, without recursion: a
|
||||
/// program nests arrays and dictionaries as deep as it likes (`[ exch ]` in a loop), and dropping
|
||||
/// them one inside the other overflows the stack. What `held` holds in its turn waits in [`HELD`]
|
||||
/// for the outermost drop, which works through it.
|
||||
fn drop_held(held: impl Iterator<Item = Obj>) {
|
||||
let holds = |o: &Obj| matches!(o, Obj::Array { .. } | Obj::Dict(_) | Obj::File { .. } | Obj::GState(_));
|
||||
// (Without the list, when the thread is ending: dropped as they come.)
|
||||
let outermost = HELD.try_with(|h| {
|
||||
let Ok(mut h) = h.try_borrow_mut() else { return false };
|
||||
let outermost = h.is_none();
|
||||
h.get_or_insert_with(Vec::new).extend(held.filter(holds));
|
||||
outermost
|
||||
});
|
||||
if !matches!(outermost, Ok(true)) {
|
||||
return;
|
||||
}
|
||||
// Each drop here puts what it held on the list instead of dropping it.
|
||||
while let Ok(Some(next)) = HELD.try_with(|h| h.try_borrow_mut().ok().and_then(|mut h| h.as_mut().and_then(Vec::pop))) {
|
||||
drop(next);
|
||||
}
|
||||
let _ = HELD.try_with(|h| h.try_borrow_mut().map(|mut h| *h = None)); // Nothing to do when the thread is ending.
|
||||
}
|
||||
|
||||
/// What [`Shared`] values may be: bytes, or objects (which may hold more of themselves).
|
||||
pub(crate) trait Held: Sized {
|
||||
/// Drop the values of storage nothing refers to any more.
|
||||
fn release(_values: Vec<Self>) {}
|
||||
}
|
||||
|
||||
impl Held for u8 {}
|
||||
|
||||
impl Held for Obj {
|
||||
fn release(values: Vec<Self>) {
|
||||
drop_held(values.into_iter());
|
||||
}
|
||||
}
|
||||
|
||||
/// A dictionary key.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
@@ -72,7 +138,7 @@ impl Obj {
|
||||
}
|
||||
|
||||
pub fn dict(d: Dict) -> Self {
|
||||
Self::Dict(Rc::new(RefCell::new(d)))
|
||||
Self::Dict(DictRef::new(d))
|
||||
}
|
||||
|
||||
/// The number this is (integers and reals).
|
||||
@@ -135,13 +201,23 @@ impl Obj {
|
||||
/// The values of a string or an array: a run of storage that other strings or arrays may share
|
||||
/// (`getinterval` makes a new object over part of the same values, as PostScript does).
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Shared<T> {
|
||||
pub(crate) struct Shared<T: Held> {
|
||||
buf: Rc<RefCell<Vec<T>>>,
|
||||
at: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl<T: Clone> Shared<T> {
|
||||
impl<T: Held> Drop for Shared<T> {
|
||||
fn drop(&mut self) {
|
||||
if Rc::strong_count(&self.buf) == 1
|
||||
&& let Ok(mut values) = self.buf.try_borrow_mut()
|
||||
{
|
||||
T::release(std::mem::take(&mut *values));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Held> Shared<T> {
|
||||
pub fn new(v: Vec<T>) -> Self {
|
||||
Self { len: v.len(), buf: Rc::new(RefCell::new(v)), at: 0 }
|
||||
}
|
||||
@@ -198,7 +274,7 @@ impl<T: Clone> Shared<T> {
|
||||
}
|
||||
|
||||
/// Hashes what [`Shared::same`] compares: the storage and the run of it.
|
||||
impl<T> Hash for Shared<T> {
|
||||
impl<T: Held> Hash for Shared<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
Rc::as_ptr(&self.buf).hash(state);
|
||||
(self.at, self.len).hash(state);
|
||||
|
||||
@@ -389,7 +389,7 @@ impl Interp<'_> {
|
||||
d.insert(Key::name("FontMatrix"), matrix_obj(Affine::scale(0.001)));
|
||||
d.insert(Key::name("FontBBox"), Obj::array(vec![Obj::Int(0), Obj::Int(-250), Obj::Int(1000), Obj::Int(1000)]));
|
||||
d.insert(Key::name("Encoding"), Obj::array(vec![Obj::name(".notdef"); 256]));
|
||||
let font = Rc::new(std::cell::RefCell::new(d));
|
||||
let font = DictRef::new(d);
|
||||
self.fonts.borrow_mut().insert(key, Obj::Dict(font.clone()));
|
||||
Ok(font)
|
||||
}
|
||||
@@ -489,7 +489,7 @@ fn transformed(font: &DictRef, m: Affine) -> DictRef {
|
||||
let mut d = font.borrow().clone();
|
||||
let fm = d.get(&Key::name("FontMatrix")).and_then(|o| o.items().and_then(|i| matrix_of(&i.borrow()))).unwrap_or(Affine::scale(0.001));
|
||||
d.insert(Key::name("FontMatrix"), matrix_obj(m * fm));
|
||||
Rc::new(std::cell::RefCell::new(d))
|
||||
DictRef::new(d)
|
||||
}
|
||||
|
||||
/// The character a glyph name stands for (`A`, `space`, `uni20AC`), else a bullet.
|
||||
|
||||
@@ -482,6 +482,9 @@ pub fn load(bytes: &[u8]) -> Result<Document, FormatError> {
|
||||
#[derive(Debug)]
|
||||
pub struct NativeFile {
|
||||
pub doc: Document,
|
||||
/// What was done to bring the document within the nesting caps
|
||||
/// ([`Document::limit_depth_noting`]: a file saved before them, or a damaged one).
|
||||
pub depth_notes: Vec<String>,
|
||||
pub info: FileInfo,
|
||||
/// ICC files by profile name (saved with Embed ICC Profiles; undecodable ones are left out).
|
||||
pub profiles: BTreeMap<String, Vec<u8>>,
|
||||
@@ -511,7 +514,11 @@ pub fn load_info(bytes: &[u8]) -> Result<(Document, FileInfo), FormatError> {
|
||||
/// [`load`], with everything else the file carries.
|
||||
pub fn load_file(bytes: &[u8]) -> Result<NativeFile, FormatError> {
|
||||
let file = unpack::Unpacked::new(bytes)?;
|
||||
let f: File = serde_json::from_slice(file.json()).map_err(|e| FormatError::NotVectorcraft(e.to_string()))?;
|
||||
// The JSON reader stops at 128 levels (a document's objects use three each).
|
||||
let f: File = serde_json::from_slice(file.json()).map_err(|e| {
|
||||
let why = if e.to_string().contains("recursion limit") { format!("its objects are nested too deep ({e})") } else { e.to_string() };
|
||||
FormatError::NotVectorcraft(why)
|
||||
})?;
|
||||
if f.format != EXTENSION && f.format != LEGACY_EXTENSION {
|
||||
return Err(FormatError::NotVectorcraft(format!("format is `{}`", f.format)));
|
||||
}
|
||||
@@ -545,8 +552,10 @@ pub fn load_file(bytes: &[u8]) -> Result<NativeFile, FormatError> {
|
||||
// Untrusted: capped, named and pointing at objects the file has.
|
||||
doc.tidy_saved_selections();
|
||||
doc.tidy_graph_designs();
|
||||
let mut depth_notes = vec![];
|
||||
doc.limit_depth_noting(&mut depth_notes);
|
||||
let profiles = f.profiles.into_iter().filter_map(|(name, icc)| Some((name, bytes_of(&icc)?))).collect();
|
||||
Ok(NativeFile { doc, info: FileInfo { version: f.version, legacy: f.format == LEGACY_EXTENSION }, profiles })
|
||||
Ok(NativeFile { doc, depth_notes, info: FileInfo { version: f.version, legacy: f.format == LEGACY_EXTENSION }, profiles })
|
||||
}
|
||||
|
||||
/// The members of a native file besides its document (which is skipped, not decoded).
|
||||
|
||||
@@ -102,7 +102,9 @@ pub struct Imported {
|
||||
/// Read an EMF or WMF file (with or without a placeable header) into a document whose one
|
||||
/// artboard is the picture's frame.
|
||||
pub fn import(bytes: &[u8]) -> Result<Imported, String> {
|
||||
import::import(bytes)
|
||||
let mut i = import::import(bytes)?;
|
||||
i.document.limit_depth_noting(&mut i.warnings);
|
||||
Ok(i)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -149,6 +149,7 @@ pub const PAST_PAGE_NOTE: &str = "art reaching past the page was clipped to it,
|
||||
pub fn import_with_report(bytes: &[u8], opts: &ImportOptions) -> Result<ImportReport, PdfError> {
|
||||
let original = crate::pages::open(bytes, opts.password.as_deref())?;
|
||||
let picked = crate::pages::picked(opts, original.pages().len())?;
|
||||
picked.iter().filter_map(|&n| original.pages().get(n)).try_for_each(crate::pages::content_too_deep)?;
|
||||
let mut ocgs = Ocgs::read(&original);
|
||||
let route = opts.layers && !ocgs.list.is_empty();
|
||||
// Content that is off imports as hidden layers: an update of the file turns every group on
|
||||
@@ -166,6 +167,7 @@ pub fn import_with_report(bytes: &[u8], opts: &ImportOptions) -> Result<ImportRe
|
||||
let all_on = turned_on.is_some();
|
||||
let pdf = turned_on.unwrap_or(original);
|
||||
let pages = pdf.pages();
|
||||
picked.iter().filter_map(|&n| pages.get(n)).try_for_each(crate::pages::content_too_deep)?;
|
||||
|
||||
let sink: Arc<Mutex<Vec<String>>> = Arc::default();
|
||||
let sink2 = sink.clone();
|
||||
@@ -417,6 +419,7 @@ pub fn import_with_report(bytes: &[u8], opts: &ImportOptions) -> Result<ImportRe
|
||||
}
|
||||
}
|
||||
}
|
||||
doc.limit_depth_noting(&mut warnings);
|
||||
Ok(ImportReport { document: doc, warnings, native: crate::editing::editing_in(&pdf), only_text })
|
||||
}
|
||||
|
||||
|
||||
@@ -33,12 +33,76 @@ pub fn is_postscript(bytes: &[u8]) -> bool {
|
||||
bytes.starts_with(b"%!PS") || bytes.starts_with(&[0xC5, 0xD0, 0xD3, 0xC6])
|
||||
}
|
||||
|
||||
/// The deepest a file's arrays and dictionaries may nest. The PDF reader (hayro) reads them by
|
||||
/// recursion, without a cap of its own: a file nested deeply enough overflows the stack, which is
|
||||
/// an abort, not an error. Far beyond what a PDF writer makes.
|
||||
const MAX_OBJECT_NESTING: usize = 256;
|
||||
|
||||
fn too_deep() -> PdfError {
|
||||
PdfError::Parse(format!("its arrays and dictionaries are nested more than {MAX_OBJECT_NESTING} deep"))
|
||||
}
|
||||
|
||||
/// Do the arrays and dictionaries in the text of `pdf` nest deeper than [`MAX_OBJECT_NESTING`]?
|
||||
/// Read as tokens (strings and comments hold none), an object at a time. The data of a stream
|
||||
/// with a filter is skipped: it isn't PDF text until decoded, which this doesn't do, so nesting
|
||||
/// inside compressed streams is not seen here.
|
||||
fn nests_too_deep(pdf: &[u8]) -> bool {
|
||||
let after =
|
||||
|from: usize, what: &[u8]| pdf.get(from..).and_then(|rest| rest.windows(what.len()).position(|w| w == what)).map(|at| from + at + what.len());
|
||||
let word = |at: usize, w: &[u8]| pdf.get(at..).is_some_and(|rest| rest.starts_with(w));
|
||||
let (mut depth, mut filtered) = (0usize, false);
|
||||
let mut i = 0;
|
||||
while let Some(&c) = pdf.get(i) {
|
||||
i += 1;
|
||||
match c {
|
||||
b'%' => i += pdf.get(i..).and_then(|rest| rest.iter().position(|c| matches!(c, b'\n' | b'\r'))).unwrap_or(pdf.len()),
|
||||
b'(' => {
|
||||
// A string: parentheses nest in it, a backslash takes the next byte.
|
||||
let mut open = 1usize;
|
||||
while open > 0 {
|
||||
match pdf.get(i) {
|
||||
None => return false,
|
||||
Some(b'\\') => i += 1,
|
||||
Some(b'(') => open += 1,
|
||||
Some(b')') => open -= 1,
|
||||
Some(_) => {}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
b'[' => depth += 1,
|
||||
b']' => depth = depth.saturating_sub(1),
|
||||
b'<' if pdf.get(i) == Some(&b'<') => (depth, i) = (depth + 1, i + 1),
|
||||
b'>' if pdf.get(i) == Some(&b'>') => (depth, i) = (depth.saturating_sub(1), i + 1),
|
||||
// A string in hexadecimal.
|
||||
b'<' => i = after(i, b">").unwrap_or(pdf.len()),
|
||||
b'/' if word(i - 1, b"/Filter") => filtered = true,
|
||||
b'e' if word(i - 1, b"endobj") => (depth, filtered) = (0, false),
|
||||
b'e' if word(i - 1, b"endstream") => i += 8,
|
||||
b's' if word(i - 1, b"stream") => {
|
||||
depth = 0;
|
||||
if std::mem::take(&mut filtered) {
|
||||
i = after(i, b"endstream").unwrap_or(pdf.len());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if depth > MAX_OBJECT_NESTING {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Read a PDF, decrypting it with `password` (none: the empty user password). The permissions
|
||||
/// password opens a file too.
|
||||
pub(crate) fn open(bytes: &[u8], password: Option<&str>) -> Result<Pdf, PdfError> {
|
||||
if is_postscript(bytes) {
|
||||
return Err(PdfError::PostScript);
|
||||
}
|
||||
if nests_too_deep(bytes) {
|
||||
return Err(too_deep());
|
||||
}
|
||||
let password = password.unwrap_or_default();
|
||||
let read = |pw: &str| Pdf::new_with_password(bytes.to_vec(), pw);
|
||||
read(password)
|
||||
@@ -57,6 +121,12 @@ pub(crate) fn open(bytes: &[u8], password: Option<&str>) -> Result<Pdf, PdfError
|
||||
})
|
||||
}
|
||||
|
||||
/// The error of a page whose content, decoded, nests arrays and dictionaries too deep (see
|
||||
/// [`MAX_OBJECT_NESTING`]): its operands are read the same way as the file's objects.
|
||||
pub(crate) fn content_too_deep(page: &Page<'_>) -> Result<(), PdfError> {
|
||||
if page.page_stream().is_some_and(nests_too_deep) { Err(too_deep()) } else { Ok(()) }
|
||||
}
|
||||
|
||||
/// The pages and their boxes. An encrypted PDF needs its `password`
|
||||
/// ([`PdfError::NeedsPassword`] / [`PdfError::WrongPassword`]).
|
||||
pub fn info(bytes: &[u8], password: Option<&str>) -> Result<PdfInfo, PdfError> {
|
||||
|
||||
+34
-14
@@ -18,10 +18,13 @@ use crate::{ImportOptions, SvgError, fnv1a};
|
||||
use css::XNode;
|
||||
use text::TextSlots;
|
||||
|
||||
pub use depth::MAX_ELEMENT_DEPTH;
|
||||
pub(crate) use depth::xml_too_deep;
|
||||
pub(crate) use fx::BLEND;
|
||||
|
||||
mod css;
|
||||
mod css_transform;
|
||||
mod depth;
|
||||
mod files;
|
||||
mod fx;
|
||||
mod spread;
|
||||
@@ -29,11 +32,30 @@ mod symbol_units;
|
||||
mod text;
|
||||
mod vector_effect;
|
||||
|
||||
/// The XML of `svg`.
|
||||
fn parse(svg: &str) -> Result<roxmltree::Document<'_>, SvgError> {
|
||||
roxmltree::Document::parse_with_options(svg, roxmltree::ParsingOptions { allow_dtd: true, ..Default::default() })
|
||||
.map_err(|e| SvgError::Parse(e.to_string()))
|
||||
}
|
||||
|
||||
pub(crate) fn import(svg: &str, opts: &ImportOptions) -> Result<(Document, Vec<String>), SvgError> {
|
||||
let (svg, found) = prepass(svg, opts);
|
||||
// Before anything reads the tree: the XML reader, usvg, and what is made of its tree, all by
|
||||
// recursion.
|
||||
let too_deep = || SvgError::TooDeep(depth::MAX_ELEMENT_DEPTH);
|
||||
if depth::xml_too_deep(svg) {
|
||||
return Err(too_deep());
|
||||
}
|
||||
let xml = parse(svg)?;
|
||||
if depth::too_deep(&xml) {
|
||||
return Err(too_deep());
|
||||
}
|
||||
let (svg, found) = prepass(svg, &xml, opts);
|
||||
// The prepass's edits are in the text: the XML is read again only when it made any.
|
||||
let xml = match &svg {
|
||||
Cow::Borrowed(_) => xml,
|
||||
Cow::Owned(edited) => parse(edited)?,
|
||||
};
|
||||
let svg = svg.as_ref();
|
||||
let xml = roxmltree::Document::parse_with_options(svg, roxmltree::ParsingOptions { allow_dtd: true, ..Default::default() })
|
||||
.map_err(|e| SvgError::Parse(e.to_string()))?;
|
||||
let units = RootUnits::of(xml.root_element());
|
||||
let root_name = root_layer_name(xml.root_element());
|
||||
let mut warnings = found.warnings;
|
||||
@@ -165,6 +187,7 @@ pub(crate) fn import(svg: &str, opts: &ImportOptions) -> Result<(Document, Vec<S
|
||||
promote_sublayers(Arc::make_mut(l), &im.sublayer_groups);
|
||||
}
|
||||
}
|
||||
im.doc.limit_depth_noting(&mut im.warnings);
|
||||
Ok((im.doc, im.warnings))
|
||||
}
|
||||
|
||||
@@ -554,7 +577,7 @@ impl Edits {
|
||||
/// * linked files are read ([`files`]);
|
||||
/// * percentage lengths in a `<symbol>` with a `viewBox` become numbers ([`symbol_units`]);
|
||||
/// * what style sheet rules with a `:not()` set goes in `style` attributes ([`not_rules`]).
|
||||
fn prepass<'s>(svg: &'s str, opts: &ImportOptions) -> (Cow<'s, str>, Found) {
|
||||
fn prepass<'s>(svg: &'s str, xml: &roxmltree::Document, opts: &ImportOptions) -> (Cow<'s, str>, Found) {
|
||||
let mut found = Found::default();
|
||||
// (`:` for prefixed elements such as `<svg:image>`.)
|
||||
let css_transform = has_css_transform(svg);
|
||||
@@ -565,9 +588,6 @@ fn prepass<'s>(svg: &'s str, opts: &ImportOptions) -> (Cow<'s, str>, Found) {
|
||||
{
|
||||
return (svg.into(), found);
|
||||
}
|
||||
let Ok(xml) = roxmltree::Document::parse_with_options(svg, roxmltree::ParsingOptions { allow_dtd: true, ..Default::default() }) else {
|
||||
return (svg.into(), found);
|
||||
};
|
||||
let mut edits = Edits::default();
|
||||
let elements = || xml.descendants().filter(|n| n.is_element());
|
||||
for a in elements().filter(|n| n.tag_name().name() == "a") {
|
||||
@@ -592,24 +612,24 @@ fn prepass<'s>(svg: &'s str, opts: &ImportOptions) -> (Cow<'s, str>, Found) {
|
||||
}
|
||||
let (display, non_scaling) = (svg.contains("display"), svg.contains(vector_effect::NON_SCALING));
|
||||
if display || non_scaling || not {
|
||||
let css = css::Styles::new(&xml);
|
||||
let css = css::Styles::new(xml);
|
||||
// First: an undisplayed object shown for usvg is shown after these.
|
||||
if not && css.has_not_rules() {
|
||||
not_rules(svg, &xml, &css, &mut edits);
|
||||
not_rules(svg, xml, &css, &mut edits);
|
||||
}
|
||||
if display {
|
||||
hidden_objects(svg, &xml, &css, &mut edits, &mut found.hidden);
|
||||
hidden_objects(svg, xml, &css, &mut edits, &mut found.hidden);
|
||||
}
|
||||
if non_scaling {
|
||||
vector_effect::find(svg, &xml, &css, &mut edits, &mut found.non_scaling, &mut found.warnings);
|
||||
vector_effect::find(svg, xml, &css, &mut edits, &mut found.non_scaling, &mut found.warnings);
|
||||
}
|
||||
}
|
||||
found.files = files::Files::read(svg, &xml, opts, &mut edits, &mut found.warnings);
|
||||
found.files = files::Files::read(svg, xml, opts, &mut edits, &mut found.warnings);
|
||||
if !symbols.is_empty() && svg.contains('%') {
|
||||
edits.list.extend(symbol_units::rewrites(&xml));
|
||||
edits.list.extend(symbol_units::rewrites(xml));
|
||||
}
|
||||
if css_transform {
|
||||
edits.list.extend(css_transform::rewrites(svg, &xml));
|
||||
edits.list.extend(css_transform::rewrites(svg, xml));
|
||||
}
|
||||
(edits.apply(svg), found)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ pub(super) type XNode<'a, 'i> = roxmltree::Node<'a, 'i>;
|
||||
|
||||
/// `name: value` declarations of a block or `style` attribute, with their `!important` flag. The
|
||||
/// `font` shorthand becomes its longhands, as usvg reads it for the rest of the drawing (#1557).
|
||||
fn parse_decls(s: &str) -> Vec<(String, String, bool)> {
|
||||
pub(super) fn parse_decls(s: &str) -> Vec<(String, String, bool)> {
|
||||
s.split(';')
|
||||
.filter_map(|d| {
|
||||
let (k, v) = d.split_once(':')?;
|
||||
@@ -371,8 +371,13 @@ impl Styles {
|
||||
Self { rules, index, cache: RefCell::default() }
|
||||
}
|
||||
|
||||
/// Do the document's style sheets have any rules?
|
||||
pub(super) fn has_rules(&self) -> bool {
|
||||
!self.rules.is_empty()
|
||||
}
|
||||
|
||||
/// Properties set on `n` by rules and its `style` attribute, after the cascade.
|
||||
fn declared(&self, n: XNode) -> Rc<HashMap<String, String>> {
|
||||
pub(super) fn declared(&self, n: XNode) -> Rc<HashMap<String, String>> {
|
||||
if let Some(m) = self.cache.borrow().get(&n.id()) {
|
||||
return m.clone();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
//! How deep an SVG's elements nest, found in the XML before usvg runs: usvg converts the tree by
|
||||
//! recursion, a few stack frames an element, so a file nested deeply enough overflows the stack
|
||||
//! (an abort, not an error). Such a file is refused: its nesting can't be merged before usvg has
|
||||
//! read it, and usvg is what can't read it.
|
||||
//!
|
||||
//! What counts is the tree usvg walks, not the XML alone: a `<use>` holds a copy of what it
|
||||
//! refers to, and a clip path, mask, pattern, marker or filter is converted where it is used
|
||||
//! (`clip-path: url(#a)` on an element of a clip path makes a chain as deep as there are clip
|
||||
//! paths). So each element's depth is the deepest of what it holds and what it refers to.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
use usvg::roxmltree;
|
||||
|
||||
use super::css::{Styles, XNode, parse_decls};
|
||||
|
||||
/// The deepest an SVG's elements may nest, references followed. Far beyond what drawing apps
|
||||
/// write, and deeper than a document's objects may nest ([`vectorcraft_doc::MAX_DEPTH`]: wrappers
|
||||
/// that hold one object aren't kept, and what is still deeper is merged into the group around
|
||||
/// it). usvg uses about 15 kB of stack for each level: the importer runs on a thread with 16 MB
|
||||
/// ([`vectorcraft_doc::depth::with_deep_stack`]), except on the web, where there is the one
|
||||
/// 1 MB stack.
|
||||
pub const MAX_ELEMENT_DEPTH: usize = if cfg!(target_arch = "wasm32") { 48 } else { 256 };
|
||||
|
||||
/// Properties whose value an element's descendants use too: the paint server they name is
|
||||
/// converted at each descendant, under everything between.
|
||||
const INHERITED: [&str; 6] = ["fill", "stroke", "marker", "marker-start", "marker-mid", "marker-end"];
|
||||
|
||||
/// The ids of the `url(#id)` references in a property value.
|
||||
fn urls(value: &str) -> impl Iterator<Item = &str> {
|
||||
value.split("url(").skip(1).filter_map(|rest| {
|
||||
let id = rest.trim_start().trim_start_matches(['"', '\'']).strip_prefix('#')?;
|
||||
id.split([')', '"', '\'']).next().map(str::trim).filter(|id| !id.is_empty())
|
||||
})
|
||||
}
|
||||
|
||||
/// The elements `n` refers to, each with whether `n`'s descendants use it too.
|
||||
fn references<'a, 'i>(n: XNode<'a, 'i>, ids: &HashMap<&str, XNode<'a, 'i>>, css: &Styles, out: &mut Vec<(XNode<'a, 'i>, bool)>) {
|
||||
let add = |out: &mut Vec<(XNode<'a, 'i>, bool)>, name: &str, value: &str| {
|
||||
let inherited = INHERITED.contains(&name);
|
||||
out.extend(urls(value).filter_map(|id| ids.get(id)).map(|t| (*t, inherited)));
|
||||
};
|
||||
for a in n.attributes() {
|
||||
match a.name() {
|
||||
"href" => out.extend(a.value().trim().strip_prefix('#').and_then(|id| ids.get(id)).map(|t| (*t, false))),
|
||||
// Read with the style sheets' rules below.
|
||||
"style" if css.has_rules() => {}
|
||||
"style" => parse_decls(a.value()).iter().for_each(|(k, v, _)| add(out, k, v)),
|
||||
name => add(out, name, a.value()),
|
||||
}
|
||||
}
|
||||
if css.has_rules() {
|
||||
css.declared(n).iter().for_each(|(k, v)| add(out, k, v));
|
||||
}
|
||||
}
|
||||
|
||||
/// Do the elements of the XML text `svg` nest deeper than [`MAX_ELEMENT_DEPTH`]? Read from the
|
||||
/// text, before any XML reader: roxmltree (ours and usvg's) reads elements by recursion too. Tags
|
||||
/// are counted as the text has them; markup in the values of a document type's entities counts
|
||||
/// ten times (how deep entities may refer to one another), on top of the deepest element.
|
||||
pub(crate) fn xml_too_deep(svg: &str) -> bool {
|
||||
let b = svg.as_bytes();
|
||||
let find =
|
||||
|from: usize, what: &[u8]| b.get(from..).and_then(|rest| rest.windows(what.len()).position(|w| w == what)).map(|at| from + at + what.len());
|
||||
// The end of the tag starting at `from` (past its `>`), and whether it closes itself.
|
||||
let tag_end = |from: usize| {
|
||||
let mut quote = None;
|
||||
for (i, c) in b.iter().enumerate().skip(from) {
|
||||
match (quote, c) {
|
||||
(None, b'"' | b'\'') => quote = Some(*c),
|
||||
(Some(q), c) if q == *c => quote = None,
|
||||
(None, b'>') => return (i + 1, b.get(i.wrapping_sub(1)) == Some(&b'/')),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
(b.len(), false)
|
||||
};
|
||||
// (now, deepest) of the elements, and of the markup inside the document type.
|
||||
let (mut elements, mut entities) = ((0usize, 0usize), (0usize, 0usize));
|
||||
let mut doctype_end = 0;
|
||||
let mut i = 0;
|
||||
while let Some(at) = b.get(i..).and_then(|rest| rest.iter().position(|c| *c == b'<')).map(|at| i + at) {
|
||||
let rest = b.get(at..).unwrap_or_default();
|
||||
let depth = if at < doctype_end { &mut entities } else { &mut elements };
|
||||
i = if rest.starts_with(b"<!--") {
|
||||
find(at, b"-->").unwrap_or(b.len())
|
||||
} else if rest.starts_with(b"<![CDATA[") {
|
||||
find(at, b"]]>").unwrap_or(b.len())
|
||||
} else if rest.starts_with(b"<?") {
|
||||
find(at, b"?>").unwrap_or(b.len())
|
||||
} else if rest.starts_with(b"<!DOCTYPE") {
|
||||
// Up to the `>` that ends it: after its internal subset (`[` … `]`) when it has one.
|
||||
let plain = tag_end(at).0;
|
||||
let subset = b.get(at..plain).is_some_and(|head| head.contains(&b'['));
|
||||
doctype_end = if subset { find(at, b"]>").unwrap_or(b.len()) } else { plain };
|
||||
at + 2
|
||||
} else if rest.starts_with(b"<!") {
|
||||
// A declaration of the document type: the markup in its value is counted as it comes.
|
||||
at + 2
|
||||
} else if rest.starts_with(b"</") {
|
||||
depth.0 = depth.0.saturating_sub(1);
|
||||
tag_end(at).0
|
||||
} else if at < doctype_end {
|
||||
// In an entity's value, itself in quotes: up to the tag's `>`.
|
||||
let end = find(at, b">").unwrap_or(b.len());
|
||||
depth.1 = depth.1.max(depth.0 + 1);
|
||||
depth.0 += usize::from(b.get(end.wrapping_sub(2)) != Some(&b'/'));
|
||||
end
|
||||
} else {
|
||||
let (end, empty) = tag_end(at);
|
||||
depth.1 = depth.1.max(depth.0 + 1);
|
||||
depth.0 += usize::from(!empty);
|
||||
end
|
||||
};
|
||||
if elements.1 + 10 * entities.1 > MAX_ELEMENT_DEPTH {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Does anything in `xml` nest deeper than [`MAX_ELEMENT_DEPTH`], references followed? Without
|
||||
/// recursion.
|
||||
pub(super) fn too_deep(xml: &roxmltree::Document) -> bool {
|
||||
let elements = || xml.descendants().filter(|n| n.is_element());
|
||||
let ids: HashMap<&str, XNode> = elements().filter_map(|n| Some((n.attribute("id")?, n))).collect();
|
||||
let css = Styles::new(xml);
|
||||
// How deep each element's own tree goes, itself included; 0 while it is being worked out: a
|
||||
// reference back to it then is a loop, which usvg leaves out.
|
||||
let mut heights: HashMap<roxmltree::NodeId, usize> = HashMap::new();
|
||||
enum Step<'a, 'i> {
|
||||
Enter(XNode<'a, 'i>),
|
||||
Leave(XNode<'a, 'i>, Vec<(XNode<'a, 'i>, bool)>),
|
||||
}
|
||||
let mut stack = vec![Step::Enter(xml.root_element())];
|
||||
while let Some(step) = stack.pop() {
|
||||
match step {
|
||||
Step::Enter(n) => {
|
||||
match heights.entry(n.id()) {
|
||||
Entry::Occupied(_) => continue,
|
||||
Entry::Vacant(v) => v.insert(0),
|
||||
};
|
||||
let mut refs = vec![];
|
||||
references(n, &ids, &css, &mut refs);
|
||||
let targets: Vec<XNode> = refs.iter().map(|(t, _)| *t).collect();
|
||||
stack.push(Step::Leave(n, refs));
|
||||
stack.extend(n.children().filter(|c| c.is_element()).chain(targets).map(Step::Enter));
|
||||
}
|
||||
Step::Leave(n, refs) => {
|
||||
let of = |n: XNode| heights.get(&n.id()).copied().unwrap_or(0);
|
||||
let held = n.children().filter(|c| c.is_element()).map(of).max().unwrap_or(0);
|
||||
let used = |inherited: bool| refs.iter().filter(|(_, i)| *i == inherited).map(|(t, _)| of(*t)).max().unwrap_or(0);
|
||||
let height = 1 + held.max(used(false)) + used(true);
|
||||
if height > MAX_ELEMENT_DEPTH {
|
||||
return true;
|
||||
}
|
||||
heights.insert(n.id(), height);
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn deep(svg: &str) -> bool {
|
||||
too_deep(&roxmltree::Document::parse(svg).unwrap())
|
||||
}
|
||||
|
||||
fn svg(body: &str) -> String {
|
||||
format!(r#"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="10" height="10">{body}</svg>"#)
|
||||
}
|
||||
|
||||
/// `n` groups in one another around a rectangle.
|
||||
fn groups(n: usize) -> String {
|
||||
format!("{}<rect width='1' height='1'/>{}", "<g>".repeat(n), "</g>".repeat(n))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn elements_nest_up_to_the_cap() {
|
||||
// The root, the groups and the rectangle.
|
||||
let (at, past) = (svg(&groups(MAX_ELEMENT_DEPTH - 2)), svg(&groups(MAX_ELEMENT_DEPTH - 1)));
|
||||
assert!(!deep(&at) && !xml_too_deep(&at));
|
||||
assert!(deep(&past) && xml_too_deep(&past));
|
||||
assert!(xml_too_deep(&svg(&groups(200_000))), "any depth is measured");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_text_is_measured_as_xml_reads_it() {
|
||||
let many = r#"<g a='>' b="<g>"><rect/></g>"#.repeat(500);
|
||||
assert!(!xml_too_deep(&svg(&many)), "side by side, with `>` and tags in attribute values");
|
||||
let hidden = format!("<!-- {0} --><![CDATA[{0}]]><?pi {0}?>", "<g>".repeat(500));
|
||||
assert!(!xml_too_deep(&svg(&hidden)), "comments, character data and instructions hold no elements");
|
||||
assert!(xml_too_deep(&format!("<svg>{}", "<g>".repeat(MAX_ELEMENT_DEPTH))), "never closed");
|
||||
assert!(!xml_too_deep(&format!("{}<svg/>", "</g>".repeat(2 * MAX_ELEMENT_DEPTH))), "ends without beginnings");
|
||||
// Entities: namespaces as drawing apps declare them, and markup that would be read ten deep.
|
||||
let names = r#"<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ <!ENTITY ns_svg "http://www.w3.org/2000/svg"> ]>"#;
|
||||
assert!(!xml_too_deep(&format!("{names}{}", svg(&groups(30)))));
|
||||
let tenth = MAX_ELEMENT_DEPTH / 10 + 1;
|
||||
let bomb = format!("<!DOCTYPE svg [ <!ENTITY a \"{}&a;{}\"> ]>", "<g>".repeat(tenth), "</g>".repeat(tenth));
|
||||
assert!(xml_too_deep(&format!("{bomb}<svg>&a;</svg>")));
|
||||
assert!(!xml_too_deep(""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_chain_of_uses_is_as_deep_as_what_it_copies() {
|
||||
let chain = |n: usize| {
|
||||
let defs: String = (0..n).map(|i| format!("<g id='g{i}'><use xlink:href='#g{}'/></g>", i + 1)).collect();
|
||||
svg(&format!("<defs>{defs}<rect id='g{n}' width='1' height='1'/></defs><use href='#g0'/>"))
|
||||
};
|
||||
assert!(!deep(&chain(10)));
|
||||
assert!(deep(&chain(MAX_ELEMENT_DEPTH / 2)), "two elements a link");
|
||||
assert!(deep(&chain(5000)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chains_of_clips_masks_and_patterns_count_by_attribute_style_and_style_sheet() {
|
||||
let by_attribute = |n: usize| -> String {
|
||||
(0..n).map(|i| format!("<clipPath id='c{i}' clip-path='url(#c{})'><rect width='1' height='1'/></clipPath>", i + 1)).collect()
|
||||
};
|
||||
let by_style = |n: usize| -> String {
|
||||
(0..n).map(|i| format!("<mask id='c{i}' style='mask: url( \"#c{}\" )'><rect width='1' height='1'/></mask>", i + 1)).collect()
|
||||
};
|
||||
let by_sheet = |n: usize| -> String {
|
||||
let rules: String = (0..n).map(|i| format!(".p{i} {{ fill: url(#c{}) }}", i + 1)).collect();
|
||||
let patterns: String = (0..n)
|
||||
.map(|i| format!("<pattern id='c{i}' width='1' height='1'><g class='p{i}'><rect width='1' height='1'/></g></pattern>"))
|
||||
.collect();
|
||||
format!("<style>{rules}</style>{patterns}")
|
||||
};
|
||||
for chain in [&by_attribute as &dyn Fn(usize) -> String, &by_style, &by_sheet] {
|
||||
let file =
|
||||
|n| svg(&format!("<defs>{}</defs><rect width='5' height='5' fill='url(#c0)' clip-path='url(#c0)' mask='url(#c0)'/>", chain(n)));
|
||||
assert!(!deep(&file(5)));
|
||||
assert!(deep(&file(MAX_ELEMENT_DEPTH)));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_paint_servers_used_side_by_side_are_not_a_chain() {
|
||||
// As drawing apps write gradients: a class each, used by objects that aren't inside one another.
|
||||
let rules: String = (0..300).map(|i| format!(".c{i}{{fill:url(#g{i})}}")).collect();
|
||||
let defs: String = (0..300).map(|i| format!("<linearGradient id='g{i}'><stop class='c{i}' offset='0'/></linearGradient>")).collect();
|
||||
let art: String = (0..300).map(|i| format!("<g class='c{i}'><rect class='c{i}' width='1' height='1'/></g>")).collect();
|
||||
assert!(!deep(&svg(&format!("<style>{rules}</style><defs>{defs}</defs>{art}"))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_loop_of_references_is_not_deep() {
|
||||
assert!(!deep(&svg("<g id='a'><use href='#b'/></g><g id='b'><use href='#a'/></g><clipPath id='c' clip-path='url(#c)'/>")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_inherited_paint_is_converted_under_everything_between() {
|
||||
// Neither the pattern nor the art is too deep; the pattern under the art's last object is.
|
||||
let half = MAX_ELEMENT_DEPTH / 2;
|
||||
let pattern = format!("<pattern id='p' width='1' height='1'>{}</pattern>", groups(half));
|
||||
assert!(!deep(&svg(&format!("<defs>{pattern}</defs><g fill='url(#p)'>{}</g>", groups(half / 2)))));
|
||||
assert!(deep(&svg(&format!("<defs>{pattern}</defs><g fill='url(#p)'>{}</g>", groups(half)))));
|
||||
}
|
||||
}
|
||||
@@ -203,12 +203,16 @@ impl Files {
|
||||
ImageHrefResolver {
|
||||
resolve_data: Box::new(move |mime, bytes, opts| {
|
||||
if mime == "image/svg+xml" {
|
||||
if nested_too_deep(&bytes) {
|
||||
return None;
|
||||
}
|
||||
self.note_text(&bytes);
|
||||
}
|
||||
data(mime, bytes, opts)
|
||||
}),
|
||||
resolve_string: Box::new(move |h, opts| match self.sources.get(h).or_else(|| self.sources.get(h.trim()))? {
|
||||
Source::Raster(kind, bytes) => Some(kind(bytes.clone())),
|
||||
Source::Svg(bytes) if nested_too_deep(bytes) => None,
|
||||
Source::Svg(bytes) => {
|
||||
self.note_text(bytes);
|
||||
usvg::Tree::from_data_nested(bytes, opts).ok().map(ImageKind::SVG)
|
||||
@@ -218,6 +222,12 @@ impl Files {
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the SVG image `bytes` nested too deep for usvg to read (as the SVG holding it would be)?
|
||||
/// It is then left out, as an image usvg can't read.
|
||||
fn nested_too_deep(bytes: &[u8]) -> bool {
|
||||
crate::text_of(bytes).is_ok_and(|text| super::xml_too_deep(&text))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
+11
-3
@@ -312,6 +312,9 @@ pub struct LinkedImage {
|
||||
pub enum SvgError {
|
||||
#[error("SVG parse error: {0}")]
|
||||
Parse(String),
|
||||
/// Its elements nest (references followed) deeper than the reader goes.
|
||||
#[error("the SVG's elements are nested more than {0} deep")]
|
||||
TooDeep(usize),
|
||||
}
|
||||
|
||||
/// Export a document as an SVG string (linked images are not returned: see [`export_full`]).
|
||||
@@ -347,7 +350,8 @@ pub struct Editing {
|
||||
|
||||
/// The native document an SVG carries, if any, and whether the SVG was edited since.
|
||||
pub fn editing(svg: &str) -> Option<Editing> {
|
||||
if !svg.contains(EDITING_NS) {
|
||||
// (An SVG nested too deep for the XML reader carries none: it isn't one of ours.)
|
||||
if !svg.contains(EDITING_NS) || import::xml_too_deep(svg) {
|
||||
return None;
|
||||
}
|
||||
let opts = usvg::roxmltree::ParsingOptions { allow_dtd: true, ..Default::default() };
|
||||
@@ -500,14 +504,18 @@ pub fn import_with_report(svg: &str) -> Result<(Document, Vec<String>), SvgError
|
||||
import_with(svg, &ImportOptions::default())
|
||||
}
|
||||
|
||||
pub use import::MAX_ELEMENT_DEPTH;
|
||||
|
||||
/// Import an SVG document reading the files it links to as `opts` says, also returning warnings.
|
||||
pub fn import_with(svg: &str, opts: &ImportOptions) -> Result<(Document, Vec<String>), SvgError> {
|
||||
import::import(svg, opts)
|
||||
// usvg converts the tree by recursion, in large stack frames: the nesting it is given is
|
||||
// capped (`import::depth`), and it gets room for that cap whatever thread asks.
|
||||
vectorcraft_doc::depth::with_deep_stack(|| import::import(svg, opts))
|
||||
}
|
||||
|
||||
/// Reads a linked file: its bytes and the link to it (absolute path, size, time and hash), or
|
||||
/// `None` when there is no readable file at the (absolute) path.
|
||||
pub type ReadFile<'a> = &'a dyn Fn(&str) -> Option<(Vec<u8>, vectorcraft_doc::LinkInfo)>;
|
||||
pub type ReadFile<'a> = &'a (dyn Fn(&str) -> Option<(Vec<u8>, vectorcraft_doc::LinkInfo)> + Sync);
|
||||
|
||||
/// How [`import_with`] reads the files an SVG's `<image>` elements link to.
|
||||
///
|
||||
|
||||
+14
-135
@@ -28,11 +28,9 @@ const STOP_TOLERANCE: f64 = 2.0;
|
||||
/// How far (levels) a pixel beside a gradient may be from the gradient's colour there and join it.
|
||||
const GROW: f64 = 10.0;
|
||||
|
||||
/// A gradient a traced path is filled with: linear, or radial (the same colour all round a point).
|
||||
/// A linear gradient a traced path is filled with.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct TracedGradient {
|
||||
/// Radial: `start` is the middle, and the stops go outwards to the circle through `end`.
|
||||
pub radial: bool,
|
||||
/// The gradient's line, in pixel coordinates: the first stop's colour is at `start` and before
|
||||
/// it, the last one's at `end` and beyond.
|
||||
pub start: Point,
|
||||
@@ -42,20 +40,10 @@ pub struct TracedGradient {
|
||||
}
|
||||
|
||||
impl TracedGradient {
|
||||
/// How far along the gradient `p` is: 0 at `start`, 1 at `end` (or on the circle through it).
|
||||
fn along(&self, p: Point) -> f64 {
|
||||
let d = self.end - self.start;
|
||||
if d.hypot2() <= 0.0 {
|
||||
0.0
|
||||
} else if self.radial {
|
||||
(p - self.start).hypot() / d.hypot()
|
||||
} else {
|
||||
(p - self.start).dot(d) / d.hypot2()
|
||||
}
|
||||
}
|
||||
/// The gradient's colour at `p`.
|
||||
pub fn color_at(&self, p: Point) -> [f64; 3] {
|
||||
let t = self.along(p).clamp(0.0, 1.0);
|
||||
let d = self.end - self.start;
|
||||
let t = if d.hypot2() > 0.0 { ((p - self.start).dot(d) / d.hypot2()).clamp(0.0, 1.0) } else { 0.0 };
|
||||
let color = |i: usize| self.stops.get(i).map_or([0.0; 3], |s| s.1.map(f64::from));
|
||||
let after = self.stops.iter().position(|s| s.0 >= t).unwrap_or(self.stops.len().saturating_sub(1));
|
||||
let Some(before) = after.checked_sub(1) else { return color(after) };
|
||||
@@ -214,7 +202,7 @@ pub(crate) fn detect(img: &Raster) -> (Vec<u32>, Vec<TracedGradient>) {
|
||||
(of, found)
|
||||
}
|
||||
|
||||
/// The gradient (linear, else radial) the pixels `members` of `img` (`w` wide) are, if they are one, and those of
|
||||
/// The linear gradient the pixels `members` of `img` (`w` wide) are, if they are one, and those of
|
||||
/// `all` (the whole area `members` are the inside of, `rim` pixels in) that have its colours.
|
||||
fn fit(img: &Raster, w: usize, members: &[usize], all: &[usize], rim: usize) -> Option<(TracedGradient, Vec<usize>)> {
|
||||
let n = members.len() as f64;
|
||||
@@ -252,101 +240,14 @@ fn fit(img: &Raster, w: usize, members: &[usize], all: &[usize], rim: usize) ->
|
||||
let (mxx, mxy, myy) = slope.iter().fold((0.0, 0.0, 0.0), |m, s| (m.0 + s.x * s.x, m.1 + s.x * s.y, m.2 + s.y * s.y));
|
||||
let spread = ((mxx - myy) / 2.0).hypot(mxy);
|
||||
let (major, minor) = ((mxx + myy) / 2.0 + spread, (mxx + myy) / 2.0 - spread);
|
||||
if major <= 0.0 || minor > 0.03 * major {
|
||||
return None;
|
||||
}
|
||||
let angle = 0.5 * (2.0 * mxy).atan2(mxx - myy);
|
||||
let line = (major > 0.0 && minor <= 0.03 * major)
|
||||
.then(|| ramp(img, w, members, all, rim, Axis::Line(middle, Vec2::new(angle.cos(), angle.sin()))))
|
||||
.flatten();
|
||||
// Not along one direction: round a point, perhaps.
|
||||
line.or_else(|| ramp(img, w, members, all, rim, Axis::Round(middle_of_rings(img, w, members)?)))
|
||||
}
|
||||
|
||||
/// What a gradient's colours go along: a line through a point, or outwards from a point.
|
||||
#[derive(Clone, Copy)]
|
||||
enum Axis {
|
||||
Line(Point, Vec2),
|
||||
Round(Point),
|
||||
}
|
||||
|
||||
impl Axis {
|
||||
/// How far (px) along it `p` is.
|
||||
fn along(self, p: Point) -> f64 {
|
||||
match self {
|
||||
Axis::Line(through, dir) => (p - through).dot(dir),
|
||||
Axis::Round(middle) => (p - middle).hypot(),
|
||||
}
|
||||
}
|
||||
/// The point `t` px along it.
|
||||
fn at(self, t: f64) -> Point {
|
||||
match self {
|
||||
Axis::Line(through, dir) => through + dir * t,
|
||||
Axis::Round(middle) => middle + Vec2::new(t, 0.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The middle of the pixels `members` if their colour goes round a point: the common middle of the
|
||||
/// circles that the pixels of one tone lie on, for three tones.
|
||||
fn middle_of_rings(img: &Raster, w: usize, members: &[usize]) -> Option<Point> {
|
||||
let rgb = |i: usize| img.rgba.get(i * 4..i * 4 + 3).map_or([0u8; 3], |p| [p[0], p[1], p[2]]);
|
||||
// By the channel that changes most.
|
||||
let (low, high) =
|
||||
members.iter().fold(([255u8; 3], [0u8; 3]), |m, &i| ([0, 1, 2].map(|k| m.0[k].min(rgb(i)[k])), [0, 1, 2].map(|k| m.1[k].max(rgb(i)[k]))));
|
||||
let channel = (0..3).max_by_key(|&k| high[k].saturating_sub(low[k]))?;
|
||||
let mut count = [0usize; 256];
|
||||
members.iter().for_each(|&i| count[rgb(i)[channel] as usize] += 1);
|
||||
let tone_at = |share: f64| {
|
||||
let mut seen = 0;
|
||||
count.iter().position(|&n| {
|
||||
seen += n;
|
||||
seen as f64 >= share * members.len() as f64
|
||||
})
|
||||
};
|
||||
let mut middles = vec![];
|
||||
for share in [0.3, 0.5, 0.7] {
|
||||
let tone = tone_at(share)? as i32;
|
||||
// The circle x² + y² + d x + e y + f = 0 nearest the pixels of that tone, by least squares.
|
||||
let (mut m, mut v) = ([[0.0f64; 3]; 3], [0.0f64; 3]);
|
||||
let mut n = 0;
|
||||
for &i in members.iter().filter(|&&i| (i32::from(rgb(i)[channel]) - tone).abs() <= 1) {
|
||||
let (x, y) = ((i % w) as f64 + 0.5, (i / w) as f64 + 0.5);
|
||||
let (row, z) = ([x, y, 1.0], -(x * x + y * y));
|
||||
for a in 0..3 {
|
||||
for b in 0..3 {
|
||||
m[a][b] += row[a] * row[b];
|
||||
}
|
||||
v[a] += row[a] * z;
|
||||
}
|
||||
n += 1;
|
||||
}
|
||||
let det = |m: &[[f64; 3]; 3]| {
|
||||
m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])
|
||||
+ m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0])
|
||||
};
|
||||
let whole = det(&m);
|
||||
if n < 30 || whole.abs() < 1e-6 {
|
||||
return None;
|
||||
}
|
||||
let solved = |col: usize| {
|
||||
let mut swapped = m;
|
||||
(0..3).for_each(|r| swapped[r][col] = v[r]);
|
||||
det(&swapped) / whole
|
||||
};
|
||||
middles.push(Point::new(-solved(0) / 2.0, -solved(1) / 2.0));
|
||||
}
|
||||
let mean = (middles.iter().fold(Vec2::ZERO, |s, p| s + p.to_vec2()) / middles.len() as f64).to_point();
|
||||
(mean.x.is_finite() && mean.y.is_finite() && middles.iter().all(|p| p.distance(mean) <= 3.0)).then_some(mean)
|
||||
}
|
||||
|
||||
/// The gradient the pixels `members` are along `axis`, if they are one (see [`fit`]).
|
||||
fn ramp(img: &Raster, w: usize, members: &[usize], all: &[usize], rim: usize, axis: Axis) -> Option<(TracedGradient, Vec<usize>)> {
|
||||
let at = |i: usize| Point::new((i % w) as f64 + 0.5, (i / w) as f64 + 0.5);
|
||||
let rgb = |i: usize| img.rgba.get(i * 4..i * 4 + 3).map_or([0.0; 3], |p| [f64::from(p[0]), f64::from(p[1]), f64::from(p[2])]);
|
||||
let radial = matches!(axis, Axis::Round(_));
|
||||
let dir = Vec2::new(angle.cos(), angle.sin());
|
||||
// The colours along it, a pixel's width at a time.
|
||||
let along = |i: usize| axis.along(at(i));
|
||||
let along = |i: usize| (at(i) - middle).dot(dir);
|
||||
let (t0, t1) = members.iter().fold((f64::INFINITY, f64::NEG_INFINITY), |m, &i| (m.0.min(along(i) - 0.5), m.1.max(along(i) + 0.5)));
|
||||
// (A radial gradient starts at its middle, whether or not the area reaches it.)
|
||||
let t0 = if radial { 0.0 } else { t0 };
|
||||
let length = t1 - t0;
|
||||
if !(MIN_LENGTH..1e6).contains(&length) {
|
||||
return None;
|
||||
@@ -405,7 +306,7 @@ fn ramp(img: &Raster, w: usize, members: &[usize], all: &[usize], rim: usize, ax
|
||||
_ => stops.push((t, c)),
|
||||
}
|
||||
}
|
||||
let (first, last) = (if radial { 0.0 } else { stops.first()?.0 }, stops.last()?.0);
|
||||
let (first, last) = (stops.first()?.0, stops.last()?.0);
|
||||
// A change of colour, not one colour.
|
||||
let change =
|
||||
stops.iter().flat_map(|a| stops.iter().map(move |b| (0..3).map(|k| (a.1[k] - b.1[k]).abs()).fold(0.0, f64::max))).fold(0.0, f64::max);
|
||||
@@ -415,19 +316,13 @@ fn ramp(img: &Raster, w: usize, members: &[usize], all: &[usize], rim: usize, ax
|
||||
return None;
|
||||
}
|
||||
let gradient = TracedGradient {
|
||||
radial,
|
||||
start: axis.at(t0 + first * length),
|
||||
end: axis.at(t0 + last * length),
|
||||
// (A radial one's first colour goes on to its middle.)
|
||||
stops: stops
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(j, &(t, c))| (if j == 0 { 0.0 } else { (t - first) / (last - first) }, c.map(|v| v.round().clamp(0.0, 255.0) as u8)))
|
||||
.collect(),
|
||||
start: middle + dir * (t0 + first * length),
|
||||
end: middle + dir * (t0 + last * length),
|
||||
stops: stops.iter().map(|&(t, c)| ((t - first) / (last - first), c.map(|v| v.round().clamp(0.0, 255.0) as u8))).collect(),
|
||||
};
|
||||
// Carried on to the ends of the whole area, each end ramp going on as it goes.
|
||||
let d = gradient.end - gradient.start;
|
||||
let place = |i: usize| gradient.along(at(i));
|
||||
let place = |i: usize| (at(i) - gradient.start).dot(d) / d.hypot2();
|
||||
let reach = rim as f64 * 1.5 / d.hypot();
|
||||
let (u0, u1) = all.iter().fold((0.0f64, 1.0f64), |m, &i| (m.0.min(place(i)), m.1.max(place(i))));
|
||||
let (u0, u1) = (u0.max(-reach), u1.min(1.0 + reach));
|
||||
@@ -444,7 +339,6 @@ fn ramp(img: &Raster, w: usize, members: &[usize], all: &[usize], rim: usize, ax
|
||||
}
|
||||
}
|
||||
let gradient = TracedGradient {
|
||||
radial,
|
||||
start: gradient.start + d * u0,
|
||||
end: gradient.start + d * u1,
|
||||
stops: stops.into_iter().map(|(u, c)| ((u - u0) / (u1 - u0), c)).collect(),
|
||||
@@ -563,21 +457,6 @@ mod tests {
|
||||
assert!(detect(&ramp(96, 96, |x, y| [40.0 + 2.0 * x, 40.0 + 2.0 * y, 90.0])).1.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn colours_going_round_a_point_are_a_radial_gradient() {
|
||||
// Yellow at (70, 50) to dark red 80 px out.
|
||||
let img = ramp(160, 120, |x, y| {
|
||||
let t = ((x - 70.0).hypot(y - 50.0) / 80.0).min(1.0);
|
||||
[250.0 - 130.0 * t, 220.0 - 190.0 * t, 60.0 - 30.0 * t]
|
||||
});
|
||||
let (_, found) = detect(&img);
|
||||
let g = found.iter().find(|g| g.radial).expect("a radial gradient");
|
||||
assert!(g.start.distance(Point::new(70.0, 50.0)) < 1.0, "{:?}", g.start);
|
||||
assert!(((g.end - g.start).hypot() - 80.0).abs() < 5.0, "{:?}", g);
|
||||
let (first, last) = (g.stops[0].1, g.stops.last().unwrap().1);
|
||||
assert!(first[0] > 240 && first[1] > 205 && last[0] < 135 && last[1] < 45, "{:?}", g.stops);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn three_stops_are_three_stops() {
|
||||
let img = ramp(200, 40, |x, _| {
|
||||
|
||||
@@ -26,12 +26,9 @@ pub enum Class {
|
||||
Tone,
|
||||
/// Linear gradients whose line and stops are known: one over the whole image, one in a disc.
|
||||
Ramp,
|
||||
/// A radial gradient whose middle and stops are known.
|
||||
Round,
|
||||
}
|
||||
|
||||
pub const CLASSES: [Class; 9] =
|
||||
[Class::Shape, Class::Poly, Class::Lines, Class::Askew, Class::Plain, Class::Flat, Class::Tone, Class::Ramp, Class::Round];
|
||||
pub const CLASSES: [Class; 8] = [Class::Shape, Class::Poly, Class::Lines, Class::Askew, Class::Plain, Class::Flat, Class::Tone, Class::Ramp];
|
||||
|
||||
impl Class {
|
||||
pub fn name(self) -> &'static str {
|
||||
@@ -44,7 +41,6 @@ impl Class {
|
||||
Class::Flat => "flat colour art",
|
||||
Class::Tone => "gradient, photo",
|
||||
Class::Ramp => "linear gradients",
|
||||
Class::Round => "radial gradient",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,11 +97,9 @@ pub struct Input {
|
||||
tone: Option<Tone>,
|
||||
}
|
||||
|
||||
/// A gradient: its line (256-unit coordinates) and its stops along it (0 to 1); or, radial, its
|
||||
/// middle, a point on its outermost circle, and its stops outwards.
|
||||
/// A linear gradient: its line (256-unit coordinates) and its stops along it (0 to 1).
|
||||
#[derive(Clone)]
|
||||
pub struct Ramp {
|
||||
pub radial: bool,
|
||||
pub start: Point,
|
||||
pub end: Point,
|
||||
pub stops: Vec<(f64, [f64; 3])>,
|
||||
@@ -114,7 +108,7 @@ pub struct Ramp {
|
||||
impl Ramp {
|
||||
pub fn color_at(&self, p: Point) -> [f64; 3] {
|
||||
let d = self.end - self.start;
|
||||
let t = if self.radial { (p - self.start).hypot() / d.hypot() } else { (p - self.start).dot(d) / d.hypot2() }.clamp(0.0, 1.0);
|
||||
let t = ((p - self.start).dot(d) / d.hypot2()).clamp(0.0, 1.0);
|
||||
let after = self.stops.iter().position(|s| s.0 >= t).unwrap().max(1);
|
||||
let (a, b) = (self.stops[after - 1], self.stops[after]);
|
||||
let k = (t - a.0) / (b.0 - a.0);
|
||||
@@ -127,12 +121,7 @@ fn two_stop_ramp() -> Ramp {
|
||||
let dir = kurbo::Vec2::from_angle(25f64.to_radians());
|
||||
let reach = kurbo::Vec2::new(128.0, 128.0).dot(dir);
|
||||
let centre = Point::new(128.0, 128.0);
|
||||
Ramp {
|
||||
radial: false,
|
||||
start: centre - dir * reach,
|
||||
end: centre + dir * reach,
|
||||
stops: vec![(0.0, [24.0, 40.0, 150.0]), (1.0, [250.0, 215.0, 60.0])],
|
||||
}
|
||||
Ramp { start: centre - dir * reach, end: centre + dir * reach, stops: vec![(0.0, [24.0, 40.0, 150.0]), (1.0, [250.0, 215.0, 60.0])] }
|
||||
}
|
||||
|
||||
/// Red through white to green across a disc, 110° from level.
|
||||
@@ -140,28 +129,12 @@ fn three_stop_ramp() -> Ramp {
|
||||
let dir = kurbo::Vec2::from_angle(110f64.to_radians());
|
||||
let centre = Point::new(128.0, 128.0);
|
||||
Ramp {
|
||||
radial: false,
|
||||
start: centre - dir * DISC,
|
||||
end: centre + dir * DISC,
|
||||
stops: vec![(0.0, [200.0, 30.0, 40.0]), (0.4, [245.0, 240.0, 230.0]), (1.0, [20.0, 120.0, 70.0])],
|
||||
}
|
||||
}
|
||||
|
||||
/// Pale yellow at (100, 150) out to deep blue 200 units away, over the whole image.
|
||||
fn radial_ramp() -> Ramp {
|
||||
let middle = Point::new(100.0, 150.0);
|
||||
Ramp {
|
||||
radial: true,
|
||||
start: middle,
|
||||
end: middle + kurbo::Vec2::new(200.0, 0.0),
|
||||
stops: vec![(0.0, [250.0, 240.0, 150.0]), (1.0, [20.0, 40.0, 130.0])],
|
||||
}
|
||||
}
|
||||
|
||||
fn radial(u: f64, v: f64, _: u32, _: u32) -> [f64; 3] {
|
||||
radial_ramp().color_at(Point::new(u * 256.0, v * 256.0))
|
||||
}
|
||||
|
||||
/// The radius of the disc the three-stop gradient fills.
|
||||
const DISC: f64 = 90.0;
|
||||
|
||||
@@ -391,7 +364,6 @@ pub fn inputs() -> Vec<Input> {
|
||||
tone("photo-like", photo),
|
||||
Input { class: Class::Ramp, ramp: Some(two_stop_ramp()), ..tone("two-stop gradient", two_stop) },
|
||||
Input { class: Class::Ramp, ramp: Some(three_stop_ramp()), ..tone("three-stop gradient in a disc", three_stop) },
|
||||
Input { class: Class::Round, ramp: Some(radial_ramp()), ..tone("radial gradient", radial) },
|
||||
];
|
||||
if let Some(input) = all.iter_mut().find(|i| i.name == "plain shapes") {
|
||||
input.plain = plain;
|
||||
|
||||
@@ -75,7 +75,7 @@ fn target(preset: &str, input: &Input) -> bool {
|
||||
"3 Colors" => return input.name == "two touching halves",
|
||||
"6 Colors" | "16 Colors" | "Flat Logo" | "Auto Color" | "6 Colors with Auto Grouping" => &[Class::Flat],
|
||||
"Default with Shapes" | "6 Colors with Shapes" => &[Class::Plain],
|
||||
name if name.ends_with("Gradients") => &[Class::Ramp, Class::Round],
|
||||
name if name.ends_with("Gradients") => &[Class::Ramp],
|
||||
"Sketched Art" => &[Class::Shape, Class::Lines],
|
||||
"Silhouettes" => &[Class::Shape],
|
||||
"Line Art" | "Outline" => &[Class::Lines],
|
||||
@@ -359,7 +359,7 @@ fn quality_report() {
|
||||
let inputs = inputs();
|
||||
for (name, _) in presets().iter().filter(|(_, p)| p.mode != vectorcraft_trace::Mode::BlackAndWhite && p.mode != vectorcraft_trace::Mode::Logo) {
|
||||
let params = TraceParams { gradients: true, ..vectorcraft_trace::preset(name).unwrap() };
|
||||
for (input, size, variant, img) in draw_all(&inputs).iter().filter(|d| !matches!(d.0.class, Class::Tone | Class::Ramp | Class::Round)) {
|
||||
for (input, size, variant, img) in draw_all(&inputs).iter().filter(|d| !matches!(d.0.class, Class::Tone | Class::Ramp)) {
|
||||
let found = trace_within(img, ¶ms, MAX_ANCHORS).map_or(0, |res| res.paths.iter().filter(|p| p.gradient.is_some()).count());
|
||||
assert_eq!(found, 0, "{name} with Gradients on {} at {size} px, {variant:?}", input.name);
|
||||
}
|
||||
|
||||
@@ -251,19 +251,12 @@ pub fn measure(input: &Input, variant: Variant, size: u32, src: &Raster, params:
|
||||
let (mut ramp_found, mut ramp_angle, mut ramp_off) = (f64::NAN, f64::NAN, f64::NAN);
|
||||
if let Some(ramp) = &input.ramp {
|
||||
let k = f64::from(size) / 256.0;
|
||||
// (Of the input's kind: a linear gradient found in a radial one is not it.)
|
||||
let found = res
|
||||
.paths
|
||||
.iter()
|
||||
.filter(|tp| tp.gradient.as_ref().is_some_and(|g| g.radial == ramp.radial))
|
||||
.max_by_key(|tp| tp.pixels)
|
||||
.and_then(|tp| tp.gradient.as_ref());
|
||||
let found = res.paths.iter().filter(|tp| tp.gradient.is_some()).max_by_key(|tp| tp.pixels).and_then(|tp| tp.gradient.as_ref());
|
||||
ramp_found = if found.is_some() { 100.0 } else { 0.0 };
|
||||
if let Some(g) = found {
|
||||
let (truth, own) = (ramp.end - ramp.start, g.end - g.start);
|
||||
let between = (truth.atan2() - own.atan2()).to_degrees().rem_euclid(180.0);
|
||||
// (A radial gradient has no direction: its middle shows in the colours along the line.)
|
||||
ramp_angle = if ramp.radial { f64::NAN } else { between.min(180.0 - between) };
|
||||
ramp_angle = between.min(180.0 - between);
|
||||
ramp_off = (0..=16)
|
||||
.map(|j| {
|
||||
let p = ramp.start + truth * (f64::from(j) / 16.0);
|
||||
@@ -288,7 +281,7 @@ pub fn measure(input: &Input, variant: Variant, size: u32, src: &Raster, params:
|
||||
let nan = f64::NAN;
|
||||
let (mut geo_mean, mut geo_max, mut miss_max, mut corners, mut kinks, mut slivers, mut sliver_area) = (nan, nan, nan, nan, nan, nan, nan);
|
||||
let mut false_shapes = if params.shapes { 0.0 } else { nan };
|
||||
if !matches!(input.class, Class::Tone | Class::Ramp | Class::Round) {
|
||||
if !matches!(input.class, Class::Tone | Class::Ramp) {
|
||||
let truth_shapes = input.scaled(size);
|
||||
let truth = Outline::new(truth_shapes.iter().map(|(p, _)| p), None);
|
||||
let traced = Outline::new(shapes.iter().map(|(p, _)| p), Some(f64::from(size)));
|
||||
|
||||
@@ -4099,6 +4099,8 @@ imageTrace Outline Obrys
|
||||
@msg recovery copy `{file}`: {e} kopie pro obnovení `{file}`: {e}
|
||||
@msg resolutions must be between 1 and 2400 ppi rozlišení musí být mezi 1 a 2400 ppi
|
||||
@msg result would exceed the canvas (coordinates out of range) výsledek by přesáhl plátno (souřadnice mimo rozsah)
|
||||
@msg objects can't be nested more than 32 deep objekty nelze vnořit hlouběji než do 32 úrovní
|
||||
@msg the SVG's elements are nested more than {0} deep prvky SVG jsou vnořeny hlouběji než do {0} úrovní
|
||||
@msg scale must be a number from {_1} to {_2}, not {_3} měřítko musí být číslo od {_1} do {_2}, ne {_3}
|
||||
@msg scale must be a number from {_1} to {_2}, not {s} měřítko musí být číslo od {_1} do {_2}, ne {s}
|
||||
@msg select (or target) objects whose appearance isn't basic vyberte (nebo zacilte) objekty, jejichž vzhled není základní
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3705,6 +3705,8 @@ theme Appearance Erscheinungsbild
|
||||
@msg recovery copy `{file}`: {e} Wiederherstellungskopie `{file}`: {e}
|
||||
@msg resolutions must be between 1 and 2400 ppi Auflösungen müssen zwischen 1 und 2400 ppi liegen
|
||||
@msg result would exceed the canvas (coordinates out of range) das Ergebnis würde die Arbeitsfläche überschreiten (Koordinaten außerhalb des Bereichs)
|
||||
@msg objects can't be nested more than 32 deep Objekte können nicht tiefer als 32 Ebenen verschachtelt werden
|
||||
@msg the SVG's elements are nested more than {0} deep die Elemente der SVG-Datei sind tiefer als {0} Ebenen verschachtelt
|
||||
@msg scale must be a number from {_1} to {_2}, not {_3} scale muss eine Zahl von {_1} bis {_2} sein, nicht {_3}
|
||||
@msg scale must be a number from {_1} to {_2}, not {s} scale muss eine Zahl von {_1} bis {_2} sein, nicht {s}
|
||||
@msg select (or target) objects whose appearance isn't basic wählen Sie Objekte aus (oder als Ziel), deren Aussehen nicht einfach ist
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3804,6 +3804,8 @@ axis Both Ambos
|
||||
@msg recovery copy `{file}`: {e} copia de recuperación `{file}`: {e}
|
||||
@msg resolutions must be between 1 and 2400 ppi las resoluciones deben estar entre 1 y 2400 ppi
|
||||
@msg result would exceed the canvas (coordinates out of range) el resultado excedería el lienzo (coordenadas fuera de rango)
|
||||
@msg objects can't be nested more than 32 deep los objetos no pueden anidarse a más de 32 niveles
|
||||
@msg the SVG's elements are nested more than {0} deep los elementos del SVG están anidados a más de {0} niveles
|
||||
@msg scale must be a number from {_1} to {_2}, not {_3} la escala debe ser un número de {_1} a {_2}, no {_3}
|
||||
@msg scale must be a number from {_1} to {_2}, not {s} la escala debe ser un número de {_1} a {_2}, no {s}
|
||||
@msg select (or target) objects whose appearance isn't basic selecciona (o apunta a) objetos cuya apariencia no sea básica
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3801,6 +3801,8 @@ axis Both Les deux
|
||||
@msg recovery copy `{file}`: {e} copie de récupération `{file}` : {e}
|
||||
@msg resolutions must be between 1 and 2400 ppi les résolutions doivent être comprises entre 1 et 2400 ppp
|
||||
@msg result would exceed the canvas (coordinates out of range) le résultat dépasserait la zone de travail (coordonnées hors limites)
|
||||
@msg objects can't be nested more than 32 deep les objets ne peuvent pas être imbriqués sur plus de 32 niveaux
|
||||
@msg the SVG's elements are nested more than {0} deep les éléments du SVG sont imbriqués sur plus de {0} niveaux
|
||||
@msg scale must be a number from {_1} to {_2}, not {_3} l’échelle doit être un nombre compris entre {_1} et {_2}, pas {_3}
|
||||
@msg scale must be a number from {_1} to {_2}, not {s} l’échelle doit être un nombre compris entre {_1} et {_2}, pas {s}
|
||||
@msg select (or target) objects whose appearance isn't basic sélectionnez (ou ciblez) des objets dont l’aspect n’est pas basique
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4441,6 +4441,8 @@ imageTrace Outline Körvonal
|
||||
@msg resolutions must be between 1 and 2400 ppi a felbontás 1 és 2400 ppi között lehet
|
||||
@msg Restored {_1} recovered document(s): save them to keep them Helyreállított dokumentumok: {_1}; mentsd őket, ha meg akarod tartani
|
||||
@msg result would exceed the canvas (coordinates out of range) az eredmény túllépné a vásznat (a koordináták tartományon kívül esnek)
|
||||
@msg objects can't be nested more than 32 deep az objektumok legfeljebb 32 szint mélyen ágyazhatók egymásba
|
||||
@msg the SVG's elements are nested more than {0} deep az SVG elemei több mint {0} szint mélyen vannak egymásba ágyazva
|
||||
@msg Save for Web: the image is empty Mentés webre: a kép üres
|
||||
@msg Save writes {_1}, not {_2}: use document.export for other formats a Mentés ezt írja: {_1}, ezt nem: {_2}; más formátumhoz használd a document.export parancsot
|
||||
@msg saved panel layout is invalid; reset the workspace first a mentett panelelrendezés érvénytelen; előbb állítsd vissza a munkaterületet
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3804,6 +3804,8 @@ axis Both Entrambi
|
||||
@msg recovery copy `{file}`: {e} copia di recupero `{file}`: {e}
|
||||
@msg resolutions must be between 1 and 2400 ppi le risoluzioni devono essere comprese tra 1 e 2400 ppi
|
||||
@msg result would exceed the canvas (coordinates out of range) il risultato supererebbe l'area di disegno (coordinate fuori intervallo)
|
||||
@msg objects can't be nested more than 32 deep gli oggetti non possono essere nidificati oltre 32 livelli
|
||||
@msg the SVG's elements are nested more than {0} deep gli elementi dell'SVG sono nidificati oltre {0} livelli
|
||||
@msg scale must be a number from {_1} to {_2}, not {_3} la scala deve essere un numero da {_1} a {_2}, non {_3}
|
||||
@msg scale must be a number from {_1} to {_2}, not {s} la scala deve essere un numero da {_1} a {_2}, non {s}
|
||||
@msg select (or target) objects whose appearance isn't basic seleziona (o imposta come destinazione) oggetti con un aspetto non di base
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3730,6 +3730,8 @@ theme Appearance 外観
|
||||
@msg no interaction in progress 進行中の操作がありません
|
||||
@msg no such object {0} オブジェクト {0} が見つかりません
|
||||
@msg result would exceed the canvas (coordinates out of range) 結果がカンバスの範囲を超えます (座標が範囲外です)
|
||||
@msg objects can't be nested more than 32 deep オブジェクトは 32 階層より深く入れ子にできません
|
||||
@msg the SVG's elements are nested more than {0} deep SVG の要素が {0} 階層より深く入れ子になっています
|
||||
@msg unknown command `{0}` `{0}` は不明なコマンドです
|
||||
@msg `{what}` closes nothing `{what}` に対応する開始部分がありません
|
||||
@msg `{what}` closes something it didn't open `{what}` が対応しない開始部分を閉じています
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3708,6 +3708,8 @@ theme Appearance 외관
|
||||
@msg no interaction in progress 진행 중인 상호작용이 없습니다
|
||||
@msg no such object {0} 개체 {0}이(가) 없습니다
|
||||
@msg result would exceed the canvas (coordinates out of range) 결과가 캔버스를 벗어납니다(좌표 범위 초과)
|
||||
@msg objects can't be nested more than 32 deep 개체는 32단계보다 깊게 중첩할 수 없습니다
|
||||
@msg the SVG's elements are nested more than {0} deep SVG 요소가 {0}단계보다 깊게 중첩되어 있습니다
|
||||
@msg unknown command `{0}` 알 수 없는 명령 `{0}`
|
||||
@msg `{what}` closes nothing `{what}`이(가) 닫는 항목이 없습니다
|
||||
@msg `{what}` closes something it didn't open `{what}`이(가) 열지 않은 항목을 닫습니다
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3965,6 +3965,8 @@ imageTrace Outline Kontur
|
||||
@msg recovery copy `{file}`: {e} kopia odzyskiwania `{file}`: {e}
|
||||
@msg resolutions must be between 1 and 2400 ppi rozdzielczości muszą mieścić się w zakresie od 1 do 2400 ppi
|
||||
@msg result would exceed the canvas (coordinates out of range) wynik wykroczyłby poza płótno (współrzędne poza zakresem)
|
||||
@msg objects can't be nested more than 32 deep obiektów nie można zagnieżdżać głębiej niż na 32 poziomy
|
||||
@msg the SVG's elements are nested more than {0} deep elementy SVG są zagnieżdżone głębiej niż na {0} poziomów
|
||||
@msg scale must be a number from {_1} to {_2}, not {_3} skala musi być liczbą od {_1} do {_2}, nie {_3}
|
||||
@msg scale must be a number from {_1} to {_2}, not {s} skala musi być liczbą od {_1} do {_2}, nie {s}
|
||||
@msg select (or target) objects whose appearance isn't basic zaznacz (lub wskaż) obiekty, których wygląd nie jest podstawowy
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3449,6 +3449,8 @@ axis Both Ambos
|
||||
@msg recovery copy `{file}`: {e} cópia de recuperação `{file}`: {e}
|
||||
@msg resolutions must be between 1 and 2400 ppi as resoluções devem estar entre 1 e 2400 ppi
|
||||
@msg result would exceed the canvas (coordinates out of range) o resultado excederia a tela (coordenadas fora do intervalo)
|
||||
@msg objects can't be nested more than 32 deep os objetos não podem ser aninhados em mais de 32 níveis
|
||||
@msg the SVG's elements are nested more than {0} deep os elementos do SVG estão aninhados em mais de {0} níveis
|
||||
@msg scale must be a number from {_1} to {_2}, not {_3} a escala deve ser um número de {_1} a {_2}, não {_3}
|
||||
@msg scale must be a number from {_1} to {_2}, not {s} a escala deve ser um número de {_1} a {_2}, não {s}
|
||||
@msg select (or target) objects whose appearance isn't basic selecione (ou direcione) objetos cuja aparência não seja básica
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3800,6 +3800,8 @@ axis Both Оба
|
||||
@msg recovery copy `{file}`: {e} копия восстановления `{file}`: {e}
|
||||
@msg resolutions must be between 1 and 2400 ppi разрешения должны быть от 1 до 2400 ppi
|
||||
@msg result would exceed the canvas (coordinates out of range) результат превысил бы холст (координаты вне диапазона)
|
||||
@msg objects can't be nested more than 32 deep объекты нельзя вкладывать глубже 32 уровней
|
||||
@msg the SVG's elements are nested more than {0} deep элементы SVG вложены глубже {0} уровней
|
||||
@msg scale must be a number from {_1} to {_2}, not {_3} масштаб должен быть числом от {_1} до {_2}, а не {_3}
|
||||
@msg scale must be a number from {_1} to {_2}, not {s} масштаб должен быть числом от {_1} до {_2}, а не {s}
|
||||
@msg select (or target) objects whose appearance isn't basic выделите (или укажите как объект) объекты, оформление которых не является основным
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3788,6 +3788,8 @@ axis Both Обидві
|
||||
@msg recovery copy `{file}`: {e} копія відновлення `{file}`: {e}
|
||||
@msg resolutions must be between 1 and 2400 ppi дозволи мають бути від 1 до 2400 ppi
|
||||
@msg result would exceed the canvas (coordinates out of range) результат перевищив би полотно (координати поза діапазоном)
|
||||
@msg objects can't be nested more than 32 deep об’єкти не можна вкладати глибше ніж на 32 рівні
|
||||
@msg the SVG's elements are nested more than {0} deep елементи SVG вкладено глибше ніж на {0} рівнів
|
||||
@msg scale must be a number from {_1} to {_2}, not {_3} масштаб має бути числом від {_1} до {_2}, а не {_3}
|
||||
@msg scale must be a number from {_1} to {_2}, not {s} масштаб має бути числом від {_1} до {_2}, а не {s}
|
||||
@msg select (or target) objects whose appearance isn't basic виділіть (або вкажіть як об’єкт) об’єкти, оформлення яких не є основним
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 713 and column 40.
|
@@ -4071,6 +4071,8 @@ theme Appearance Giao diện
|
||||
@msg resolutions must be between 1 and 2400 ppi độ phân giải phải nằm trong khoảng 1 đến 2400 ppi
|
||||
@msg Restored {_1} recovered document(s): save them to keep them Đã phục hồi {_1} tài liệu: hãy lưu để giữ lại
|
||||
@msg result would exceed the canvas (coordinates out of range) kết quả sẽ vượt quá vùng vẽ (tọa độ ngoài phạm vi)
|
||||
@msg objects can't be nested more than 32 deep không thể lồng các đối tượng sâu quá 32 cấp
|
||||
@msg the SVG's elements are nested more than {0} deep các phần tử SVG lồng nhau sâu quá {0} cấp
|
||||
@msg Save for Web: the image is empty Lưu cho Web: ảnh trống
|
||||
@msg Save writes {_1}, not {_2}: use document.export for other formats Lưu ghi {_1}, không phải {_2}: dùng document.export cho các định dạng khác
|
||||
@msg saved panel layout is invalid; reset the workspace first bố cục bảng đã lưu không hợp lệ; hãy đặt lại không gian làm việc trước
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 3642 and column 10.
|
+249
-289
@@ -1,6 +1,6 @@
|
||||
# Image Trace quality
|
||||
|
||||
> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-14 · **Change:** minor (Gradients: radial gradients)
|
||||
> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-14 · **Change:** minor (Gradients: grown over noise and soft rims)
|
||||
|
||||
What Image Trace (`crates/trace`) makes of images whose right answer is known, measured by a harness and
|
||||
compared with the numbers before each change. Nothing here is a judgement by eye, and nothing is compared
|
||||
@@ -28,7 +28,6 @@ anti-aliasing):
|
||||
| plain shapes | a circle, a rectangle, a square, a rounded rectangle, an ellipse and a hexagon, each alone on white (measured from the Shapes change on, not at the baseline) |
|
||||
| linear gradients | a two-stop gradient over the whole image at 25 degrees, and a three-stop gradient at 110 degrees in a disc on white: their lines and stops are known (measured from the Gradients change on, not at the baseline) |
|
||||
| flat colour art | a disc of two halves in different colours that touch; a badge of four colours on white |
|
||||
| radial gradient | pale yellow at a point going out to deep blue 200 units away, over the whole image: its middle and stops are known (measured from the radial-gradients change on, not before) |
|
||||
| gradient, photo | a smooth two-way gradient with a glow; a photo-like image (soft-edged shaded objects, texture, sensor noise) |
|
||||
|
||||
The letters are drawn by hand from lines and curves: the repository has no font to set them in.
|
||||
@@ -54,8 +53,8 @@ The letters are drawn by hand from lines and curves: the repository has no font
|
||||
| shapes % | with Shapes on, the share of the plain shapes that came out as that shape (a shape, not a path, whose outline lies within 0.6 px of the true one) |
|
||||
| false shapes | with Shapes on, paths made a shape whose outline strays more than 0.6 px from the art (a shape the art does not have, or one put where it is not) |
|
||||
| grouped % | with Auto Grouping on, the share of the paths that were put inside another (the picture is painted as the app groups it for every other measure of that row: each path together with those inside it, in the order they were traced in; a ΔE equal to the row without the option says grouping changed nothing that shows) |
|
||||
| gradient paths | paths filled with a gradient, linear or radial (on inputs that are flat colour, every one would be a gradient that is not there) |
|
||||
| found %, angle off, ramp off | on the linear- and radial-gradient inputs: the share of them in which a gradient of that kind was found; and for those found, the largest angle (degrees) between the true gradient line and the traced one (linear ones), and the largest difference (levels of a channel, 0 to 255) between the true colours and the traced gradient's at 17 points along the true line |
|
||||
| gradient paths | paths filled with a linear gradient (on inputs that are flat colour, every one would be a gradient that is not there) |
|
||||
| found %, angle off, ramp off | on the linear-gradient inputs: the share of them in which a gradient was found; and for those found, the largest angle (degrees) between the true gradient line and the traced one, and the largest difference (levels of a channel, 0 to 255) between the true colours and the traced gradient's at 17 points along the true line |
|
||||
| outside px | how far the trace reaches outside the image: a curve that strays |
|
||||
|
||||
Rows named "…, enhanced" are that preset's enhanced version (Auto Grouping on; Shapes on in all but High
|
||||
@@ -89,7 +88,7 @@ Each preset on the inputs it is meant for, all sizes and variants.
|
||||
| Technical Drawing | polygons, star, letter A, lines, askew shapes and lines | 2.73 | 13.67 | 0.210 | 1.43 | 105.76 | 4.7 | 31 | 2.01 | 100 | 9 | 85 | 5.9 | – | – | – | – | 0.1 | 0.0 | – | – | – |
|
||||
| Flat Logo | two touching halves, four-colour badge | 0.43 | 3.53 | 3.106 | 88.50 | 0.78 | 69.9 | 352 | 38.92 | 38 | 10 | 80 | 237.0 | 0.0 | 0 | 13.8 | – | 59.1 | 0.2 | – | – | – |
|
||||
|
||||
### Now (with radial gradients)
|
||||
### Now (with gradients grown over noise and soft rims)
|
||||
|
||||
| preset | inputs | ΔE | edge ΔE | off mean | off max | missed max | paths | anchors | × art | lines % | upright % | corners % | kinks | odd colours | odd px | gap px | overlap px | specks | outside px | centre off | width off | anchors a stroke | shapes % | false shapes | grouped % | gradient paths | found % | angle off | ramp off |
|
||||
|:--|:--|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
||||
@@ -113,10 +112,10 @@ Each preset on the inputs it is meant for, all sizes and variants.
|
||||
| 6 Colors with Auto Grouping | two touching halves, four-colour badge | 0.55 | 4.99 | 0.140 | 1.34 | 1.19 | 4.0 | 49 | 3.07 | 39 | 16 | 91 | 6.1 | 0.0 | 0 | 0.3 | 0.3 | 0.0 | 0.0 | – | – | – | – | 0.00 | 27 | 0.0 | – | – | – |
|
||||
| Shades of Gray with Auto Grouping | gradient, photo-like | 9.26 | 9.06 | – | – | – | 16.6 | 700 | – | 51 | 40 | – | – | – | – | 0.0 | – | 0.5 | 0.0 | – | – | – | – | – | 47 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo with Auto Grouping | gradient, photo-like | 1.75 | 1.98 | – | – | – | 120.7 | 9929 | – | 38 | 36 | – | – | – | – | 0.0 | – | 10.1 | 0.0 | – | – | – | – | – | 69 | 0.0 | – | – | – |
|
||||
| 6 Colors, no Gradients | two-stop gradient, three-stop gradient in a disc, radial gradient | 2.29 | 2.90 | – | – | – | 7.0 | 480 | – | 20 | 15 | – | – | – | – | 4.7 | 11.6 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors with Gradients | two-stop gradient, three-stop gradient in a disc, radial gradient | 0.59 | 1.06 | – | – | – | 0.9 | 41 | – | 7 | 7 | – | – | – | – | 1.1 | 0.8 | 0.0 | 0.0 | – | – | – | – | – | – | 0.9 | 90 | 1.5 | 28 |
|
||||
| High Fidelity Photo, no Gradients | two-stop gradient, three-stop gradient in a disc, radial gradient | 0.85 | 2.31 | – | – | – | 31.4 | 2747 | – | 38 | 37 | – | – | – | – | 0.0 | – | 1.4 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo with Gradients | two-stop gradient, three-stop gradient in a disc, radial gradient | 0.48 | 1.03 | – | – | – | 5.8 | 365 | – | 14 | 8 | – | – | – | – | 0.0 | – | 0.5 | 0.0 | – | – | – | – | – | – | 0.9 | 90 | 1.5 | 28 |
|
||||
| 6 Colors, no Gradients | two-stop gradient, three-stop gradient in a disc | 2.12 | 3.04 | – | – | – | 6.4 | 469 | – | 21 | 14 | – | – | – | – | 3.9 | 12.7 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors with Gradients | two-stop gradient, three-stop gradient in a disc | 0.62 | 1.34 | – | – | – | 1.2 | 60 | – | 0 | 0 | – | – | – | – | 1.6 | 1.2 | 0.0 | 0.0 | – | – | – | – | – | – | 0.9 | 86 | 1.5 | 21 |
|
||||
| High Fidelity Photo, no Gradients | two-stop gradient, three-stop gradient in a disc | 0.79 | 2.98 | – | – | – | 38.1 | 3827 | – | 31 | 30 | – | – | – | – | 0.0 | – | 1.1 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo with Gradients | two-stop gradient, three-stop gradient in a disc | 0.46 | 1.29 | – | – | – | 8.2 | 545 | – | 1 | 0 | – | – | – | – | 0.0 | – | 0.8 | 0.0 | – | – | – | – | – | – | 0.9 | 86 | 1.5 | 21 |
|
||||
| Default, enhanced | circle, ellipses, badge with a hole, letter D, polygons, star, letter A | 2.60 | 9.88 | 0.083 | 1.00 | 2.18 | 1.9 | 16 | 1.59 | 36 | 6 | 83 | 0.4 | – | – | 0.3 | 0.5 | 0.0 | 0.0 | – | – | – | – | 0.02 | 14 | 0.0 | – | – | – |
|
||||
| Auto Color, enhanced | two touching halves, four-colour badge | 0.55 | 5.00 | 0.139 | 1.33 | 1.00 | 4.0 | 48 | 3.03 | 41 | 16 | 100 | 6.0 | 0.0 | 0 | 1.3 | 1.1 | 0.0 | 0.0 | – | – | – | – | 0.00 | 27 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo, enhanced | gradient, photo-like | 1.75 | 1.98 | – | – | – | 120.7 | 9929 | – | 38 | 36 | – | – | – | – | 0.0 | – | 10.1 | 0.0 | – | – | – | – | – | 69 | 0.0 | – | – | – |
|
||||
@@ -132,7 +131,7 @@ Each preset on the inputs it is meant for, all sizes and variants.
|
||||
| Technical Drawing, enhanced | polygons, star, letter A, lines, askew shapes and lines | 2.65 | 10.93 | 0.128 | 1.46 | 105.64 | 4.7 | 34 | 2.26 | 86 | 19 | 86 | 0.8 | – | – | – | – | 0.5 | 0.0 | – | – | – | – | 0.09 | 0 | 0.0 | – | – | – |
|
||||
| Outline, enhanced | lines | 2.61 | 9.39 | 0.050 | 0.88 | 105.74 | 5.0 | 10 | 0.52 | 99 | 4 | – | – | – | – | – | – | 0.0 | 0.0 | 0.039 | 0.02 | 2.0 | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
|
||||
The sections below are the numbers now (with radial gradients).
|
||||
The sections below are the numbers now (with gradients grown over noise and soft rims).
|
||||
|
||||
## 1. Each preset on the inputs it is meant for
|
||||
|
||||
@@ -160,10 +159,10 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| 6 Colors with Auto Grouping | two touching halves, four-colour badge | 0.55 | 4.99 | 0.140 | 1.34 | 1.19 | 4.0 | 49 | 3.07 | 39 | 16 | 91 | 6.1 | 0.0 | 0 | 0.3 | 0.3 | 0.0 | 0.0 | – | – | – | – | 0.00 | 27 | 0.0 | – | – | – |
|
||||
| Shades of Gray with Auto Grouping | gradient, photo-like | 9.26 | 9.06 | – | – | – | 16.6 | 700 | – | 51 | 40 | – | – | – | – | 0.0 | – | 0.5 | 0.0 | – | – | – | – | – | 47 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo with Auto Grouping | gradient, photo-like | 1.75 | 1.98 | – | – | – | 120.7 | 9929 | – | 38 | 36 | – | – | – | – | 0.0 | – | 10.1 | 0.0 | – | – | – | – | – | 69 | 0.0 | – | – | – |
|
||||
| 6 Colors, no Gradients | two-stop gradient, three-stop gradient in a disc, radial gradient | 2.29 | 2.90 | – | – | – | 7.0 | 480 | – | 20 | 15 | – | – | – | – | 4.7 | 11.6 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors with Gradients | two-stop gradient, three-stop gradient in a disc, radial gradient | 0.59 | 1.06 | – | – | – | 0.9 | 41 | – | 7 | 7 | – | – | – | – | 1.1 | 0.8 | 0.0 | 0.0 | – | – | – | – | – | – | 0.9 | 90 | 1.5 | 28 |
|
||||
| High Fidelity Photo, no Gradients | two-stop gradient, three-stop gradient in a disc, radial gradient | 0.85 | 2.31 | – | – | – | 31.4 | 2747 | – | 38 | 37 | – | – | – | – | 0.0 | – | 1.4 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo with Gradients | two-stop gradient, three-stop gradient in a disc, radial gradient | 0.48 | 1.03 | – | – | – | 5.8 | 365 | – | 14 | 8 | – | – | – | – | 0.0 | – | 0.5 | 0.0 | – | – | – | – | – | – | 0.9 | 90 | 1.5 | 28 |
|
||||
| 6 Colors, no Gradients | two-stop gradient, three-stop gradient in a disc | 2.12 | 3.04 | – | – | – | 6.4 | 469 | – | 21 | 14 | – | – | – | – | 3.9 | 12.7 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors with Gradients | two-stop gradient, three-stop gradient in a disc | 0.62 | 1.34 | – | – | – | 1.2 | 60 | – | 0 | 0 | – | – | – | – | 1.6 | 1.2 | 0.0 | 0.0 | – | – | – | – | – | – | 0.9 | 86 | 1.5 | 21 |
|
||||
| High Fidelity Photo, no Gradients | two-stop gradient, three-stop gradient in a disc | 0.79 | 2.98 | – | – | – | 38.1 | 3827 | – | 31 | 30 | – | – | – | – | 0.0 | – | 1.1 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo with Gradients | two-stop gradient, three-stop gradient in a disc | 0.46 | 1.29 | – | – | – | 8.2 | 545 | – | 1 | 0 | – | – | – | – | 0.0 | – | 0.8 | 0.0 | – | – | – | – | – | – | 0.9 | 86 | 1.5 | 21 |
|
||||
| Default, enhanced | circle, ellipses, badge with a hole, letter D, polygons, star, letter A | 2.60 | 9.88 | 0.083 | 1.00 | 2.18 | 1.9 | 16 | 1.59 | 36 | 6 | 83 | 0.4 | – | – | 0.3 | 0.5 | 0.0 | 0.0 | – | – | – | – | 0.02 | 14 | 0.0 | – | – | – |
|
||||
| Auto Color, enhanced | two touching halves, four-colour badge | 0.55 | 5.00 | 0.139 | 1.33 | 1.00 | 4.0 | 48 | 3.03 | 41 | 16 | 100 | 6.0 | 0.0 | 0 | 1.3 | 1.1 | 0.0 | 0.0 | – | – | – | – | 0.00 | 27 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo, enhanced | gradient, photo-like | 1.75 | 1.98 | – | – | – | 120.7 | 9929 | – | 38 | 36 | – | – | – | – | 0.0 | – | 10.1 | 0.0 | – | – | – | – | – | 69 | 0.0 | – | – | – |
|
||||
@@ -191,7 +190,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Default | flat colour art | 19.91 | 17.97 | 0.172 | 0.51 | 179.34 | 1.5 | 16 | 1.17 | 14 | 14 | 0 | 0.0 | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Default | gradient, photo | 39.03 | 38.64 | – | – | – | 3.2 | 595 | – | 55 | 41 | – | – | – | – | 18.8 | 35.5 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| Default | linear gradients | 25.64 | 29.86 | – | – | – | 2.0 | 43 | – | 33 | 32 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Default | radial gradient | 37.68 | 37.79 | – | – | – | 2.0 | 19 | – | 32 | 32 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Auto Color | curved shapes | 0.06 | 2.43 | 0.043 | 0.27 | 0.28 | 1.8 | 16 | 1.77 | 16 | 16 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Auto Color | polygons | 0.06 | 2.42 | 0.041 | 0.42 | 1.39 | 2.0 | 16 | 1.43 | 87 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Auto Color | thin lines | 0.70 | 5.57 | 0.066 | 0.50 | 105.72 | 5.0 | 38 | 1.88 | 43 | 3 | – | – | 4.0 | 3225 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -200,7 +198,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Auto Color | flat colour art | 0.13 | 2.72 | 0.057 | 0.31 | 0.30 | 3.0 | 28 | 2.00 | 43 | 19 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Auto Color | gradient, photo | 2.07 | 2.39 | – | – | – | 159.3 | 4441 | – | 21 | 8 | – | – | – | – | 37.6 | 46.7 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| Auto Color | linear gradients | 1.02 | 1.74 | – | – | – | 15.7 | 1272 | – | 12 | 8 | – | – | – | – | 9.1 | 7.4 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Auto Color | radial gradient | 1.53 | 1.53 | – | – | – | 19.3 | 1917 | – | 10 | 10 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo | curved shapes | 0.04 | 1.63 | 0.026 | 0.15 | 0.15 | 1.2 | 19 | 2.11 | 21 | 21 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| High Fidelity Photo | polygons | 0.06 | 2.33 | 0.039 | 0.50 | 1.32 | 1.7 | 17 | 1.47 | 88 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| High Fidelity Photo | thin lines | 0.35 | 6.05 | 0.085 | 0.90 | 4.35 | 40.3 | 348 | 17.42 | 35 | 9 | – | – | 27.3 | 4505 | 0.0 | – | 19.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -209,7 +206,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| High Fidelity Photo | flat colour art | 0.14 | 4.16 | 0.029 | 0.20 | 0.20 | 3.5 | 73 | 4.59 | 35 | 34 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| High Fidelity Photo | gradient, photo | 1.80 | 2.05 | – | – | – | 134.7 | 11212 | – | 39 | 37 | – | – | – | – | 0.0 | – | 7.3 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| High Fidelity Photo | linear gradients | 0.64 | 3.29 | – | – | – | 34.5 | 4318 | – | 32 | 31 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo | radial gradient | 0.80 | 0.80 | – | – | – | 14.7 | 245 | – | 58 | 57 | – | – | – | – | 0.0 | – | 0.3 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Low Fidelity Photo | curved shapes | 0.07 | 2.74 | 0.048 | 0.31 | 0.31 | 1.2 | 13 | 1.44 | 18 | 18 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Low Fidelity Photo | polygons | 0.06 | 2.49 | 0.042 | 0.42 | 1.39 | 1.7 | 14 | 1.28 | 86 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Low Fidelity Photo | thin lines | 0.49 | 5.70 | 0.082 | 0.70 | 45.31 | 7.0 | 56 | 2.80 | 49 | 11 | – | – | 4.0 | 3985 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -218,7 +214,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Low Fidelity Photo | flat colour art | 0.15 | 4.25 | 0.044 | 0.28 | 0.28 | 3.5 | 54 | 3.38 | 31 | 29 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Low Fidelity Photo | gradient, photo | 2.53 | 2.80 | – | – | – | 42.7 | 2307 | – | 43 | 37 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| Low Fidelity Photo | linear gradients | 0.69 | 3.09 | – | – | – | 24.3 | 1061 | – | 31 | 31 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Low Fidelity Photo | radial gradient | 0.74 | 0.74 | – | – | – | 12.3 | 241 | – | 57 | 57 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 3 Colors | curved shapes | 0.07 | 2.74 | 0.048 | 0.31 | 0.31 | 1.8 | 16 | 1.67 | 15 | 15 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 3 Colors | polygons | 0.06 | 2.49 | 0.042 | 0.42 | 1.39 | 2.0 | 16 | 1.42 | 86 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 3 Colors | thin lines | 0.43 | 4.48 | 0.117 | 1.04 | 45.31 | 5.0 | 43 | 2.13 | 54 | 13 | – | – | 2.0 | 308 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -227,7 +222,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| 3 Colors | flat colour art | 1.31 | 3.61 | 0.125 | 0.90 | 60.25 | 2.5 | 25 | 1.86 | 45 | 21 | 100 | 0.0 | 1.0 | 9914 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 3 Colors | gradient, photo | 7.49 | 7.60 | – | – | – | 5.7 | 524 | – | 48 | 40 | – | – | – | – | 6.9 | 8.7 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| 3 Colors | linear gradients | 4.45 | 5.79 | – | – | – | 3.0 | 78 | – | 28 | 24 | – | – | – | – | 10.3 | 1.9 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 3 Colors | radial gradient | 4.57 | 4.48 | – | – | – | 3.0 | 81 | – | 20 | 19 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors | curved shapes | 0.06 | 2.43 | 0.043 | 0.27 | 0.28 | 1.8 | 16 | 1.77 | 16 | 16 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors | polygons | 0.06 | 2.40 | 0.041 | 0.42 | 1.39 | 2.0 | 16 | 1.45 | 86 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors | thin lines | 0.49 | 4.76 | 0.108 | 0.70 | 45.31 | 4.0 | 30 | 1.50 | 63 | 19 | – | – | 1.7 | 413 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -236,7 +230,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| 6 Colors | flat colour art | 0.13 | 2.72 | 0.057 | 0.31 | 0.30 | 3.0 | 28 | 2.00 | 43 | 19 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors | gradient, photo | 5.00 | 5.28 | – | – | – | 13.0 | 829 | – | 37 | 28 | – | – | – | – | 6.9 | 8.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| 6 Colors | linear gradients | 2.07 | 3.07 | – | – | – | 6.2 | 266 | – | 20 | 14 | – | – | – | – | 2.4 | 9.3 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors | radial gradient | 2.69 | 2.67 | – | – | – | 8.0 | 240 | – | 17 | 17 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 16 Colors | curved shapes | 0.05 | 2.21 | 0.038 | 0.24 | 0.25 | 1.8 | 17 | 1.83 | 16 | 16 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 16 Colors | polygons | 0.06 | 2.34 | 0.039 | 0.42 | 1.39 | 2.0 | 16 | 1.48 | 86 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 16 Colors | thin lines | 0.39 | 3.90 | 0.113 | 0.70 | 23.53 | 8.7 | 52 | 2.58 | 56 | 17 | – | – | 5.7 | 322 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -245,7 +238,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| 16 Colors | flat colour art | 0.12 | 2.53 | 0.051 | 0.31 | 0.30 | 3.0 | 28 | 2.11 | 43 | 19 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 16 Colors | gradient, photo | 3.00 | 3.30 | – | – | – | 47.2 | 2126 | – | 30 | 16 | – | – | – | – | 15.2 | 19.6 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| 16 Colors | linear gradients | 0.98 | 1.67 | – | – | – | 15.8 | 1340 | – | 8 | 6 | – | – | – | – | 13.9 | 15.5 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 16 Colors | radial gradient | 1.47 | 1.47 | – | – | – | 23.0 | 2876 | – | 8 | 8 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Shades of Gray | curved shapes | 0.07 | 2.70 | 0.047 | 0.31 | 0.31 | 1.2 | 13 | 1.45 | 18 | 18 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Shades of Gray | polygons | 0.06 | 2.28 | 0.039 | 0.41 | 1.26 | 1.7 | 13 | 1.18 | 89 | 5 | 95 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Shades of Gray | thin lines | 0.56 | 7.08 | 0.088 | 0.68 | 45.31 | 10.3 | 73 | 3.65 | 55 | 11 | – | – | 8.0 | 4319 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -254,7 +246,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Shades of Gray | flat colour art | 7.33 | 11.24 | 0.257 | 1.47 | 179.39 | 4.7 | 199 | 18.39 | 22 | 22 | 50 | 0.3 | 3.7 | 173367 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Shades of Gray | gradient, photo | 9.71 | 9.55 | – | – | – | 18.3 | 753 | – | 51 | 41 | – | – | – | – | 0.0 | – | 0.5 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| Shades of Gray | linear gradients | 5.25 | 8.40 | – | – | – | 9.0 | 477 | – | 31 | 31 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Shades of Gray | radial gradient | 5.24 | 5.13 | – | – | – | 4.0 | 19 | – | 60 | 58 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Black and White Logo | curved shapes | 0.03 | 1.48 | 0.024 | 0.16 | 0.16 | 1.2 | 20 | 2.12 | 21 | 21 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Black and White Logo | polygons | 0.06 | 2.36 | 0.040 | 0.47 | 1.26 | 1.7 | 14 | 1.24 | 93 | 8 | 95 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Black and White Logo | thin lines | 0.59 | 6.00 | 0.105 | 0.50 | 77.21 | 10.3 | 44 | 2.18 | 90 | 10 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -263,7 +254,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Black and White Logo | flat colour art | 19.90 | 17.76 | 0.157 | 0.30 | 179.51 | 1.0 | 18 | 1.12 | 23 | 23 | 0 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Black and White Logo | gradient, photo | 38.97 | 38.53 | – | – | – | 9.0 | 634 | – | 73 | 54 | – | – | – | – | – | – | 1.2 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| Black and White Logo | linear gradients | 25.62 | 29.78 | – | – | – | 1.5 | 127 | – | 46 | 33 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Black and White Logo | radial gradient | 37.66 | 37.78 | – | – | – | 1.0 | 12 | – | 58 | 58 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Sketched Art | curved shapes | 0.14 | 5.71 | 0.110 | 0.46 | 0.46 | 1.2 | 12 | 1.37 | 16 | 16 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Sketched Art | polygons | 0.12 | 4.71 | 0.085 | 0.37 | 1.08 | 1.7 | 13 | 1.16 | 86 | 5 | 93 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Sketched Art | thin lines | 0.47 | 5.70 | 0.113 | 0.96 | 52.59 | 4.3 | 29 | 1.45 | 64 | 3 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -272,7 +262,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Sketched Art | flat colour art | 20.25 | 19.55 | 0.146 | 1.15 | 179.63 | 1.5 | 26 | 1.53 | 16 | 16 | 0 | 0.3 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Sketched Art | gradient, photo | 45.42 | 45.21 | – | – | – | 1.0 | 244 | – | 46 | 35 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| Sketched Art | linear gradients | 29.20 | 33.47 | – | – | – | 1.5 | 54 | – | 35 | 34 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Sketched Art | radial gradient | 43.27 | 43.47 | – | – | – | 0.0 | 0 | – | – | – | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Silhouettes | curved shapes | 0.35 | 14.53 | 0.281 | 0.69 | 0.69 | 1.2 | 12 | 1.33 | 16 | 16 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Silhouettes | polygons | 0.34 | 13.44 | 0.251 | 0.64 | 1.67 | 1.7 | 14 | 1.28 | 74 | 6 | 86 | 0.1 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Silhouettes | thin lines | 0.99 | 13.74 | 0.266 | 0.77 | 18.26 | 5.0 | 30 | 1.50 | 67 | 12 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -281,7 +270,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Silhouettes | flat colour art | 23.83 | 33.06 | 0.200 | 0.69 | 188.27 | 1.0 | 11 | 0.77 | 25 | 25 | 0 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Silhouettes | gradient, photo | 61.57 | 61.32 | – | – | – | 0.2 | 2 | – | 47 | 21 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| Silhouettes | linear gradients | 39.85 | 46.48 | – | – | – | 1.0 | 37 | – | 1 | 0 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Silhouettes | radial gradient | 58.74 | 58.99 | – | – | – | 0.0 | 0 | – | – | – | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Line Art | curved shapes | 0.04 | 1.83 | 0.031 | 0.22 | 0.22 | 1.2 | 16 | 1.70 | 20 | 20 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Line Art | polygons | 0.05 | 2.11 | 0.036 | 0.47 | 1.26 | 1.7 | 14 | 1.26 | 89 | 5 | 95 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Line Art | thin lines | 0.52 | 4.09 | 0.040 | 0.47 | 105.72 | 3.3 | 29 | 1.45 | 40 | 0 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -290,7 +278,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Line Art | flat colour art | 19.90 | 17.83 | 0.162 | 0.42 | 179.43 | 1.0 | 18 | 1.30 | 21 | 21 | 0 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Line Art | gradient, photo | 38.98 | 38.54 | – | – | – | 7.7 | 472 | – | 58 | 44 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| Line Art | linear gradients | 25.63 | 29.80 | – | – | – | 1.5 | 95 | – | 33 | 32 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Line Art | radial gradient | 37.67 | 37.78 | – | – | – | 1.0 | 8 | – | 57 | 57 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Technical Drawing | curved shapes | 0.03 | 1.48 | 0.024 | 0.16 | 0.16 | 1.2 | 20 | 2.12 | 21 | 21 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Technical Drawing | polygons | 0.06 | 2.36 | 0.040 | 0.47 | 1.26 | 1.7 | 14 | 1.23 | 94 | 8 | 95 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Technical Drawing | thin lines | 0.50 | 5.46 | 0.109 | 0.50 | 55.93 | 15.3 | 62 | 3.12 | 86 | 14 | – | – | – | – | – | – | 3.3 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -299,7 +286,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Technical Drawing | flat colour art | 19.90 | 17.76 | 0.157 | 0.30 | 179.51 | 1.0 | 18 | 1.12 | 23 | 23 | 0 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Technical Drawing | gradient, photo | 38.94 | 38.51 | – | – | – | 20.0 | 659 | – | 73 | 51 | – | – | – | – | – | – | 11.7 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| Technical Drawing | linear gradients | 25.62 | 29.80 | – | – | – | 1.5 | 118 | – | 49 | 33 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Technical Drawing | radial gradient | 37.66 | 37.78 | – | – | – | 1.0 | 12 | – | 58 | 58 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Outline | curved shapes | 23.38 | 44.76 | 0.499 | 0.71 | 0.52 | 1.2 | 16 | 1.70 | 20 | 20 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Outline | polygons | 17.94 | 44.26 | 0.494 | 0.94 | 0.76 | 1.7 | 14 | 1.26 | 89 | 5 | 95 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Outline | thin lines | 0.51 | 3.57 | 0.028 | 0.41 | 105.74 | 3.3 | 7 | 0.33 | 100 | 7 | – | – | – | – | – | – | 0.0 | 0.0 | 0.020 | 0.02 | 2.0 | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -308,7 +294,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Outline | flat colour art | 26.69 | 32.18 | 0.494 | 0.92 | 178.93 | 1.0 | 18 | 1.30 | 21 | 21 | 0 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Outline | gradient, photo | 39.38 | 39.18 | – | – | – | 7.5 | 445 | – | 59 | 43 | – | – | – | – | – | – | 3.3 | 0.5 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| Outline | linear gradients | 25.08 | 30.80 | – | – | – | 1.5 | 92 | – | 33 | 32 | – | – | – | – | – | – | 0.0 | 0.5 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Outline | radial gradient | 36.88 | 36.89 | – | – | – | 1.0 | 8 | – | 57 | 57 | – | – | – | – | – | – | 0.0 | 0.5 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Flat Logo | curved shapes | 0.06 | 2.14 | 0.036 | 0.25 | 0.25 | 1.8 | 31 | 3.38 | 19 | 6 | 100 | 0.0 | 0.0 | 0 | 6.8 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Flat Logo | polygons | 0.09 | 3.44 | 0.060 | 0.35 | 1.03 | 2.0 | 35 | 3.17 | 67 | 0 | 94 | 0.0 | 0.0 | 0 | 6.8 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Flat Logo | thin lines | 1.17 | 11.78 | 0.050 | 0.49 | all | 3.0 | 189 | 9.45 | 28 | 9 | – | – | 0.0 | 0 | 5467.1 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -317,7 +302,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Flat Logo | flat colour art | 0.07 | 1.53 | 0.065 | 0.31 | 0.27 | 3.0 | 36 | 3.51 | 47 | 11 | 100 | 0.0 | 0.0 | 0 | 6.8 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Flat Logo | gradient, photo | refused | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
| Flat Logo | linear gradients | 6.49 | 6.47 | – | – | – | 484.0 | 4773 | – | 58 | 0 | – | – | – | – | 146.0 | – | 446.7 | 0.1 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Flat Logo | radial gradient | 7.15 | 7.10 | – | – | – | 963.7 | 5719 | – | 8 | 0 | – | – | – | – | 188.6 | – | 746.0 | 0.6 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| Default with Shapes | curved shapes | 0.08 | 3.21 | 0.056 | 0.38 | 0.38 | 1.8 | 13 | 1.44 | 14 | 14 | 100 | 0.0 | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Default with Shapes | polygons | 0.07 | 2.58 | 0.045 | 0.50 | 1.26 | 2.0 | 13 | 1.16 | 97 | 5 | 100 | 0.0 | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Default with Shapes | thin lines | 0.54 | 4.50 | 0.049 | 0.47 | 105.72 | 3.3 | 25 | 1.27 | 40 | 0 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -326,7 +310,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Default with Shapes | flat colour art | 19.91 | 17.94 | 0.180 | 0.39 | 179.45 | 1.5 | 16 | 1.01 | 14 | 14 | 0 | 0.0 | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Default with Shapes | gradient, photo | 39.03 | 38.64 | – | – | – | 3.2 | 595 | – | 55 | 41 | – | – | – | – | 18.8 | 35.5 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| Default with Shapes | linear gradients | 25.64 | 29.86 | – | – | – | 2.0 | 43 | – | 33 | 32 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | 0 | – | – |
|
||||
| Default with Shapes | radial gradient | 37.68 | 37.79 | – | – | – | 2.0 | 19 | – | 32 | 32 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors with Shapes | curved shapes | 0.05 | 2.25 | 0.039 | 0.27 | 0.28 | 1.8 | 15 | 1.59 | 16 | 16 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors with Shapes | polygons | 0.06 | 2.28 | 0.042 | 0.63 | 1.39 | 2.0 | 14 | 1.27 | 94 | 7 | 99 | 0.0 | 0.0 | 0 | 2.0 | 2.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors with Shapes | thin lines | 0.49 | 4.79 | 0.108 | 0.70 | 45.31 | 4.0 | 30 | 1.50 | 63 | 19 | – | – | 1.7 | 413 | 8.1 | 2.3 | 0.0 | 0.0 | – | – | – | – | 0.33 | – | 0.0 | – | – | – |
|
||||
@@ -335,7 +318,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| 6 Colors with Shapes | flat colour art | 0.13 | 2.72 | 0.057 | 0.31 | 0.30 | 3.0 | 28 | 2.00 | 43 | 19 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors with Shapes | gradient, photo | 5.00 | 5.28 | – | – | – | 13.0 | 828 | – | 37 | 28 | – | – | – | – | 7.5 | 10.6 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors with Shapes | linear gradients | 2.07 | 3.07 | – | – | – | 6.2 | 266 | – | 20 | 14 | – | – | – | – | 2.4 | 9.3 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors with Shapes | radial gradient | 2.69 | 2.67 | – | – | – | 8.0 | 228 | – | 18 | 18 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors with Auto Grouping | curved shapes | 0.06 | 2.43 | 0.043 | 0.27 | 0.28 | 1.8 | 16 | 1.77 | 16 | 16 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 17 | 0.0 | – | – | – |
|
||||
| 6 Colors with Auto Grouping | polygons | 0.06 | 2.40 | 0.041 | 0.42 | 1.39 | 2.0 | 16 | 1.45 | 86 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 11 | 0.0 | – | – | – |
|
||||
| 6 Colors with Auto Grouping | thin lines | 0.49 | 4.76 | 0.108 | 0.70 | 45.31 | 4.0 | 30 | 1.50 | 63 | 19 | – | – | 1.7 | 413 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
@@ -344,7 +326,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| 6 Colors with Auto Grouping | flat colour art | 0.13 | 2.72 | 0.057 | 0.31 | 0.30 | 3.0 | 28 | 2.00 | 43 | 19 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 30 | 0.0 | – | – | – |
|
||||
| 6 Colors with Auto Grouping | gradient, photo | 5.00 | 5.28 | – | – | – | 13.0 | 829 | – | 37 | 28 | – | – | – | – | 6.9 | 8.0 | 0.0 | 0.0 | – | – | – | – | – | 15 | 0.0 | – | – | – |
|
||||
| 6 Colors with Auto Grouping | linear gradients | 2.07 | 3.07 | – | – | – | 6.2 | 266 | – | 20 | 14 | – | – | – | – | 2.4 | 9.3 | 0.0 | 0.0 | – | – | – | – | – | 0 | 0.0 | 0 | – | – |
|
||||
| 6 Colors with Auto Grouping | radial gradient | 2.69 | 2.67 | – | – | – | 8.0 | 240 | – | 17 | 17 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | 33 | 0.0 | 0 | – | – |
|
||||
| Shades of Gray with Auto Grouping | curved shapes | 0.07 | 2.70 | 0.047 | 0.31 | 0.31 | 1.2 | 13 | 1.45 | 18 | 18 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Shades of Gray with Auto Grouping | polygons | 0.06 | 2.28 | 0.039 | 0.41 | 1.26 | 1.7 | 13 | 1.18 | 89 | 5 | 95 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Shades of Gray with Auto Grouping | thin lines | 0.56 | 7.08 | 0.088 | 0.68 | 45.31 | 10.3 | 73 | 3.65 | 55 | 11 | – | – | 8.0 | 4319 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
@@ -353,7 +334,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Shades of Gray with Auto Grouping | flat colour art | 7.33 | 11.24 | 0.257 | 1.47 | 179.39 | 4.7 | 199 | 18.39 | 22 | 22 | 50 | 0.3 | 3.7 | 173367 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 52 | 0.0 | – | – | – |
|
||||
| Shades of Gray with Auto Grouping | gradient, photo | 9.71 | 9.55 | – | – | – | 18.3 | 753 | – | 51 | 41 | – | – | – | – | 0.0 | – | 0.5 | 0.0 | – | – | – | – | – | 53 | 0.0 | – | – | – |
|
||||
| Shades of Gray with Auto Grouping | linear gradients | 5.25 | 8.40 | – | – | – | 9.0 | 477 | – | 31 | 31 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | 68 | 0.0 | 0 | – | – |
|
||||
| Shades of Gray with Auto Grouping | radial gradient | 5.24 | 5.13 | – | – | – | 4.0 | 19 | – | 60 | 58 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | 0 | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo with Auto Grouping | curved shapes | 0.04 | 1.63 | 0.026 | 0.15 | 0.15 | 1.2 | 19 | 2.11 | 21 | 21 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo with Auto Grouping | polygons | 0.06 | 2.33 | 0.039 | 0.50 | 1.32 | 1.7 | 17 | 1.47 | 88 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo with Auto Grouping | thin lines | 0.35 | 6.05 | 0.085 | 0.90 | 4.35 | 40.3 | 348 | 17.42 | 35 | 9 | – | – | 27.3 | 4505 | 0.0 | – | 19.0 | 0.0 | – | – | – | – | 0.00 | 23 | 0.0 | – | – | – |
|
||||
@@ -362,7 +342,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| High Fidelity Photo with Auto Grouping | flat colour art | 0.14 | 4.16 | 0.029 | 0.20 | 0.20 | 3.5 | 73 | 4.59 | 35 | 34 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 25 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo with Auto Grouping | gradient, photo | 1.80 | 2.05 | – | – | – | 134.7 | 11212 | – | 39 | 37 | – | – | – | – | 0.0 | – | 7.3 | 0.0 | – | – | – | – | – | 69 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo with Auto Grouping | linear gradients | 0.64 | 3.29 | – | – | – | 34.5 | 4318 | – | 32 | 31 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | 72 | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo with Auto Grouping | radial gradient | 0.80 | 0.80 | – | – | – | 14.7 | 245 | – | 58 | 57 | – | – | – | – | 0.0 | – | 0.3 | 0.0 | – | – | – | – | – | 27 | 0.0 | 0 | – | – |
|
||||
| 6 Colors, no Gradients | curved shapes | 0.06 | 2.43 | 0.043 | 0.27 | 0.28 | 1.8 | 16 | 1.77 | 16 | 16 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors, no Gradients | polygons | 0.06 | 2.40 | 0.041 | 0.42 | 1.39 | 2.0 | 16 | 1.45 | 86 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors, no Gradients | thin lines | 0.49 | 4.76 | 0.108 | 0.70 | 45.31 | 4.0 | 30 | 1.50 | 63 | 19 | – | – | 1.7 | 413 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -371,7 +350,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| 6 Colors, no Gradients | flat colour art | 0.13 | 2.72 | 0.057 | 0.31 | 0.30 | 3.0 | 28 | 2.00 | 43 | 19 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors, no Gradients | gradient, photo | 5.00 | 5.28 | – | – | – | 13.0 | 829 | – | 37 | 28 | – | – | – | – | 6.9 | 8.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| 6 Colors, no Gradients | linear gradients | 2.07 | 3.07 | – | – | – | 6.2 | 266 | – | 20 | 14 | – | – | – | – | 2.4 | 9.3 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors, no Gradients | radial gradient | 2.69 | 2.67 | – | – | – | 8.0 | 240 | – | 17 | 17 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors with Gradients | curved shapes | 0.06 | 2.43 | 0.043 | 0.27 | 0.28 | 1.8 | 16 | 1.77 | 16 | 16 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors with Gradients | polygons | 0.06 | 2.40 | 0.041 | 0.42 | 1.39 | 2.0 | 16 | 1.45 | 86 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors with Gradients | thin lines | 0.49 | 4.76 | 0.108 | 0.70 | 45.31 | 4.0 | 30 | 1.50 | 63 | 19 | – | – | 1.7 | 413 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -380,7 +358,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| 6 Colors with Gradients | flat colour art | 0.13 | 2.72 | 0.057 | 0.31 | 0.30 | 3.0 | 28 | 2.00 | 43 | 19 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| 6 Colors with Gradients | gradient, photo | 4.49 | 4.84 | – | – | – | 15.0 | 909 | – | 36 | 27 | – | – | – | – | 9.7 | 12.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.7 | – | – | – |
|
||||
| 6 Colors with Gradients | linear gradients | 0.40 | 1.09 | – | – | – | 1.3 | 39 | – | 0 | 0 | – | – | – | – | 0.5 | 1.1 | 0.0 | 0.0 | – | – | – | – | – | – | 0.8 | 83 | 0.2 | 5 |
|
||||
| 6 Colors with Gradients | radial gradient | 0.25 | 0.25 | – | – | – | 0.0 | 0 | – | – | – | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | – | 3 |
|
||||
| High Fidelity Photo, no Gradients | curved shapes | 0.04 | 1.63 | 0.026 | 0.15 | 0.15 | 1.2 | 19 | 2.11 | 21 | 21 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| High Fidelity Photo, no Gradients | polygons | 0.06 | 2.33 | 0.039 | 0.50 | 1.32 | 1.7 | 17 | 1.47 | 88 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| High Fidelity Photo, no Gradients | thin lines | 0.35 | 6.05 | 0.085 | 0.90 | 4.35 | 40.3 | 348 | 17.42 | 35 | 9 | – | – | 27.3 | 4505 | 0.0 | – | 19.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -389,7 +366,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| High Fidelity Photo, no Gradients | flat colour art | 0.14 | 4.16 | 0.029 | 0.20 | 0.20 | 3.5 | 73 | 4.59 | 35 | 34 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| High Fidelity Photo, no Gradients | gradient, photo | 1.80 | 2.05 | – | – | – | 134.7 | 11212 | – | 39 | 37 | – | – | – | – | 0.0 | – | 7.3 | 0.0 | – | – | – | – | – | – | 0.0 | – | – | – |
|
||||
| High Fidelity Photo, no Gradients | linear gradients | 0.64 | 3.29 | – | – | – | 34.5 | 4318 | – | 32 | 31 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo, no Gradients | radial gradient | 0.80 | 0.80 | – | – | – | 14.7 | 245 | – | 58 | 57 | – | – | – | – | 0.0 | – | 0.3 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo with Gradients | curved shapes | 0.04 | 1.63 | 0.026 | 0.15 | 0.15 | 1.2 | 19 | 2.11 | 21 | 21 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| High Fidelity Photo with Gradients | polygons | 0.06 | 2.33 | 0.039 | 0.50 | 1.32 | 1.7 | 17 | 1.47 | 88 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| High Fidelity Photo with Gradients | thin lines | 0.35 | 6.05 | 0.085 | 0.90 | 4.35 | 40.3 | 348 | 17.42 | 35 | 9 | – | – | 27.3 | 4505 | 0.0 | – | 19.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
@@ -398,7 +374,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| High Fidelity Photo with Gradients | flat colour art | 0.14 | 4.16 | 0.029 | 0.20 | 0.20 | 3.5 | 73 | 4.59 | 35 | 34 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | – | 0.0 | – | – | – |
|
||||
| High Fidelity Photo with Gradients | gradient, photo | 1.79 | 2.04 | – | – | – | 138.0 | 11156 | – | 40 | 39 | – | – | – | – | 0.0 | – | 9.2 | 0.0 | – | – | – | – | – | – | 0.8 | – | – | – |
|
||||
| High Fidelity Photo with Gradients | linear gradients | 0.23 | 1.19 | – | – | – | 6.0 | 252 | – | 0 | 0 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.8 | 83 | 0.2 | 5 |
|
||||
| High Fidelity Photo with Gradients | radial gradient | 0.25 | 0.25 | – | – | – | 0.0 | 0 | – | – | – | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | – | 3 |
|
||||
| Default, enhanced | curved shapes | 0.08 | 3.21 | 0.056 | 0.38 | 0.38 | 1.8 | 13 | 1.44 | 14 | 14 | 100 | 0.0 | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 17 | 0.0 | – | – | – |
|
||||
| Default, enhanced | polygons | 0.07 | 2.58 | 0.045 | 0.50 | 1.26 | 2.0 | 13 | 1.16 | 97 | 5 | 100 | 0.0 | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 11 | 0.0 | – | – | – |
|
||||
| Default, enhanced | thin lines | 0.54 | 4.50 | 0.049 | 0.47 | 105.72 | 3.3 | 25 | 1.27 | 40 | 0 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
@@ -407,7 +382,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Default, enhanced | flat colour art | 19.91 | 17.94 | 0.180 | 0.39 | 179.45 | 1.5 | 16 | 1.01 | 14 | 14 | 0 | 0.0 | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 17 | 0.0 | – | – | – |
|
||||
| Default, enhanced | gradient, photo | 39.03 | 38.64 | – | – | – | 3.2 | 595 | – | 55 | 41 | – | – | – | – | 18.8 | 35.5 | 0.0 | 0.0 | – | – | – | – | 0.00 | 15 | 0.0 | – | – | – |
|
||||
| Default, enhanced | linear gradients | 25.64 | 29.86 | – | – | – | 2.0 | 43 | – | 33 | 32 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Default, enhanced | radial gradient | 37.68 | 37.79 | – | – | – | 2.0 | 19 | – | 32 | 32 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Auto Color, enhanced | curved shapes | 0.05 | 2.25 | 0.039 | 0.27 | 0.28 | 1.8 | 15 | 1.59 | 16 | 16 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 17 | 0.0 | – | – | – |
|
||||
| Auto Color, enhanced | polygons | 0.06 | 2.30 | 0.042 | 0.63 | 1.39 | 2.0 | 14 | 1.25 | 95 | 7 | 99 | 0.0 | 0.0 | 0 | 2.0 | 2.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 11 | 0.0 | – | – | – |
|
||||
| Auto Color, enhanced | thin lines | 0.70 | 5.57 | 0.067 | 1.08 | 105.72 | 5.0 | 38 | 1.88 | 43 | 3 | – | – | 4.0 | 3225 | 5.2 | 4.6 | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
@@ -416,7 +390,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Auto Color, enhanced | flat colour art | 0.13 | 2.72 | 0.057 | 0.31 | 0.30 | 3.0 | 28 | 2.00 | 43 | 19 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 30 | 0.0 | – | – | – |
|
||||
| Auto Color, enhanced | gradient, photo | 2.08 | 2.39 | – | – | – | 159.3 | 4439 | – | 22 | 9 | – | – | – | – | 41.7 | 51.9 | 0.0 | 0.5 | – | – | – | – | 0.00 | 8 | 0.0 | – | – | – |
|
||||
| Auto Color, enhanced | linear gradients | 1.02 | 1.74 | – | – | – | 15.7 | 1272 | – | 12 | 8 | – | – | – | – | 9.1 | 7.4 | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Auto Color, enhanced | radial gradient | 1.53 | 1.53 | – | – | – | 19.3 | 1879 | – | 10 | 10 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 38 | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo, enhanced | curved shapes | 0.04 | 1.63 | 0.026 | 0.15 | 0.15 | 1.2 | 19 | 2.11 | 21 | 21 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo, enhanced | polygons | 0.06 | 2.33 | 0.039 | 0.50 | 1.32 | 1.7 | 17 | 1.47 | 88 | 7 | 93 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo, enhanced | thin lines | 0.35 | 6.05 | 0.085 | 0.90 | 4.35 | 40.3 | 348 | 17.42 | 35 | 9 | – | – | 27.3 | 4505 | 0.0 | – | 19.0 | 0.0 | – | – | – | – | 0.00 | 23 | 0.0 | – | – | – |
|
||||
@@ -425,7 +398,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| High Fidelity Photo, enhanced | flat colour art | 0.14 | 4.16 | 0.029 | 0.20 | 0.20 | 3.5 | 73 | 4.59 | 35 | 34 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 25 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo, enhanced | gradient, photo | 1.80 | 2.05 | – | – | – | 134.7 | 11212 | – | 39 | 37 | – | – | – | – | 0.0 | – | 7.3 | 0.0 | – | – | – | – | – | 69 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo, enhanced | linear gradients | 0.64 | 3.29 | – | – | – | 34.5 | 4318 | – | 32 | 31 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | 72 | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo, enhanced | radial gradient | 0.80 | 0.80 | – | – | – | 14.7 | 245 | – | 58 | 57 | – | – | – | – | 0.0 | – | 0.3 | 0.0 | – | – | – | – | – | 27 | 0.0 | 0 | – | – |
|
||||
| Low Fidelity Photo, enhanced | curved shapes | 0.06 | 2.52 | 0.043 | 0.31 | 0.31 | 1.2 | 12 | 1.29 | 18 | 18 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 1.00 | 0 | 0.0 | – | – | – |
|
||||
| Low Fidelity Photo, enhanced | polygons | 0.06 | 2.34 | 0.039 | 0.42 | 1.39 | 1.7 | 12 | 1.13 | 95 | 7 | 99 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 1.00 | 0 | 0.0 | – | – | – |
|
||||
| Low Fidelity Photo, enhanced | thin lines | 0.49 | 5.73 | 0.082 | 0.68 | 45.31 | 7.0 | 53 | 2.63 | 53 | 11 | – | – | 4.0 | 3989 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 1.67 | 0 | 0.0 | – | – | – |
|
||||
@@ -434,7 +406,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Low Fidelity Photo, enhanced | flat colour art | 0.15 | 4.19 | 0.042 | 0.28 | 0.20 | 3.5 | 48 | 2.93 | 32 | 31 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 1.00 | 25 | 0.0 | – | – | – |
|
||||
| Low Fidelity Photo, enhanced | gradient, photo | 2.53 | 2.80 | – | – | – | 42.7 | 2307 | – | 43 | 37 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 60 | 0.0 | – | – | – |
|
||||
| Low Fidelity Photo, enhanced | linear gradients | 0.69 | 3.09 | – | – | – | 24.3 | 1045 | – | 31 | 31 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 79 | 0.0 | 0 | – | – |
|
||||
| Low Fidelity Photo, enhanced | radial gradient | 0.74 | 0.74 | – | – | – | 12.3 | 241 | – | 57 | 57 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 23 | 0.0 | 0 | – | – |
|
||||
| 3 Colors, enhanced | curved shapes | 0.06 | 2.52 | 0.043 | 0.31 | 0.31 | 1.8 | 14 | 1.53 | 15 | 15 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 17 | 0.0 | – | – | – |
|
||||
| 3 Colors, enhanced | polygons | 0.06 | 2.34 | 0.043 | 0.63 | 1.39 | 2.0 | 14 | 1.26 | 94 | 7 | 99 | 0.0 | 0.0 | 0 | 2.0 | 2.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 11 | 0.0 | – | – | – |
|
||||
| 3 Colors, enhanced | thin lines | 0.43 | 4.49 | 0.117 | 1.04 | 45.31 | 5.0 | 41 | 2.05 | 57 | 13 | – | – | 2.0 | 308 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.33 | 0 | 0.0 | – | – | – |
|
||||
@@ -443,7 +414,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| 3 Colors, enhanced | flat colour art | 1.31 | 3.58 | 0.124 | 0.90 | 60.11 | 2.5 | 23 | 1.77 | 45 | 20 | 100 | 0.0 | 1.0 | 9912 | 9.0 | 9.0 | 0.0 | 0.0 | – | – | – | – | 0.33 | 25 | 0.0 | – | – | – |
|
||||
| 3 Colors, enhanced | gradient, photo | 7.49 | 7.60 | – | – | – | 5.7 | 524 | – | 48 | 40 | – | – | – | – | 7.0 | 8.8 | 0.0 | 0.0 | – | – | – | – | 0.00 | 20 | 0.0 | – | – | – |
|
||||
| 3 Colors, enhanced | linear gradients | 4.45 | 5.79 | – | – | – | 3.0 | 78 | – | 28 | 24 | – | – | – | – | 10.3 | 1.9 | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| 3 Colors, enhanced | radial gradient | 4.57 | 4.48 | – | – | – | 3.0 | 44 | – | 20 | 20 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 25 | 0.0 | 0 | – | – |
|
||||
| 6 Colors, enhanced | curved shapes | 0.05 | 2.25 | 0.039 | 0.27 | 0.28 | 1.8 | 15 | 1.59 | 16 | 16 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 17 | 0.0 | – | – | – |
|
||||
| 6 Colors, enhanced | polygons | 0.06 | 2.28 | 0.042 | 0.63 | 1.39 | 2.0 | 14 | 1.27 | 94 | 7 | 99 | 0.0 | 0.0 | 0 | 2.0 | 2.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 11 | 0.0 | – | – | – |
|
||||
| 6 Colors, enhanced | thin lines | 0.49 | 4.79 | 0.108 | 0.70 | 45.31 | 4.0 | 30 | 1.50 | 63 | 19 | – | – | 1.7 | 413 | 8.1 | 2.3 | 0.0 | 0.0 | – | – | – | – | 0.33 | 0 | 0.0 | – | – | – |
|
||||
@@ -452,7 +422,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| 6 Colors, enhanced | flat colour art | 0.13 | 2.72 | 0.057 | 0.31 | 0.30 | 3.0 | 28 | 2.00 | 43 | 19 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 30 | 0.0 | – | – | – |
|
||||
| 6 Colors, enhanced | gradient, photo | 5.00 | 5.28 | – | – | – | 13.0 | 828 | – | 37 | 28 | – | – | – | – | 7.5 | 10.6 | 0.0 | 0.0 | – | – | – | – | 0.00 | 13 | 0.0 | – | – | – |
|
||||
| 6 Colors, enhanced | linear gradients | 2.07 | 3.07 | – | – | – | 6.2 | 266 | – | 20 | 14 | – | – | – | – | 2.4 | 9.3 | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| 6 Colors, enhanced | radial gradient | 2.69 | 2.67 | – | – | – | 8.0 | 228 | – | 18 | 18 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 33 | 0.0 | 0 | – | – |
|
||||
| 16 Colors, enhanced | curved shapes | 0.05 | 2.06 | 0.034 | 0.24 | 0.25 | 1.8 | 16 | 1.64 | 16 | 16 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 17 | 0.0 | – | – | – |
|
||||
| 16 Colors, enhanced | polygons | 0.05 | 2.22 | 0.041 | 0.63 | 1.39 | 2.0 | 14 | 1.28 | 94 | 7 | 99 | 0.0 | 0.0 | 0 | 2.0 | 2.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 11 | 0.0 | – | – | – |
|
||||
| 16 Colors, enhanced | thin lines | 0.39 | 3.93 | 0.113 | 0.70 | 23.53 | 8.7 | 52 | 2.58 | 56 | 17 | – | – | 5.7 | 322 | 8.1 | 2.3 | 0.0 | 0.0 | – | – | – | – | 0.33 | 0 | 0.0 | – | – | – |
|
||||
@@ -461,7 +430,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| 16 Colors, enhanced | flat colour art | 0.12 | 2.53 | 0.052 | 0.31 | 0.30 | 3.0 | 28 | 2.11 | 43 | 19 | 100 | 0.0 | 0.0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 30 | 0.0 | – | – | – |
|
||||
| 16 Colors, enhanced | gradient, photo | 3.00 | 3.30 | – | – | – | 47.2 | 2126 | – | 30 | 16 | – | – | – | – | 15.2 | 19.6 | 0.0 | 0.0 | – | – | – | – | 0.00 | 15 | 0.0 | – | – | – |
|
||||
| 16 Colors, enhanced | linear gradients | 0.98 | 1.67 | – | – | – | 15.8 | 1340 | – | 8 | 6 | – | – | – | – | 13.9 | 15.5 | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| 16 Colors, enhanced | radial gradient | 1.47 | 1.47 | – | – | – | 23.0 | 2787 | – | 8 | 8 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 33 | 0.0 | 0 | – | – |
|
||||
| Shades of Gray, enhanced | curved shapes | 0.06 | 2.53 | 0.044 | 0.31 | 0.31 | 1.2 | 12 | 1.29 | 18 | 18 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 1.00 | 0 | 0.0 | – | – | – |
|
||||
| Shades of Gray, enhanced | polygons | 0.07 | 2.49 | 0.042 | 0.50 | 1.26 | 1.7 | 11 | 1.03 | 99 | 5 | 100 | 0.0 | 0.0 | 0 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 1.00 | 0 | 0.0 | – | – | – |
|
||||
| Shades of Gray, enhanced | thin lines | 0.56 | 7.12 | 0.089 | 0.68 | 45.31 | 10.3 | 73 | 3.65 | 55 | 11 | – | – | 8.0 | 4322 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 1.00 | 0 | 0.0 | – | – | – |
|
||||
@@ -470,7 +438,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Shades of Gray, enhanced | flat colour art | 7.33 | 11.09 | 0.244 | 1.47 | 179.46 | 4.7 | 161 | 13.44 | 24 | 24 | 50 | 0.0 | 3.7 | 173377 | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 1.33 | 36 | 0.0 | – | – | – |
|
||||
| Shades of Gray, enhanced | gradient, photo | 9.71 | 9.55 | – | – | – | 18.3 | 753 | – | 51 | 41 | – | – | – | – | 0.0 | – | 0.5 | 0.0 | – | – | – | – | 0.00 | 53 | 0.0 | – | – | – |
|
||||
| Shades of Gray, enhanced | linear gradients | 5.25 | 8.40 | – | – | – | 9.0 | 474 | – | 31 | 31 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 63 | 0.0 | 0 | – | – |
|
||||
| Shades of Gray, enhanced | radial gradient | 5.24 | 5.13 | – | – | – | 4.0 | 19 | – | 60 | 58 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Black and White Logo, enhanced | curved shapes | 0.03 | 1.46 | 0.022 | 0.16 | 0.16 | 1.2 | 16 | 1.67 | 21 | 21 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Black and White Logo, enhanced | polygons | 0.07 | 2.68 | 0.046 | 0.50 | 1.26 | 1.7 | 11 | 1.03 | 99 | 8 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Black and White Logo, enhanced | thin lines | 0.60 | 6.03 | 0.105 | 0.50 | 77.21 | 10.3 | 44 | 2.18 | 90 | 10 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
@@ -479,7 +446,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Black and White Logo, enhanced | flat colour art | 19.90 | 17.76 | 0.171 | 0.30 | 179.47 | 1.0 | 18 | 1.12 | 23 | 23 | 0 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Black and White Logo, enhanced | gradient, photo | 38.97 | 38.53 | – | – | – | 9.0 | 634 | – | 73 | 54 | – | – | – | – | – | – | 1.2 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Black and White Logo, enhanced | linear gradients | 25.62 | 29.78 | – | – | – | 1.5 | 127 | – | 46 | 33 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Black and White Logo, enhanced | radial gradient | 37.66 | 37.78 | – | – | – | 1.0 | 12 | – | 58 | 58 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Sketched Art, enhanced | curved shapes | 0.13 | 5.38 | 0.103 | 0.46 | 0.46 | 1.2 | 11 | 1.24 | 16 | 16 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Sketched Art, enhanced | polygons | 0.13 | 5.02 | 0.090 | 0.49 | 1.08 | 1.7 | 12 | 1.07 | 94 | 5 | 98 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Sketched Art, enhanced | thin lines | 0.47 | 5.72 | 0.114 | 0.96 | 52.59 | 4.3 | 29 | 1.45 | 64 | 3 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.33 | 0 | 0.0 | – | – | – |
|
||||
@@ -488,7 +454,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Sketched Art, enhanced | flat colour art | 20.24 | 19.33 | 0.158 | 0.83 | 179.59 | 1.5 | 15 | 1.00 | 16 | 16 | 0 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.50 | 25 | 0.0 | – | – | – |
|
||||
| Sketched Art, enhanced | gradient, photo | 45.42 | 45.21 | – | – | – | 1.0 | 244 | – | 46 | 35 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Sketched Art, enhanced | linear gradients | 29.20 | 33.47 | – | – | – | 1.5 | 54 | – | 35 | 34 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Sketched Art, enhanced | radial gradient | 43.28 | 43.49 | – | – | – | 0.0 | 0 | – | – | – | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Silhouettes, enhanced | curved shapes | 0.35 | 14.33 | 0.277 | 0.69 | 0.69 | 1.2 | 11 | 1.24 | 16 | 16 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Silhouettes, enhanced | polygons | 0.35 | 13.66 | 0.255 | 0.74 | 1.67 | 1.7 | 13 | 1.20 | 82 | 6 | 93 | 0.1 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.11 | 0 | 0.0 | – | – | – |
|
||||
| Silhouettes, enhanced | thin lines | 0.99 | 13.79 | 0.267 | 1.08 | 18.26 | 5.0 | 30 | 1.50 | 67 | 12 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 1.00 | 0 | 0.0 | – | – | – |
|
||||
@@ -497,7 +462,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Silhouettes, enhanced | flat colour art | 23.82 | 32.43 | 0.189 | 0.35 | 188.27 | 1.0 | 6 | 0.53 | 37 | 37 | 0 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Silhouettes, enhanced | gradient, photo | 61.57 | 61.32 | – | – | – | 0.2 | 2 | – | 47 | 21 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Silhouettes, enhanced | linear gradients | 39.85 | 46.48 | – | – | – | 1.0 | 37 | – | 1 | 0 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Silhouettes, enhanced | radial gradient | 58.75 | 59.00 | – | – | – | 0.0 | 0 | – | – | – | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Line Art, enhanced | curved shapes | 0.04 | 1.76 | 0.029 | 0.22 | 0.22 | 1.2 | 14 | 1.46 | 20 | 20 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Line Art, enhanced | polygons | 0.07 | 2.38 | 0.040 | 0.50 | 1.26 | 1.7 | 11 | 1.04 | 98 | 5 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Line Art, enhanced | thin lines | 0.52 | 4.12 | 0.040 | 0.47 | 105.72 | 3.3 | 29 | 1.45 | 40 | 0 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
@@ -506,7 +470,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Line Art, enhanced | flat colour art | 19.90 | 17.84 | 0.168 | 0.30 | 179.50 | 1.0 | 16 | 1.03 | 21 | 21 | 0 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Line Art, enhanced | gradient, photo | 38.98 | 38.54 | – | – | – | 7.7 | 472 | – | 58 | 44 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Line Art, enhanced | linear gradients | 25.63 | 29.80 | – | – | – | 1.5 | 95 | – | 33 | 32 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Line Art, enhanced | radial gradient | 37.67 | 37.78 | – | – | – | 1.0 | 8 | – | 57 | 57 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Technical Drawing, enhanced | curved shapes | 0.03 | 1.46 | 0.022 | 0.16 | 0.16 | 1.2 | 16 | 1.67 | 21 | 21 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Technical Drawing, enhanced | polygons | 0.07 | 2.68 | 0.046 | 0.50 | 1.26 | 1.7 | 11 | 1.02 | 100 | 8 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Technical Drawing, enhanced | thin lines | 0.50 | 5.50 | 0.110 | 0.50 | 55.93 | 15.3 | 62 | 3.12 | 86 | 14 | – | – | – | – | – | – | 3.3 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
@@ -515,7 +478,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Technical Drawing, enhanced | flat colour art | 19.90 | 17.76 | 0.171 | 0.30 | 179.47 | 1.0 | 18 | 1.12 | 23 | 23 | 0 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Technical Drawing, enhanced | gradient, photo | 38.94 | 38.51 | – | – | – | 20.0 | 659 | – | 73 | 51 | – | – | – | – | – | – | 11.7 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Technical Drawing, enhanced | linear gradients | 25.62 | 29.80 | – | – | – | 1.5 | 118 | – | 49 | 33 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Technical Drawing, enhanced | radial gradient | 37.66 | 37.78 | – | – | – | 1.0 | 12 | – | 58 | 58 | – | – | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Outline, enhanced | curved shapes | 23.38 | 44.76 | 0.499 | 0.71 | 0.52 | 1.2 | 16 | 1.70 | 20 | 20 | 100 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Outline, enhanced | polygons | 17.94 | 44.26 | 0.494 | 0.94 | 0.76 | 1.7 | 14 | 1.26 | 89 | 5 | 95 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Outline, enhanced | thin lines | 0.51 | 3.57 | 0.028 | 0.41 | 105.74 | 3.3 | 7 | 0.33 | 100 | 7 | – | – | – | – | – | – | 0.0 | 0.0 | 0.020 | 0.02 | 2.0 | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
@@ -524,7 +486,6 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| Outline, enhanced | flat colour art | 26.69 | 32.18 | 0.494 | 0.92 | 178.93 | 1.0 | 18 | 1.30 | 21 | 21 | 0 | 0.0 | – | – | – | – | 0.0 | 0.0 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Outline, enhanced | gradient, photo | 39.38 | 39.18 | – | – | – | 7.5 | 445 | – | 59 | 43 | – | – | – | – | – | – | 3.3 | 0.5 | – | – | – | – | 0.00 | 0 | 0.0 | – | – | – |
|
||||
| Outline, enhanced | linear gradients | 25.08 | 30.80 | – | – | – | 1.5 | 92 | – | 33 | 32 | – | – | – | – | – | – | 0.0 | 0.5 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
| Outline, enhanced | radial gradient | 36.88 | 36.89 | – | – | – | 1.0 | 8 | – | 57 | 57 | – | – | – | – | – | – | 0.0 | 0.5 | – | – | – | – | 0.00 | 0 | 0.0 | 0 | – | – |
|
||||
|
||||
## 3. Each preset on its inputs, by variant (256 px)
|
||||
|
||||
@@ -630,26 +591,26 @@ All sizes and variants (clean, aliased, blurred, noisy, scanned) of those inputs
|
||||
| High Fidelity Photo with Auto Grouping | blurred | 1.59 | 1.95 | – | – | – | 72.0 | 7450 | – | 40 | 39 | – | – | – | – | 0.0 | – | 0.5 | 0.0 | – | – | – | – | – | 65 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo with Auto Grouping | noisy | 2.02 | 2.19 | – | – | – | 155.5 | 10670 | – | 33 | 31 | – | – | – | – | 0.0 | – | 18.5 | 0.0 | – | – | – | – | – | 72 | 0.0 | – | – | – |
|
||||
| High Fidelity Photo with Auto Grouping | scanned | 1.45 | 1.55 | – | – | – | 140.5 | 9723 | – | 36 | 35 | – | – | – | – | 0.0 | – | 24.5 | 0.0 | – | – | – | – | – | 75 | 0.0 | – | – | – |
|
||||
| 6 Colors, no Gradients | clean | 2.28 | 2.94 | – | – | – | 6.8 | 257 | – | 19 | 15 | – | – | – | – | 1.6 | 6.2 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors, no Gradients | aliased | 2.26 | 2.94 | – | – | – | 7.0 | 414 | – | 21 | 15 | – | – | – | – | 0.0 | 0.4 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors, no Gradients | blurred | 2.28 | 3.35 | – | – | – | 6.7 | 310 | – | 21 | 15 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors, no Gradients | noisy | 2.54 | 2.88 | – | – | – | 8.3 | 912 | – | 20 | 13 | – | – | – | – | 12.6 | 30.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors, no Gradients | scanned | 2.15 | 2.32 | – | – | – | 7.0 | 954 | – | 22 | 14 | – | – | – | – | 15.2 | 32.6 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors with Gradients | clean | 0.35 | 0.81 | – | – | – | 0.9 | 26 | – | 0 | 0 | – | – | – | – | 0.4 | 0.7 | 0.0 | 0.0 | – | – | – | – | – | – | 0.9 | 89 | 0.2 | 5 |
|
||||
| 6 Colors with Gradients | aliased | 0.21 | 0.58 | – | – | – | 0.3 | 4 | – | 0 | 0 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | 0.2 | 5 |
|
||||
| 6 Colors with Gradients | blurred | 0.29 | 1.56 | – | – | – | 0.3 | 16 | – | 0 | 0 | – | – | – | – | 4.7 | 2.4 | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | 0.3 | 6 |
|
||||
| 6 Colors with Gradients | noisy | 1.17 | 1.33 | – | – | – | 0.3 | 9 | – | 0 | 0 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | 0.2 | 10 |
|
||||
| 6 Colors with Gradients | scanned | 1.38 | 1.55 | – | – | – | 2.3 | 179 | – | 29 | 27 | – | – | – | – | 1.8 | 1.1 | 0.0 | 0.0 | – | – | – | – | – | – | 0.7 | 67 | 1.5 | 28 |
|
||||
| High Fidelity Photo, no Gradients | clean | 0.69 | 2.46 | – | – | – | 27.9 | 2961 | – | 41 | 40 | – | – | – | – | 0.0 | – | 0.1 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo, no Gradients | aliased | 0.75 | 2.61 | – | – | – | 29.7 | 2191 | – | 40 | 40 | – | – | – | – | 0.0 | – | 0.3 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo, no Gradients | blurred | 0.78 | 2.47 | – | – | – | 27.0 | 2284 | – | 41 | 40 | – | – | – | – | 0.0 | – | 0.3 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo, no Gradients | noisy | 1.24 | 2.25 | – | – | – | 29.3 | 2956 | – | 29 | 25 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo, no Gradients | scanned | 1.09 | 1.48 | – | – | – | 50.3 | 2914 | – | 37 | 36 | – | – | – | – | 0.0 | – | 9.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo with Gradients | clean | 0.24 | 0.87 | – | – | – | 4.0 | 168 | – | 0 | 0 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.9 | 89 | 0.2 | 5 |
|
||||
| High Fidelity Photo with Gradients | aliased | 0.21 | 0.41 | – | – | – | 0.3 | 16 | – | 0 | 0 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | 0.2 | 5 |
|
||||
| High Fidelity Photo with Gradients | blurred | 0.29 | 1.53 | – | – | – | 0.3 | 32 | – | 1 | 0 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | 0.3 | 6 |
|
||||
| High Fidelity Photo with Gradients | noisy | 1.17 | 1.29 | – | – | – | 3.0 | 84 | – | 33 | 9 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | 0.2 | 10 |
|
||||
| High Fidelity Photo with Gradients | scanned | 0.98 | 1.36 | – | – | – | 25.0 | 1915 | – | 30 | 28 | – | – | – | – | 0.0 | – | 3.7 | 0.0 | – | – | – | – | – | – | 0.7 | 67 | 1.5 | 28 |
|
||||
| 6 Colors, no Gradients | clean | 2.07 | 3.07 | – | – | – | 6.2 | 266 | – | 20 | 14 | – | – | – | – | 2.4 | 9.3 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors, no Gradients | aliased | 2.04 | 3.07 | – | – | – | 6.5 | 500 | – | 22 | 14 | – | – | – | – | 0.0 | 0.6 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors, no Gradients | blurred | 2.08 | 3.69 | – | – | – | 6.0 | 344 | – | 23 | 14 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors, no Gradients | noisy | 2.36 | 2.87 | – | – | – | 8.0 | 864 | – | 19 | 12 | – | – | – | – | 10.5 | 30.5 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors, no Gradients | scanned | 2.16 | 2.41 | – | – | – | 6.0 | 776 | – | 20 | 12 | – | – | – | – | 9.8 | 30.4 | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| 6 Colors with Gradients | clean | 0.40 | 1.09 | – | – | – | 1.3 | 39 | – | 0 | 0 | – | – | – | – | 0.5 | 1.1 | 0.0 | 0.0 | – | – | – | – | – | – | 0.8 | 83 | 0.2 | 5 |
|
||||
| 6 Colors with Gradients | aliased | 0.22 | 0.77 | – | – | – | 0.5 | 6 | – | 0 | 0 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | 0.2 | 5 |
|
||||
| 6 Colors with Gradients | blurred | 0.33 | 2.23 | – | – | – | 0.5 | 24 | – | 0 | 0 | – | – | – | – | 7.1 | 3.7 | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | 0.3 | 6 |
|
||||
| 6 Colors with Gradients | noisy | 1.02 | 1.27 | – | – | – | 0.5 | 14 | – | 0 | 0 | – | – | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | 0.2 | 8 |
|
||||
| 6 Colors with Gradients | scanned | 1.57 | 1.82 | – | – | – | 3.0 | 264 | – | 3 | 0 | – | – | – | – | 2.8 | 1.6 | 0.0 | 0.0 | – | – | – | – | – | – | 0.5 | 50 | 1.5 | 21 |
|
||||
| High Fidelity Photo, no Gradients | clean | 0.64 | 3.29 | – | – | – | 34.5 | 4318 | – | 32 | 31 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo, no Gradients | aliased | 0.67 | 3.46 | – | – | – | 37.5 | 3184 | – | 32 | 31 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo, no Gradients | blurred | 0.72 | 3.25 | – | – | – | 33.5 | 3324 | – | 32 | 31 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo, no Gradients | noisy | 1.15 | 2.67 | – | – | – | 37.5 | 3468 | – | 29 | 28 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo, no Gradients | scanned | 1.05 | 1.62 | – | – | – | 54.5 | 3858 | – | 29 | 28 | – | – | – | – | 0.0 | – | 7.5 | 0.0 | – | – | – | – | – | – | 0.0 | 0 | – | – |
|
||||
| High Fidelity Photo with Gradients | clean | 0.23 | 1.19 | – | – | – | 6.0 | 252 | – | 0 | 0 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 0.8 | 83 | 0.2 | 5 |
|
||||
| High Fidelity Photo with Gradients | aliased | 0.21 | 0.52 | – | – | – | 0.5 | 24 | – | 0 | 0 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | 0.2 | 5 |
|
||||
| High Fidelity Photo with Gradients | blurred | 0.33 | 2.20 | – | – | – | 0.5 | 48 | – | 1 | 0 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | 0.3 | 6 |
|
||||
| High Fidelity Photo with Gradients | noisy | 1.02 | 1.21 | – | – | – | 1.5 | 116 | – | 0 | 0 | – | – | – | – | 0.0 | – | 0.0 | 0.0 | – | – | – | – | – | – | 1.0 | 100 | 0.2 | 8 |
|
||||
| High Fidelity Photo with Gradients | scanned | 0.97 | 1.55 | – | – | – | 37.0 | 2868 | – | 5 | 3 | – | – | – | – | 0.0 | – | 5.5 | 0.0 | – | – | – | – | – | – | 0.5 | 50 | 1.5 | 21 |
|
||||
| Default, enhanced | clean | 0.08 | 2.94 | 0.051 | 0.50 | 1.26 | 1.9 | 13 | 1.32 | 50 | 10 | 100 | 0.0 | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 14 | 0.0 | – | – | – |
|
||||
| Default, enhanced | aliased | 0.36 | 19.23 | 0.194 | 1.00 | 1.35 | 1.9 | 14 | 1.42 | 28 | 8 | 98 | 0.0 | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.14 | 14 | 0.0 | – | – | – |
|
||||
| Default, enhanced | blurred | 0.81 | 16.50 | 0.073 | 0.98 | 2.18 | 1.9 | 22 | 2.15 | 17 | 5 | 38 | 1.3 | – | – | 0.0 | 0.0 | 0.0 | 0.0 | – | – | – | – | 0.00 | 14 | 0.0 | – | – | – |
|
||||
@@ -761,240 +722,239 @@ One trace at a time on this machine (all cores); memory is the peak allocated ab
|
||||
|
||||
| preset | image | megapixels | result |
|
||||
|:--|:--|--:|:--|
|
||||
| Default | photo-like | 1 | 0.06 s, 29 paths, 6278 anchors, 12 MB |
|
||||
| Default | four-colour badge | 1 | 0.03 s, 3 paths, 64 anchors, 12 MB |
|
||||
| Auto Color | photo-like | 1 | 0.18 s, 732 paths, 45265 anchors, 24 MB |
|
||||
| Auto Color | four-colour badge | 1 | 0.07 s, 5 paths, 84 anchors, 12 MB |
|
||||
| High Fidelity Photo | photo-like | 1 | 0.25 s, 968 paths, 117041 anchors, 129 MB |
|
||||
| High Fidelity Photo | four-colour badge | 1 | 0.08 s, 6 paths, 172 anchors, 23 MB |
|
||||
| Low Fidelity Photo | photo-like | 1 | 0.16 s, 129 paths, 23014 anchors, 99 MB |
|
||||
| Low Fidelity Photo | four-colour badge | 1 | 0.06 s, 6 paths, 136 anchors, 23 MB |
|
||||
| 3 Colors | photo-like | 1 | 0.11 s, 9 paths, 3341 anchors, 18 MB |
|
||||
| 3 Colors | four-colour badge | 1 | 0.06 s, 4 paths, 88 anchors, 12 MB |
|
||||
| 6 Colors | photo-like | 1 | 0.16 s, 78 paths, 9076 anchors, 24 MB |
|
||||
| 6 Colors | four-colour badge | 1 | 0.06 s, 5 paths, 84 anchors, 12 MB |
|
||||
| 16 Colors | photo-like | 1 | 0.13 s, 178 paths, 20470 anchors, 28 MB |
|
||||
| Default | photo-like | 1 | 0.04 s, 29 paths, 6278 anchors, 12 MB |
|
||||
| Default | four-colour badge | 1 | 0.02 s, 3 paths, 64 anchors, 12 MB |
|
||||
| Auto Color | photo-like | 1 | 0.17 s, 732 paths, 45265 anchors, 24 MB |
|
||||
| Auto Color | four-colour badge | 1 | 0.05 s, 5 paths, 84 anchors, 12 MB |
|
||||
| High Fidelity Photo | photo-like | 1 | 0.22 s, 968 paths, 117041 anchors, 171 MB |
|
||||
| High Fidelity Photo | four-colour badge | 1 | 0.06 s, 6 paths, 172 anchors, 23 MB |
|
||||
| Low Fidelity Photo | photo-like | 1 | 0.12 s, 129 paths, 23014 anchors, 105 MB |
|
||||
| Low Fidelity Photo | four-colour badge | 1 | 0.05 s, 6 paths, 136 anchors, 23 MB |
|
||||
| 3 Colors | photo-like | 1 | 0.09 s, 9 paths, 3341 anchors, 18 MB |
|
||||
| 3 Colors | four-colour badge | 1 | 0.05 s, 4 paths, 88 anchors, 13 MB |
|
||||
| 6 Colors | photo-like | 1 | 0.10 s, 78 paths, 9076 anchors, 24 MB |
|
||||
| 6 Colors | four-colour badge | 1 | 0.05 s, 5 paths, 84 anchors, 12 MB |
|
||||
| 16 Colors | photo-like | 1 | 0.11 s, 178 paths, 20470 anchors, 26 MB |
|
||||
| 16 Colors | four-colour badge | 1 | 0.05 s, 5 paths, 88 anchors, 12 MB |
|
||||
| Shades of Gray | photo-like | 1 | 0.12 s, 81 paths, 6698 anchors, 43 MB |
|
||||
| Shades of Gray | four-colour badge | 1 | 0.08 s, 10 paths, 725 anchors, 34 MB |
|
||||
| Shades of Gray | photo-like | 1 | 0.10 s, 81 paths, 6698 anchors, 41 MB |
|
||||
| Shades of Gray | four-colour badge | 1 | 0.06 s, 10 paths, 725 anchors, 34 MB |
|
||||
| Black and White Logo | photo-like | 1 | 0.04 s, 71 paths, 4933 anchors, 8 MB |
|
||||
| Black and White Logo | four-colour badge | 1 | 0.02 s, 1 paths, 47 anchors, 6 MB |
|
||||
| Sketched Art | photo-like | 1 | 0.05 s, 5 paths, 2873 anchors, 8 MB |
|
||||
| Sketched Art | four-colour badge | 1 | 0.03 s, 2 paths, 114 anchors, 6 MB |
|
||||
| Silhouettes | photo-like | 1 | 0.04 s, 2 paths, 556 anchors, 9 MB |
|
||||
| Silhouettes | four-colour badge | 1 | 0.03 s, 1 paths, 24 anchors, 6 MB |
|
||||
| Line Art | photo-like | 1 | 0.05 s, 54 paths, 4495 anchors, 8 MB |
|
||||
| Line Art | four-colour badge | 1 | 0.03 s, 1 paths, 38 anchors, 6 MB |
|
||||
| Technical Drawing | photo-like | 1 | 0.05 s, 221 paths, 6258 anchors, 8 MB |
|
||||
| Technical Drawing | four-colour badge | 1 | 0.03 s, 1 paths, 47 anchors, 6 MB |
|
||||
| Outline | photo-like | 1 | 0.07 s, 45 paths, 4110 anchors, 16 MB |
|
||||
| Outline | four-colour badge | 1 | 0.05 s, 1 paths, 38 anchors, 11 MB |
|
||||
| Flat Logo | photo-like | 1 | refused after 0.13 s (not flat art), 40 MB |
|
||||
| Flat Logo | four-colour badge | 1 | 0.73 s, 5 paths, 78 anchors, 146 MB |
|
||||
| Default with Shapes | photo-like | 1 | 0.06 s, 29 paths, 6278 anchors, 12 MB |
|
||||
| Sketched Art | photo-like | 1 | 0.04 s, 5 paths, 2873 anchors, 8 MB |
|
||||
| Sketched Art | four-colour badge | 1 | 0.02 s, 2 paths, 114 anchors, 6 MB |
|
||||
| Silhouettes | photo-like | 1 | 0.03 s, 2 paths, 556 anchors, 9 MB |
|
||||
| Silhouettes | four-colour badge | 1 | 0.02 s, 1 paths, 24 anchors, 6 MB |
|
||||
| Line Art | photo-like | 1 | 0.04 s, 54 paths, 4495 anchors, 8 MB |
|
||||
| Line Art | four-colour badge | 1 | 0.02 s, 1 paths, 38 anchors, 6 MB |
|
||||
| Technical Drawing | photo-like | 1 | 0.04 s, 221 paths, 6258 anchors, 8 MB |
|
||||
| Technical Drawing | four-colour badge | 1 | 0.02 s, 1 paths, 47 anchors, 6 MB |
|
||||
| Outline | photo-like | 1 | 0.05 s, 45 paths, 4110 anchors, 16 MB |
|
||||
| Outline | four-colour badge | 1 | 0.03 s, 1 paths, 38 anchors, 11 MB |
|
||||
| Flat Logo | photo-like | 1 | refused after 0.14 s (not flat art), 40 MB |
|
||||
| Flat Logo | four-colour badge | 1 | 0.66 s, 5 paths, 78 anchors, 146 MB |
|
||||
| Default with Shapes | photo-like | 1 | 0.05 s, 29 paths, 6278 anchors, 12 MB |
|
||||
| Default with Shapes | four-colour badge | 1 | 0.02 s, 3 paths, 62 anchors, 12 MB |
|
||||
| 6 Colors with Shapes | photo-like | 1 | 0.11 s, 78 paths, 9076 anchors, 24 MB |
|
||||
| 6 Colors with Shapes | four-colour badge | 1 | 0.05 s, 5 paths, 84 anchors, 13 MB |
|
||||
| 6 Colors with Auto Grouping | photo-like | 1 | 0.16 s, 78 paths, 9076 anchors, 24 MB |
|
||||
| 6 Colors with Auto Grouping | four-colour badge | 1 | 0.06 s, 5 paths, 84 anchors, 12 MB |
|
||||
| Shades of Gray with Auto Grouping | photo-like | 1 | 0.19 s, 81 paths, 6698 anchors, 31 MB |
|
||||
| Shades of Gray with Auto Grouping | four-colour badge | 1 | 0.17 s, 10 paths, 725 anchors, 26 MB |
|
||||
| High Fidelity Photo with Auto Grouping | photo-like | 1 | 1.36 s, 968 paths, 117041 anchors, 51 MB |
|
||||
| High Fidelity Photo with Auto Grouping | four-colour badge | 1 | 0.11 s, 6 paths, 172 anchors, 24 MB |
|
||||
| 6 Colors, no Gradients | photo-like | 1 | 0.26 s, 78 paths, 9076 anchors, 24 MB |
|
||||
| 6 Colors, no Gradients | four-colour badge | 1 | 0.11 s, 5 paths, 84 anchors, 13 MB |
|
||||
| 6 Colors with Gradients | photo-like | 1 | 0.36 s, 78 paths, 9076 anchors, 32 MB |
|
||||
| 6 Colors with Gradients | four-colour badge | 1 | 0.13 s, 5 paths, 84 anchors, 12 MB |
|
||||
| High Fidelity Photo, no Gradients | photo-like | 1 | 0.27 s, 968 paths, 117041 anchors, 138 MB |
|
||||
| High Fidelity Photo, no Gradients | four-colour badge | 1 | 0.08 s, 6 paths, 172 anchors, 23 MB |
|
||||
| High Fidelity Photo with Gradients | photo-like | 1 | 0.35 s, 968 paths, 117041 anchors, 122 MB |
|
||||
| High Fidelity Photo with Gradients | four-colour badge | 1 | 0.13 s, 6 paths, 172 anchors, 23 MB |
|
||||
| Default, enhanced | photo-like | 1 | 0.09 s, 29 paths, 6278 anchors, 12 MB |
|
||||
| Default, enhanced | four-colour badge | 1 | 0.03 s, 3 paths, 62 anchors, 12 MB |
|
||||
| Auto Color, enhanced | photo-like | 1 | 0.23 s, 732 paths, 45260 anchors, 17 MB |
|
||||
| Auto Color, enhanced | four-colour badge | 1 | 0.07 s, 5 paths, 84 anchors, 12 MB |
|
||||
| High Fidelity Photo, enhanced | photo-like | 1 | 0.32 s, 968 paths, 117041 anchors, 160 MB |
|
||||
| High Fidelity Photo, enhanced | four-colour badge | 1 | 0.05 s, 6 paths, 172 anchors, 24 MB |
|
||||
| Low Fidelity Photo, enhanced | photo-like | 1 | 0.16 s, 129 paths, 23014 anchors, 105 MB |
|
||||
| Low Fidelity Photo, enhanced | four-colour badge | 1 | 0.07 s, 6 paths, 116 anchors, 23 MB |
|
||||
| 3 Colors, enhanced | photo-like | 1 | 0.10 s, 9 paths, 3341 anchors, 18 MB |
|
||||
| 6 Colors with Shapes | four-colour badge | 1 | 0.05 s, 5 paths, 84 anchors, 12 MB |
|
||||
| 6 Colors with Auto Grouping | photo-like | 1 | 0.10 s, 78 paths, 9076 anchors, 24 MB |
|
||||
| 6 Colors with Auto Grouping | four-colour badge | 1 | 0.05 s, 5 paths, 84 anchors, 12 MB |
|
||||
| Shades of Gray with Auto Grouping | photo-like | 1 | 0.10 s, 81 paths, 6698 anchors, 41 MB |
|
||||
| Shades of Gray with Auto Grouping | four-colour badge | 1 | 0.06 s, 10 paths, 725 anchors, 34 MB |
|
||||
| High Fidelity Photo with Auto Grouping | photo-like | 1 | 0.24 s, 968 paths, 117041 anchors, 169 MB |
|
||||
| High Fidelity Photo with Auto Grouping | four-colour badge | 1 | 0.05 s, 6 paths, 172 anchors, 23 MB |
|
||||
| 6 Colors, no Gradients | photo-like | 1 | 0.09 s, 78 paths, 9076 anchors, 24 MB |
|
||||
| 6 Colors, no Gradients | four-colour badge | 1 | 0.07 s, 5 paths, 84 anchors, 12 MB |
|
||||
| 6 Colors with Gradients | photo-like | 1 | 0.15 s, 78 paths, 9076 anchors, 32 MB |
|
||||
| 6 Colors with Gradients | four-colour badge | 1 | 0.08 s, 5 paths, 84 anchors, 12 MB |
|
||||
| High Fidelity Photo, no Gradients | photo-like | 1 | 0.23 s, 968 paths, 117041 anchors, 170 MB |
|
||||
| High Fidelity Photo, no Gradients | four-colour badge | 1 | 0.06 s, 6 paths, 172 anchors, 23 MB |
|
||||
| High Fidelity Photo with Gradients | photo-like | 1 | 0.26 s, 968 paths, 117041 anchors, 169 MB |
|
||||
| High Fidelity Photo with Gradients | four-colour badge | 1 | 0.09 s, 6 paths, 172 anchors, 23 MB |
|
||||
| Default, enhanced | photo-like | 1 | 0.05 s, 29 paths, 6278 anchors, 12 MB |
|
||||
| Default, enhanced | four-colour badge | 1 | 0.02 s, 3 paths, 62 anchors, 12 MB |
|
||||
| Auto Color, enhanced | photo-like | 1 | 0.17 s, 732 paths, 45260 anchors, 27 MB |
|
||||
| Auto Color, enhanced | four-colour badge | 1 | 0.05 s, 5 paths, 84 anchors, 12 MB |
|
||||
| High Fidelity Photo, enhanced | photo-like | 1 | 0.26 s, 968 paths, 117041 anchors, 169 MB |
|
||||
| High Fidelity Photo, enhanced | four-colour badge | 1 | 0.05 s, 6 paths, 172 anchors, 23 MB |
|
||||
| Low Fidelity Photo, enhanced | photo-like | 1 | 0.14 s, 129 paths, 23014 anchors, 105 MB |
|
||||
| Low Fidelity Photo, enhanced | four-colour badge | 1 | 0.05 s, 6 paths, 116 anchors, 23 MB |
|
||||
| 3 Colors, enhanced | photo-like | 1 | 0.09 s, 9 paths, 3341 anchors, 18 MB |
|
||||
| 3 Colors, enhanced | four-colour badge | 1 | 0.05 s, 4 paths, 76 anchors, 13 MB |
|
||||
| 6 Colors, enhanced | photo-like | 1 | 0.12 s, 78 paths, 9076 anchors, 24 MB |
|
||||
| 6 Colors, enhanced | four-colour badge | 1 | 0.07 s, 5 paths, 84 anchors, 12 MB |
|
||||
| 16 Colors, enhanced | photo-like | 1 | 0.16 s, 178 paths, 20467 anchors, 32 MB |
|
||||
| 16 Colors, enhanced | four-colour badge | 1 | 0.08 s, 5 paths, 88 anchors, 12 MB |
|
||||
| Shades of Gray, enhanced | photo-like | 1 | 0.13 s, 81 paths, 6698 anchors, 42 MB |
|
||||
| Shades of Gray, enhanced | four-colour badge | 1 | 0.09 s, 10 paths, 623 anchors, 34 MB |
|
||||
| Black and White Logo, enhanced | photo-like | 1 | 0.08 s, 71 paths, 4933 anchors, 8 MB |
|
||||
| Black and White Logo, enhanced | four-colour badge | 1 | 0.03 s, 1 paths, 46 anchors, 6 MB |
|
||||
| Sketched Art, enhanced | photo-like | 1 | 0.06 s, 5 paths, 2873 anchors, 8 MB |
|
||||
| Sketched Art, enhanced | four-colour badge | 1 | 0.03 s, 2 paths, 37 anchors, 6 MB |
|
||||
| Silhouettes, enhanced | photo-like | 1 | 0.06 s, 2 paths, 556 anchors, 9 MB |
|
||||
| Silhouettes, enhanced | four-colour badge | 1 | 0.03 s, 1 paths, 8 anchors, 6 MB |
|
||||
| Line Art, enhanced | photo-like | 1 | 0.08 s, 54 paths, 4495 anchors, 8 MB |
|
||||
| 6 Colors, enhanced | photo-like | 1 | 0.10 s, 78 paths, 9076 anchors, 24 MB |
|
||||
| 6 Colors, enhanced | four-colour badge | 1 | 0.05 s, 5 paths, 84 anchors, 12 MB |
|
||||
| 16 Colors, enhanced | photo-like | 1 | 0.13 s, 178 paths, 20467 anchors, 31 MB |
|
||||
| 16 Colors, enhanced | four-colour badge | 1 | 0.05 s, 5 paths, 88 anchors, 12 MB |
|
||||
| Shades of Gray, enhanced | photo-like | 1 | 0.10 s, 81 paths, 6698 anchors, 40 MB |
|
||||
| Shades of Gray, enhanced | four-colour badge | 1 | 0.06 s, 10 paths, 623 anchors, 35 MB |
|
||||
| Black and White Logo, enhanced | photo-like | 1 | 0.05 s, 71 paths, 4933 anchors, 8 MB |
|
||||
| Black and White Logo, enhanced | four-colour badge | 1 | 0.02 s, 1 paths, 46 anchors, 6 MB |
|
||||
| Sketched Art, enhanced | photo-like | 1 | 0.04 s, 5 paths, 2873 anchors, 8 MB |
|
||||
| Sketched Art, enhanced | four-colour badge | 1 | 0.02 s, 2 paths, 37 anchors, 6 MB |
|
||||
| Silhouettes, enhanced | photo-like | 1 | 0.04 s, 2 paths, 556 anchors, 9 MB |
|
||||
| Silhouettes, enhanced | four-colour badge | 1 | 0.02 s, 1 paths, 8 anchors, 6 MB |
|
||||
| Line Art, enhanced | photo-like | 1 | 0.05 s, 54 paths, 4495 anchors, 8 MB |
|
||||
| Line Art, enhanced | four-colour badge | 1 | 0.02 s, 1 paths, 37 anchors, 6 MB |
|
||||
| Technical Drawing, enhanced | photo-like | 1 | 0.06 s, 221 paths, 6258 anchors, 8 MB |
|
||||
| Technical Drawing, enhanced | photo-like | 1 | 0.05 s, 221 paths, 6258 anchors, 8 MB |
|
||||
| Technical Drawing, enhanced | four-colour badge | 1 | 0.02 s, 1 paths, 46 anchors, 6 MB |
|
||||
| Outline, enhanced | photo-like | 1 | 0.05 s, 45 paths, 4110 anchors, 16 MB |
|
||||
| Outline, enhanced | four-colour badge | 1 | 0.03 s, 1 paths, 38 anchors, 11 MB |
|
||||
| Default | photo-like | 4 | 0.23 s, 48 paths, 14438 anchors, 49 MB |
|
||||
| Default | four-colour badge | 4 | 0.15 s, 3 paths, 72 anchors, 48 MB |
|
||||
| Auto Color | photo-like | 4 | 0.56 s, 1469 paths, 149389 anchors, 90 MB |
|
||||
| Auto Color | four-colour badge | 4 | 0.35 s, 5 paths, 92 anchors, 46 MB |
|
||||
| High Fidelity Photo | photo-like | 4 | 1.17 s, 4479 paths, 337884 anchors, 579 MB |
|
||||
| High Fidelity Photo | four-colour badge | 4 | 0.46 s, 6 paths, 200 anchors, 91 MB |
|
||||
| Low Fidelity Photo | photo-like | 4 | 1.55 s, 299 paths, 61601 anchors, 422 MB |
|
||||
| Low Fidelity Photo | four-colour badge | 4 | 0.32 s, 6 paths, 152 anchors, 97 MB |
|
||||
| 3 Colors | photo-like | 4 | 0.41 s, 20 paths, 8473 anchors, 72 MB |
|
||||
| 3 Colors | four-colour badge | 4 | 0.45 s, 4 paths, 122 anchors, 53 MB |
|
||||
| 6 Colors | photo-like | 4 | 4.40 s, 115 paths, 23295 anchors, 71 MB |
|
||||
| 6 Colors | four-colour badge | 4 | 0.49 s, 5 paths, 92 anchors, 50 MB |
|
||||
| 16 Colors | photo-like | 4 | 1.06 s, 353 paths, 52770 anchors, 108 MB |
|
||||
| 16 Colors | four-colour badge | 4 | 0.43 s, 5 paths, 96 anchors, 47 MB |
|
||||
| Shades of Gray | photo-like | 4 | 0.47 s, 137 paths, 18823 anchors, 162 MB |
|
||||
| Shades of Gray | four-colour badge | 4 | 0.43 s, 10 paths, 1256 anchors, 135 MB |
|
||||
| Black and White Logo | photo-like | 4 | 0.32 s, 208 paths, 13546 anchors, 32 MB |
|
||||
| Black and White Logo | four-colour badge | 4 | 0.14 s, 1 paths, 57 anchors, 24 MB |
|
||||
| Sketched Art | photo-like | 4 | 0.30 s, 9 paths, 5387 anchors, 32 MB |
|
||||
| Sketched Art | four-colour badge | 4 | 0.14 s, 2 paths, 196 anchors, 24 MB |
|
||||
| Silhouettes | photo-like | 4 | 0.26 s, 2 paths, 1465 anchors, 36 MB |
|
||||
| Silhouettes | four-colour badge | 4 | 0.16 s, 1 paths, 28 anchors, 24 MB |
|
||||
| Line Art | photo-like | 4 | 0.34 s, 127 paths, 11330 anchors, 32 MB |
|
||||
| Line Art | four-colour badge | 4 | 0.16 s, 1 paths, 42 anchors, 24 MB |
|
||||
| Technical Drawing | photo-like | 4 | 0.39 s, 931 paths, 20628 anchors, 32 MB |
|
||||
| Technical Drawing | four-colour badge | 4 | 0.20 s, 1 paths, 57 anchors, 24 MB |
|
||||
| Outline | photo-like | 4 | 0.56 s, 113 paths, 10815 anchors, 64 MB |
|
||||
| Outline | four-colour badge | 4 | 0.24 s, 1 paths, 42 anchors, 44 MB |
|
||||
| Flat Logo | photo-like | 4 | refused after 0.32 s (not flat art), 40 MB |
|
||||
| Flat Logo | four-colour badge | 4 | 2.19 s, 5 paths, 69 anchors, 146 MB |
|
||||
| Default with Shapes | photo-like | 4 | 0.64 s, 48 paths, 14438 anchors, 49 MB |
|
||||
| Default with Shapes | four-colour badge | 4 | 0.31 s, 3 paths, 72 anchors, 48 MB |
|
||||
| 6 Colors with Shapes | photo-like | 4 | 2.91 s, 115 paths, 23292 anchors, 98 MB |
|
||||
| 6 Colors with Shapes | four-colour badge | 4 | 0.42 s, 5 paths, 92 anchors, 49 MB |
|
||||
| 6 Colors with Auto Grouping | photo-like | 4 | 1.17 s, 115 paths, 23295 anchors, 88 MB |
|
||||
| 6 Colors with Auto Grouping | four-colour badge | 4 | 0.56 s, 5 paths, 92 anchors, 38 MB |
|
||||
| Shades of Gray with Auto Grouping | photo-like | 4 | 1.23 s, 137 paths, 18823 anchors, 178 MB |
|
||||
| Shades of Gray with Auto Grouping | four-colour badge | 4 | 0.72 s, 10 paths, 1256 anchors, 134 MB |
|
||||
| High Fidelity Photo with Auto Grouping | photo-like | 4 | 3.26 s, 4479 paths, 337884 anchors, 505 MB |
|
||||
| High Fidelity Photo with Auto Grouping | four-colour badge | 4 | 0.44 s, 6 paths, 200 anchors, 97 MB |
|
||||
| 6 Colors, no Gradients | photo-like | 4 | 1.07 s, 115 paths, 23295 anchors, 98 MB |
|
||||
| 6 Colors, no Gradients | four-colour badge | 4 | 0.43 s, 5 paths, 92 anchors, 48 MB |
|
||||
| 6 Colors with Gradients | photo-like | 4 | 3.07 s, 115 paths, 23295 anchors, 128 MB |
|
||||
| 6 Colors with Gradients | four-colour badge | 4 | 1.00 s, 5 paths, 92 anchors, 46 MB |
|
||||
| High Fidelity Photo, no Gradients | photo-like | 4 | 3.26 s, 4479 paths, 337884 anchors, 199 MB |
|
||||
| High Fidelity Photo, no Gradients | four-colour badge | 4 | 0.84 s, 6 paths, 200 anchors, 90 MB |
|
||||
| High Fidelity Photo with Gradients | photo-like | 4 | 6.06 s, 4479 paths, 337884 anchors, 244 MB |
|
||||
| High Fidelity Photo with Gradients | four-colour badge | 4 | 0.76 s, 6 paths, 200 anchors, 97 MB |
|
||||
| Default, enhanced | photo-like | 4 | 0.39 s, 48 paths, 14438 anchors, 49 MB |
|
||||
| Default, enhanced | four-colour badge | 4 | 0.20 s, 3 paths, 72 anchors, 48 MB |
|
||||
| Auto Color, enhanced | photo-like | 4 | 1.26 s, 1469 paths, 149374 anchors, 78 MB |
|
||||
| Auto Color, enhanced | four-colour badge | 4 | 0.41 s, 5 paths, 92 anchors, 49 MB |
|
||||
| High Fidelity Photo, enhanced | photo-like | 4 | 1.82 s, 4479 paths, 337884 anchors, 499 MB |
|
||||
| High Fidelity Photo, enhanced | four-colour badge | 4 | 0.42 s, 6 paths, 200 anchors, 97 MB |
|
||||
| Low Fidelity Photo, enhanced | photo-like | 4 | 1.27 s, 299 paths, 61598 anchors, 369 MB |
|
||||
| Low Fidelity Photo, enhanced | four-colour badge | 4 | 0.48 s, 6 paths, 128 anchors, 94 MB |
|
||||
| 3 Colors, enhanced | photo-like | 4 | 0.86 s, 20 paths, 8471 anchors, 71 MB |
|
||||
| 3 Colors, enhanced | four-colour badge | 4 | 0.37 s, 4 paths, 84 anchors, 51 MB |
|
||||
| 6 Colors, enhanced | photo-like | 4 | 0.70 s, 115 paths, 23292 anchors, 100 MB |
|
||||
| 6 Colors, enhanced | four-colour badge | 4 | 0.59 s, 5 paths, 92 anchors, 51 MB |
|
||||
| 16 Colors, enhanced | photo-like | 4 | 1.97 s, 353 paths, 52772 anchors, 64 MB |
|
||||
| 16 Colors, enhanced | four-colour badge | 4 | 0.37 s, 5 paths, 96 anchors, 47 MB |
|
||||
| Shades of Gray, enhanced | photo-like | 4 | 1.05 s, 137 paths, 18823 anchors, 178 MB |
|
||||
| Shades of Gray, enhanced | four-colour badge | 4 | 0.48 s, 10 paths, 1056 anchors, 119 MB |
|
||||
| Black and White Logo, enhanced | photo-like | 4 | 0.34 s, 208 paths, 13546 anchors, 32 MB |
|
||||
| Black and White Logo, enhanced | four-colour badge | 4 | 0.13 s, 1 paths, 57 anchors, 24 MB |
|
||||
| Sketched Art, enhanced | photo-like | 4 | 0.33 s, 9 paths, 5387 anchors, 32 MB |
|
||||
| Sketched Art, enhanced | four-colour badge | 4 | 0.16 s, 2 paths, 38 anchors, 24 MB |
|
||||
| Silhouettes, enhanced | photo-like | 4 | 0.35 s, 2 paths, 1465 anchors, 36 MB |
|
||||
| Silhouettes, enhanced | four-colour badge | 4 | 0.12 s, 1 paths, 8 anchors, 24 MB |
|
||||
| Line Art, enhanced | photo-like | 4 | 0.38 s, 127 paths, 11330 anchors, 32 MB |
|
||||
| Line Art, enhanced | four-colour badge | 4 | 0.15 s, 1 paths, 42 anchors, 24 MB |
|
||||
| Technical Drawing, enhanced | photo-like | 4 | 0.36 s, 931 paths, 20628 anchors, 32 MB |
|
||||
| Technical Drawing, enhanced | four-colour badge | 4 | 0.14 s, 1 paths, 57 anchors, 24 MB |
|
||||
| Outline, enhanced | photo-like | 4 | 0.48 s, 113 paths, 10815 anchors, 64 MB |
|
||||
| Outline, enhanced | four-colour badge | 4 | 0.21 s, 1 paths, 42 anchors, 44 MB |
|
||||
| Default | photo-like | 16 | 1.67 s, 127 paths, 34034 anchors, 199 MB |
|
||||
| Default | four-colour badge | 16 | 1.03 s, 3 paths, 88 anchors, 184 MB |
|
||||
| Auto Color | photo-like | 16 | 4.38 s, 5390 paths, 454670 anchors, 277 MB |
|
||||
| Auto Color | four-colour badge | 16 | 1.23 s, 5 paths, 112 anchors, 185 MB |
|
||||
| High Fidelity Photo | photo-like | 16 | 6.61 s, 31139 paths, 1192715 anchors, 880 MB |
|
||||
| High Fidelity Photo | four-colour badge | 16 | 1.73 s, 6 paths, 264 anchors, 263 MB |
|
||||
| Low Fidelity Photo | photo-like | 16 | 4.52 s, 2036 paths, 182778 anchors, 722 MB |
|
||||
| Low Fidelity Photo | four-colour badge | 16 | 1.42 s, 6 paths, 180 anchors, 263 MB |
|
||||
| 3 Colors | photo-like | 16 | 1.60 s, 76 paths, 23024 anchors, 290 MB |
|
||||
| 3 Colors | four-colour badge | 16 | 1.08 s, 4 paths, 190 anchors, 205 MB |
|
||||
| 6 Colors | photo-like | 16 | 1.38 s, 470 paths, 60831 anchors, 298 MB |
|
||||
| 6 Colors | four-colour badge | 16 | 1.30 s, 5 paths, 112 anchors, 185 MB |
|
||||
| 16 Colors | photo-like | 16 | 2.06 s, 1973 paths, 145642 anchors, 284 MB |
|
||||
| 16 Colors | four-colour badge | 16 | 1.73 s, 5 paths, 114 anchors, 184 MB |
|
||||
| Shades of Gray | photo-like | 16 | 2.27 s, 686 paths, 53654 anchors, 407 MB |
|
||||
| Shades of Gray | four-colour badge | 16 | 1.61 s, 9 paths, 2208 anchors, 270 MB |
|
||||
| Black and White Logo | photo-like | 16 | 1.19 s, 1128 paths, 45273 anchors, 129 MB |
|
||||
| Black and White Logo | four-colour badge | 16 | 0.48 s, 1 paths, 69 anchors, 88 MB |
|
||||
| Sketched Art | photo-like | 16 | 1.14 s, 15 paths, 11486 anchors, 128 MB |
|
||||
| Sketched Art | four-colour badge | 16 | 0.50 s, 2 paths, 361 anchors, 88 MB |
|
||||
| Silhouettes | photo-like | 16 | 1.54 s, 3 paths, 3350 anchors, 144 MB |
|
||||
| Silhouettes | four-colour badge | 16 | 0.54 s, 1 paths, 32 anchors, 95 MB |
|
||||
| Line Art | photo-like | 16 | 1.10 s, 713 paths, 37370 anchors, 129 MB |
|
||||
| Line Art | four-colour badge | 16 | 0.41 s, 1 paths, 49 anchors, 88 MB |
|
||||
| Technical Drawing | photo-like | 16 | 1.27 s, 4577 paths, 76559 anchors, 130 MB |
|
||||
| Technical Drawing | four-colour badge | 16 | 0.40 s, 1 paths, 69 anchors, 88 MB |
|
||||
| Outline | photo-like | 16 | 1.38 s, 632 paths, 34884 anchors, 256 MB |
|
||||
| Outline | four-colour badge | 16 | 1.03 s, 1 paths, 49 anchors, 176 MB |
|
||||
| Flat Logo | photo-like | 16 | refused after 0.32 s (not flat art), 40 MB |
|
||||
| Flat Logo | four-colour badge | 16 | 1.16 s, 5 paths, 67 anchors, 146 MB |
|
||||
| Default with Shapes | photo-like | 16 | 1.07 s, 127 paths, 34034 anchors, 199 MB |
|
||||
| Default with Shapes | four-colour badge | 16 | 0.56 s, 3 paths, 88 anchors, 184 MB |
|
||||
| 6 Colors with Shapes | photo-like | 16 | 1.43 s, 470 paths, 60823 anchors, 298 MB |
|
||||
| 6 Colors with Shapes | four-colour badge | 16 | 1.10 s, 5 paths, 112 anchors, 185 MB |
|
||||
| 6 Colors with Auto Grouping | photo-like | 16 | 1.76 s, 470 paths, 60831 anchors, 299 MB |
|
||||
| 6 Colors with Auto Grouping | four-colour badge | 16 | 1.15 s, 5 paths, 112 anchors, 185 MB |
|
||||
| Shades of Gray with Auto Grouping | photo-like | 16 | 2.53 s, 686 paths, 53654 anchors, 407 MB |
|
||||
| Shades of Gray with Auto Grouping | four-colour badge | 16 | 1.81 s, 9 paths, 2208 anchors, 270 MB |
|
||||
| High Fidelity Photo with Auto Grouping | photo-like | 16 | 9.24 s, 31139 paths, 1192715 anchors, 880 MB |
|
||||
| High Fidelity Photo with Auto Grouping | four-colour badge | 16 | 1.14 s, 6 paths, 264 anchors, 257 MB |
|
||||
| 6 Colors, no Gradients | photo-like | 16 | 1.31 s, 470 paths, 60831 anchors, 298 MB |
|
||||
| 6 Colors, no Gradients | four-colour badge | 16 | 1.68 s, 5 paths, 112 anchors, 189 MB |
|
||||
| 6 Colors with Gradients | photo-like | 16 | 5.44 s, 470 paths, 60831 anchors, 512 MB |
|
||||
| 6 Colors with Gradients | four-colour badge | 16 | 1.98 s, 5 paths, 112 anchors, 188 MB |
|
||||
| High Fidelity Photo, no Gradients | photo-like | 16 | 6.82 s, 31139 paths, 1192715 anchors, 864 MB |
|
||||
| Default | photo-like | 4 | 0.20 s, 48 paths, 14438 anchors, 49 MB |
|
||||
| Default | four-colour badge | 4 | 0.10 s, 3 paths, 72 anchors, 48 MB |
|
||||
| Auto Color | photo-like | 4 | 0.44 s, 1469 paths, 149389 anchors, 105 MB |
|
||||
| Auto Color | four-colour badge | 4 | 0.19 s, 5 paths, 92 anchors, 47 MB |
|
||||
| High Fidelity Photo | photo-like | 4 | 0.80 s, 4479 paths, 337884 anchors, 636 MB |
|
||||
| High Fidelity Photo | four-colour badge | 4 | 0.25 s, 6 paths, 200 anchors, 94 MB |
|
||||
| Low Fidelity Photo | photo-like | 4 | 0.40 s, 299 paths, 61601 anchors, 395 MB |
|
||||
| Low Fidelity Photo | four-colour badge | 4 | 0.41 s, 6 paths, 152 anchors, 97 MB |
|
||||
| 3 Colors | photo-like | 4 | 0.79 s, 20 paths, 8473 anchors, 73 MB |
|
||||
| 3 Colors | four-colour badge | 4 | 0.30 s, 4 paths, 122 anchors, 53 MB |
|
||||
| 6 Colors | photo-like | 4 | 0.34 s, 115 paths, 23295 anchors, 100 MB |
|
||||
| 6 Colors | four-colour badge | 4 | 0.22 s, 5 paths, 92 anchors, 46 MB |
|
||||
| 16 Colors | photo-like | 4 | 0.34 s, 353 paths, 52770 anchors, 129 MB |
|
||||
| 16 Colors | four-colour badge | 4 | 0.22 s, 5 paths, 96 anchors, 47 MB |
|
||||
| Shades of Gray | photo-like | 4 | 0.32 s, 137 paths, 18823 anchors, 156 MB |
|
||||
| Shades of Gray | four-colour badge | 4 | 0.28 s, 10 paths, 1256 anchors, 136 MB |
|
||||
| Black and White Logo | photo-like | 4 | 0.20 s, 208 paths, 13546 anchors, 32 MB |
|
||||
| Black and White Logo | four-colour badge | 4 | 0.08 s, 1 paths, 57 anchors, 24 MB |
|
||||
| Sketched Art | photo-like | 4 | 0.20 s, 9 paths, 5387 anchors, 32 MB |
|
||||
| Sketched Art | four-colour badge | 4 | 0.09 s, 2 paths, 196 anchors, 24 MB |
|
||||
| Silhouettes | photo-like | 4 | 0.21 s, 2 paths, 1465 anchors, 36 MB |
|
||||
| Silhouettes | four-colour badge | 4 | 0.08 s, 1 paths, 28 anchors, 24 MB |
|
||||
| Line Art | photo-like | 4 | 0.20 s, 127 paths, 11330 anchors, 32 MB |
|
||||
| Line Art | four-colour badge | 4 | 0.09 s, 1 paths, 42 anchors, 24 MB |
|
||||
| Technical Drawing | photo-like | 4 | 0.20 s, 931 paths, 20628 anchors, 32 MB |
|
||||
| Technical Drawing | four-colour badge | 4 | 0.08 s, 1 paths, 57 anchors, 24 MB |
|
||||
| Outline | photo-like | 4 | 0.25 s, 113 paths, 10815 anchors, 64 MB |
|
||||
| Outline | four-colour badge | 4 | 0.13 s, 1 paths, 42 anchors, 44 MB |
|
||||
| Flat Logo | photo-like | 4 | refused after 0.14 s (not flat art), 40 MB |
|
||||
| Flat Logo | four-colour badge | 4 | 0.67 s, 5 paths, 69 anchors, 146 MB |
|
||||
| Default with Shapes | photo-like | 4 | 0.22 s, 48 paths, 14438 anchors, 49 MB |
|
||||
| Default with Shapes | four-colour badge | 4 | 0.10 s, 3 paths, 72 anchors, 48 MB |
|
||||
| 6 Colors with Shapes | photo-like | 4 | 0.31 s, 115 paths, 23292 anchors, 100 MB |
|
||||
| 6 Colors with Shapes | four-colour badge | 4 | 0.19 s, 5 paths, 92 anchors, 46 MB |
|
||||
| 6 Colors with Auto Grouping | photo-like | 4 | 0.34 s, 115 paths, 23295 anchors, 100 MB |
|
||||
| 6 Colors with Auto Grouping | four-colour badge | 4 | 0.21 s, 5 paths, 92 anchors, 47 MB |
|
||||
| Shades of Gray with Auto Grouping | photo-like | 4 | 0.32 s, 137 paths, 18823 anchors, 155 MB |
|
||||
| Shades of Gray with Auto Grouping | four-colour badge | 4 | 0.30 s, 10 paths, 1256 anchors, 136 MB |
|
||||
| High Fidelity Photo with Auto Grouping | photo-like | 4 | 0.85 s, 4479 paths, 337884 anchors, 639 MB |
|
||||
| High Fidelity Photo with Auto Grouping | four-colour badge | 4 | 0.23 s, 6 paths, 200 anchors, 94 MB |
|
||||
| 6 Colors, no Gradients | photo-like | 4 | 0.27 s, 115 paths, 23295 anchors, 100 MB |
|
||||
| 6 Colors, no Gradients | four-colour badge | 4 | 0.19 s, 5 paths, 92 anchors, 46 MB |
|
||||
| 6 Colors with Gradients | photo-like | 4 | 0.78 s, 115 paths, 23295 anchors, 128 MB |
|
||||
| 6 Colors with Gradients | four-colour badge | 4 | 0.49 s, 5 paths, 92 anchors, 48 MB |
|
||||
| High Fidelity Photo, no Gradients | photo-like | 4 | 0.72 s, 4479 paths, 337884 anchors, 633 MB |
|
||||
| High Fidelity Photo, no Gradients | four-colour badge | 4 | 0.23 s, 6 paths, 200 anchors, 97 MB |
|
||||
| High Fidelity Photo with Gradients | photo-like | 4 | 1.06 s, 4479 paths, 337884 anchors, 642 MB |
|
||||
| High Fidelity Photo with Gradients | four-colour badge | 4 | 0.34 s, 6 paths, 200 anchors, 96 MB |
|
||||
| Default, enhanced | photo-like | 4 | 0.22 s, 48 paths, 14438 anchors, 49 MB |
|
||||
| Default, enhanced | four-colour badge | 4 | 0.10 s, 3 paths, 72 anchors, 48 MB |
|
||||
| Auto Color, enhanced | photo-like | 4 | 0.49 s, 1469 paths, 149374 anchors, 113 MB |
|
||||
| Auto Color, enhanced | four-colour badge | 4 | 0.18 s, 5 paths, 92 anchors, 46 MB |
|
||||
| High Fidelity Photo, enhanced | photo-like | 4 | 0.83 s, 4479 paths, 337884 anchors, 638 MB |
|
||||
| High Fidelity Photo, enhanced | four-colour badge | 4 | 0.23 s, 6 paths, 200 anchors, 93 MB |
|
||||
| Low Fidelity Photo, enhanced | photo-like | 4 | 0.39 s, 299 paths, 61598 anchors, 408 MB |
|
||||
| Low Fidelity Photo, enhanced | four-colour badge | 4 | 0.23 s, 6 paths, 128 anchors, 93 MB |
|
||||
| 3 Colors, enhanced | photo-like | 4 | 0.28 s, 20 paths, 8471 anchors, 73 MB |
|
||||
| 3 Colors, enhanced | four-colour badge | 4 | 0.19 s, 4 paths, 84 anchors, 51 MB |
|
||||
| 6 Colors, enhanced | photo-like | 4 | 0.30 s, 115 paths, 23292 anchors, 100 MB |
|
||||
| 6 Colors, enhanced | four-colour badge | 4 | 0.19 s, 5 paths, 92 anchors, 46 MB |
|
||||
| 16 Colors, enhanced | photo-like | 4 | 0.33 s, 353 paths, 52772 anchors, 126 MB |
|
||||
| 16 Colors, enhanced | four-colour badge | 4 | 0.19 s, 5 paths, 96 anchors, 46 MB |
|
||||
| Shades of Gray, enhanced | photo-like | 4 | 0.30 s, 137 paths, 18823 anchors, 163 MB |
|
||||
| Shades of Gray, enhanced | four-colour badge | 4 | 0.26 s, 10 paths, 1056 anchors, 137 MB |
|
||||
| Black and White Logo, enhanced | photo-like | 4 | 0.21 s, 208 paths, 13546 anchors, 32 MB |
|
||||
| Black and White Logo, enhanced | four-colour badge | 4 | 0.08 s, 1 paths, 57 anchors, 24 MB |
|
||||
| Sketched Art, enhanced | photo-like | 4 | 0.19 s, 9 paths, 5387 anchors, 32 MB |
|
||||
| Sketched Art, enhanced | four-colour badge | 4 | 0.08 s, 2 paths, 38 anchors, 24 MB |
|
||||
| Silhouettes, enhanced | photo-like | 4 | 0.22 s, 2 paths, 1465 anchors, 36 MB |
|
||||
| Silhouettes, enhanced | four-colour badge | 4 | 0.08 s, 1 paths, 8 anchors, 24 MB |
|
||||
| Line Art, enhanced | photo-like | 4 | 0.21 s, 127 paths, 11330 anchors, 32 MB |
|
||||
| Line Art, enhanced | four-colour badge | 4 | 0.09 s, 1 paths, 42 anchors, 24 MB |
|
||||
| Technical Drawing, enhanced | photo-like | 4 | 0.21 s, 931 paths, 20628 anchors, 32 MB |
|
||||
| Technical Drawing, enhanced | four-colour badge | 4 | 0.08 s, 1 paths, 57 anchors, 24 MB |
|
||||
| Outline, enhanced | photo-like | 4 | 0.24 s, 113 paths, 10815 anchors, 64 MB |
|
||||
| Outline, enhanced | four-colour badge | 4 | 0.12 s, 1 paths, 42 anchors, 44 MB |
|
||||
| Default | photo-like | 16 | 1.08 s, 127 paths, 34034 anchors, 199 MB |
|
||||
| Default | four-colour badge | 16 | 0.51 s, 3 paths, 88 anchors, 184 MB |
|
||||
| Auto Color | photo-like | 16 | 1.66 s, 5390 paths, 454670 anchors, 277 MB |
|
||||
| Auto Color | four-colour badge | 16 | 0.84 s, 5 paths, 112 anchors, 184 MB |
|
||||
| High Fidelity Photo | photo-like | 16 | 4.31 s, 31139 paths, 1192715 anchors, 880 MB |
|
||||
| High Fidelity Photo | four-colour badge | 16 | 1.10 s, 6 paths, 264 anchors, 257 MB |
|
||||
| Low Fidelity Photo | photo-like | 16 | 1.98 s, 2036 paths, 182778 anchors, 754 MB |
|
||||
| Low Fidelity Photo | four-colour badge | 16 | 1.09 s, 6 paths, 180 anchors, 257 MB |
|
||||
| 3 Colors | photo-like | 16 | 1.50 s, 76 paths, 23024 anchors, 290 MB |
|
||||
| 3 Colors | four-colour badge | 16 | 1.05 s, 4 paths, 190 anchors, 213 MB |
|
||||
| 6 Colors | photo-like | 16 | 1.57 s, 470 paths, 60831 anchors, 298 MB |
|
||||
| 6 Colors | four-colour badge | 16 | 1.07 s, 5 paths, 112 anchors, 184 MB |
|
||||
| 16 Colors | photo-like | 16 | 1.68 s, 1973 paths, 145642 anchors, 303 MB |
|
||||
| 16 Colors | four-colour badge | 16 | 1.09 s, 5 paths, 114 anchors, 188 MB |
|
||||
| Shades of Gray | photo-like | 16 | 2.48 s, 686 paths, 53654 anchors, 407 MB |
|
||||
| Shades of Gray | four-colour badge | 16 | 1.96 s, 9 paths, 2208 anchors, 270 MB |
|
||||
| Black and White Logo | photo-like | 16 | 1.37 s, 1128 paths, 45273 anchors, 129 MB |
|
||||
| Black and White Logo | four-colour badge | 16 | 0.47 s, 1 paths, 69 anchors, 88 MB |
|
||||
| Sketched Art | photo-like | 16 | 1.19 s, 15 paths, 11486 anchors, 128 MB |
|
||||
| Sketched Art | four-colour badge | 16 | 0.52 s, 2 paths, 361 anchors, 88 MB |
|
||||
| Silhouettes | photo-like | 16 | 1.45 s, 3 paths, 3350 anchors, 144 MB |
|
||||
| Silhouettes | four-colour badge | 16 | 0.48 s, 1 paths, 32 anchors, 95 MB |
|
||||
| Line Art | photo-like | 16 | 1.23 s, 713 paths, 37370 anchors, 129 MB |
|
||||
| Line Art | four-colour badge | 16 | 0.50 s, 1 paths, 49 anchors, 88 MB |
|
||||
| Technical Drawing | photo-like | 16 | 1.58 s, 4577 paths, 76559 anchors, 130 MB |
|
||||
| Technical Drawing | four-colour badge | 16 | 0.44 s, 1 paths, 69 anchors, 88 MB |
|
||||
| Outline | photo-like | 16 | 1.47 s, 632 paths, 34884 anchors, 256 MB |
|
||||
| Outline | four-colour badge | 16 | 0.75 s, 1 paths, 49 anchors, 176 MB |
|
||||
| Flat Logo | photo-like | 16 | refused after 0.20 s (not flat art), 40 MB |
|
||||
| Flat Logo | four-colour badge | 16 | 0.80 s, 5 paths, 67 anchors, 146 MB |
|
||||
| Default with Shapes | photo-like | 16 | 1.19 s, 127 paths, 34034 anchors, 199 MB |
|
||||
| Default with Shapes | four-colour badge | 16 | 0.54 s, 3 paths, 88 anchors, 184 MB |
|
||||
| 6 Colors with Shapes | photo-like | 16 | 1.40 s, 470 paths, 60823 anchors, 298 MB |
|
||||
| 6 Colors with Shapes | four-colour badge | 16 | 1.00 s, 5 paths, 112 anchors, 185 MB |
|
||||
| 6 Colors with Auto Grouping | photo-like | 16 | 1.64 s, 470 paths, 60831 anchors, 298 MB |
|
||||
| 6 Colors with Auto Grouping | four-colour badge | 16 | 1.04 s, 5 paths, 112 anchors, 185 MB |
|
||||
| Shades of Gray with Auto Grouping | photo-like | 16 | 2.19 s, 686 paths, 53654 anchors, 407 MB |
|
||||
| Shades of Gray with Auto Grouping | four-colour badge | 16 | 1.63 s, 9 paths, 2208 anchors, 270 MB |
|
||||
| High Fidelity Photo with Auto Grouping | photo-like | 16 | 9.72 s, 31139 paths, 1192715 anchors, 880 MB |
|
||||
| High Fidelity Photo with Auto Grouping | four-colour badge | 16 | 1.64 s, 6 paths, 264 anchors, 257 MB |
|
||||
| 6 Colors, no Gradients | photo-like | 16 | 1.66 s, 470 paths, 60831 anchors, 298 MB |
|
||||
| 6 Colors, no Gradients | four-colour badge | 16 | 1.13 s, 5 paths, 112 anchors, 184 MB |
|
||||
| 6 Colors with Gradients | photo-like | 16 | 3.71 s, 470 paths, 60831 anchors, 512 MB |
|
||||
| 6 Colors with Gradients | four-colour badge | 16 | 1.71 s, 5 paths, 112 anchors, 188 MB |
|
||||
| High Fidelity Photo, no Gradients | photo-like | 16 | 4.87 s, 31139 paths, 1192715 anchors, 880 MB |
|
||||
| High Fidelity Photo, no Gradients | four-colour badge | 16 | 1.50 s, 6 paths, 264 anchors, 257 MB |
|
||||
| High Fidelity Photo with Gradients | photo-like | 16 | 7.42 s, 31139 paths, 1192715 anchors, 880 MB |
|
||||
| High Fidelity Photo with Gradients | four-colour badge | 16 | 1.55 s, 6 paths, 264 anchors, 257 MB |
|
||||
| Default, enhanced | photo-like | 16 | 1.17 s, 127 paths, 34034 anchors, 199 MB |
|
||||
| High Fidelity Photo with Gradients | photo-like | 16 | 6.74 s, 31139 paths, 1192715 anchors, 880 MB |
|
||||
| High Fidelity Photo with Gradients | four-colour badge | 16 | 1.68 s, 6 paths, 264 anchors, 257 MB |
|
||||
| Default, enhanced | photo-like | 16 | 1.18 s, 127 paths, 34034 anchors, 199 MB |
|
||||
| Default, enhanced | four-colour badge | 16 | 0.57 s, 3 paths, 88 anchors, 184 MB |
|
||||
| Auto Color, enhanced | photo-like | 16 | 2.46 s, 5390 paths, 454626 anchors, 256 MB |
|
||||
| Auto Color, enhanced | four-colour badge | 16 | 1.50 s, 5 paths, 112 anchors, 185 MB |
|
||||
| High Fidelity Photo, enhanced | photo-like | 16 | 8.24 s, 31139 paths, 1192715 anchors, 880 MB |
|
||||
| High Fidelity Photo, enhanced | four-colour badge | 16 | 1.20 s, 6 paths, 264 anchors, 257 MB |
|
||||
| Low Fidelity Photo, enhanced | photo-like | 16 | 2.12 s, 2036 paths, 182770 anchors, 754 MB |
|
||||
| Low Fidelity Photo, enhanced | four-colour badge | 16 | 1.45 s, 6 paths, 149 anchors, 263 MB |
|
||||
| 3 Colors, enhanced | photo-like | 16 | 1.94 s, 76 paths, 23019 anchors, 290 MB |
|
||||
| 3 Colors, enhanced | four-colour badge | 16 | 1.34 s, 4 paths, 98 anchors, 205 MB |
|
||||
| 6 Colors, enhanced | photo-like | 16 | 2.03 s, 470 paths, 60823 anchors, 298 MB |
|
||||
| 6 Colors, enhanced | four-colour badge | 16 | 1.43 s, 5 paths, 112 anchors, 198 MB |
|
||||
| 16 Colors, enhanced | photo-like | 16 | 5.71 s, 1973 paths, 145623 anchors, 298 MB |
|
||||
| 16 Colors, enhanced | four-colour badge | 16 | 1.45 s, 5 paths, 114 anchors, 185 MB |
|
||||
| Shades of Gray, enhanced | photo-like | 16 | 3.00 s, 686 paths, 53648 anchors, 407 MB |
|
||||
| Shades of Gray, enhanced | four-colour badge | 16 | 1.60 s, 9 paths, 1989 anchors, 263 MB |
|
||||
| Black and White Logo, enhanced | photo-like | 16 | 1.23 s, 1128 paths, 45272 anchors, 129 MB |
|
||||
| Black and White Logo, enhanced | four-colour badge | 16 | 0.43 s, 1 paths, 69 anchors, 88 MB |
|
||||
| Sketched Art, enhanced | photo-like | 16 | 1.15 s, 15 paths, 11486 anchors, 128 MB |
|
||||
| Sketched Art, enhanced | four-colour badge | 16 | 0.40 s, 2 paths, 44 anchors, 88 MB |
|
||||
| Silhouettes, enhanced | photo-like | 16 | 1.40 s, 3 paths, 3350 anchors, 144 MB |
|
||||
| Silhouettes, enhanced | four-colour badge | 16 | 0.44 s, 1 paths, 8 anchors, 95 MB |
|
||||
| Line Art, enhanced | photo-like | 16 | 1.20 s, 713 paths, 37370 anchors, 129 MB |
|
||||
| Line Art, enhanced | four-colour badge | 16 | 0.41 s, 1 paths, 49 anchors, 88 MB |
|
||||
| Technical Drawing, enhanced | photo-like | 16 | 1.36 s, 4577 paths, 76558 anchors, 130 MB |
|
||||
| Technical Drawing, enhanced | four-colour badge | 16 | 0.39 s, 1 paths, 69 anchors, 88 MB |
|
||||
| Outline, enhanced | photo-like | 16 | 1.34 s, 632 paths, 34884 anchors, 256 MB |
|
||||
| Outline, enhanced | four-colour badge | 16 | 0.58 s, 1 paths, 49 anchors, 176 MB |
|
||||
| Auto Color, enhanced | photo-like | 16 | 2.31 s, 5390 paths, 454626 anchors, 283 MB |
|
||||
| Auto Color, enhanced | four-colour badge | 16 | 0.98 s, 5 paths, 112 anchors, 188 MB |
|
||||
| High Fidelity Photo, enhanced | photo-like | 16 | 9.09 s, 31139 paths, 1192715 anchors, 880 MB |
|
||||
| High Fidelity Photo, enhanced | four-colour badge | 16 | 1.47 s, 6 paths, 264 anchors, 263 MB |
|
||||
| Low Fidelity Photo, enhanced | photo-like | 16 | 2.70 s, 2036 paths, 182770 anchors, 754 MB |
|
||||
| Low Fidelity Photo, enhanced | four-colour badge | 16 | 1.60 s, 6 paths, 149 anchors, 257 MB |
|
||||
| 3 Colors, enhanced | photo-like | 16 | 1.82 s, 76 paths, 23019 anchors, 290 MB |
|
||||
| 3 Colors, enhanced | four-colour badge | 16 | 1.24 s, 4 paths, 98 anchors, 205 MB |
|
||||
| 6 Colors, enhanced | photo-like | 16 | 2.20 s, 470 paths, 60823 anchors, 298 MB |
|
||||
| 6 Colors, enhanced | four-colour badge | 16 | 2.19 s, 5 paths, 112 anchors, 185 MB |
|
||||
| 16 Colors, enhanced | photo-like | 16 | 2.03 s, 1973 paths, 145623 anchors, 303 MB |
|
||||
| 16 Colors, enhanced | four-colour badge | 16 | 1.13 s, 5 paths, 114 anchors, 188 MB |
|
||||
| Shades of Gray, enhanced | photo-like | 16 | 2.76 s, 686 paths, 53648 anchors, 407 MB |
|
||||
| Shades of Gray, enhanced | four-colour badge | 16 | 3.36 s, 9 paths, 1989 anchors, 270 MB |
|
||||
| Black and White Logo, enhanced | photo-like | 16 | 1.58 s, 1128 paths, 45272 anchors, 129 MB |
|
||||
| Black and White Logo, enhanced | four-colour badge | 16 | 0.59 s, 1 paths, 69 anchors, 88 MB |
|
||||
| Sketched Art, enhanced | photo-like | 16 | 1.52 s, 15 paths, 11486 anchors, 128 MB |
|
||||
| Sketched Art, enhanced | four-colour badge | 16 | 0.54 s, 2 paths, 44 anchors, 88 MB |
|
||||
| Silhouettes, enhanced | photo-like | 16 | 1.82 s, 3 paths, 3350 anchors, 144 MB |
|
||||
| Silhouettes, enhanced | four-colour badge | 16 | 0.56 s, 1 paths, 8 anchors, 95 MB |
|
||||
| Line Art, enhanced | photo-like | 16 | 1.43 s, 713 paths, 37370 anchors, 129 MB |
|
||||
| Line Art, enhanced | four-colour badge | 16 | 0.58 s, 1 paths, 49 anchors, 88 MB |
|
||||
| Technical Drawing, enhanced | photo-like | 16 | 1.76 s, 4577 paths, 76558 anchors, 130 MB |
|
||||
| Technical Drawing, enhanced | four-colour badge | 16 | 0.52 s, 1 paths, 69 anchors, 88 MB |
|
||||
| Outline, enhanced | photo-like | 16 | 1.64 s, 632 paths, 34884 anchors, 256 MB |
|
||||
| Outline, enhanced | four-colour badge | 16 | 0.73 s, 1 paths, 49 anchors, 176 MB |
|
||||
|
||||
## Revision history
|
||||
|
||||
| date | change |
|
||||
|:--|:--|
|
||||
| 2026-10-14 | Gradients: colours going out from a point are a radial gradient (not merged: beyond the documented option, which is for linear gradients; waits for the owner); a radial-gradient input with known middle and stops (found in all 7 drawings; 6 Colors on it, clean: 8 paths and ΔE 2.69 down to one path and 0.25) |
|
||||
| 2026-10-14 | Gradients: a gradient that noise or a soft rim broke into pieces is found in its largest piece and grown over the rest (blurred and noisy linear gradients: 3 to 11 paths beside the gradient down to 0.5 with 6 Colors, 24 to 56 down to 0.5 to 1.5 with High Fidelity Photo) |
|
||||
| 2026-10-14 | Enhanced versions of the presets (Auto Grouping, and Shapes in all but High Fidelity Photo; Flat Logo has none), each measured beside its preset; a hole that one colour fills is the same shape as what fills it, rectangles are sized by where their sides lie, and a group keeps its paths in the order they were traced in (grouped, a letter with a counter was painted with a light seam: Default with Auto Grouping, edge ΔE 10.24 to 9.88) |
|
||||
| 2026-10-14 | Create: Strokes: a line whose ink is cut square at its ends gets square caps, and a wide line whose skeleton hooks towards a corner of its end ends on the line it was following (Outline: largest distance 2.94 px to 0.88; aliased lines 0.88 to 0.81) |
|
||||
|
||||
Reference in new issue
Block a user