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 54c006368..de7b357f5 100644
--- a/plugins/convertPathData.js
+++ b/plugins/convertPathData.js
@@ -35,6 +35,7 @@ let arcTolerance;
* tolerance: number,
* },
* straightCurves: boolean,
+ * convertToQ: boolean,
* lineShorthands: boolean,
* convertToZ: boolean,
* curveSmoothShorthands: boolean,
@@ -86,6 +87,7 @@ exports.fn = (root, params) => {
tolerance: 0.5, // percentage of radius
},
straightCurves = true,
+ convertToQ = true,
lineShorthands = true,
convertToZ = true,
curveSmoothShorthands = true,
@@ -109,6 +111,7 @@ exports.fn = (root, params) => {
applyTransformsStroked,
makeArcs,
straightCurves,
+ convertToQ,
lineShorthands,
convertToZ,
curveSmoothShorthands,
@@ -674,6 +677,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
+
+===
+
+
+
+@@@
+
+