diff --git a/docs/03-plugins/convert-path-data.mdx b/docs/03-plugins/convert-path-data.mdx index 66848688f..1f1dc3cdd 100644 --- a/docs/03-plugins/convert-path-data.mdx +++ b/docs/03-plugins/convert-path-data.mdx @@ -15,6 +15,9 @@ svgo: straightCurves: description: If to convert curve commands that are effectively straight lines to line commands. default: true + convertToQ: + description: If to convert cubic beziers to quadratic beziers when they effectively are. + default: true lineShorthands: description: If to convert regular lines to an explicit horizontal or vertical line where possible. default: true diff --git a/plugins/convertPathData.js b/plugins/convertPathData.js index 0ee7824ea..102cde4f1 100644 --- a/plugins/convertPathData.js +++ b/plugins/convertPathData.js @@ -45,6 +45,7 @@ let arcTolerance; * tolerance: number, * }, * straightCurves: boolean, + * convertToQ: boolean, * lineShorthands: boolean, * convertToZ: boolean, * curveSmoothShorthands: boolean, @@ -96,6 +97,7 @@ exports.fn = (root, params) => { tolerance: 0.5, // percentage of radius }, straightCurves = true, + convertToQ = true, lineShorthands = true, convertToZ = true, curveSmoothShorthands = true, @@ -119,6 +121,7 @@ exports.fn = (root, params) => { applyTransformsStroked, makeArcs, straightCurves, + convertToQ, lineShorthands, convertToZ, curveSmoothShorthands, @@ -697,6 +700,44 @@ function filters( } } + // degree-lower c to q when possible + // m 0 12 C 4 4 8 4 12 12 → M 0 12 Q 6 0 12 12 + if (params.convertToQ && command == 'c') { + const x1 = + // @ts-ignore + 0.75 * (item.base[0] + data[0]) - 0.25 * item.base[0]; + const x2 = + // @ts-ignore + 0.75 * (item.base[0] + data[2]) - 0.25 * (item.base[0] + data[4]); + if (Math.abs(x1 - x2) < error * 2) { + const y1 = + // @ts-ignore + 0.75 * (item.base[1] + data[1]) - 0.25 * item.base[1]; + const y2 = + // @ts-ignore + 0.75 * (item.base[1] + data[3]) - 0.25 * (item.base[1] + data[5]); + if (Math.abs(y1 - y2) < error * 2) { + const newData = data.slice(); + newData.splice( + 0, + 4, + // @ts-ignore + x1 + x2 - item.base[0], + // @ts-ignore + y1 + y2 - item.base[1], + ); + roundData(newData); + const originalLength = cleanupOutData(data, params).length, + newLength = cleanupOutData(newData, params).length; + if (newLength < originalLength) { + command = 'q'; + data = newData; + if (next && next.command == 's') makeLonghand(next, data); // fix up next curve + } + } + } + } + // horizontal and vertical line shorthands // l 50 0 → h 50 // l 0 50 → v 50 diff --git a/plugins/plugins-types.d.ts b/plugins/plugins-types.d.ts index 1d4740e7b..e94e71378 100644 --- a/plugins/plugins-types.d.ts +++ b/plugins/plugins-types.d.ts @@ -41,6 +41,7 @@ type DefaultPlugins = { tolerance: number; }; straightCurves?: boolean; + convertToQ?: boolean; lineShorthands?: boolean; convertToZ?: boolean; curveSmoothShorthands?: boolean; diff --git a/test/plugins/convertPathData.16.svg b/test/plugins/convertPathData.16.svg index 4fcee12fa..29302d876 100644 --- a/test/plugins/convertPathData.16.svg +++ b/test/plugins/convertPathData.16.svg @@ -7,7 +7,7 @@ - + @@@ diff --git a/test/plugins/convertPathData.35.svg b/test/plugins/convertPathData.35.svg new file mode 100644 index 000000000..432c2878c --- /dev/null +++ b/test/plugins/convertPathData.35.svg @@ -0,0 +1,13 @@ +Should convert C to Q + +=== + + + + + +@@@ + + + +