vectorizer.ai

vectorizer.ai free download

当前为 2024-06-16 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name vectorizer.ai
  3. // @version 0.0.3
  4. // @description vectorizer.ai free download
  5. // @icon https://d1j8j7mb8gx2ao.cloudfront.net/p/assets/logos/vectorizer-ai-logo_1c2b7a3ae82c1def79ab4c0e9cc83bcc.svg
  6.  
  7. // @author ml98
  8. // @namespace http://tampermonkey.net/
  9. // @license MIT
  10.  
  11. // @match https://vectorizer.ai/images/*
  12. // @grant none
  13. // @run-at document-start
  14. // ==/UserScript==
  15.  
  16. let state = 0;
  17. let data = { width: 1, height: 1, curves: [], style: {} };
  18.  
  19. function proxy_functions(object, apply = (f, _this, args) => f.apply(_this, args)) {
  20. const descriptors = Object.getOwnPropertyDescriptors(object);
  21. Object.keys(descriptors).filter(
  22. (name) => descriptors[name].value instanceof Function
  23. ).forEach((f) => {
  24. object[f] = new Proxy(object[f], { apply });
  25. });
  26. }
  27.  
  28. function F(strings, ...values) {
  29. return strings[0] + values.map(
  30. (value, i) => value.toFixed(2).replace(/\.?0+$/,'') + strings[i+1]
  31. ).join('');
  32. }
  33.  
  34. function path2svg(name, args) {
  35. switch (name) {
  36. case "moveTo": {
  37. let [x, y] = args;
  38. return F`M ${x} ${y}`;
  39. }
  40. case "lineTo": {
  41. let [x, y] = args;
  42. return F`L ${x} ${y}`;
  43. }
  44. case "ellipse": {
  45. let [cx, cy, rx, ry, rotation, theta1, theta2, ccw] = args;
  46. let dx = rx * Math.cos(theta2), dy = ry * Math.sin(theta2);
  47. let c = Math.cos(rotation), s = Math.sin(rotation);
  48. let ex= cx + c * dx - s * dy, ey = cy + s * dx + c * dy;
  49. let angle = rotation * (180 / Math.PI);
  50. let large_arc = (theta2 - theta1) % (2 * Math.PI) > Math.PI ? 1 : 0;
  51. let sweep = ccw ? 0 : 1;
  52. return F`A ${rx} ${ry} ${angle} ${large_arc} ${sweep} ${ex} ${ey}`;
  53. }
  54. case "bezierCurveTo": {
  55. let [cp1x, cp1y, cp2x, cp2y, x, y] = args;
  56. return F`C ${cp1x} ${cp1y} ${cp2x} ${cp2y} ${x} ${y}`;
  57. }
  58. case "quadraticCurveTo": {
  59. let [cpx, cpy, x, y] = args;
  60. return F`Q ${cpx} ${cpy} ${x} ${y}`;
  61. }
  62. case "closePath": {
  63. return `Z`;
  64. }
  65. default: {
  66. // throw new Error("unimplemented path", name);
  67. return `ERROR`;
  68. }
  69. }
  70. }
  71.  
  72. proxy_functions(Path2D.prototype, (f, _this, args) => {
  73. _this.s ??= "";
  74. // _this.s += `${f.name}[${args.toString()}] `;
  75. _this.s += path2svg(f.name, args);
  76. return f.apply(_this, args);
  77. });
  78.  
  79. proxy_functions(CanvasRenderingContext2D.prototype, (f, _this, args) => {
  80. if(_this.canvas.id) {
  81. // width, height
  82. }
  83. if(!_this.canvas.id) {
  84. switch(f.name) {
  85. case 'drawImage':
  86. if(state == 0) {
  87. data.width = args[3];
  88. data.height = args[4];
  89. state = 1;
  90. }
  91. break;
  92. case 'clip':
  93. if(state == 1) {
  94. // console.log(_this.lineWidth, _this.lineJoin);
  95. data.curves = [];
  96. data.style = { lineWidth: _this.lineWidth, lineJoin: _this.lineJoin };
  97. state = 2;
  98. }
  99. break;
  100. case 'fill':
  101. if(state == 2) {
  102. // console.log(f.name, _this.fillStyle, args[0].s);
  103. if(!args[0].s) {
  104. state = 1;
  105. }
  106. data.curves.push({fill: _this.fillStyle, d: args[0].s});
  107. }
  108. break;
  109. case 'stroke':
  110. if(state == 2) {
  111. // console.log(f.name, _this.strokeStyle, args[0].s);
  112. if(!args[0].s) {
  113. state = 1;
  114. }
  115. data.curves.push({stroke: _this.strokeStyle, d: args[0].s});
  116. }
  117. break;
  118. case 'restore':
  119. if(state == 2) {
  120. state = 3;
  121. console.log(data);
  122. create_download_button();
  123. }
  124. break;
  125. }
  126. }
  127. return f.apply(_this, args);
  128. });
  129.  
  130. function svg_element(tag, attributes) {
  131. const element = document.createElementNS('http://www.w3.org/2000/svg', tag);
  132. for (let attr in attributes) {
  133. element.setAttribute(attr, attributes[attr]);
  134. }
  135. return element;
  136. }
  137.  
  138. function create_svg() {
  139. const { width, height, curves, style } = data;
  140. const svg = svg_element('svg', {
  141. xmlns: 'http://www.w3.org/2000/svg',
  142. viewBox: `0 0 ${width} ${height}`,
  143. width,
  144. height,
  145. });
  146.  
  147. curves.forEach(({d, fill, stroke}) => {
  148. const path = fill ? {d, fill} : {d, stroke};
  149. const element = svg_element('path', path);
  150. svg.appendChild(element);
  151. });
  152.  
  153. return svg;
  154. }
  155.  
  156. function create_download_button() {
  157. const svg = create_svg();
  158. const content = new XMLSerializer().serializeToString(svg);
  159. const type = 'image/svg+xml';
  160. const url = URL.createObjectURL(new Blob([content], {type}));
  161.  
  162. const button = document.querySelector('#App-DownloadLink');
  163. const a = button.cloneNode(true);
  164. button.before(a);
  165. a.style.borderRadius = 0;
  166. a.querySelector('.showPaid').style.display = 'none';
  167. a.querySelector('.showFree').style.display = 'inline';
  168. a.href = url;
  169. a.target = '_blank';
  170. a.download = 'result.svg';
  171. }