-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add plugin simplifyPaths to reduce the number of points in paths and polylines while maintaining approximately the same overall shape #1698
base: main
Are you sure you want to change the base?
Conversation
1bca2ff
to
b97526b
Compare
Thanks for reviewing @jguddas! I resolved that suggestion and rebased onto main |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
this would be cool to try out, any ideas if this will reach main? |
b97526b
to
ec0f227
Compare
I resolved the merge conflicts again. Let's see where this goes. |
Otherwise, it will strip out the move commands and make paths be continuous even tho they shouldn't be. Co-authored-by: Jakob Guddas <[email protected]>
Hey @MarcelRobitaille I ended up borrowing your code and rewriting it a little. I couldn't get your one working in typescript. The plugin file was this (I know, really rough, I have no idea how plugins works. I hard coded values instead of supporting params because I couldn't figure that out): // contents of simplifyPaths.ts
import paper from 'paper-jsdom'
paper.setup();
const processNode = node => {
if(node?.attributes?.d){
var path = new paper.Path({pathData: node.attributes.d })
path.closePath();
path.flatten(0.5)
path.simplify(0.001);
var svg = path.exportSVG({asString: true})
var matches = svg.match(/d="([^"]+)"/)
if(matches){
node.attributes.d = matches[1]
}
}
node.children.forEach(child => {
processNode(child)
})
}
const fn = () => ({
root: {
enter: node => {
processNode(node)
}
}
})
export default {
name,
fn
}; then I used it like so: import {optimize} from "svgo";
import simplifyPaths from "./simplifyPaths.ts";
const result = optimize(originalSvgString, {
multipass: true,
plugins: [
'preset-default',
simplifyPaths
]
});
const optimizedSvgString = result.data; however, in the end I found it was twice as fast to optimise the SVG outside of the svgo pipeline, so now I'm using paper.js as a separate post processing script after svgo does its thing. |
Fixes #411
This pull request adds a new plugin that can be used to approximate paths and polylines to further optimize SVGs. This takes advantage of Paper.js, as suggested by @jeromew.
I not find a construct in Paper.js to represent
<polyline>
s, but I found a way to convert these into paths. Then, the samepath.simplify()
method can be used.The available parameters are as follows:
This plugin can have big savings even if
path.simplify()
is not usesimplifyThreshold = null
. This is because<path>
is often more compact than<polyline>
and because Paper.js prints thed
attribute very compactly.With this plugin, I was able to get one of my personal SVGs from 188KiB down to 40KiB. I also added some tests in the
test/plugins
folder.I did notice that this plugin must come before
mergePaths
. Even the following code with totally mess up an SVG if it comes aftermergePaths
. All this code is doing is parsing a<path>
'sd
attribute with Paper.js, and printing it in Paper.js's format. It seems like that format is not compatible withmergePaths
. To be honest, I'm not entirely sure what's going on here.This plugin also depends on
paper
andpaper-jsdom
. I'm not sure how to handle that either.