svger-cli 3.1.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +399 -0
- package/README.md +448 -37
- package/SECURITY.md +3 -3
- package/assets/svges/500px.svg +3 -0
- package/assets/svges/adobe.svg +3 -0
- package/assets/svges/adonis.svg +3 -0
- package/assets/svges/aeroplane-1.svg +3 -0
- package/assets/svges/agenda.svg +3 -0
- package/assets/svges/airbnb.svg +3 -0
- package/assets/svges/airtable.svg +3 -0
- package/assets/svges/alarm-1.svg +7 -0
- package/assets/svges/align-text-center.svg +6 -0
- package/assets/svges/align-text-left.svg +6 -0
- package/assets/svges/align-text-right.svg +6 -0
- package/assets/svges/alpinejs.svg +4 -0
- package/assets/svges/amazon-original.svg +5 -0
- package/assets/svges/amazon-pay.svg +7 -0
- package/assets/svges/amazon.svg +10 -0
- package/assets/svges/ambulance-1.svg +4 -0
- package/assets/svges/amd.svg +3 -0
- package/assets/svges/amex.svg +4 -0
- package/assets/svges/anchor.svg +3 -0
- package/assets/svges/android-old.svg +3 -0
- package/assets/svges/android.svg +3 -0
- package/assets/svges/angellist.svg +3 -0
- package/assets/svges/angle-double-down.svg +4 -0
- package/assets/svges/angle-double-left.svg +4 -0
- package/assets/svges/angle-double-right.svg +4 -0
- package/assets/svges/angle-double-up.svg +4 -0
- package/assets/svges/angular.svg +3 -0
- package/assets/svges/app-store.svg +3 -0
- package/assets/svges/apple-brand.svg +3 -0
- package/assets/svges/apple-music-alt.svg +3 -0
- package/assets/svges/apple-music.svg +3 -0
- package/assets/svges/apple-pay.svg +3 -0
- package/assets/svges/arc-browser.svg +6 -0
- package/assets/svges/arrow-all-direction.svg +6 -0
- package/assets/svges/arrow-angular-top-left.svg +3 -0
- package/assets/svges/arrow-angular-top-right.svg +3 -0
- package/assets/svges/arrow-both-direction-horizontal-1.svg +3 -0
- package/assets/svges/arrow-both-direction-vertical-1.svg +3 -0
- package/assets/svges/arrow-downward.svg +3 -0
- package/assets/svges/arrow-left-circle.svg +4 -0
- package/assets/svges/arrow-left.svg +3 -0
- package/assets/svges/arrow-right-circle.svg +4 -0
- package/assets/svges/arrow-right.svg +3 -0
- package/assets/svges/arrow-upward.svg +3 -0
- package/assets/svges/asana.svg +3 -0
- package/assets/svges/astro.svg +4 -0
- package/assets/svges/atlassian.svg +3 -0
- package/assets/svges/audi-alt.svg +3 -0
- package/assets/svges/audi.svg +3 -0
- package/assets/svges/aws.svg +3 -0
- package/assets/svges/azure.svg +3 -0
- package/assets/svges/badge-decagram-percent.svg +6 -0
- package/assets/svges/balloons.svg +3 -0
- package/assets/svges/ban-2.svg +3 -0
- package/assets/svges/bar-chart-4.svg +6 -0
- package/assets/svges/bar-chart-dollar.svg +6 -0
- package/assets/svges/basket-shopping-3.svg +5 -0
- package/assets/svges/beat.svg +3 -0
- package/assets/svges/behance.svg +5 -0
- package/assets/svges/bell-1.svg +3 -0
- package/assets/svges/bike.svg +6 -0
- package/assets/svges/bing.svg +5 -0
- package/assets/svges/bitbucket.svg +5 -0
- package/assets/svges/bitcoin.svg +5 -0
- package/assets/svges/bittorrent.svg +6 -0
- package/assets/svges/blogger-alt.svg +3 -0
- package/assets/svges/blogger.svg +3 -0
- package/assets/svges/bluetooth-logo.svg +3 -0
- package/assets/svges/bluetooth.svg +3 -0
- package/assets/svges/bmw.svg +7 -0
- package/assets/svges/board-writing-3.svg +3 -0
- package/assets/svges/bold.svg +3 -0
- package/assets/svges/bolt-2.svg +3 -0
- package/assets/svges/bolt-3.svg +3 -0
- package/assets/svges/book-1.svg +4 -0
- package/assets/svges/bookmark-1.svg +3 -0
- package/assets/svges/bookmark-circle.svg +4 -0
- package/assets/svges/books-2.svg +3 -0
- package/assets/svges/bootstrap-5-square.svg +3 -0
- package/assets/svges/bootstrap-5.svg +3 -0
- package/assets/svges/box-archive-1.svg +4 -0
- package/assets/svges/box-closed.svg +3 -0
- package/assets/svges/box-gift-1.svg +3 -0
- package/assets/svges/brave.svg +3 -0
- package/assets/svges/bricks.svg +3 -0
- package/assets/svges/bridge-3.svg +3 -0
- package/assets/svges/briefcase-1.svg +3 -0
- package/assets/svges/briefcase-2.svg +3 -0
- package/assets/svges/briefcase-plus-1.svg +4 -0
- package/assets/svges/brush-1-rotated.svg +3 -0
- package/assets/svges/brush-2.svg +3 -0
- package/assets/svges/btc.svg +3 -0
- package/assets/svges/bug-1.svg +3 -0
- package/assets/svges/buildings-1.svg +5 -0
- package/assets/svges/bulb-2.svg +3 -0
- package/assets/svges/bulb-4.svg +9 -0
- package/assets/svges/burger-1.svg +3 -0
- package/assets/svges/burger-drink.svg +4 -0
- package/assets/svges/bus-1.svg +5 -0
- package/assets/svges/busket-ball.svg +3 -0
- package/assets/svges/cake-1.svg +3 -0
- package/assets/svges/calculator-1.svg +8 -0
- package/assets/svges/calculator-2.svg +13 -0
- package/assets/svges/calendar-days.svg +9 -0
- package/assets/svges/camera-1.svg +4 -0
- package/assets/svges/camera-movie-1.svg +3 -0
- package/assets/svges/candy-cane-2.svg +3 -0
- package/assets/svges/candy-round-1.svg +3 -0
- package/assets/svges/canva.svg +3 -0
- package/assets/svges/capsule-1.svg +3 -0
- package/assets/svges/car-2.svg +5 -0
- package/assets/svges/car-4.svg +3 -0
- package/assets/svges/car-6.svg +5 -0
- package/assets/svges/caravan-1.svg +3 -0
- package/assets/svges/cart-1.svg +5 -0
- package/assets/svges/cart-2.svg +5 -0
- package/assets/svges/cash-app.svg +3 -0
- package/assets/svges/certificate-badge-1.svg +6 -0
- package/assets/svges/chat-bubble-2.svg +5 -0
- package/assets/svges/check-circle-1.svg +4 -0
- package/assets/svges/check-square-2.svg +4 -0
- package/assets/svges/check.svg +3 -0
- package/assets/svges/chevron-down-circle.svg +4 -0
- package/assets/svges/chevron-down.svg +3 -0
- package/assets/svges/chevron-left-circle.svg +4 -0
- package/assets/svges/chevron-left.svg +3 -0
- package/assets/svges/chevron-right-circle.svg +4 -0
- package/assets/svges/chevron-up-circle.svg +4 -0
- package/assets/svges/chevron-up.svg +3 -0
- package/assets/svges/chrome.svg +6 -0
- package/assets/svges/chromecast.svg +3 -0
- package/assets/svges/cisco.svg +3 -0
- package/assets/svges/claude.svg +3 -0
- package/assets/svges/clickup.svg +4 -0
- package/assets/svges/clipboard.svg +3 -0
- package/assets/svges/cloud-2.svg +3 -0
- package/assets/svges/cloud-bolt-1.svg +4 -0
- package/assets/svges/cloud-bolt-2.svg +4 -0
- package/assets/svges/cloud-check-circle.svg +5 -0
- package/assets/svges/cloud-download.svg +5 -0
- package/assets/svges/cloud-iot-2.svg +3 -0
- package/assets/svges/cloud-rain.svg +6 -0
- package/assets/svges/cloud-refresh-clockwise.svg +5 -0
- package/assets/svges/cloud-sun.svg +9 -0
- package/assets/svges/cloud-upload.svg +5 -0
- package/assets/svges/cloudflare.svg +3 -0
- package/assets/svges/code-1.svg +5 -0
- package/assets/svges/code-s.svg +5 -0
- package/assets/svges/codepen.svg +3 -0
- package/assets/svges/coffee-cup-2.svg +6 -0
- package/assets/svges/coinbase.svg +10 -0
- package/assets/svges/colour-palette-3.svg +7 -0
- package/assets/svges/comment-1-share.svg +4 -0
- package/assets/svges/comment-1-text.svg +5 -0
- package/assets/svges/comment-1.svg +3 -0
- package/assets/svges/compass-drafting-2.svg +3 -0
- package/assets/svges/connectdevelop.svg +3 -0
- package/assets/svges/copilot.svg +8 -0
- package/assets/svges/coral.svg +3 -0
- package/assets/svges/cpanel.svg +3 -0
- package/assets/svges/crane-4.svg +3 -0
- package/assets/svges/creative-commons.svg +4 -0
- package/assets/svges/credit-card-multiple.svg +3 -0
- package/assets/svges/crop-2.svg +3 -0
- package/assets/svges/crown-3.svg +3 -0
- package/assets/svges/css3.svg +3 -0
- package/assets/svges/dashboard-square-1.svg +6 -0
- package/assets/svges/database-2.svg +3 -0
- package/assets/svges/deno.svg +4 -0
- package/assets/svges/dev.svg +3 -0
- package/assets/svges/dialogflow.svg +4 -0
- package/assets/svges/diamonds-1.svg +3 -0
- package/assets/svges/diamonds-2.svg +3 -0
- package/assets/svges/digitalocean.svg +3 -0
- package/assets/svges/diners-club.svg +38 -0
- package/assets/svges/direction-ltr.svg +4 -0
- package/assets/svges/direction-rtl.svg +4 -0
- package/assets/svges/discord-chat.svg +5 -0
- package/assets/svges/discord.svg +3 -0
- package/assets/svges/discover.svg +3 -0
- package/assets/svges/docker.svg +3 -0
- package/assets/svges/dollar-circle.svg +4 -0
- package/assets/svges/dollar.svg +3 -0
- package/assets/svges/double-quotes-end-1.svg +4 -0
- package/assets/svges/download-1.svg +4 -0
- package/assets/svges/download-circle-1.svg +4 -0
- package/assets/svges/dribbble-symbol.svg +3 -0
- package/assets/svges/dribbble.svg +3 -0
- package/assets/svges/drizzle.svg +6 -0
- package/assets/svges/dropbox.svg +7 -0
- package/assets/svges/drupal.svg +3 -0
- package/assets/svges/dumbbell-1.svg +3 -0
- package/assets/svges/edge.svg +3 -0
- package/assets/svges/emoji-expressionless-flat-eyes.svg +6 -0
- package/assets/svges/emoji-expressionless.svg +6 -0
- package/assets/svges/emoji-grin.svg +6 -0
- package/assets/svges/emoji-sad.svg +6 -0
- package/assets/svges/emoji-smile-side.svg +6 -0
- package/assets/svges/emoji-smile-sunglass.svg +5 -0
- package/assets/svges/emoji-smile-tongue.svg +3 -0
- package/assets/svges/emoji-smile.svg +6 -0
- package/assets/svges/enter-down.svg +4 -0
- package/assets/svges/enter.svg +4 -0
- package/assets/svges/envato.svg +4 -0
- package/assets/svges/envelope-1.svg +3 -0
- package/assets/svges/eraser-1.svg +4 -0
- package/assets/svges/ethereum-logo.svg +4 -0
- package/assets/svges/euro.svg +3 -0
- package/assets/svges/exit-up.svg +4 -0
- package/assets/svges/exit.svg +4 -0
- package/assets/svges/expand-arrow-1.svg +3 -0
- package/assets/svges/expand-square-4.svg +6 -0
- package/assets/svges/expressjs.svg +4 -0
- package/assets/svges/eye.svg +4 -0
- package/assets/svges/facebook-messenger.svg +3 -0
- package/assets/svges/facebook-rounded.svg +4 -0
- package/assets/svges/facebook-square.svg +3 -0
- package/assets/svges/facebook.svg +3 -0
- package/assets/svges/facetime.svg +3 -0
- package/assets/svges/figma.svg +3 -0
- package/assets/svges/file-format-zip.svg +4 -0
- package/assets/svges/file-multiple.svg +4 -0
- package/assets/svges/file-pencil.svg +4 -0
- package/assets/svges/file-plus-circle.svg +5 -0
- package/assets/svges/file-question.svg +5 -0
- package/assets/svges/file-xmark.svg +4 -0
- package/assets/svges/firebase.svg +3 -0
- package/assets/svges/firefox.svg +3 -0
- package/assets/svges/firework-rocket-4.svg +3 -0
- package/assets/svges/fitbit.svg +3 -0
- package/assets/svges/flag-1.svg +3 -0
- package/assets/svges/flag-2.svg +3 -0
- package/assets/svges/flickr.svg +4 -0
- package/assets/svges/floppy-disk-1.svg +3 -0
- package/assets/svges/flower-2.svg +3 -0
- package/assets/svges/flutter.svg +3 -0
- package/assets/svges/folder-1.svg +3 -0
- package/assets/svges/ford.svg +3 -0
- package/assets/svges/framer.svg +3 -0
- package/assets/svges/funnel-1.svg +3 -0
- package/assets/svges/gallery.svg +4 -0
- package/assets/svges/game-pad-modern-1.svg +6 -0
- package/assets/svges/gatsby.svg +3 -0
- package/assets/svges/gauge-1.svg +5 -0
- package/assets/svges/gear-1.svg +4 -0
- package/assets/svges/gears-3.svg +6 -0
- package/assets/svges/gemini.svg +3 -0
- package/assets/svges/git.svg +3 -0
- package/assets/svges/github.svg +3 -0
- package/assets/svges/glass-juice-1.svg +3 -0
- package/assets/svges/globe-1.svg +3 -0
- package/assets/svges/globe-stand.svg +4 -0
- package/assets/svges/go.svg +7 -0
- package/assets/svges/goodreads.svg +3 -0
- package/assets/svges/google-cloud.svg +3 -0
- package/assets/svges/google-drive.svg +3 -0
- package/assets/svges/google-meet.svg +3 -0
- package/assets/svges/google-pay.svg +3 -0
- package/assets/svges/google-wallet.svg +3 -0
- package/assets/svges/google.svg +3 -0
- package/assets/svges/graduation-cap-1.svg +3 -0
- package/assets/svges/grammarly.svg +3 -0
- package/assets/svges/hacker-news.svg +3 -0
- package/assets/svges/hammer-1.svg +3 -0
- package/assets/svges/hammer-2.svg +3 -0
- package/assets/svges/hand-mic.svg +3 -0
- package/assets/svges/hand-shake.svg +3 -0
- package/assets/svges/hand-stop.svg +3 -0
- package/assets/svges/hand-taking-dollar.svg +4 -0
- package/assets/svges/hand-taking-leaf-1.svg +5 -0
- package/assets/svges/hand-taking-user.svg +5 -0
- package/assets/svges/hashnode.svg +3 -0
- package/assets/svges/hat-chef-3.svg +3 -0
- package/assets/svges/headphone-1.svg +3 -0
- package/assets/svges/heart.svg +3 -0
- package/assets/svges/helicopter-2.svg +4 -0
- package/assets/svges/helmet-safety-1.svg +3 -0
- package/assets/svges/hierarchy-1.svg +9 -0
- package/assets/svges/highlighter-1.svg +3 -0
- package/assets/svges/highlighter-2.svg +3 -0
- package/assets/svges/home-2.svg +3 -0
- package/assets/svges/hospital-2.svg +4 -0
- package/assets/svges/hourglass.svg +3 -0
- package/assets/svges/html5.svg +4 -0
- package/assets/svges/ibm.svg +3 -0
- package/assets/svges/id-card.svg +7 -0
- package/assets/svges/imdb.svg +7 -0
- package/assets/svges/indent.svg +8 -0
- package/assets/svges/info.svg +4 -0
- package/assets/svges/injection-1.svg +3 -0
- package/assets/svges/instagram-logotype.svg +3 -0
- package/assets/svges/instagram.svg +4 -0
- package/assets/svges/intel.svg +4 -0
- package/assets/svges/ios.svg +3 -0
- package/assets/svges/island-2.svg +4 -0
- package/assets/svges/jaguar.svg +3 -0
- package/assets/svges/jamstack.svg +3 -0
- package/assets/svges/java.svg +3 -0
- package/assets/svges/javascript.svg +3 -0
- package/assets/svges/jcb.svg +3 -0
- package/assets/svges/joomla.svg +6 -0
- package/assets/svges/jsfiddle.svg +4 -0
- package/assets/svges/key-1.svg +3 -0
- package/assets/svges/keyboard.svg +12 -0
- package/assets/svges/knife-fork-1.svg +5 -0
- package/assets/svges/kubernetes.svg +11 -0
- package/assets/svges/label-dollar-2.svg +4 -0
- package/assets/svges/laptop-2.svg +3 -0
- package/assets/svges/laptop-phone.svg +5 -0
- package/assets/svges/laravel.svg +3 -0
- package/assets/svges/layers-1.svg +4 -0
- package/assets/svges/layout-26.svg +3 -0
- package/assets/svges/layout-9.svg +3 -0
- package/assets/svges/leaf-1.svg +3 -0
- package/assets/svges/leaf-6.svg +4 -0
- package/assets/svges/lemon-squeezy.svg +6 -0
- package/assets/svges/life-guard-tube-1.svg +3 -0
- package/assets/svges/line-dashed.svg +5 -0
- package/assets/svges/line-dotted.svg +8 -0
- package/assets/svges/line-height.svg +7 -0
- package/assets/svges/line.svg +3 -0
- package/assets/svges/lineicons.svg +6 -0
- package/assets/svges/link-2-angular-right.svg +3 -0
- package/assets/svges/linkedin.svg +3 -0
- package/assets/svges/location-arrow-right.svg +3 -0
- package/assets/svges/locked-1.svg +4 -0
- package/assets/svges/locked-2.svg +4 -0
- package/assets/svges/loom.svg +3 -0
- package/assets/svges/magento.svg +4 -0
- package/assets/svges/magnet.svg +3 -0
- package/assets/svges/mailchimp.svg +3 -0
- package/assets/svges/map-marker-1.svg +6 -0
- package/assets/svges/map-marker-5.svg +4 -0
- package/assets/svges/map-pin-5.svg +3 -0
- package/assets/svges/markdown.svg +5 -0
- package/assets/svges/mastercard.svg +7 -0
- package/assets/svges/medium-alt.svg +3 -0
- package/assets/svges/medium.svg +3 -0
- package/assets/svges/megaphone-1.svg +3 -0
- package/assets/svges/menu-cheesburger.svg +8 -0
- package/assets/svges/menu-hamburger-1.svg +5 -0
- package/assets/svges/menu-meatballs-1.svg +5 -0
- package/assets/svges/menu-meatballs-2.svg +5 -0
- package/assets/svges/mercedes.svg +3 -0
- package/assets/svges/message-2-question.svg +5 -0
- package/assets/svges/message-2.svg +3 -0
- package/assets/svges/message-3-text.svg +5 -0
- package/assets/svges/meta-alt.svg +3 -0
- package/assets/svges/meta.svg +7 -0
- package/assets/svges/microphone-1.svg +4 -0
- package/assets/svges/microscope.svg +3 -0
- package/assets/svges/microsoft-edge.svg +5 -0
- package/assets/svges/microsoft-teams.svg +6 -0
- package/assets/svges/microsoft.svg +6 -0
- package/assets/svges/minus-circle.svg +4 -0
- package/assets/svges/minus.svg +3 -0
- package/assets/svges/mongodb.svg +3 -0
- package/assets/svges/monitor-code.svg +5 -0
- package/assets/svges/monitor-mac.svg +3 -0
- package/assets/svges/monitor.svg +3 -0
- package/assets/svges/moon-half-right-5.svg +3 -0
- package/assets/svges/mountains-2.svg +3 -0
- package/assets/svges/mouse-2.svg +3 -0
- package/assets/svges/mushroom-1.svg +3 -0
- package/assets/svges/mushroom-5.svg +6 -0
- package/assets/svges/music.svg +3 -0
- package/assets/svges/mysql.svg +3 -0
- package/assets/svges/nasa.svg +3 -0
- package/assets/svges/netflix.svg +3 -0
- package/assets/svges/netlify.svg +3 -0
- package/assets/svges/next-step-2.svg +3 -0
- package/assets/svges/nextjs.svg +3 -0
- package/assets/svges/nike.svg +3 -0
- package/assets/svges/nissan.svg +3 -0
- package/assets/svges/nodejs-alt.svg +3 -0
- package/assets/svges/nodejs.svg +3 -0
- package/assets/svges/notebook-1.svg +3 -0
- package/assets/svges/notion.svg +3 -0
- package/assets/svges/npm.svg +3 -0
- package/assets/svges/nuxt.svg +3 -0
- package/assets/svges/nvidia.svg +3 -0
- package/assets/svges/oculus.svg +4 -0
- package/assets/svges/open-ai.svg +3 -0
- package/assets/svges/opera-mini.svg +3 -0
- package/assets/svges/oracle.svg +3 -0
- package/assets/svges/outdent.svg +8 -0
- package/assets/svges/paddle.svg +3 -0
- package/assets/svges/page-break-1.svg +7 -0
- package/assets/svges/pagination.svg +7 -0
- package/assets/svges/paint-bucket.svg +3 -0
- package/assets/svges/paint-roller-1.svg +3 -0
- package/assets/svges/paperclip-1.svg +3 -0
- package/assets/svges/party-flags.svg +3 -0
- package/assets/svges/party-spray.svg +3 -0
- package/assets/svges/patreon.svg +3 -0
- package/assets/svges/pause.svg +4 -0
- package/assets/svges/payoneer.svg +4 -0
- package/assets/svges/paypal.svg +4 -0
- package/assets/svges/pen-to-square.svg +4 -0
- package/assets/svges/pencil-1.svg +3 -0
- package/assets/svges/pepsi.svg +4 -0
- package/assets/svges/phone.svg +4 -0
- package/assets/svges/photos.svg +4 -0
- package/assets/svges/php.svg +3 -0
- package/assets/svges/pie-chart-2.svg +3 -0
- package/assets/svges/pilcrow.svg +3 -0
- package/assets/svges/pimjo-logo.svg +9 -0
- package/assets/svges/pimjo-symbol.svg +3 -0
- package/assets/svges/pinterest.svg +3 -0
- package/assets/svges/pizza-2.svg +6 -0
- package/assets/svges/placeholder-dollar.svg +4 -0
- package/assets/svges/plantscale.svg +3 -0
- package/assets/svges/play-store.svg +3 -0
- package/assets/svges/play.svg +3 -0
- package/assets/svges/playstation.svg +5 -0
- package/assets/svges/plug-1.svg +3 -0
- package/assets/svges/plus-circle.svg +4 -0
- package/assets/svges/plus.svg +3 -0
- package/assets/svges/pnpm.svg +10 -0
- package/assets/svges/postgresql.svg +3 -0
- package/assets/svges/postman.svg +3 -0
- package/assets/svges/pound.svg +3 -0
- package/assets/svges/power-button.svg +4 -0
- package/assets/svges/previous-step-2.svg +3 -0
- package/assets/svges/printer.svg +3 -0
- package/assets/svges/prisma.svg +3 -0
- package/assets/svges/producthunt.svg +4 -0
- package/assets/svges/proton-mail-logo.svg +3 -0
- package/assets/svges/proton-mail-symbol.svg +3 -0
- package/assets/svges/python.svg +3 -0
- package/assets/svges/question-mark-circle.svg +5 -0
- package/assets/svges/question-mark.svg +4 -0
- package/assets/svges/quora.svg +4 -0
- package/assets/svges/radis.svg +3 -0
- package/assets/svges/react.svg +3 -0
- package/assets/svges/reddit.svg +6 -0
- package/assets/svges/refresh-circle-1-clockwise.svg +4 -0
- package/assets/svges/refresh-dollar-1.svg +5 -0
- package/assets/svges/refresh-user-1.svg +6 -0
- package/assets/svges/remix-js.svg +4 -0
- package/assets/svges/road-1.svg +6 -0
- package/assets/svges/rocket-5.svg +5 -0
- package/assets/svges/route-1.svg +7 -0
- package/assets/svges/rss-right.svg +6 -0
- package/assets/svges/ruler-1.svg +3 -0
- package/assets/svges/ruler-pen.svg +4 -0
- package/assets/svges/rupee.svg +3 -0
- package/assets/svges/safari.svg +35 -0
- package/assets/svges/sanity.svg +20 -0
- package/assets/svges/school-bench-1.svg +4 -0
- package/assets/svges/school-bench-2.svg +4 -0
- package/assets/svges/scissors-1-vertical.svg +4 -0
- package/assets/svges/scoter.svg +8 -0
- package/assets/svges/scroll-down-2.svg +6 -0
- package/assets/svges/search-1.svg +3 -0
- package/assets/svges/search-2.svg +4 -0
- package/assets/svges/search-minus.svg +4 -0
- package/assets/svges/search-plus.svg +4 -0
- package/assets/svges/search-text.svg +5 -0
- package/assets/svges/select-cursor-1.svg +10 -0
- package/assets/svges/seo-monitor.svg +6 -0
- package/assets/svges/service-bell-1.svg +3 -0
- package/assets/svges/share-1-circle.svg +4 -0
- package/assets/svges/share-1.svg +3 -0
- package/assets/svges/share-2.svg +4 -0
- package/assets/svges/shield-2-check.svg +4 -0
- package/assets/svges/shield-2.svg +3 -0
- package/assets/svges/shield-dollar.svg +4 -0
- package/assets/svges/shift-left.svg +4 -0
- package/assets/svges/shift-right.svg +4 -0
- package/assets/svges/ship-1.svg +5 -0
- package/assets/svges/shirt-1.svg +3 -0
- package/assets/svges/shopify.svg +3 -0
- package/assets/svges/shovel.svg +3 -0
- package/assets/svges/shuffle.svg +3 -0
- package/assets/svges/sign-post-left.svg +3 -0
- package/assets/svges/signal-app.svg +3 -0
- package/assets/svges/signs-post-2.svg +3 -0
- package/assets/svges/sketch.svg +3 -0
- package/assets/svges/skype.svg +3 -0
- package/assets/svges/slack.svg +10 -0
- package/assets/svges/slice-2.svg +3 -0
- package/assets/svges/sliders-horizontal-square-2.svg +7 -0
- package/assets/svges/slideshare.svg +5 -0
- package/assets/svges/snapchat.svg +3 -0
- package/assets/svges/sort-alphabetical.svg +5 -0
- package/assets/svges/sort-high-to-low.svg +7 -0
- package/assets/svges/soundcloud.svg +3 -0
- package/assets/svges/spacex.svg +4 -0
- package/assets/svges/spellcheck.svg +4 -0
- package/assets/svges/spinner-2-sacle.svg +10 -0
- package/assets/svges/spinner-3.svg +3 -0
- package/assets/svges/sports.svg +3 -0
- package/assets/svges/spotify-alt.svg +6 -0
- package/assets/svges/spotify.svg +3 -0
- package/assets/svges/squarespace.svg +3 -0
- package/assets/svges/stackoverflow.svg +8 -0
- package/assets/svges/stamp.svg +3 -0
- package/assets/svges/star-fat-half-2.svg +4 -0
- package/assets/svges/star-fat.svg +3 -0
- package/assets/svges/star-sharp-disabled.svg +4 -0
- package/assets/svges/statista.svg +3 -0
- package/assets/svges/steam.svg +5 -0
- package/assets/svges/stethoscope-1.svg +3 -0
- package/assets/svges/stopwatch.svg +5 -0
- package/assets/svges/storage-hdd-2.svg +4 -0
- package/assets/svges/strikethrough-1.svg +5 -0
- package/assets/svges/stripe.svg +9 -0
- package/assets/svges/stumbleupon.svg +3 -0
- package/assets/svges/sun-1.svg +11 -0
- package/assets/svges/supabase.svg +5 -0
- package/assets/svges/surfboard-2.svg +3 -0
- package/assets/svges/svelte.svg +3 -0
- package/assets/svges/swift.svg +3 -0
- package/assets/svges/tab.svg +4 -0
- package/assets/svges/tailwindcss.svg +3 -0
- package/assets/svges/target-user.svg +5 -0
- package/assets/svges/telegram.svg +3 -0
- package/assets/svges/telephone-1.svg +4 -0
- package/assets/svges/telephone-3.svg +5 -0
- package/assets/svges/tesla.svg +3 -0
- package/assets/svges/text-format-remove.svg +5 -0
- package/assets/svges/text-format.svg +5 -0
- package/assets/svges/text-paragraph.svg +6 -0
- package/assets/svges/thumbs-down-3.svg +3 -0
- package/assets/svges/thumbs-up-3.svg +3 -0
- package/assets/svges/ticket-1.svg +3 -0
- package/assets/svges/tickets-3.svg +7 -0
- package/assets/svges/tiktok-alt.svg +3 -0
- package/assets/svges/tiktok.svg +3 -0
- package/assets/svges/tower-broadcast-1.svg +7 -0
- package/assets/svges/toyota.svg +4 -0
- package/assets/svges/train-1.svg +4 -0
- package/assets/svges/train-3.svg +5 -0
- package/assets/svges/trash-3.svg +5 -0
- package/assets/svges/tree-2.svg +3 -0
- package/assets/svges/trees-3.svg +3 -0
- package/assets/svges/trello.svg +3 -0
- package/assets/svges/trend-down-1.svg +3 -0
- package/assets/svges/trend-up-1.svg +3 -0
- package/assets/svges/trophy-1.svg +3 -0
- package/assets/svges/trowel-1.svg +3 -0
- package/assets/svges/truck-delivery-1.svg +3 -0
- package/assets/svges/tumblr.svg +3 -0
- package/assets/svges/turborepo.svg +4 -0
- package/assets/svges/twitch.svg +3 -0
- package/assets/svges/twitter-old.svg +3 -0
- package/assets/svges/typescript.svg +3 -0
- package/assets/svges/uber-symbol.svg +3 -0
- package/assets/svges/uber.svg +3 -0
- package/assets/svges/ubuntu.svg +3 -0
- package/assets/svges/underline.svg +4 -0
- package/assets/svges/unlink-2-angular-eft.svg +8 -0
- package/assets/svges/unlocked-2.svg +4 -0
- package/assets/svges/unsplash.svg +4 -0
- package/assets/svges/upload-1.svg +4 -0
- package/assets/svges/upload-circle-1.svg +4 -0
- package/assets/svges/user-4.svg +4 -0
- package/assets/svges/user-multiple-4.svg +6 -0
- package/assets/svges/vector-nodes-6.svg +3 -0
- package/assets/svges/vector-nodes-7.svg +3 -0
- package/assets/svges/vercel.svg +3 -0
- package/assets/svges/vimeo.svg +3 -0
- package/assets/svges/visa.svg +3 -0
- package/assets/svges/vite.svg +6 -0
- package/assets/svges/vk.svg +3 -0
- package/assets/svges/vmware.svg +4 -0
- package/assets/svges/volkswagen.svg +8 -0
- package/assets/svges/volume-1.svg +5 -0
- package/assets/svges/volume-high.svg +6 -0
- package/assets/svges/volume-low.svg +4 -0
- package/assets/svges/volume-mute.svg +6 -0
- package/assets/svges/volume-off.svg +3 -0
- package/assets/svges/vs-code.svg +3 -0
- package/assets/svges/vuejs.svg +3 -0
- package/assets/svges/wallet-1.svg +3 -0
- package/assets/svges/watch-beat-1.svg +4 -0
- package/assets/svges/water-drop-1.svg +4 -0
- package/assets/svges/webflow.svg +3 -0
- package/assets/svges/webhooks.svg +3 -0
- package/assets/svges/wechat.svg +4 -0
- package/assets/svges/weight-machine-1.svg +4 -0
- package/assets/svges/whatsapp.svg +3 -0
- package/assets/svges/wheelbarrow-empty.svg +3 -0
- package/assets/svges/wheelchair-1.svg +3 -0
- package/assets/svges/windows.svg +6 -0
- package/assets/svges/wise.svg +3 -0
- package/assets/svges/wordpress.svg +3 -0
- package/assets/svges/www-cursor.svg +5 -0
- package/assets/svges/www.svg +4 -0
- package/assets/svges/x.svg +3 -0
- package/assets/svges/xampp.svg +5 -0
- package/assets/svges/xbox.svg +6 -0
- package/assets/svges/xmark-circle.svg +4 -0
- package/assets/svges/xmark.svg +3 -0
- package/assets/svges/xrp.svg +3 -0
- package/assets/svges/yahoo.svg +3 -0
- package/assets/svges/yarn.svg +4 -0
- package/assets/svges/ycombinator.svg +3 -0
- package/assets/svges/yen.svg +3 -0
- package/assets/svges/youtube-kids.svg +3 -0
- package/assets/svges/youtube-music.svg +4 -0
- package/assets/svges/youtube.svg +3 -0
- package/assets/svges/zapier.svg +3 -0
- package/assets/svges/zero-size.svg +6 -0
- package/assets/svges/zoom.svg +4 -0
- package/bin/test-svger.js +163 -0
- package/dist/__tests__/__mocks__/visual-diff.d.ts +7 -0
- package/dist/__tests__/__mocks__/visual-diff.js +13 -0
- package/dist/__tests__/fixtures.js +18 -18
- package/dist/cli.js +148 -2
- package/dist/config.js +4 -1
- package/dist/core/enhanced-plugin-manager.d.ts +107 -0
- package/dist/core/enhanced-plugin-manager.js +315 -0
- package/dist/core/error-handler.d.ts +1 -1
- package/dist/core/error-handler.js +14 -17
- package/dist/core/framework-templates.js +37 -47
- package/dist/core/logger.js +0 -1
- package/dist/core/performance-engine.js +10 -15
- package/dist/core/plugin-manager.js +4 -4
- package/dist/core/style-compiler.d.ts +0 -1
- package/dist/core/style-compiler.js +3 -6
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/integrations/babel.d.ts +1 -1
- package/dist/integrations/babel.js +31 -12
- package/dist/integrations/jest-preset.js +1 -1
- package/dist/integrations/rollup.js +29 -10
- package/dist/integrations/vite.js +29 -14
- package/dist/integrations/webpack.d.ts +1 -0
- package/dist/integrations/webpack.js +29 -10
- package/dist/optimizers/advanced-stages.d.ts +40 -0
- package/dist/optimizers/advanced-stages.js +297 -0
- package/dist/optimizers/basic-cleaner.d.ts +68 -0
- package/dist/optimizers/basic-cleaner.js +198 -0
- package/dist/optimizers/collapse-useless-groups.d.ts +26 -0
- package/dist/optimizers/collapse-useless-groups.js +104 -0
- package/dist/optimizers/command-optimizer.d.ts +48 -0
- package/dist/optimizers/command-optimizer.js +299 -0
- package/dist/optimizers/index.d.ts +14 -0
- package/dist/optimizers/index.js +15 -0
- package/dist/optimizers/move-attrs-to-parent.d.ts +31 -0
- package/dist/optimizers/move-attrs-to-parent.js +115 -0
- package/dist/optimizers/numeric-optimizer.d.ts +43 -0
- package/dist/optimizers/numeric-optimizer.js +383 -0
- package/dist/optimizers/optimizer-pipeline.d.ts +39 -0
- package/dist/optimizers/optimizer-pipeline.js +81 -0
- package/dist/optimizers/path-deduplicator.d.ts +37 -0
- package/dist/optimizers/path-deduplicator.js +406 -0
- package/dist/optimizers/path-parser.d.ts +60 -0
- package/dist/optimizers/path-parser.js +428 -0
- package/dist/optimizers/path-shortener.d.ts +41 -0
- package/dist/optimizers/path-shortener.js +274 -0
- package/dist/optimizers/path-simplifier.d.ts +30 -0
- package/dist/optimizers/path-simplifier.js +326 -0
- package/dist/optimizers/remove-hidden-empty.d.ts +29 -0
- package/dist/optimizers/remove-hidden-empty.js +130 -0
- package/dist/optimizers/remove-unused-defs.d.ts +24 -0
- package/dist/optimizers/remove-unused-defs.js +132 -0
- package/dist/optimizers/shape-conversion.d.ts +74 -0
- package/dist/optimizers/shape-conversion.js +277 -0
- package/dist/optimizers/style-optimizer.d.ts +30 -0
- package/dist/optimizers/style-optimizer.js +324 -0
- package/dist/optimizers/svg-tree-parser.d.ts +55 -0
- package/dist/optimizers/svg-tree-parser.js +352 -0
- package/dist/optimizers/transform-collapsing.d.ts +38 -0
- package/dist/optimizers/transform-collapsing.js +444 -0
- package/dist/optimizers/transform-optimizer.d.ts +65 -0
- package/dist/optimizers/transform-optimizer.js +320 -0
- package/dist/optimizers/tree-serializer.d.ts +46 -0
- package/dist/optimizers/tree-serializer.js +190 -0
- package/dist/optimizers/tree-stages.d.ts +27 -0
- package/dist/optimizers/tree-stages.js +141 -0
- package/dist/optimizers/types.d.ts +207 -0
- package/dist/optimizers/types.js +122 -0
- package/dist/plugins/color-replacer.d.ts +39 -0
- package/dist/plugins/color-replacer.js +126 -0
- package/dist/plugins/gradient-optimizer.d.ts +33 -0
- package/dist/plugins/gradient-optimizer.js +197 -0
- package/dist/plugins/stroke-normalizer.d.ts +33 -0
- package/dist/plugins/stroke-normalizer.js +166 -0
- package/dist/plugins/watermark-remover.d.ts +32 -0
- package/dist/plugins/watermark-remover.js +133 -0
- package/dist/processors/svg-processor.d.ts +17 -2
- package/dist/processors/svg-processor.js +108 -32
- package/dist/services/config.d.ts +4 -0
- package/dist/services/config.js +62 -1
- package/dist/services/file-watcher.d.ts +1 -1
- package/dist/services/file-watcher.js +1 -1
- package/dist/services/svg-service.d.ts +6 -0
- package/dist/services/svg-service.js +66 -16
- package/dist/types/index.d.ts +1 -0
- package/dist/types/plugin-system.d.ts +153 -0
- package/dist/types/plugin-system.js +5 -0
- package/dist/utils/visual-diff.d.ts +150 -0
- package/dist/utils/visual-diff.js +247 -0
- package/dist/watch.js +0 -2
- package/docs/COMPLETE-ACHIEVEMENT-SUMMARY.md +401 -0
- package/docs/MIGRATION-4.0.0.md +271 -0
- package/docs/PIPELINE-INTEGRATION.md +406 -0
- package/docs/PLUGIN-DEVELOPMENT-GUIDE.md +807 -0
- package/docs/QUICK-REFERENCE.md +176 -0
- package/docs/SAMPLE-SVGS-TESTING.md +276 -0
- package/docs/archive/PHASE-1-ARCHITECTURE.md +345 -0
- package/docs/archive/PHASE-1-IMPLEMENTATION.md +307 -0
- package/docs/archive/PHASE-1-SUMMARY.md +298 -0
- package/docs/archive/PHASE-2-COMPLETE.md +207 -0
- package/docs/archive/PHASE-3-SUMMARY.md +149 -0
- package/docs/archive/PHASE-4.3-COMMAND-OPTIMIZER.md +323 -0
- package/docs/archive/PHASE-4.4-PATH-SIMPLIFICATION.md +81 -0
- package/docs/archive/PHASE-4.5-PATH-DEDUPLICATION.md +449 -0
- package/docs/archive/PHASE-5.1-SUCCESS-REPORT.md +207 -0
- package/docs/archive/PHASE-5.1-TRANSFORM-COLLAPSING.md +362 -0
- package/docs/archive/PHASE-6.1-SHAPE-CONVERSION-DESIGN.md +518 -0
- package/docs/archive/PHASE-6.2-PLUGIN-SYSTEM-STATUS.md +403 -0
- package/docs/archive/PHASE-6.3-FINAL-STATUS.md +193 -0
- package/docs/archive/PHASE-6.3-VALIDATION-PROGRESS.md +345 -0
- package/docs/archive/PHASE-6.3-VISUAL-DIFF-DESIGN.md +553 -0
- package/docs/archive/PHASE-6.3-VISUAL-DIFF-SUMMARY.md +367 -0
- package/docs/archive/PHASE-6.3-XML-SERIALIZATION-FIX.md +210 -0
- package/docs/archive/RELEASE-NOTES-3.2.0.md +344 -0
- package/docs/archive/RELEASE-PREP-3.2.0.md +376 -0
- package/docs/performance/PERFORMANCE-RESULTS.md +31 -0
- package/docs/performance/REAL-WORLD-BENCHMARKS.md +159 -0
- package/package.json +16 -6
- package/DEVELOPMENT.md +0 -353
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 4.2: Path Shortener
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* 1. Merge consecutive same commands (e.g., L10 20 L30 40 → L10 20 30 40)
|
|
6
|
+
* 2. Convert relative ↔ absolute if shorter (smart size comparison)
|
|
7
|
+
* 3. Replace L with H/V where possible (horizontal/vertical lines)
|
|
8
|
+
* 4. Optimize command sequence for minimal byte size
|
|
9
|
+
*/
|
|
10
|
+
import { serializePath, toAbsolute, toRelative, compareAbsoluteRelativeSize, } from './path-parser.js';
|
|
11
|
+
/**
|
|
12
|
+
* Check if two commands can be merged (same type and both absolute or both relative)
|
|
13
|
+
*/
|
|
14
|
+
function canMergeCommands(cmd1, cmd2) {
|
|
15
|
+
// Must be same type
|
|
16
|
+
if (cmd1.type !== cmd2.type) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
// Can't merge Z
|
|
20
|
+
if (cmd1.type === 'Z' || cmd1.type === 'z') {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
// Only merge commands that support multiple coordinate sets
|
|
24
|
+
const mergeable = ['L', 'l', 'C', 'c', 'S', 's', 'Q', 'q', 'T', 't'];
|
|
25
|
+
return mergeable.includes(cmd1.type);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Merge consecutive commands of the same type
|
|
29
|
+
*/
|
|
30
|
+
export function mergeConsecutiveCommands(commands) {
|
|
31
|
+
if (commands.length === 0)
|
|
32
|
+
return commands;
|
|
33
|
+
const merged = [];
|
|
34
|
+
let currentCmd = null;
|
|
35
|
+
for (const cmd of commands) {
|
|
36
|
+
if (!currentCmd) {
|
|
37
|
+
currentCmd = { ...cmd, values: [...cmd.values] };
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
// Try to merge with current
|
|
41
|
+
if (canMergeCommands(currentCmd, cmd)) {
|
|
42
|
+
// Merge values
|
|
43
|
+
currentCmd.values.push(...cmd.values);
|
|
44
|
+
currentCmd.absolutePosition = cmd.absolutePosition;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Push current and start new
|
|
48
|
+
merged.push(currentCmd);
|
|
49
|
+
currentCmd = { ...cmd, values: [...cmd.values] };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (currentCmd) {
|
|
53
|
+
merged.push(currentCmd);
|
|
54
|
+
}
|
|
55
|
+
return merged;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Convert L commands to H/V where beneficial
|
|
59
|
+
* L10 20 → H10 V20 (if horizontal or vertical movement)
|
|
60
|
+
*/
|
|
61
|
+
export function convertLtoHV(commands, precision = 3) {
|
|
62
|
+
const optimized = [];
|
|
63
|
+
let prevX = 0;
|
|
64
|
+
let prevY = 0;
|
|
65
|
+
for (const cmd of commands) {
|
|
66
|
+
// Only optimize single-coordinate L/l commands
|
|
67
|
+
if ((cmd.type === 'L' || cmd.type === 'l') && cmd.values.length === 2) {
|
|
68
|
+
const [x, y] = cmd.values;
|
|
69
|
+
if (cmd.type === 'L') {
|
|
70
|
+
// Absolute
|
|
71
|
+
const isHorizontal = Math.abs(y - prevY) < 1e-6;
|
|
72
|
+
const isVertical = Math.abs(x - prevX) < 1e-6;
|
|
73
|
+
if (isHorizontal) {
|
|
74
|
+
// Convert to H
|
|
75
|
+
const hCmd = {
|
|
76
|
+
type: 'H',
|
|
77
|
+
values: [x],
|
|
78
|
+
absolutePosition: cmd.absolutePosition,
|
|
79
|
+
};
|
|
80
|
+
const lSize = serializePath([cmd], precision).length;
|
|
81
|
+
const hSize = serializePath([hCmd], precision).length;
|
|
82
|
+
if (hSize < lSize) {
|
|
83
|
+
optimized.push(hCmd);
|
|
84
|
+
prevX = x;
|
|
85
|
+
prevY = y;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else if (isVertical) {
|
|
90
|
+
// Convert to V
|
|
91
|
+
const vCmd = {
|
|
92
|
+
type: 'V',
|
|
93
|
+
values: [y],
|
|
94
|
+
absolutePosition: cmd.absolutePosition,
|
|
95
|
+
};
|
|
96
|
+
const lSize = serializePath([cmd], precision).length;
|
|
97
|
+
const vSize = serializePath([vCmd], precision).length;
|
|
98
|
+
if (vSize < lSize) {
|
|
99
|
+
optimized.push(vCmd);
|
|
100
|
+
prevX = x;
|
|
101
|
+
prevY = y;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// Relative l
|
|
108
|
+
const isHorizontal = Math.abs(y) < 1e-6;
|
|
109
|
+
const isVertical = Math.abs(x) < 1e-6;
|
|
110
|
+
if (isHorizontal && x !== 0) {
|
|
111
|
+
// Convert to h
|
|
112
|
+
const hCmd = {
|
|
113
|
+
type: 'h',
|
|
114
|
+
values: [x],
|
|
115
|
+
absolutePosition: cmd.absolutePosition,
|
|
116
|
+
};
|
|
117
|
+
const lSize = serializePath([cmd], precision).length;
|
|
118
|
+
const hSize = serializePath([hCmd], precision).length;
|
|
119
|
+
if (hSize < lSize) {
|
|
120
|
+
optimized.push(hCmd);
|
|
121
|
+
prevX = cmd.absolutePosition.x;
|
|
122
|
+
prevY = cmd.absolutePosition.y;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else if (isVertical && y !== 0) {
|
|
127
|
+
// Convert to v
|
|
128
|
+
const vCmd = {
|
|
129
|
+
type: 'v',
|
|
130
|
+
values: [y],
|
|
131
|
+
absolutePosition: cmd.absolutePosition,
|
|
132
|
+
};
|
|
133
|
+
const lSize = serializePath([cmd], precision).length;
|
|
134
|
+
const vSize = serializePath([vCmd], precision).length;
|
|
135
|
+
if (vSize < lSize) {
|
|
136
|
+
optimized.push(vCmd);
|
|
137
|
+
prevX = cmd.absolutePosition.x;
|
|
138
|
+
prevY = cmd.absolutePosition.y;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Keep original command
|
|
145
|
+
optimized.push(cmd);
|
|
146
|
+
if (cmd.absolutePosition) {
|
|
147
|
+
prevX = cmd.absolutePosition.x;
|
|
148
|
+
prevY = cmd.absolutePosition.y;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return optimized;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Convert commands to absolute or relative based on size
|
|
155
|
+
*/
|
|
156
|
+
export function optimizeAbsoluteRelative(commands, precision = 3) {
|
|
157
|
+
const optimized = [];
|
|
158
|
+
let prevX = 0;
|
|
159
|
+
let prevY = 0;
|
|
160
|
+
for (const cmd of commands) {
|
|
161
|
+
// M command: first should be absolute, rest can be optimized as L
|
|
162
|
+
if (cmd.type === 'M' || cmd.type === 'm') {
|
|
163
|
+
// First M should typically be absolute
|
|
164
|
+
if (optimized.length === 0) {
|
|
165
|
+
const absCmd = toAbsolute(cmd, prevX, prevY);
|
|
166
|
+
optimized.push(absCmd);
|
|
167
|
+
prevX = absCmd.absolutePosition.x;
|
|
168
|
+
prevY = absCmd.absolutePosition.y;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// Compare sizes
|
|
173
|
+
const diff = compareAbsoluteRelativeSize(cmd, prevX, prevY, precision);
|
|
174
|
+
if (diff > 0) {
|
|
175
|
+
// Relative is shorter
|
|
176
|
+
const relCmd = toRelative(cmd, prevX, prevY);
|
|
177
|
+
optimized.push(relCmd);
|
|
178
|
+
}
|
|
179
|
+
else if (diff < 0) {
|
|
180
|
+
// Absolute is shorter
|
|
181
|
+
const absCmd = toAbsolute(cmd, prevX, prevY);
|
|
182
|
+
optimized.push(absCmd);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
// Same size, keep original
|
|
186
|
+
optimized.push(cmd);
|
|
187
|
+
}
|
|
188
|
+
// Update position
|
|
189
|
+
if (cmd.absolutePosition) {
|
|
190
|
+
prevX = cmd.absolutePosition.x;
|
|
191
|
+
prevY = cmd.absolutePosition.y;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return optimized;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Remove redundant commands
|
|
198
|
+
* - Remove M commands that move to current position
|
|
199
|
+
* - Remove L commands with distance 0
|
|
200
|
+
*/
|
|
201
|
+
export function removeRedundantCommands(commands) {
|
|
202
|
+
const filtered = [];
|
|
203
|
+
let prevX = 0;
|
|
204
|
+
let prevY = 0;
|
|
205
|
+
for (const cmd of commands) {
|
|
206
|
+
let isRedundant = false;
|
|
207
|
+
// Check for redundant M/m (move to same position)
|
|
208
|
+
if (cmd.type === 'M' && cmd.values.length === 2) {
|
|
209
|
+
const [x, y] = cmd.values;
|
|
210
|
+
if (Math.abs(x - prevX) < 1e-6 && Math.abs(y - prevY) < 1e-6) {
|
|
211
|
+
isRedundant = true;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else if (cmd.type === 'm' && cmd.values.length === 2) {
|
|
215
|
+
const [dx, dy] = cmd.values;
|
|
216
|
+
if (Math.abs(dx) < 1e-6 && Math.abs(dy) < 1e-6) {
|
|
217
|
+
isRedundant = true;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Check for redundant L/l (zero-length line)
|
|
221
|
+
if (cmd.type === 'L' && cmd.values.length === 2) {
|
|
222
|
+
const [x, y] = cmd.values;
|
|
223
|
+
if (Math.abs(x - prevX) < 1e-6 && Math.abs(y - prevY) < 1e-6) {
|
|
224
|
+
isRedundant = true;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else if (cmd.type === 'l' && cmd.values.length === 2) {
|
|
228
|
+
const [dx, dy] = cmd.values;
|
|
229
|
+
if (Math.abs(dx) < 1e-6 && Math.abs(dy) < 1e-6) {
|
|
230
|
+
isRedundant = true;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (!isRedundant) {
|
|
234
|
+
filtered.push(cmd);
|
|
235
|
+
if (cmd.absolutePosition) {
|
|
236
|
+
prevX = cmd.absolutePosition.x;
|
|
237
|
+
prevY = cmd.absolutePosition.y;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return filtered;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Comprehensive path shortening pipeline
|
|
245
|
+
*/
|
|
246
|
+
export function shortenPath(commands, precision = 3) {
|
|
247
|
+
const originalCount = commands.length;
|
|
248
|
+
// Step 1: Remove redundant commands
|
|
249
|
+
let optimized = removeRedundantCommands(commands);
|
|
250
|
+
const removedRedundant = originalCount - optimized.length;
|
|
251
|
+
// Step 2: Merge consecutive same commands
|
|
252
|
+
const beforeMerge = optimized.length;
|
|
253
|
+
optimized = mergeConsecutiveCommands(optimized);
|
|
254
|
+
const mergedCommands = beforeMerge - optimized.length;
|
|
255
|
+
// Step 3: Convert L to H/V where beneficial
|
|
256
|
+
const beforeHV = serializePath(optimized, precision).length;
|
|
257
|
+
optimized = convertLtoHV(optimized, precision);
|
|
258
|
+
const afterHV = serializePath(optimized, precision).length;
|
|
259
|
+
const convertedToHV = beforeHV - afterHV;
|
|
260
|
+
// Step 4: Optimize absolute/relative
|
|
261
|
+
const beforeAbsRel = serializePath(optimized, precision).length;
|
|
262
|
+
optimized = optimizeAbsoluteRelative(optimized, precision);
|
|
263
|
+
const afterAbsRel = serializePath(optimized, precision).length;
|
|
264
|
+
const convertedAbsRel = beforeAbsRel - afterAbsRel;
|
|
265
|
+
return {
|
|
266
|
+
commands: optimized,
|
|
267
|
+
stats: {
|
|
268
|
+
mergedCommands,
|
|
269
|
+
convertedToHV,
|
|
270
|
+
convertedAbsRel,
|
|
271
|
+
removedRedundant,
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 4.4: Path Simplification
|
|
3
|
+
*
|
|
4
|
+
* Implements Douglas-Peucker and Visvalingam-Whyatt algorithms for intelligent
|
|
5
|
+
* polyline and polygon simplification. Reduces point count while preserving
|
|
6
|
+
* visual fidelity.
|
|
7
|
+
*
|
|
8
|
+
* Target: 5-15% additional reduction on complex/hand-drawn paths
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Douglas-Peucker: Recursive subdivision algorithm (great for angular paths)
|
|
12
|
+
* - Visvalingam-Whyatt: Area-based triangulation (great for smooth curves)
|
|
13
|
+
* - Tolerance-based: Configurable precision vs size tradeoff
|
|
14
|
+
* - Curve-aware: Only simplifies L/H/V commands, preserves C/Q/S/T/A
|
|
15
|
+
*/
|
|
16
|
+
import type { OptConfig } from './types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Simplify a path by reducing the number of linear points
|
|
19
|
+
*/
|
|
20
|
+
export declare function simplifyPath(pathData: string, config: OptConfig, algorithm?: 'douglas-peucker' | 'visvalingam'): {
|
|
21
|
+
simplified: string;
|
|
22
|
+
pointsRemoved: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Optimization stage for path simplification
|
|
26
|
+
*/
|
|
27
|
+
export declare function pathSimplificationStage(config: OptConfig): {
|
|
28
|
+
name: string;
|
|
29
|
+
transform(svgContent: string): Promise<string>;
|
|
30
|
+
};
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 4.4: Path Simplification
|
|
3
|
+
*
|
|
4
|
+
* Implements Douglas-Peucker and Visvalingam-Whyatt algorithms for intelligent
|
|
5
|
+
* polyline and polygon simplification. Reduces point count while preserving
|
|
6
|
+
* visual fidelity.
|
|
7
|
+
*
|
|
8
|
+
* Target: 5-15% additional reduction on complex/hand-drawn paths
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Douglas-Peucker: Recursive subdivision algorithm (great for angular paths)
|
|
12
|
+
* - Visvalingam-Whyatt: Area-based triangulation (great for smooth curves)
|
|
13
|
+
* - Tolerance-based: Configurable precision vs size tradeoff
|
|
14
|
+
* - Curve-aware: Only simplifies L/H/V commands, preserves C/Q/S/T/A
|
|
15
|
+
*/
|
|
16
|
+
import { parsePath, serializePath } from './path-parser.js';
|
|
17
|
+
import { OptLevel } from './types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Calculate perpendicular distance from point to line segment
|
|
20
|
+
*/
|
|
21
|
+
function perpendicularDistance(point, lineStart, lineEnd) {
|
|
22
|
+
const dx = lineEnd.x - lineStart.x;
|
|
23
|
+
const dy = lineEnd.y - lineStart.y;
|
|
24
|
+
// Magnitude
|
|
25
|
+
const mag = Math.sqrt(dx * dx + dy * dy);
|
|
26
|
+
if (mag === 0) {
|
|
27
|
+
return Math.sqrt(Math.pow(point.x - lineStart.x, 2) + Math.pow(point.y - lineStart.y, 2));
|
|
28
|
+
}
|
|
29
|
+
// Perpendicular distance
|
|
30
|
+
const u = ((point.x - lineStart.x) * dx + (point.y - lineStart.y) * dy) / (mag * mag);
|
|
31
|
+
if (u < 0) {
|
|
32
|
+
// Closest to start
|
|
33
|
+
return Math.sqrt(Math.pow(point.x - lineStart.x, 2) + Math.pow(point.y - lineStart.y, 2));
|
|
34
|
+
}
|
|
35
|
+
else if (u > 1) {
|
|
36
|
+
// Closest to end
|
|
37
|
+
return Math.sqrt(Math.pow(point.x - lineEnd.x, 2) + Math.pow(point.y - lineEnd.y, 2));
|
|
38
|
+
}
|
|
39
|
+
// Perpendicular point
|
|
40
|
+
const px = lineStart.x + u * dx;
|
|
41
|
+
const py = lineStart.y + u * dy;
|
|
42
|
+
return Math.sqrt(Math.pow(point.x - px, 2) + Math.pow(point.y - py, 2));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Douglas-Peucker algorithm for polyline simplification
|
|
46
|
+
*
|
|
47
|
+
* Recursive subdivision algorithm that finds the point with maximum distance
|
|
48
|
+
* from the line segment and splits there if it exceeds tolerance.
|
|
49
|
+
*
|
|
50
|
+
* Best for: Angular paths, architectural drawings, logos
|
|
51
|
+
* Time: O(n log n) average, O(n²) worst
|
|
52
|
+
*/
|
|
53
|
+
function douglasPeucker(points, tolerance) {
|
|
54
|
+
if (points.length <= 2) {
|
|
55
|
+
return points;
|
|
56
|
+
}
|
|
57
|
+
// Find point with maximum distance
|
|
58
|
+
let maxDist = 0;
|
|
59
|
+
let maxIndex = 0;
|
|
60
|
+
const start = points[0];
|
|
61
|
+
const end = points[points.length - 1];
|
|
62
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
63
|
+
const dist = perpendicularDistance(points[i], start, end);
|
|
64
|
+
if (dist > maxDist) {
|
|
65
|
+
maxDist = dist;
|
|
66
|
+
maxIndex = i;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// If max distance is greater than tolerance, recursively simplify
|
|
70
|
+
if (maxDist > tolerance) {
|
|
71
|
+
const left = douglasPeucker(points.slice(0, maxIndex + 1), tolerance);
|
|
72
|
+
const right = douglasPeucker(points.slice(maxIndex), tolerance);
|
|
73
|
+
// Combine results (remove duplicate middle point)
|
|
74
|
+
return [...left.slice(0, -1), ...right];
|
|
75
|
+
}
|
|
76
|
+
// All points between start and end can be removed
|
|
77
|
+
return [start, end];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Calculate area of triangle formed by three points
|
|
81
|
+
*/
|
|
82
|
+
function triangleArea(p1, p2, p3) {
|
|
83
|
+
return Math.abs((p1.x * (p2.y - p3.y) + p2.x * (p3.y - p1.y) + p3.x * (p1.y - p2.y)) / 2);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Visvalingam-Whyatt algorithm for polyline simplification
|
|
87
|
+
*
|
|
88
|
+
* Progressive removal of points with smallest triangular area. More
|
|
89
|
+
* consistent results than Douglas-Peucker for smooth curves.
|
|
90
|
+
*
|
|
91
|
+
* Best for: Hand-drawn paths, organic shapes, smooth curves
|
|
92
|
+
* Time: O(n log n) with heap, O(n²) with simple implementation
|
|
93
|
+
*/
|
|
94
|
+
function visvalingamWhyatt(points, tolerance) {
|
|
95
|
+
if (points.length <= 2) {
|
|
96
|
+
return points;
|
|
97
|
+
}
|
|
98
|
+
// Build initial triangle list
|
|
99
|
+
const triangles = new Array(points.length).fill(null);
|
|
100
|
+
// Calculate areas for all triangles
|
|
101
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
102
|
+
triangles[i] = {
|
|
103
|
+
index: i,
|
|
104
|
+
area: triangleArea(points[i - 1], points[i], points[i + 1]),
|
|
105
|
+
prev: triangles[i - 1],
|
|
106
|
+
next: null,
|
|
107
|
+
};
|
|
108
|
+
if (triangles[i - 1]) {
|
|
109
|
+
triangles[i - 1].next = triangles[i];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Convert tolerance to minimum area threshold
|
|
113
|
+
// Higher tolerance = larger minimum area = more aggressive simplification
|
|
114
|
+
const minArea = tolerance * tolerance;
|
|
115
|
+
// Remove points with smallest area below threshold
|
|
116
|
+
let removed = true;
|
|
117
|
+
while (removed) {
|
|
118
|
+
removed = false;
|
|
119
|
+
let minTriangle = null;
|
|
120
|
+
let minIdx = -1;
|
|
121
|
+
// Find triangle with smallest area
|
|
122
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
123
|
+
if (triangles[i] && triangles[i].area < minArea) {
|
|
124
|
+
if (!minTriangle || triangles[i].area < minTriangle.area) {
|
|
125
|
+
minTriangle = triangles[i];
|
|
126
|
+
minIdx = i;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (minTriangle) {
|
|
131
|
+
// Remove the point
|
|
132
|
+
triangles[minIdx] = null;
|
|
133
|
+
removed = true;
|
|
134
|
+
// Update adjacent triangles
|
|
135
|
+
const prevIdx = minIdx - 1;
|
|
136
|
+
const nextIdx = minIdx + 1;
|
|
137
|
+
// Find previous and next non-null triangles
|
|
138
|
+
let prevNonNull = prevIdx;
|
|
139
|
+
while (prevNonNull >= 0 && !triangles[prevNonNull]) {
|
|
140
|
+
prevNonNull--;
|
|
141
|
+
}
|
|
142
|
+
let nextNonNull = nextIdx;
|
|
143
|
+
while (nextNonNull < triangles.length && !triangles[nextNonNull]) {
|
|
144
|
+
nextNonNull++;
|
|
145
|
+
}
|
|
146
|
+
// Update previous triangle
|
|
147
|
+
if (prevNonNull >= 1 && nextNonNull < points.length) {
|
|
148
|
+
let prevPrevIdx = prevNonNull - 1;
|
|
149
|
+
while (prevPrevIdx >= 0 && !triangles[prevPrevIdx]) {
|
|
150
|
+
prevPrevIdx--;
|
|
151
|
+
}
|
|
152
|
+
if (prevPrevIdx >= 0) {
|
|
153
|
+
triangles[prevNonNull].area = triangleArea(points[prevPrevIdx], points[prevNonNull], points[nextNonNull]);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Update next triangle
|
|
157
|
+
if (nextNonNull < points.length - 1) {
|
|
158
|
+
let nextNextIdx = nextNonNull + 1;
|
|
159
|
+
while (nextNextIdx < points.length && !triangles[nextNextIdx]) {
|
|
160
|
+
nextNextIdx++;
|
|
161
|
+
}
|
|
162
|
+
if (nextNextIdx < points.length) {
|
|
163
|
+
triangles[nextNonNull].area = triangleArea(points[prevNonNull], points[nextNonNull], points[nextNextIdx]);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Collect remaining points
|
|
169
|
+
return points.filter((_, i) => i === 0 || i === points.length - 1 || triangles[i] !== null);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Convert path commands to point array (only L/H/V commands)
|
|
173
|
+
*/
|
|
174
|
+
function extractLinearPoints(commands, startX, startY) {
|
|
175
|
+
const points = [{ x: startX, y: startY, cmdIndex: 0 }];
|
|
176
|
+
const indices = [0];
|
|
177
|
+
let currentX = startX;
|
|
178
|
+
let currentY = startY;
|
|
179
|
+
for (let i = 0; i < commands.length; i++) {
|
|
180
|
+
const cmd = commands[i];
|
|
181
|
+
const isRelative = cmd.type === cmd.type.toLowerCase();
|
|
182
|
+
switch (cmd.type.toUpperCase()) {
|
|
183
|
+
case 'L': {
|
|
184
|
+
const x = isRelative ? currentX + cmd.values[0] : cmd.values[0];
|
|
185
|
+
const y = isRelative ? currentY + cmd.values[1] : cmd.values[1];
|
|
186
|
+
points.push({ x, y, cmdIndex: i + 1 });
|
|
187
|
+
indices.push(i + 1);
|
|
188
|
+
currentX = x;
|
|
189
|
+
currentY = y;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
case 'H': {
|
|
193
|
+
const x = isRelative ? currentX + cmd.values[0] : cmd.values[0];
|
|
194
|
+
points.push({ x, y: currentY, cmdIndex: i + 1 });
|
|
195
|
+
indices.push(i + 1);
|
|
196
|
+
currentX = x;
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
case 'V': {
|
|
200
|
+
const y = isRelative ? currentY + cmd.values[0] : cmd.values[0];
|
|
201
|
+
points.push({ x: currentX, y, cmdIndex: i + 1 });
|
|
202
|
+
indices.push(i + 1);
|
|
203
|
+
currentY = y;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
default:
|
|
207
|
+
// Update position for other commands but don't add to points
|
|
208
|
+
if (cmd.type.toUpperCase() === 'M') {
|
|
209
|
+
currentX = isRelative ? currentX + cmd.values[0] : cmd.values[0];
|
|
210
|
+
currentY = isRelative ? currentY + cmd.values[1] : cmd.values[1];
|
|
211
|
+
}
|
|
212
|
+
else if (cmd.type.toUpperCase() === 'C') {
|
|
213
|
+
currentX = isRelative ? currentX + cmd.values[4] : cmd.values[4];
|
|
214
|
+
currentY = isRelative ? currentY + cmd.values[5] : cmd.values[5];
|
|
215
|
+
}
|
|
216
|
+
else if (cmd.type.toUpperCase() === 'Q') {
|
|
217
|
+
currentX = isRelative ? currentX + cmd.values[2] : cmd.values[2];
|
|
218
|
+
currentY = isRelative ? currentY + cmd.values[3] : cmd.values[3];
|
|
219
|
+
}
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return { points, indices };
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Simplify a path by reducing the number of linear points
|
|
227
|
+
*/
|
|
228
|
+
export function simplifyPath(pathData, config, algorithm = 'douglas-peucker') {
|
|
229
|
+
const parsed = parsePath(pathData);
|
|
230
|
+
const commands = parsed.commands;
|
|
231
|
+
if (commands.length === 0) {
|
|
232
|
+
return { simplified: pathData, pointsRemoved: 0 };
|
|
233
|
+
}
|
|
234
|
+
// Get tolerance from config
|
|
235
|
+
const tolerance = config.pathTolerance || 0.5;
|
|
236
|
+
let totalPointsRemoved = 0;
|
|
237
|
+
const result = [];
|
|
238
|
+
let i = 0;
|
|
239
|
+
while (i < commands.length) {
|
|
240
|
+
const cmd = commands[i];
|
|
241
|
+
// Always keep M commands
|
|
242
|
+
if (cmd.type.toUpperCase() === 'M') {
|
|
243
|
+
result.push(cmd);
|
|
244
|
+
i++;
|
|
245
|
+
// Find the next M or end of path
|
|
246
|
+
const segmentStart = i;
|
|
247
|
+
let segmentEnd = i;
|
|
248
|
+
while (segmentEnd < commands.length &&
|
|
249
|
+
commands[segmentEnd].type.toUpperCase() !== 'M') {
|
|
250
|
+
segmentEnd++;
|
|
251
|
+
}
|
|
252
|
+
// Extract linear segment
|
|
253
|
+
const segment = commands.slice(segmentStart, segmentEnd);
|
|
254
|
+
const { points } = extractLinearPoints(segment, cmd.values[0], cmd.values[1]);
|
|
255
|
+
// Only simplify if we have enough points
|
|
256
|
+
if (points.length > 2) {
|
|
257
|
+
// Choose algorithm
|
|
258
|
+
const simplified = algorithm === 'visvalingam'
|
|
259
|
+
? visvalingamWhyatt(points, tolerance)
|
|
260
|
+
: douglasPeucker(points, tolerance);
|
|
261
|
+
totalPointsRemoved += points.length - simplified.length;
|
|
262
|
+
// Convert back to commands (skip first point, it's the M)
|
|
263
|
+
for (let j = 1; j < simplified.length; j++) {
|
|
264
|
+
result.push({
|
|
265
|
+
type: 'L',
|
|
266
|
+
values: [simplified[j].x, simplified[j].y],
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
// Add any non-linear commands that were in the segment
|
|
270
|
+
for (let j = 0; j < segment.length; j++) {
|
|
271
|
+
const c = segment[j];
|
|
272
|
+
if (c.type.toUpperCase() !== 'L' &&
|
|
273
|
+
c.type.toUpperCase() !== 'H' &&
|
|
274
|
+
c.type.toUpperCase() !== 'V') {
|
|
275
|
+
result.push(c);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
// Too few points, keep as-is
|
|
281
|
+
result.push(...segment);
|
|
282
|
+
}
|
|
283
|
+
i = segmentEnd;
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
result.push(cmd);
|
|
287
|
+
i++;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return {
|
|
291
|
+
simplified: serializePath(result, 2),
|
|
292
|
+
pointsRemoved: totalPointsRemoved,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Optimization stage for path simplification
|
|
297
|
+
*/
|
|
298
|
+
export function pathSimplificationStage(config) {
|
|
299
|
+
return {
|
|
300
|
+
name: 'path-simplification',
|
|
301
|
+
async transform(svgContent) {
|
|
302
|
+
if (!config.enablePathSimplification) {
|
|
303
|
+
return svgContent;
|
|
304
|
+
}
|
|
305
|
+
let modified = false;
|
|
306
|
+
let totalPointsRemoved = 0;
|
|
307
|
+
// Choose algorithm based on optimization level
|
|
308
|
+
const algorithm = config.optimizationLevel === OptLevel.MAXIMUM
|
|
309
|
+
? 'visvalingam'
|
|
310
|
+
: 'douglas-peucker';
|
|
311
|
+
const result = svgContent.replace(/<path[^>]*\sd="([^"]+)"[^>]*>/g, (match, pathData) => {
|
|
312
|
+
const { simplified, pointsRemoved } = simplifyPath(pathData, config, algorithm);
|
|
313
|
+
if (pointsRemoved > 0) {
|
|
314
|
+
modified = true;
|
|
315
|
+
totalPointsRemoved += pointsRemoved;
|
|
316
|
+
return match.replace(`d="${pathData}"`, `d="${simplified}"`);
|
|
317
|
+
}
|
|
318
|
+
return match;
|
|
319
|
+
});
|
|
320
|
+
if (modified) {
|
|
321
|
+
console.log(`[path-simplification] Removed ${totalPointsRemoved} points using ${algorithm}`);
|
|
322
|
+
}
|
|
323
|
+
return result;
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remove Hidden and Empty Elements
|
|
3
|
+
* Drop empty <text>, invisible elements (display:none, visibility:hidden, opacity=0)
|
|
4
|
+
* Recursively check children before removing
|
|
5
|
+
*/
|
|
6
|
+
import type { SVGNode } from './svg-tree-parser.js';
|
|
7
|
+
/**
|
|
8
|
+
* Remove hidden and empty elements from tree
|
|
9
|
+
*/
|
|
10
|
+
export declare function removeHiddenAndEmptyElements(root: SVGNode): {
|
|
11
|
+
removedCount: number;
|
|
12
|
+
removedNodes: Array<{
|
|
13
|
+
tag: string;
|
|
14
|
+
reason: string;
|
|
15
|
+
}>;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Remove hidden and empty elements stage
|
|
19
|
+
*/
|
|
20
|
+
export declare function removeHiddenAndEmptyElementsStage(root: SVGNode): {
|
|
21
|
+
modified: boolean;
|
|
22
|
+
stats: {
|
|
23
|
+
removedCount: number;
|
|
24
|
+
removedNodes: Array<{
|
|
25
|
+
tag: string;
|
|
26
|
+
reason: string;
|
|
27
|
+
}>;
|
|
28
|
+
};
|
|
29
|
+
};
|