├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── HISTORY.md ├── LICENSE ├── Makefile ├── README.md ├── scour.sublime-project ├── scour ├── __init__.py ├── scour.py ├── stats.py ├── svg_regex.py ├── svg_transform.py └── yocto_css.py ├── setup.py ├── test_css.py ├── test_scour.py ├── tox.ini └── unittests ├── adobe.svg ├── cascading-default-attribute-removal.svg ├── cdata.svg ├── collapse-gradients-gradientUnits.svg ├── collapse-gradients-preserve-xlink-href.svg ├── collapse-gradients.svg ├── collapse-same-path-points.svg ├── collapse-straight-path-segments.svg ├── color-formats.svg ├── comment-beside-xml-decl.svg ├── comments.svg ├── commonized-referenced-elements.svg ├── css-reference.svg ├── descriptive-elements-with-text.svg ├── doctype.svg ├── dont-collapse-gradients.svg ├── dont-convert-short-color-names.svg ├── duplicate-gradient-stops-pct.svg ├── duplicate-gradient-stops.svg ├── duplicate-gradients-update-style.svg ├── empty-descriptive-elements.svg ├── empty-g.svg ├── empty-style.svg ├── encoding-iso-8859-15.svg ├── encoding-utf8.svg ├── entities.svg ├── fill-none.svg ├── flowtext-less.svg ├── flowtext.svg ├── font-styles.svg ├── full-descriptive-elements.svg ├── gradient-default-attrs.svg ├── group-creation.svg ├── group-no-creation-tspan.svg ├── group-no-creation.svg ├── group-sibling-merge-crash.svg ├── group-sibling-merge.svg ├── groups-in-switch-with-id.svg ├── groups-in-switch.svg ├── groups-with-title-desc.svg ├── ids-protect.svg ├── ids-to-strip.svg ├── ids.svg ├── important-groups-in-defs.svg ├── inkscape.svg ├── minimal.svg ├── move-common-attributes-to-grandparent.svg ├── move-common-attributes-to-parent.svg ├── nested-defs.svg ├── nested-useless-groups.svg ├── newlines.svg ├── no-collapse-lines.svg ├── orient-marker.svg ├── overflow-marker.svg ├── overflow-svg.svg ├── path-abs-to-rel.svg ├── path-bez-optimize.svg ├── path-command-rewrites.svg ├── path-elliptical-flags.svg ├── path-implicit-line.svg ├── path-line-optimize.svg ├── path-no-optimize.svg ├── path-precision-control-points.svg ├── path-precision.svg ├── path-quad-optimize.svg ├── path-simple-triangle.svg ├── path-sn.svg ├── path-truncate-zeros-calc.svg ├── path-truncate-zeros.svg ├── path-use-scientific-notation.svg ├── path-with-caps.svg ├── path-with-closepath.svg ├── polygon-coord-neg-first.svg ├── polygon-coord-neg.svg ├── polygon-coord.svg ├── polygon.svg ├── polyline-coord-neg-first.svg ├── polyline-coord-neg.svg ├── polyline-coord.svg ├── protection.svg ├── quot-in-url.svg ├── quotes-in-styles.svg ├── raster-formats.svg ├── raster-paths-local.svg ├── raster-paths-remote.svg ├── raster.gif ├── raster.jpg ├── raster.png ├── redundant-svg-namespace.svg ├── referenced-elements-1.svg ├── referenced-font.svg ├── refs-in-defs.svg ├── remove-default-attr-order.svg ├── remove-default-attr-std-deviation.svg ├── remove-duplicate-gradients-master-without-id.svg ├── remove-duplicate-gradients.svg ├── remove-unused-attributes-on-parent.svg ├── scour-lengths.svg ├── shorten-ids-stable-output.svg ├── shorten-ids.svg ├── sodipodi.svg ├── straight-curve.svg ├── stroke-none.svg ├── stroke-nowidth.svg ├── stroke-transparent.svg ├── style-cdata.svg ├── style-to-attr.svg ├── style.svg ├── transform-matrix-is-identity.svg ├── transform-matrix-is-rotate-135.svg ├── transform-matrix-is-rotate-225.svg ├── transform-matrix-is-rotate-45.svg ├── transform-matrix-is-rotate-90.svg ├── transform-matrix-is-rotate-neg-45.svg ├── transform-matrix-is-rotate-neg-90.svg ├── transform-matrix-is-scale-2-3.svg ├── transform-matrix-is-scale-neg-1.svg ├── transform-matrix-is-translate.svg ├── transform-rotate-fold-3args.svg ├── transform-rotate-is-identity.svg ├── transform-rotate-trim-range-719.5.svg ├── transform-rotate-trim-range-neg-540.0.svg ├── transform-scale-is-identity.svg ├── transform-skewX-is-identity.svg ├── transform-skewY-is-identity.svg ├── transform-translate-is-identity.svg ├── unreferenced-defs.svg ├── unreferenced-font.svg ├── unreferenced-linearGradient.svg ├── unreferenced-pattern.svg ├── unreferenced-radialGradient.svg ├── useless-defs.svg ├── viewbox-create.svg ├── viewbox-remove.svg ├── whitespace-defs.svg ├── whitespace.svg ├── xml-namespace-attrs.svg ├── xml-ns-decl.svg ├── xml-space.svg └── xml-well-formed.svg /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | *.sublime-workspace 3 | build 4 | dist 5 | *.egg-info 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: python 4 | 5 | python: 6 | - pypy 7 | - 2.7 8 | - 3.4 9 | - 3.5 10 | - 3.6 11 | - 3.7 12 | - 3.8 13 | - 3.9 14 | - 3.10-dev 15 | install: 16 | - pip install tox-travis codecov 17 | 18 | script: 19 | - tox 20 | 21 | matrix: 22 | fast_finish: true 23 | 24 | include: 25 | - python: 3.9 26 | env: 27 | - TOXENV=flake8 28 | 29 | after_success: 30 | - coverage combine && codecov 31 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions to Scour are welcome, feel free to create a pull request! 4 | 5 | In order to be able to merge your PR as fast as possible please try to stick to the following guidelines. 6 | 7 | > _**TL;DR** (if you now what you're doing) – Always run [`make check`](https://github.com/scour-project/scour/blob/master/Makefile) before creating a PR to check for common problems._ 8 | 9 | 10 | ## Code Style 11 | 12 | The Scour project tries to follow the coding conventions described in [PEP 8 - The Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/). While there are some inconsistencies in existing code (e.g. with respect to naming conventions and the usage of globals), new code should always abide by the standard. 13 | 14 | To quickly check for common mistakes you can use [`flake8`](https://pypi.python.org/pypi/flake8). Our [Makefile](https://github.com/scour-project/scour/blob/master/Makefile) has a convenience target with the correct options: 15 | ```Makefile 16 | make flake8 17 | ``` 18 | 19 | ## Unit Tests 20 | 21 | In order to check functionality of Scour and prevent any regressions in existing code a number of tests exist which use the [`unittest`](https://docs.python.org/library/unittest.html) unit testing framework which ships with Python. You can quickly run the tests by using the [Makefile](https://github.com/scour-project/scour/blob/master/Makefile) convenience target: 22 | ```Makefile 23 | make test 24 | ``` 25 | 26 | These tests are run automatically on all PRs using [TravisCI](https://travis-ci.org/scour-project/scour) and have to pass at all times! When you add new functionality you should always include suitable tests with your PR (see [`test_scour.py`](https://github.com/scour-project/scour/blob/master/test_scour.py)). 27 | 28 | ### Coverage 29 | 30 | To ensure that all possible code conditions are covered by a test you can use [`coverage`](https://pypi.python.org/pypi/coverage). The [Makefile](https://github.com/scour-project/scour/blob/master/Makefile) convenience target automatically creates an HTML report in `htmlcov/index.html`: 31 | ```Makefile 32 | make coverage 33 | ``` 34 | 35 | These reports are also created automatically by our TravisCI builds and are accessible via [Codecov](https://codecov.io/gh/scour-project/scour) 36 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # Release Notes for Scour 2 | 3 | ## Version 0.38.2 (2020-11-22) 4 | * Fix another regression caused by new feature to merge sibling groups ([#260](https://github.com/scour-project/scour/issues/260)) 5 | 6 | ## Version 0.38.1 (2020-09-02) 7 | * Fix regression caused by new feature to merge sibling groups ([#260](https://github.com/scour-project/scour/issues/260)) 8 | 9 | ## Version 0.38 (2020-08-06) 10 | * Fix issue with dropping xlink:href attribute when collapsing referenced gradients ([#206](https://github.com/scour-project/scour/pull/206)) 11 | * Fix issue with dropping ID while de-duplicating gradients ([#207](https://github.com/scour-project/scour/pull/207)) 12 | * Improve `--shorten-ids` so it re-maps IDs that are already used in the document if they're shorter ([#187](https://github.com/scour-project/scour/pull/187)) 13 | * Fix whitespace handling for SVG 1.2 flowed text ([#235](https://github.com/scour-project/scour/issues/235)) 14 | * Improvement: Merge sibling `` nodes with identical attributes ([#208](https://github.com/scour-project/scour/pull/208)) 15 | * Improve performance of XML serialization ([#247](https://github.com/scour-project/scour/pull/247)) 16 | * Improve performance of gradient de-duplication ([#248](https://github.com/scour-project/scour/pull/248)) 17 | * Some general performance improvements ([#249](https://github.com/scour-project/scour/pull/249)) 18 | 19 | ## Version 0.37 (2018-07-04) 20 | * Fix escaping of quotes in attribute values. ([#152](https://github.com/scour-project/scour/pull/152)) 21 | * A lot of performance improvements making processing significantly faster in many cases. ([#167](https://github.com/scour-project/scour/pull/167), [#169](https://github.com/scour-project/scour/pull/169), [#171](https://github.com/scour-project/scour/pull/171), [#185](https://github.com/scour-project/scour/pull/185)) 22 | * Fix exception when removing duplicated gradients while `--keep-unreferenced-defs` is used ([#173](https://github.com/scour-project/scour/pull/173)) 23 | * Remove some illegal optimizations of `m0 0` sub-path commands ([#178](https://github.com/scour-project/scour/pull/178)) 24 | * Fix and improve handling of boolean flags in elliptical arc path commands ([#183](https://github.com/scour-project/scour/pull/183)) 25 | * Fix exception when shorthand transform `scale(1)` with single number is used ([#191](https://github.com/scour-project/scour/pull/191)) 26 | * Fix exception when using two-number forms of the filter attributes `baseFrequency`, `order`, `radius` and `stdDeviation` ([#192](https://github.com/scour-project/scour/pull/192)) 27 | * Improve whitespace handling in text nodes fixing an issue where scouring added spaces in error and reducing file size in many cases ([#199](https://github.com/scour-project/scour/pull/199)) 28 | * Drop official support for Python 3.3. (While it will probably continue to work for a while compatibility is not guaranteed anymore. If you continue to use Scour with Python 3.3 and should find/fix any compatibility issues pull requests are welcome, though.) 29 | 30 | 31 | ## Version 0.36 (2017-08-06) 32 | * Fix embedding of raster images which was broken in most cases and did not work at all in Python 3. ([#120](https://github.com/scour-project/scour/issues/120)) 33 | * Some minor fixes for statistics output. 34 | * Greatly improve the algorithm to reduce numeric precision. 35 | * Precision was not properly reduced for some numbers. 36 | * Only use reduced precision if it results in a shorter string representation, otherwise preserve full precision in output (e.g. use "123" instead of "1e2" when precision is set to 1). 37 | * Reduce precision of lengths in `viewBox` ([#127](https://github.com/scour-project/scour/issues/127)) 38 | * Add option `--set-c-precision` which allows to set a reduced numeric precision for control points.
Control points determine how a path is bent in between two nodes and are less sensitive to a reduced precision than the position coordinates of the nodes themselves. This option can be used to save a few additional bytes without affecting visual appearance negatively. 39 | * Fix: Unnecessary whitespace was not stripped from elliptical paths. ([#89](https://github.com/scour-project/scour/issues/89)) 40 | * Improve and fix functionality to collapse straight paths segments. ([#146](https://github.com/scour-project/scour/issues/146)) 41 | * Collapse subpaths of moveto `m` and lineto `l`commands if they have the same direction (before we only collapsed horizontal/vertical `h`/`v` lineto commands). 42 | * Attempt to collapse lineto `l` commands into a preceding moveto `m` command (these are then called "implicit lineto commands") 43 | * Do not collapse straight path segments in paths that have intermediate markers. ([#145](https://github.com/scour-project/scour/issues/145)) 44 | * Preserve empty path segments if they have `stroke-linecap` set to `round` or `square`. They render no visible line but a tiny dot or square. 45 | 46 | 47 | ## Version 0.35 (2016-09-14) 48 | 49 | * Drop official support for Python 2.6. (While it will probably continue to work for a while compatibility is not guaranteed anymore. If you continue to use Scour with Python 2.6 and should find/fix any compatibility issues pull requests are welcome, though.) 50 | * Fix: Unused IDs were not shortened when `--shorten-ids` was used. ([#19](https://github.com/scour-project/scour/issues/62)) 51 | * Fix: Most elements were still removed from `` when `--keep-unreferenced-defs` was used. ([#62](https://github.com/scour-project/scour/issues/62)) 52 | * Improve escaping of single/double quotes ('/") in attributes. ([#64](https://github.com/scour-project/scour/issues/64)) 53 | * Print usage information if no input file was specified (and no data is available from `stdin`). ([#65](https://github.com/scour-project/scour/issues/65)) 54 | * Redirect informational output to `stderr` when SVG is output to `stdout`. ([#67](https://github.com/scour-project/scour/issues/67)) 55 | * Allow elements to be found via `Document.getElementById()` in the minidom document returned by scourXmlFile(). ([#68](https://github.com/scour-project/scour/issues/68)) 56 | * Improve code to remove default attribute values and add a lot of new default values. ([#70](https://github.com/scour-project/scour/issues/70)) 57 | * Fix: Only attempt to group elements that the content model allows to be children of a `` when `--create-groups` is specified. ([#98](https://github.com/scour-project/scour/issues/98)) 58 | * Fix: Update list of SVG presentation attributes allowing more styles to be converted to attributes and remove two entries (`line-height` and `visibility`) that were actually invalid. ([#99](https://github.com/scour-project/scour/issues/99)) 59 | * Add three options that work analogous to `--remove-metadata` (removes `` elements) ([#102](https://github.com/scour-project/scour/issues/102)) 60 | * `--remove-titles` (removes `` elements) 61 | * `--remove-descriptions` (removes `<desc>` elements) 62 | * `--remove-descriptive-elements` (removes all of the descriptive elements, i.e. `<title>`, `<desc>` and `<metadata>`) 63 | * Fix removal rules for the `overflow` attribute. ([#104](https://github.com/scour-project/scour/issues/104)) 64 | * Improvement: Automatically order all attributes ([#105](https://github.com/scour-project/scour/issues/105)), as well as `style` declarations ([#107](https://github.com/scour-project/scour/issues/107)) allowing for a constant output across multiple runs of Scour. Before order could change arbitrarily. 65 | * Improve path scouring. ([#108](https://github.com/scour-project/scour/issues/108))<br>Notably Scour performs all calculations with enhanced precision now, guaranteeing maximum accuracy when optimizing path data. Numerical precision is reduced as a last step of the optimization according to the `--precision` option. 66 | * Fix replacement of removed duplicate gradients if the `fill`/`stroke` properties contained a fallback. ([#109](https://github.com/scour-project/scour/issues/109)) 67 | * Fix conversion of cubic Bézier "curveto" commands into "shorthand/smooth curveto" commands. ([#110](https://github.com/scour-project/scour/issues/110)) 68 | * Fix some issues due to removal of properties without considering inheritance rules. ([#111](https://github.com/scour-project/scour/issues/111)) 69 | 70 | 71 | ## Version 0.34 (2016-07-25) 72 | 73 | * Add a function to sanitize an arbitrary Python object containing options for Scour as attributes (usage: `Scour.sanitizeOptions(options)`).<br>This simplifies usage of the Scour module by other scripts while avoiding any compatibility issues that might arise when options are added/removed/renamed in Scour. ([#44](https://github.com/scour-project/scour/issues/44)) 74 | * Input/output file can now be specified as positional arguments (e.g. `scour input.svg output.svg`). ([#46](https://github.com/scour-project/scour/issues/46)) 75 | * Improve `--help` output by intuitively arranging options in groups. ([#46](https://github.com/scour-project/scour/issues/46)) 76 | * Add option `--error-on-flowtext` to raise an exception whenever a non-standard `<flowText>` element is found (which is only supported in Inkscape). If this option is not specified a warning will be shown. ([#53](https://github.com/scour-project/scour/issues/53)) 77 | * Automate tests with continuous integration via Travis. ([#52](https://github.com/scour-project/scour/issues/52)) 78 | 79 | 80 | ## Version 0.33 (2016-01-29) 81 | 82 | * Add support for removal of editor data of Sketch. ([#37](https://github.com/scour-project/scour/issues/37)) 83 | * Add option `--verbose` (or `-v`) to show detailed statistics after running Scour. By default only a single line containing the most important information is output now. 84 | 85 | 86 | ## Version 0.32 (2015-12-10) 87 | 88 | * Add functionality to remove unused XML namespace declarations from the `<svg>` root element. ([#14](https://github.com/scour-project/scour/issues/14)) 89 | * Restore unittests which were lost during move to GitHub. ([#24](https://github.com/scour-project/scour/issues/24)) 90 | * Fix a potential regex matching issue in `points` attribute of `<polygon>` and `<polyline>` elements. ([#24](https://github.com/scour-project/scour/issues/24)) 91 | * Fix a crash with `points` attribute of `<polygon>` and `<polyline>` starting with a negative number. ([#24](https://github.com/scour-project/scour/issues/24)) 92 | * Fix encoding issues when input file contained unicode characters. ([#27](https://github.com/scour-project/scour/issues/27)) 93 | * Fix encoding issues when using `stding`/`stdout` as input/output. ([#27](https://github.com/scour-project/scour/issues/27)) 94 | * Fix removal of comments. If a node contained multiple comments usually not all of them were removed. ([#28](https://github.com/scour-project/scour/issues/28)) 95 | 96 | 97 | ## Version 0.31 (2015-11-16) 98 | 99 | * Ensure Python 3 compatibility. ([#8](https://github.com/scour-project/scour/issues/8)) 100 | * Add option `--nindent` to set the number of spaces/tabs used for indentation (defaults to 1). ([#13](https://github.com/scour-project/scour/issues/13)) 101 | * Add option `--no-line-breaks` to suppress output of line breaks and indentation altogether. ([#13](https://github.com/scour-project/scour/issues/13)) 102 | * Add option `--strip-xml-space` which removes the specification of `xml:space="preserve"` on the `<svg>` root element which would otherwise disallow Scour to make any whitespace changes in output. ([#13](https://github.com/scour-project/scour/issues/13)) 103 | 104 | 105 | ## Version 0.30 (2014-08-05) 106 | 107 | * Fix ignoring of additional args when invoked from scons. 108 | 109 | 110 | ## Version 0.29 (2014-07-26) 111 | 112 | * Add option `--keep-unreferenced-defs` to preserve elements in `<defs>` that are not referenced and would be removed otherwise. ([#2](https://github.com/scour-project/scour/issues/2)) 113 | * Add option to ignore unknown cmd line opts. 114 | 115 | 116 | ## Version 0.28 (2014-01-12) 117 | 118 | * Add option `--shorten-ids-prefix` which allows to add a custom prefix to all shortened IDs. ([#1](https://github.com/scour-project/scour/issues/1)) 119 | 120 | 121 | ## Version 0.27 (2013-10-26) 122 | 123 | * Allow direct calling of the Scour module. 124 | 125 | 126 | ## Version 0.26 (2013-10-22) 127 | 128 | * Re-release of Scour 0.26, re-packaged as a Python module [available from PyPI](https://pypi.python.org/pypi/scour) (Thanks to [Tobias Oberstet](https://github.com/oberstet)!). 129 | * Development moved to GitHub (https://github.com/scour-project/scour). 130 | 131 | 132 | ## Version 0.26 (2011-05-09) 133 | 134 | * Fix [Bug 702423](https://bugs.launchpad.net/scour/+bug/702423) to function well in the presence of multiple identical gradients and `--disable-style-to-xml`. 135 | * Fix [Bug 722544](https://bugs.launchpad.net/scour/+bug/722544) to properly optimize transformation matrices. Also optimize more things away in transformation specifications. (Thanks to Johan Sundström for the patch.) 136 | * Fix [Bug 616150](https://bugs.launchpad.net/scour/+bug/616150) to run faster using the `--create-groups` option. 137 | * Fix [Bug 708515](https://bugs.launchpad.net/scour/+bug/562784) to handle raster embedding better in the presence of file:// URLs. 138 | * Fix [Bug 714717](https://bugs.launchpad.net/scour/+bug/714717) to avoid deleting renderable CurveTo commands in paths, which happen to end where they started. 139 | * Per [Bug 714727](https://bugs.launchpad.net/scour/+bug/714727) and [Bug 714720](https://bugs.launchpad.net/scour/+bug/714720), Scour now deletes text attributes, including "text-align", from elements and groups of elements that only contain shapes. (Thanks to Jan Thor for the patches.) 140 | * Per [Bug 714731](https://bugs.launchpad.net/scour/+bug/714731), remove the default value of more SVG attributes. (Thanks to Jan Thor for the patch.) 141 | * Fix [Bug 717826](https://bugs.launchpad.net/scour/+bug/717826) to emit the correct line terminator (CR LF) in optimized SVG content on the version of Scour used in Inkscape on Windows. 142 | * Fix [Bug 734933](https://bugs.launchpad.net/scour/+bug/734933) to avoid deleting renderable LineTo commands in paths, which happen to end where they started, if their stroke-linecap property has the value "round". 143 | * Fix [Bug 717254](https://bugs.launchpad.net/scour/+bug/717254) to delete `<defs>` elements that become empty after unreferenced element removal. (Thanks to Jan Thor for the patch.) 144 | * Fix [Bug 627372](https://bugs.launchpad.net/scour/+bug/627372) to future-proof the parameter passing between Scour and Inkscape. (Thanks to Bernd Feige for the patch.) 145 | * Fix [Bug 638764](https://bugs.launchpad.net/scour/+bug/638764), which crashed Scour due to [Python Issue 2531](http://bugs.python.org/issue2531) regarding floating-point handling in ArcTo path commands. (Thanks to [Walther](https://launchpad.net/~walther-md) for investigating this bug.) 146 | * Per [Bug 654759](https://bugs.launchpad.net/scour/+bug/654759), enable librsvg workarounds by default in Scour. 147 | * Added ID change and removal protection options per [bug 492277](https://bugs.launchpad.net/scour/+bug/492277): `--protect-ids-noninkscape`, `--protect-ids-prefix`, `--protect-ids-list`. (Thanks to Jan Thor for this patch.) 148 | 149 | 150 | ## Version 0.25 (2010-07-11) 151 | 152 | * Fix [Bug 541889](https://bugs.launchpad.net/scour/+bug/541889) to parse polygon/polyline points missing whitespace/comma separating a negative value. Always output points attributes as comma-separated. 153 | * Fix [Bug 519698](https://bugs.launchpad.net/scour/+bug/519698) to properly parse move commands that have line segments. 154 | * Fix [Bug 577940](https://bugs.launchpad.net/scour/+bug/577940) to include stroke-dasharray into list of style properties turned into XML attributes. 155 | * Fix [Bug 562784](https://bugs.launchpad.net/scour/+bug/562784), typo in Inkscape description 156 | * Fix [Bug 603988](https://bugs.launchpad.net/scour/+bug/603988), do not commonize attributes if the element is referenced elsewhere. 157 | * Fix [Bug 604000](https://bugs.launchpad.net/scour/+bug/604000), correctly remove default overflow attributes. 158 | * Fix [Bug 603994](https://bugs.launchpad.net/scour/+bug/603994), fix parsing of `<style>` element contents when a CDATA is present 159 | * Fix [Bug 583758](https://bugs.launchpad.net/scour/+bug/583758), added a bit to the Inkscape help text saying that groups aren't collapsed if IDs are also not stripped. 160 | * Fix [Bug 583458](https://bugs.launchpad.net/scour/+bug/583458), another typo in the Inkscape help tab. 161 | * Fix [Bug 594930](https://bugs.launchpad.net/scour/+bug/594930), In a `<switch>`, require one level of `<g>` if there was a `<g>` in the file already. Otherwise, only the first subelement of the `<g>` is chosen and rendered. 162 | * Fix [Bug 576958](https://bugs.launchpad.net/scour/+bug/576958), "Viewbox option doesn't work when units are set", when renderer workarounds are disabled. 163 | * Added many options: `--remove-metadata`, `--quiet`, `--enable-comment-stripping`, `--shorten-ids`, `--renderer-workaround`. 164 | 165 | 166 | ## Version 0.24 (2010-02-05) 167 | 168 | * Fix [Bug 517064](https://bugs.launchpad.net/scour/+bug/517064) to make XML well-formed again 169 | * Fix [Bug 503750](https://bugs.launchpad.net/scour/+bug/503750) fix Inkscape extension to correctly pass `--enable-viewboxing` 170 | * Fix [Bug 511186](https://bugs.launchpad.net/scour/+bug/511186) to allow comments outside of the root `<svg>` node 171 | 172 | 173 | ## Version 0.23 (2010-01-04) 174 | 175 | * Fix [Bug 482215](https://bugs.launchpad.net/scour/+bug/482215) by using os.linesep to end lines 176 | * Fix unittests to run properly in Windows 177 | * Removed default scaling of image to 100%/100% and creating a viewBox. Added `--enable-viewboxing` option to explicitly turn that on 178 | * Fix [Bug 503034](https://bugs.launchpad.net/scour/+bug/503034) by only removing children of a group if the group itself has not been referenced anywhere else in the file 179 | 180 | 181 | ## Version 0.22 (2009-11-09) 182 | 183 | * Fix [Bug 449803](https://bugs.launchpad.net/scour/+bug/449803) by ensuring input and output filenames differ. 184 | * Fix [Bug 453737](https://bugs.launchpad.net/scour/+bug/453737) by updated Inkscape's scour extension with a UI 185 | * Fix whitespace collapsing on non-textual elements that had xml:space="preserve" 186 | * Fix [Bug 479669](https://bugs.launchpad.net/scour/+bug/479669) to handle empty `<style>` elements. 187 | 188 | 189 | ## Version 0.21 (2009-09-27) 190 | 191 | * Fix [Bug 427309](https://bugs.launchpad.net/scour/+bug/427309) by updated Scour inkscape extension file to include yocto_css.py 192 | * Fix [Bug 435689](https://bugs.launchpad.net/scour/+bug/435689) by properly preserving whitespace in XML serialization 193 | * Fix [Bug 436569](https://bugs.launchpad.net/scour/+bug/436569) by getting `xlink:href` prefix correct with invalid SVG 194 | 195 | 196 | ## Version 0.20 (2009-08-31) 197 | 198 | * Fix [Bug 368716](https://bugs.launchpad.net/scour/+bug/368716) by implementing a really tiny CSS parser to find out if any style element have rules referencing gradients, filters, etc 199 | * Remove unused attributes from parent elements 200 | * Fix a bug with polygon/polyline point parsing if there was whitespace at the end 201 | 202 | 203 | ## Version 0.19 (2009-08-13) 204 | 205 | * Fix XML serialization bug: `xmlns:XXX` prefixes not preserved when not in default namespace 206 | * Fix XML serialization bug: remapping to default namespace was not actually removing the old prefix 207 | * Move common attributes to ancestor elements 208 | * Fix [Bug 412754](https://bugs.launchpad.net/scour/+bug/401628): Elliptical arc commands must have comma/whitespace separating the coordinates 209 | * Scour lengths for svg x,y,width,height,*opacity,stroke-width,stroke-miterlimit 210 | 211 | 212 | ## Version 0.18 (2009-08-09) 213 | 214 | * Remove attributes of gradients if they contain default values 215 | * Reduce bezier/quadratic (c/q) segments to their shorthand equivalents (s/t) 216 | * Move to a custom XML serialization such that `id`/`xml:id` is printed first (Thanks to Richard Hutch for the suggestion) 217 | * Added `--indent` option to specify indentation type (default='space', other options: 'none', 'tab') 218 | 219 | 220 | ## Version 0.17 (2009-08-03) 221 | 222 | * Only convert to #RRGGBB format if the color name will actually be shorter 223 | * Remove duplicate gradients 224 | * Remove empty q,a path segments 225 | * Scour polyline coordinates just like path/polygon 226 | * Scour lengths from most attributes 227 | * Remove redundant SVG namespace declarations and prefixes 228 | 229 | 230 | ## Version 0.16 (2009-07-30) 231 | 232 | * Fix [Bug 401628](https://bugs.launchpad.net/scour/+bug/401628): Keep namespace declarations when using `--keep-editor-data` (Thanks YoNoSoyTu!) 233 | * Remove trailing zeros after decimal places for all path coordinates 234 | * Use scientific notation in path coordinates if that representation is shorter 235 | * Scour polygon coordinates just like path coordinates 236 | * Add XML prolog to scour output to ensure valid XML, added `--strip-xml-prolog` option 237 | 238 | 239 | ## Version 0.15 (2009-07-05) 240 | 241 | * added `--keep-editor-data` command-line option 242 | * Fix [Bug 395645](https://bugs.launchpad.net/scour/+bug/395645): Keep all identified children inside a defs (Thanks Frederik!) 243 | * Fix [Bug 395647](https://bugs.launchpad.net/scour/+bug/395647): Do not remove closepath (Z) path segments 244 | 245 | 246 | ## Version 0.14 (2009-06-10) 247 | 248 | * Collapse adjacent commands of the same type 249 | * Convert straight curves into line commands 250 | * Eliminate last segment in a polygon 251 | * Rework command-line argument parsing 252 | * Fix bug in embedRasters() caused by new command-line parsing 253 | * added `--disable-embed-rasters` command-line option 254 | 255 | 256 | ## Version 0.13 (2009-05-19) 257 | 258 | * properly deal with `fill="url("#foo")"` 259 | * properly handle paths with more than 1 pair of coordinates in the first Move command 260 | * remove font/text styles from shape elements (font-weight, font-size, line-height, etc) 261 | * remove -inkscape-font-specification styles 262 | * added `--set-precision` argument to set the number of significant digits (defaults to 5 now) 263 | * collapse consecutive h,v coords/segments that go in the same direction 264 | 265 | 266 | ## Version 0.12 (2009-05-17) 267 | 268 | * upgraded enthought's path parser to handle scientific notation in path coordinates 269 | * convert colors to #RRGGBB format 270 | * added option to disable color conversion 271 | 272 | 273 | ## Version 0.11 (2009-04-28) 274 | 275 | * convert gradient stop offsets from percentages to float 276 | * convert gradient stop offsets to integers if possible (0 or 1) 277 | * fix bug in line-to-hv conversion 278 | * handle non-ASCII characters (Unicode) 279 | * remove empty line or curve segments from path 280 | * added option to prevent style-to-xml conversion 281 | * handle compressed svg (svgz) on the input and output 282 | * added total time taken to the report 283 | * Removed XML pretty printing because of [this problem](http://ronrothman.com/public/leftbraned/xml-dom-minidom-toprettyxml-and-silly-whitespace/). 284 | 285 | 286 | ## Version 0.10 (2009-04-27) 287 | 288 | * Remove path with empty d attributes 289 | * Sanitize path data (remove unnecessary whitespace) 290 | * Convert from absolute to relative path data 291 | * Remove trailing zeroes from path data 292 | * Limit to no more than 6 digits of precision 293 | * Remove empty line segments 294 | * Convert lines to horiz/vertical line segments where possible 295 | * Remove some more default styles (`display:none`, `visibility:visible`, `overflow:visible`, 296 | `marker:none`) 297 | 298 | 299 | ## Version 0.09 (2009-04-25) 300 | 301 | * Fix bug when removing stroke styles 302 | * Remove gradients that are only referenced by one other gradient 303 | * Added option to prevent group collapsing 304 | * Prevent groups with title/desc children from being collapsed 305 | * Remove stroke="none" 306 | 307 | 308 | ## Version 0.08 (2009-04-22) 309 | 310 | * Remove unnecessary nested `<g>` elements 311 | * Remove duplicate gradient stops (same offset, stop-color, stop-opacity) 312 | * Always keep fonts inside `<defs>`, always keep ids on fonts 313 | * made ID stripping optional (disabled by default) 314 | 315 | 316 | ## Version 0.07 (2009-04-15) 317 | 318 | * moved all functionality into a module level function named 'scour' and began adding unit tests 319 | * prevent metadata from being removed if they contain only text nodes 320 | * Remove unreferenced pattern and gradient elements outside of defs 321 | * Removal of extra whitespace, pretty printing of XML 322 | 323 | 324 | ## Version 0.06 (2009-04-13) 325 | 326 | * Prevent error when stroke-width property value has a unit 327 | * Convert width/height into a viewBox where possible 328 | * Convert all referenced rasters into base64 encoded URLs if the files can be found 329 | 330 | 331 | ## Version 0.05 (2009-04-07) 332 | 333 | * Removes unreferenced elements in a `<defs>` 334 | * Removes all inkscape, sodipodi, adobe elements 335 | * Removes all inkscape, sodipodi, adobe attributes 336 | * Remove all unused namespace declarations on the document element 337 | * Removes any empty `<defs>`, `<metadata>`, or `<g>` elements 338 | * Style fix-ups: 339 | * Fixes any style properties like this: `style="fill: url(#linearGradient1000) rgb(0, 0, 0);"` 340 | * Removes any style property of: `opacity: 1;` 341 | * Removes any stroke properties when `stroke=none` or `stroke-opacity=0` or `stroke-width=0` 342 | * Removes any fill properties when `fill=none` or `fill-opacity=0` 343 | * Removes all fill/stroke properties when `opacity=0` 344 | * Removes any `stop-opacity: 1` 345 | * Removes any `fill-opacity: 1` 346 | * Removes any `stroke-opacity: 1` 347 | * Convert style properties into SVG attributes 348 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: clean install 2 | 3 | install: 4 | python setup.py install 5 | 6 | clean: 7 | rm -rf build 8 | rm -rf dist 9 | rm -rf scour.egg-info 10 | rm -rf .tox 11 | rm -f .coverage* 12 | rm -rf htmlcov 13 | find . -name "*.pyc" -type f -exec rm -f {} \; 14 | find . -name "*__pycache__" -type d -prune -exec rm -rf {} \; 15 | 16 | publish: clean 17 | python setup.py register 18 | python setup.py sdist upload 19 | 20 | check: test flake8 21 | 22 | 23 | 24 | test: 25 | python test_scour.py 26 | 27 | test_version: 28 | PYTHONPATH=. python -m scour.scour --version 29 | 30 | test_help: 31 | PYTHONPATH=. python -m scour.scour --help 32 | 33 | flake8: 34 | flake8 --max-line-length=119 35 | 36 | coverage: 37 | coverage run --source=scour test_scour.py 38 | coverage html 39 | coverage report 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scour 2 | 3 | [![PyPI](https://img.shields.io/pypi/v/scour.svg)](https://pypi.python.org/pypi/scour "Package listing on PyPI") 4 |   5 | [![Build status](https://img.shields.io/travis/scour-project/scour.svg)](https://travis-ci.org/scour-project/scour "Build status (via TravisCI)") 6 | [![Codecov](https://img.shields.io/codecov/c/github/scour-project/scour.svg)](https://codecov.io/gh/scour-project/scour "Code coverage (via Codecov)") 7 | 8 | --- 9 | 10 | Scour is an SVG optimizer/cleaner written in Python that reduces the size of scalable vector graphics by optimizing structure and removing unnecessary data. 11 | 12 | It can be used to create streamlined vector graphics suitable for web deployment, publishing/sharing or further processing. 13 | 14 | The goal of Scour is to output a file that renders identically at a fraction of the size by removing a lot of redundant information created by most SVG editors. Optimization options are typically lossless but can be tweaked for more aggressive cleaning. 15 | 16 | Scour is open-source and licensed under [Apache License 2.0](https://github.com/codedread/scour/blob/master/LICENSE). 17 | 18 | Scour was originally developed by Jeff "codedread" Schiller and Louis Simard in in 2010. 19 | The project moved to GitLab in 2013 an is now maintained by Tobias "oberstet" Oberstein and Patrick "Ede_123" Storz. 20 | 21 | ## Installation 22 | 23 | Scour requires [Python](https://www.python.org) 2.7 or 3.4+. Further, for installation, [pip](https://pip.pypa.io) should be used. 24 | 25 | To install the [latest release](https://pypi.python.org/pypi/scour) of Scour from PyPI: 26 | 27 | ```console 28 | pip install scour 29 | ``` 30 | 31 | To install the [latest trunk](https://github.com/codedread/scour) version (which might be broken!) from GitHub: 32 | 33 | ```console 34 | pip install https://github.com/codedread/scour/archive/master.zip 35 | ``` 36 | 37 | ## Usage 38 | 39 | Standard: 40 | 41 | ```console 42 | scour -i input.svg -o output.svg 43 | ``` 44 | 45 | Better (for older versions of Internet Explorer): 46 | 47 | ```console 48 | scour -i input.svg -o output.svg --enable-viewboxing 49 | ``` 50 | 51 | Maximum scrubbing: 52 | 53 | ```console 54 | scour -i input.svg -o output.svg --enable-viewboxing --enable-id-stripping \ 55 | --enable-comment-stripping --shorten-ids --indent=none 56 | ``` 57 | 58 | Maximum scrubbing and a compressed SVGZ file: 59 | 60 | ```console 61 | scour -i input.svg -o output.svgz --enable-viewboxing --enable-id-stripping \ 62 | --enable-comment-stripping --shorten-ids --indent=none 63 | ``` 64 | -------------------------------------------------------------------------------- /scour.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": 3 | [ 4 | { 5 | "name": "Scour", 6 | "path": ".", 7 | "folder_exclude_patterns": ["*.egg-info", "build", "dist"], 8 | "file_exclude_patterns": ["*.pyc", "*.pyo", "*.pyd"] 9 | } 10 | ], 11 | "settings": 12 | { 13 | "default_encoding": "UTF-8", 14 | "detect_indentation": false, 15 | "ensure_newline_at_eof_on_save": true, 16 | "tab_size": 3, 17 | "translate_tabs_to_spaces": true, 18 | "trim_trailing_white_space_on_save": true, 19 | "use_tab_stops": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scour/__init__.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Copyright (C) 2010 Jeff Schiller, 2010 Louis Simard, 2013-2015 Tavendo GmbH 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | ############################################################################### 18 | 19 | __version__ = u'0.38.2' 20 | -------------------------------------------------------------------------------- /scour/stats.py: -------------------------------------------------------------------------------- 1 | class ScourStats(object): 2 | 3 | __slots__ = ( 4 | 'num_elements_removed', 5 | 'num_attributes_removed', 6 | 'num_style_properties_fixed', 7 | 'num_bytes_saved_in_colors', 8 | 'num_ids_removed', 9 | 'num_comments_removed', 10 | 'num_style_properties_fixed', 11 | 'num_rasters_embedded', 12 | 'num_path_segments_removed', 13 | 'num_points_removed_from_polygon', 14 | 'num_bytes_saved_in_path_data', 15 | 'num_bytes_saved_in_colors', 16 | 'num_bytes_saved_in_comments', 17 | 'num_bytes_saved_in_ids', 18 | 'num_bytes_saved_in_lengths', 19 | 'num_bytes_saved_in_transforms', 20 | ) 21 | 22 | def __init__(self): 23 | self.reset() 24 | 25 | def reset(self): 26 | # Set all stats to 0 27 | for attr in self.__slots__: 28 | setattr(self, attr, 0) 29 | -------------------------------------------------------------------------------- /scour/svg_regex.py: -------------------------------------------------------------------------------- 1 | # This software is OSI Certified Open Source Software. 2 | # OSI Certified is a certification mark of the Open Source Initiative. 3 | # 4 | # Copyright (c) 2006, Enthought, Inc. 5 | # All rights reserved. 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions are met: 9 | # 10 | # * Redistributions of source code must retain the above copyright notice, this 11 | # list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # * Neither the name of Enthought, Inc. nor the names of its contributors may 16 | # be used to endorse or promote products derived from this software without 17 | # specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 23 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | """ Small hand-written recursive descent parser for SVG <path> data. 31 | 32 | 33 | In [1]: from svg_regex import svg_parser 34 | 35 | In [3]: svg_parser.parse('M 10,20 30,40V50 60 70') 36 | Out[3]: [('M', [(10.0, 20.0), (30.0, 40.0)]), ('V', [50.0, 60.0, 70.0])] 37 | 38 | In [4]: svg_parser.parse('M 0.6051.5') # An edge case 39 | Out[4]: [('M', [(0.60509999999999997, 0.5)])] 40 | 41 | In [5]: svg_parser.parse('M 100-200') # Another edge case 42 | Out[5]: [('M', [(100.0, -200.0)])] 43 | """ 44 | from __future__ import absolute_import 45 | 46 | import re 47 | from decimal import Decimal, getcontext 48 | from functools import partial 49 | 50 | 51 | # Sentinel. 52 | 53 | 54 | class _EOF(object): 55 | 56 | def __repr__(self): 57 | return 'EOF' 58 | 59 | 60 | EOF = _EOF() 61 | 62 | lexicon = [ 63 | ('float', r'[-+]?(?:(?:[0-9]*\.[0-9]+)|(?:[0-9]+\.?))(?:[Ee][-+]?[0-9]+)?'), 64 | ('int', r'[-+]?[0-9]+'), 65 | ('command', r'[AaCcHhLlMmQqSsTtVvZz]'), 66 | ] 67 | 68 | 69 | class Lexer(object): 70 | """ Break SVG path data into tokens. 71 | 72 | The SVG spec requires that tokens are greedy. This lexer relies on Python's 73 | regexes defaulting to greediness. 74 | 75 | This style of implementation was inspired by this article: 76 | 77 | http://www.gooli.org/blog/a-simple-lexer-in-python/ 78 | """ 79 | 80 | def __init__(self, lexicon): 81 | self.lexicon = lexicon 82 | parts = [] 83 | for name, regex in lexicon: 84 | parts.append('(?P<%s>%s)' % (name, regex)) 85 | self.regex_string = '|'.join(parts) 86 | self.regex = re.compile(self.regex_string) 87 | 88 | def lex(self, text): 89 | """ Yield (token_type, str_data) tokens. 90 | 91 | The last token will be (EOF, None) where EOF is the singleton object 92 | defined in this module. 93 | """ 94 | for match in self.regex.finditer(text): 95 | for name, _ in self.lexicon: 96 | m = match.group(name) 97 | if m is not None: 98 | yield (name, m) 99 | break 100 | yield (EOF, None) 101 | 102 | 103 | svg_lexer = Lexer(lexicon) 104 | 105 | 106 | class SVGPathParser(object): 107 | """ Parse SVG <path> data into a list of commands. 108 | 109 | Each distinct command will take the form of a tuple (command, data). The 110 | `command` is just the character string that starts the command group in the 111 | <path> data, so 'M' for absolute moveto, 'm' for relative moveto, 'Z' for 112 | closepath, etc. The kind of data it carries with it depends on the command. 113 | For 'Z' (closepath), it's just None. The others are lists of individual 114 | argument groups. Multiple elements in these lists usually mean to repeat the 115 | command. The notable exception is 'M' (moveto) where only the first element 116 | is truly a moveto. The remainder are implicit linetos. 117 | 118 | See the SVG documentation for the interpretation of the individual elements 119 | for each command. 120 | 121 | The main method is `parse(text)`. It can only consume actual strings, not 122 | filelike objects or iterators. 123 | """ 124 | 125 | def __init__(self, lexer=svg_lexer): 126 | self.lexer = lexer 127 | 128 | self.command_dispatch = { 129 | 'Z': self.rule_closepath, 130 | 'z': self.rule_closepath, 131 | 'M': self.rule_moveto_or_lineto, 132 | 'm': self.rule_moveto_or_lineto, 133 | 'L': self.rule_moveto_or_lineto, 134 | 'l': self.rule_moveto_or_lineto, 135 | 'H': self.rule_orthogonal_lineto, 136 | 'h': self.rule_orthogonal_lineto, 137 | 'V': self.rule_orthogonal_lineto, 138 | 'v': self.rule_orthogonal_lineto, 139 | 'C': self.rule_curveto3, 140 | 'c': self.rule_curveto3, 141 | 'S': self.rule_curveto2, 142 | 's': self.rule_curveto2, 143 | 'Q': self.rule_curveto2, 144 | 'q': self.rule_curveto2, 145 | 'T': self.rule_curveto1, 146 | 't': self.rule_curveto1, 147 | 'A': self.rule_elliptical_arc, 148 | 'a': self.rule_elliptical_arc, 149 | } 150 | 151 | # self.number_tokens = set(['int', 'float']) 152 | self.number_tokens = list(['int', 'float']) 153 | 154 | def parse(self, text): 155 | """ Parse a string of SVG <path> data. 156 | """ 157 | gen = self.lexer.lex(text) 158 | next_val_fn = partial(next, *(gen,)) 159 | token = next_val_fn() 160 | return self.rule_svg_path(next_val_fn, token) 161 | 162 | def rule_svg_path(self, next_val_fn, token): 163 | commands = [] 164 | while token[0] is not EOF: 165 | if token[0] != 'command': 166 | raise SyntaxError("expecting a command; got %r" % (token,)) 167 | rule = self.command_dispatch[token[1]] 168 | command_group, token = rule(next_val_fn, token) 169 | commands.append(command_group) 170 | return commands 171 | 172 | def rule_closepath(self, next_val_fn, token): 173 | command = token[1] 174 | token = next_val_fn() 175 | return (command, []), token 176 | 177 | def rule_moveto_or_lineto(self, next_val_fn, token): 178 | command = token[1] 179 | token = next_val_fn() 180 | coordinates = [] 181 | while token[0] in self.number_tokens: 182 | pair, token = self.rule_coordinate_pair(next_val_fn, token) 183 | coordinates.extend(pair) 184 | return (command, coordinates), token 185 | 186 | def rule_orthogonal_lineto(self, next_val_fn, token): 187 | command = token[1] 188 | token = next_val_fn() 189 | coordinates = [] 190 | while token[0] in self.number_tokens: 191 | coord, token = self.rule_coordinate(next_val_fn, token) 192 | coordinates.append(coord) 193 | return (command, coordinates), token 194 | 195 | def rule_curveto3(self, next_val_fn, token): 196 | command = token[1] 197 | token = next_val_fn() 198 | coordinates = [] 199 | while token[0] in self.number_tokens: 200 | pair1, token = self.rule_coordinate_pair(next_val_fn, token) 201 | pair2, token = self.rule_coordinate_pair(next_val_fn, token) 202 | pair3, token = self.rule_coordinate_pair(next_val_fn, token) 203 | coordinates.extend(pair1) 204 | coordinates.extend(pair2) 205 | coordinates.extend(pair3) 206 | return (command, coordinates), token 207 | 208 | def rule_curveto2(self, next_val_fn, token): 209 | command = token[1] 210 | token = next_val_fn() 211 | coordinates = [] 212 | while token[0] in self.number_tokens: 213 | pair1, token = self.rule_coordinate_pair(next_val_fn, token) 214 | pair2, token = self.rule_coordinate_pair(next_val_fn, token) 215 | coordinates.extend(pair1) 216 | coordinates.extend(pair2) 217 | return (command, coordinates), token 218 | 219 | def rule_curveto1(self, next_val_fn, token): 220 | command = token[1] 221 | token = next_val_fn() 222 | coordinates = [] 223 | while token[0] in self.number_tokens: 224 | pair1, token = self.rule_coordinate_pair(next_val_fn, token) 225 | coordinates.extend(pair1) 226 | return (command, coordinates), token 227 | 228 | def rule_elliptical_arc(self, next_val_fn, token): 229 | command = token[1] 230 | token = next_val_fn() 231 | arguments = [] 232 | while token[0] in self.number_tokens: 233 | rx = Decimal(token[1]) * 1 234 | if rx < Decimal("0.0"): 235 | raise SyntaxError("expecting a nonnegative number; got %r" % (token,)) 236 | 237 | token = next_val_fn() 238 | if token[0] not in self.number_tokens: 239 | raise SyntaxError("expecting a number; got %r" % (token,)) 240 | ry = Decimal(token[1]) * 1 241 | if ry < Decimal("0.0"): 242 | raise SyntaxError("expecting a nonnegative number; got %r" % (token,)) 243 | 244 | token = next_val_fn() 245 | if token[0] not in self.number_tokens: 246 | raise SyntaxError("expecting a number; got %r" % (token,)) 247 | axis_rotation = Decimal(token[1]) * 1 248 | 249 | token = next_val_fn() 250 | if token[1][0] not in ('0', '1'): 251 | raise SyntaxError("expecting a boolean flag; got %r" % (token,)) 252 | large_arc_flag = Decimal(token[1][0]) * 1 253 | 254 | if len(token[1]) > 1: 255 | token = list(token) 256 | token[1] = token[1][1:] 257 | else: 258 | token = next_val_fn() 259 | if token[1][0] not in ('0', '1'): 260 | raise SyntaxError("expecting a boolean flag; got %r" % (token,)) 261 | sweep_flag = Decimal(token[1][0]) * 1 262 | 263 | if len(token[1]) > 1: 264 | token = list(token) 265 | token[1] = token[1][1:] 266 | else: 267 | token = next_val_fn() 268 | if token[0] not in self.number_tokens: 269 | raise SyntaxError("expecting a number; got %r" % (token,)) 270 | x = Decimal(token[1]) * 1 271 | 272 | token = next_val_fn() 273 | if token[0] not in self.number_tokens: 274 | raise SyntaxError("expecting a number; got %r" % (token,)) 275 | y = Decimal(token[1]) * 1 276 | 277 | token = next_val_fn() 278 | arguments.extend([rx, ry, axis_rotation, large_arc_flag, sweep_flag, x, y]) 279 | 280 | return (command, arguments), token 281 | 282 | def rule_coordinate(self, next_val_fn, token): 283 | if token[0] not in self.number_tokens: 284 | raise SyntaxError("expecting a number; got %r" % (token,)) 285 | x = getcontext().create_decimal(token[1]) 286 | token = next_val_fn() 287 | return x, token 288 | 289 | def rule_coordinate_pair(self, next_val_fn, token): 290 | # Inline these since this rule is so common. 291 | if token[0] not in self.number_tokens: 292 | raise SyntaxError("expecting a number; got %r" % (token,)) 293 | x = getcontext().create_decimal(token[1]) 294 | token = next_val_fn() 295 | if token[0] not in self.number_tokens: 296 | raise SyntaxError("expecting a number; got %r" % (token,)) 297 | y = getcontext().create_decimal(token[1]) 298 | token = next_val_fn() 299 | return [x, y], token 300 | 301 | 302 | svg_parser = SVGPathParser() 303 | -------------------------------------------------------------------------------- /scour/svg_transform.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # SVG transformation list parser 5 | # 6 | # Copyright 2010 Louis Simard 7 | # 8 | # This file is part of Scour, http://www.codedread.com/scour/ 9 | # 10 | # Licensed under the Apache License, Version 2.0 (the "License"); 11 | # you may not use this file except in compliance with the License. 12 | # You may obtain a copy of the License at 13 | # 14 | # http://www.apache.org/licenses/LICENSE-2.0 15 | # 16 | # Unless required by applicable law or agreed to in writing, software 17 | # distributed under the License is distributed on an "AS IS" BASIS, 18 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | # See the License for the specific language governing permissions and 20 | # limitations under the License. 21 | 22 | """ Small recursive descent parser for SVG transform="" data. 23 | 24 | 25 | In [1]: from svg_transform import svg_transform_parser 26 | 27 | In [3]: svg_transform_parser.parse('translate(50, 50)') 28 | Out[3]: [('translate', [50.0, 50.0])] 29 | 30 | In [4]: svg_transform_parser.parse('translate(50)') 31 | Out[4]: [('translate', [50.0])] 32 | 33 | In [5]: svg_transform_parser.parse('rotate(36 50,50)') 34 | Out[5]: [('rotate', [36.0, 50.0, 50.0])] 35 | 36 | In [6]: svg_transform_parser.parse('rotate(36)') 37 | Out[6]: [('rotate', [36.0])] 38 | 39 | In [7]: svg_transform_parser.parse('skewX(20)') 40 | Out[7]: [('skewX', [20.0])] 41 | 42 | In [8]: svg_transform_parser.parse('skewY(40)') 43 | Out[8]: [('skewX', [20.0])] 44 | 45 | In [9]: svg_transform_parser.parse('scale(2 .5)') 46 | Out[9]: [('scale', [2.0, 0.5])] 47 | 48 | In [10]: svg_transform_parser.parse('scale(.5)') 49 | Out[10]: [('scale', [0.5])] 50 | 51 | In [11]: svg_transform_parser.parse('matrix(1 0 50 0 1 80)') 52 | Out[11]: [('matrix', [1.0, 0.0, 50.0, 0.0, 1.0, 80.0])] 53 | 54 | Multiple transformations are supported: 55 | 56 | In [12]: svg_transform_parser.parse('translate(30 -30) rotate(36)') 57 | Out[12]: [('translate', [30.0, -30.0]), ('rotate', [36.0])] 58 | """ 59 | from __future__ import absolute_import 60 | 61 | import re 62 | from decimal import Decimal 63 | from functools import partial 64 | 65 | from six.moves import range 66 | 67 | 68 | # Sentinel. 69 | class _EOF(object): 70 | 71 | def __repr__(self): 72 | return 'EOF' 73 | 74 | 75 | EOF = _EOF() 76 | 77 | lexicon = [ 78 | ('float', r'[-+]?(?:(?:[0-9]*\.[0-9]+)|(?:[0-9]+\.?))(?:[Ee][-+]?[0-9]+)?'), 79 | ('int', r'[-+]?[0-9]+'), 80 | ('command', r'(?:matrix|translate|scale|rotate|skew[XY])'), 81 | ('coordstart', r'\('), 82 | ('coordend', r'\)'), 83 | ] 84 | 85 | 86 | class Lexer(object): 87 | """ Break SVG path data into tokens. 88 | 89 | The SVG spec requires that tokens are greedy. This lexer relies on Python's 90 | regexes defaulting to greediness. 91 | 92 | This style of implementation was inspired by this article: 93 | 94 | http://www.gooli.org/blog/a-simple-lexer-in-python/ 95 | """ 96 | 97 | def __init__(self, lexicon): 98 | self.lexicon = lexicon 99 | parts = [] 100 | for name, regex in lexicon: 101 | parts.append('(?P<%s>%s)' % (name, regex)) 102 | self.regex_string = '|'.join(parts) 103 | self.regex = re.compile(self.regex_string) 104 | 105 | def lex(self, text): 106 | """ Yield (token_type, str_data) tokens. 107 | 108 | The last token will be (EOF, None) where EOF is the singleton object 109 | defined in this module. 110 | """ 111 | for match in self.regex.finditer(text): 112 | for name, _ in self.lexicon: 113 | m = match.group(name) 114 | if m is not None: 115 | yield (name, m) 116 | break 117 | yield (EOF, None) 118 | 119 | 120 | svg_lexer = Lexer(lexicon) 121 | 122 | 123 | class SVGTransformationParser(object): 124 | """ Parse SVG transform="" data into a list of commands. 125 | 126 | Each distinct command will take the form of a tuple (type, data). The 127 | `type` is the character string that defines the type of transformation in the 128 | transform data, so either of "translate", "rotate", "scale", "matrix", 129 | "skewX" and "skewY". Data is always a list of numbers contained within the 130 | transformation's parentheses. 131 | 132 | See the SVG documentation for the interpretation of the individual elements 133 | for each transformation. 134 | 135 | The main method is `parse(text)`. It can only consume actual strings, not 136 | filelike objects or iterators. 137 | """ 138 | 139 | def __init__(self, lexer=svg_lexer): 140 | self.lexer = lexer 141 | 142 | self.command_dispatch = { 143 | 'translate': self.rule_1or2numbers, 144 | 'scale': self.rule_1or2numbers, 145 | 'skewX': self.rule_1number, 146 | 'skewY': self.rule_1number, 147 | 'rotate': self.rule_1or3numbers, 148 | 'matrix': self.rule_6numbers, 149 | } 150 | 151 | # self.number_tokens = set(['int', 'float']) 152 | self.number_tokens = list(['int', 'float']) 153 | 154 | def parse(self, text): 155 | """ Parse a string of SVG transform="" data. 156 | """ 157 | gen = self.lexer.lex(text) 158 | next_val_fn = partial(next, *(gen,)) 159 | 160 | commands = [] 161 | token = next_val_fn() 162 | while token[0] is not EOF: 163 | command, token = self.rule_svg_transform(next_val_fn, token) 164 | commands.append(command) 165 | return commands 166 | 167 | def rule_svg_transform(self, next_val_fn, token): 168 | if token[0] != 'command': 169 | raise SyntaxError("expecting a transformation type; got %r" % (token,)) 170 | command = token[1] 171 | rule = self.command_dispatch[command] 172 | token = next_val_fn() 173 | if token[0] != 'coordstart': 174 | raise SyntaxError("expecting '('; got %r" % (token,)) 175 | numbers, token = rule(next_val_fn, token) 176 | if token[0] != 'coordend': 177 | raise SyntaxError("expecting ')'; got %r" % (token,)) 178 | token = next_val_fn() 179 | return (command, numbers), token 180 | 181 | def rule_1or2numbers(self, next_val_fn, token): 182 | numbers = [] 183 | # 1st number is mandatory 184 | token = next_val_fn() 185 | number, token = self.rule_number(next_val_fn, token) 186 | numbers.append(number) 187 | # 2nd number is optional 188 | number, token = self.rule_optional_number(next_val_fn, token) 189 | if number is not None: 190 | numbers.append(number) 191 | 192 | return numbers, token 193 | 194 | def rule_1number(self, next_val_fn, token): 195 | # this number is mandatory 196 | token = next_val_fn() 197 | number, token = self.rule_number(next_val_fn, token) 198 | numbers = [number] 199 | return numbers, token 200 | 201 | def rule_1or3numbers(self, next_val_fn, token): 202 | numbers = [] 203 | # 1st number is mandatory 204 | token = next_val_fn() 205 | number, token = self.rule_number(next_val_fn, token) 206 | numbers.append(number) 207 | # 2nd number is optional 208 | number, token = self.rule_optional_number(next_val_fn, token) 209 | if number is not None: 210 | # but, if the 2nd number is provided, the 3rd is mandatory. 211 | # we can't have just 2. 212 | numbers.append(number) 213 | 214 | number, token = self.rule_number(next_val_fn, token) 215 | numbers.append(number) 216 | 217 | return numbers, token 218 | 219 | def rule_6numbers(self, next_val_fn, token): 220 | numbers = [] 221 | token = next_val_fn() 222 | # all numbers are mandatory 223 | for i in range(6): 224 | number, token = self.rule_number(next_val_fn, token) 225 | numbers.append(number) 226 | return numbers, token 227 | 228 | def rule_number(self, next_val_fn, token): 229 | if token[0] not in self.number_tokens: 230 | raise SyntaxError("expecting a number; got %r" % (token,)) 231 | x = Decimal(token[1]) * 1 232 | token = next_val_fn() 233 | return x, token 234 | 235 | def rule_optional_number(self, next_val_fn, token): 236 | if token[0] not in self.number_tokens: 237 | return None, token 238 | else: 239 | x = Decimal(token[1]) * 1 240 | token = next_val_fn() 241 | return x, token 242 | 243 | 244 | svg_transform_parser = SVGTransformationParser() 245 | -------------------------------------------------------------------------------- /scour/yocto_css.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # yocto-css, an extremely bare minimum CSS parser 5 | # 6 | # Copyright 2009 Jeff Schiller 7 | # 8 | # This file is part of Scour, http://www.codedread.com/scour/ 9 | # 10 | # Licensed under the Apache License, Version 2.0 (the "License"); 11 | # you may not use this file except in compliance with the License. 12 | # You may obtain a copy of the License at 13 | # 14 | # http://www.apache.org/licenses/LICENSE-2.0 15 | # 16 | # Unless required by applicable law or agreed to in writing, software 17 | # distributed under the License is distributed on an "AS IS" BASIS, 18 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | # See the License for the specific language governing permissions and 20 | # limitations under the License. 21 | 22 | # In order to resolve Bug 368716 (https://bugs.launchpad.net/scour/+bug/368716) 23 | # scour needed a bare-minimum CSS parser in order to determine if some elements 24 | # were still referenced by CSS properties. 25 | 26 | # I looked at css-py (a CSS parser built in Python), but that library 27 | # is about 35k of Python and requires ply to be installed. I just need 28 | # something very basic to suit scour's needs. 29 | 30 | # yocto-css takes a string of CSS and tries to spit out a list of rules 31 | # A rule is an associative array (dictionary) with the following keys: 32 | # - selector: contains the string of the selector (see CSS grammar) 33 | # - properties: contains an associative array of CSS properties for this rule 34 | 35 | # TODO: need to build up some unit tests for yocto_css 36 | 37 | # stylesheet : [ CDO | CDC | S | statement ]*; 38 | # statement : ruleset | at-rule; 39 | # at-rule : ATKEYWORD S* any* [ block | ';' S* ]; 40 | # block : '{' S* [ any | block | ATKEYWORD S* | ';' S* ]* '}' S*; 41 | # ruleset : selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*; 42 | # selector : any+; 43 | # declaration : property S* ':' S* value; 44 | # property : IDENT; 45 | # value : [ any | block | ATKEYWORD S* ]+; 46 | # any : [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING 47 | # | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES 48 | # | DASHMATCH | FUNCTION S* any* ')' 49 | # | '(' S* any* ')' | '[' S* any* ']' ] S*; 50 | 51 | 52 | def parseCssString(str): 53 | rules = [] 54 | # first, split on } to get the rule chunks 55 | chunks = str.split('}') 56 | for chunk in chunks: 57 | # second, split on { to get the selector and the list of properties 58 | bits = chunk.split('{') 59 | if len(bits) != 2: 60 | continue 61 | rule = {} 62 | rule['selector'] = bits[0].strip() 63 | # third, split on ; to get the property declarations 64 | bites = bits[1].strip().split(';') 65 | if len(bites) < 1: 66 | continue 67 | props = {} 68 | for bite in bites: 69 | # fourth, split on : to get the property name and value 70 | nibbles = bite.strip().split(':') 71 | if len(nibbles) != 2: 72 | continue 73 | props[nibbles[0].strip()] = nibbles[1].strip() 74 | rule['properties'] = props 75 | rules.append(rule) 76 | return rules 77 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Copyright (C) 2013-2014 Tavendo GmbH 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | ############################################################################### 18 | 19 | import os 20 | import re 21 | 22 | from setuptools import find_packages, setup 23 | 24 | LONGDESC = """ 25 | Scour is an SVG optimizer/cleaner that reduces the size of scalable 26 | vector graphics by optimizing structure and removing unnecessary data. 27 | 28 | It can be used to create streamlined vector graphics suitable for web 29 | deployment, publishing/sharing or further processing. 30 | 31 | The goal of Scour is to output a file that renders identically at a 32 | fraction of the size by removing a lot of redundant information created 33 | by most SVG editors. Optimization options are typically lossless but can 34 | be tweaked for more aggressive cleaning. 35 | 36 | Website 37 | - http://www.codedread.com/scour/ (original website) 38 | - https://github.com/scour-project/scour (today) 39 | 40 | Authors: 41 | - Jeff Schiller, Louis Simard (original authors) 42 | - Tobias Oberstein (maintainer) 43 | - Patrick Storz (maintainer) 44 | """ 45 | 46 | VERSIONFILE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "scour", "__init__.py") 47 | verstrline = open(VERSIONFILE, "rt").read() 48 | VSRE = r"^__version__ = u['\"]([^'\"]*)['\"]" 49 | mo = re.search(VSRE, verstrline, re.M) 50 | if mo: 51 | verstr = mo.group(1) 52 | else: 53 | raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,)) 54 | 55 | 56 | setup( 57 | name='scour', 58 | version=verstr, 59 | description='Scour SVG Optimizer', 60 | # long_description = open("README.md").read(), 61 | long_description=LONGDESC, 62 | license='Apache License 2.0', 63 | author='Jeff Schiller', 64 | author_email='codedread@gmail.com', 65 | url='https://github.com/scour-project/scour', 66 | platforms=('Any'), 67 | install_requires=['six>=1.9.0'], 68 | packages=find_packages(), 69 | zip_safe=True, 70 | entry_points={ 71 | 'console_scripts': [ 72 | 'scour = scour.scour:run' 73 | ]}, 74 | classifiers=["License :: OSI Approved :: Apache Software License", 75 | "Development Status :: 5 - Production/Stable", 76 | "Environment :: Console", 77 | "Intended Audience :: Developers", 78 | "Intended Audience :: System Administrators", 79 | "Operating System :: OS Independent", 80 | "Programming Language :: Python", 81 | "Topic :: Internet", 82 | "Topic :: Software Development :: Build Tools", 83 | "Topic :: Software Development :: Pre-processors", 84 | "Topic :: Multimedia :: Graphics :: Graphics Conversion", 85 | "Topic :: Utilities"], 86 | keywords='svg optimizer' 87 | ) 88 | -------------------------------------------------------------------------------- /test_css.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Test Harness for Scour 5 | # 6 | # Copyright 2010 Jeff Schiller 7 | # 8 | # This file is part of Scour, http://www.codedread.com/scour/ 9 | # 10 | # Licensed under the Apache License, Version 2.0 (the "License"); 11 | # you may not use this file except in compliance with the License. 12 | # You may obtain a copy of the License at 13 | # 14 | # http://www.apache.org/licenses/LICENSE-2.0 15 | # 16 | # Unless required by applicable law or agreed to in writing, software 17 | # distributed under the License is distributed on an "AS IS" BASIS, 18 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | # See the License for the specific language governing permissions and 20 | # limitations under the License. 21 | 22 | from __future__ import absolute_import 23 | 24 | import unittest 25 | 26 | from scour.yocto_css import parseCssString 27 | 28 | 29 | class Blank(unittest.TestCase): 30 | 31 | def runTest(self): 32 | r = parseCssString('') 33 | self.assertEqual(len(r), 0, 'Blank string returned non-empty list') 34 | self.assertEqual(type(r), type([]), 'Blank string returned non list') 35 | 36 | 37 | class ElementSelector(unittest.TestCase): 38 | 39 | def runTest(self): 40 | r = parseCssString('foo {}') 41 | self.assertEqual(len(r), 1, 'Element selector not returned') 42 | self.assertEqual(r[0]['selector'], 'foo', 'Selector for foo not returned') 43 | self.assertEqual(len(r[0]['properties']), 0, 'Property list for foo not empty') 44 | 45 | 46 | class ElementSelectorWithProperty(unittest.TestCase): 47 | 48 | def runTest(self): 49 | r = parseCssString('foo { bar: baz}') 50 | self.assertEqual(len(r), 1, 'Element selector not returned') 51 | self.assertEqual(r[0]['selector'], 'foo', 'Selector for foo not returned') 52 | self.assertEqual(len(r[0]['properties']), 1, 'Property list for foo did not have 1') 53 | self.assertEqual(r[0]['properties']['bar'], 'baz', 'Property bar did not have baz value') 54 | 55 | 56 | if __name__ == '__main__': 57 | unittest.main() 58 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = 3 | pypy 4 | py27 5 | py34 6 | py35 7 | py36 8 | py37 9 | py38 10 | py39 11 | py310 12 | flake8 13 | 14 | 15 | 16 | [testenv] 17 | deps = 18 | six 19 | coverage 20 | 21 | commands = 22 | scour --version 23 | coverage run --parallel-mode --source=scour test_scour.py 24 | 25 | 26 | [testenv:flake8] 27 | deps = 28 | flake8 29 | 30 | commands = 31 | flake8 --max-line-length=119 32 | -------------------------------------------------------------------------------- /unittests/adobe.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg" 3 | xmlns:x="http://ns.adobe.com/Extensibility/1.0/" 4 | xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/" 5 | xmlns:graph="http://ns.adobe.com/Graphs/1.0/" 6 | xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" 7 | xmlns:f="http://ns.adobe.com/Flows/1.0/" 8 | xmlns:ir="http://ns.adobe.com/ImageReplacement/1.0/" 9 | xmlns:custom="http://ns.adobe.com/GenericCustomNamespace/1.0/" 10 | xmlns:xpath="http://ns.adobe.com/XPath/1.0/" 11 | xmlns:ok="A.namespace.we.want.left.in" 12 | i:viewOrigin="190.2959 599.1841" i:rulerOrigin="0 0" i:pageBounds="0 792 612 0"> 13 | <x:foo>bar</x:foo> 14 | <i:foo>bar</i:foo> 15 | <graph:foo>bar</graph:foo> 16 | <a:foo>bar</a:foo> 17 | <f:foo>bar</f:foo> 18 | <ir:foo>bar</ir:foo> 19 | <custom:foo>bar</custom:foo> 20 | <xpath:foo>bar</xpath:foo> 21 | <variableSets xmlns="http://ns.adobe.com/Variables/1.0/"> 22 | <variableSet varSetName="binding1" locked="none"> 23 | <variables/> 24 | <v:sampleDataSets xmlns="http://ns.adobe.com/GenericCustomNamespace/1.0/" xmlns:v="http://ns.adobe.com/Variables/1.0/"/> 25 | </variableSet> 26 | </variableSets> 27 | <sfw xmlns="http://ns.adobe.com/SaveForWeb/1.0/"> 28 | <slices/> 29 | <sliceSourceBounds y="191.664" x="190.296" width="225.72" height="407.52" bottomLeftOrigin="true"/> 30 | </sfw> 31 | <rect width="300" height="200" fill="green" 32 | x:baz="1" 33 | i:baz="1" 34 | graph:baz="1" 35 | a:baz="1" 36 | f:baz="1" 37 | ir:baz="1" 38 | custom:baz='1' 39 | xpath:baz="1" 40 | xmlns:v="http://ns.adobe.Variables/1.0/" 41 | v:baz="1" 42 | xmlns:sfw="http://ns.adobe.com/SaveForWeb/1.0/" 43 | sfw:baz="1" 44 | ok:baz="1" /> 45 | </svg> 46 | -------------------------------------------------------------------------------- /unittests/cascading-default-attribute-removal.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 3 | <path style="fill-rule:evenodd;stroke-linecap:butt;stroke-width:1.00;stroke:#000" d="m1,1z"/> 4 | <path style="fill-rule:nonzero;stroke-linecap:butt;stroke:#000" d="m1,1z"/> 5 | <g style="stroke:#f00;marker:none"> 6 | <path style="marker-start:none;fill-rule:evenodd;stroke-linecap:butt" d="m1,1z"/> 7 | <path style="fill-rule:nonzero" d="m1,1z"/> 8 | <g style="fill:#f0f;text-anchor:stop;fill-rule:evenodd;stroke-linecap:round;marker:url(#nirvana)"> 9 | <path style="marker-start:none;fill-rule:evenodd;stroke-linecap:butt" d="m1,1z"/> 10 | <path style="color:#000;fill-rule:nonzero;" d="m1,1z"/> 11 | <path d="m1,1z"/> 12 | </g> 13 | <g style="fill:#f0f;text-anchor:stop;fill-rule:evenodd;stroke-linecap:round;marker:url(#nirvana)"> 14 | <path style="marker-start:none;fill-rule:evenodd;stroke-linecap:butt" d="m1,1z"/> 15 | <path style="color:#000;fill-rule:nonzero;" d="m1,1z"/> 16 | </g> 17 | <g style="text-anchor:stop;fill-rule:nonzero;marker:none;stroke-linecap:butt"> 18 | <path style="marker-start:none;fill-rule:evenodd;stroke-linecap:butt" d="m1,1z"/> 19 | <path style="fill-rule:nonzero;" d="m1,1z"/> 20 | <path d="m1,1z"/> 21 | </g> 22 | </g> 23 | </svg> 24 | -------------------------------------------------------------------------------- /unittests/cdata.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg"> 3 | <script type="application/ecmascript"><![CDATA[ 4 | alert('pb&j'); 5 | ]]></script> 6 | </svg> 7 | -------------------------------------------------------------------------------- /unittests/collapse-gradients-gradientUnits.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 3 | <defs> 4 | <linearGradient id="g1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"> 5 | <stop offset="0" stop-color="blue" /> 6 | <stop offset="1" stop-color="yellow" /> 7 | </linearGradient> 8 | <radialGradient id="g2" xlink:href="#g1" cx="50%" cy="50%" r="30%" gradientUnits="objectBoundingBox"/> 9 | </defs> 10 | <rect fill="url(#g2)" width="200" height="200"/> 11 | </svg> 12 | -------------------------------------------------------------------------------- /unittests/collapse-gradients-preserve-xlink-href.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 3 | <defs> 4 | <linearGradient id="g1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"> 5 | <stop offset="0" stop-color="blue" /> 6 | <stop offset="1" stop-color="yellow" /> 7 | </linearGradient> 8 | <radialGradient id="g2" xlink:href="#g1" cx="100" cy="100" r="70"/> 9 | <radialGradient id="g3" xlink:href="#g2" cx="100" cy="100" r="70"/> 10 | </defs> 11 | <rect fill="url(#g1)" width="200" height="200"/> 12 | <rect fill="url(#g3)" width="200" height="200" y="200"/> 13 | </svg> 14 | -------------------------------------------------------------------------------- /unittests/collapse-gradients.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 3 | <defs> 4 | <linearGradient id="grad1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" spreadMethod="reflect" gradientTransform="matrix(1,2,3,4,5,6)"> 5 | <stop offset="0" stop-color="blue" /> 6 | <stop offset="1" stop-color="yellow" /> 7 | </linearGradient> 8 | <radialGradient id="grad2" xlink:href="#grad1" cx="100" cy="100" r="70"/> 9 | </defs> 10 | <rect fill="url(#grad2)" width="200" height="200"/> 11 | </svg> 12 | -------------------------------------------------------------------------------- /unittests/collapse-same-path-points.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="210" height="210"> 3 | <path stroke="yellow" fill="red" d="M100,100 L200.12345,200.12345 C215,205 185,195 200.12345,200.12345 Z"/> 4 | </svg> 5 | -------------------------------------------------------------------------------- /unittests/collapse-straight-path-segments.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"> 3 | <defs> 4 | <marker id="dot"> 5 | <circle r="5px"/> 6 | </marker> 7 | </defs> 8 | 9 | <!-- h/v commands should be collapsed into a single h/v commands --> 10 | <path d="m0 0h10 20"/> 11 | <path d="m0 0v10 20"/> 12 | <path d="m0 0h10 0.5v10 0.5"/> 13 | <!-- h/v commands should not be collapsed if they have different direction --> 14 | <path d="m0 0h10 -1v10 -1"/> 15 | <!-- h/v commands should also be collapsed if only start/end markers are present --> 16 | <path d="m0 0h10 20" marker-start="url(#dot)" marker-end="url(#dot)"/> 17 | <path d="m0 0h10 20" style="marker-start:url(#dot);marker-end:url(#dot)"/> 18 | <!-- h/v commands should be preserved if intermediate markers are present --> 19 | <path d="m0 0h10 20" marker="url(#dot)"/> 20 | <path d="m0 0h10 20" marker-mid="url(#dot)"/> 21 | <path d="m0 0h10 20" style="marker:url(#dot)"/> 22 | <path d="m0 0h10 20" style="marker-mid:url(#dot)"/> 23 | 24 | <!-- all consecutive lineto commands pointing into the sam direction 25 | should be collapsed into a single (implicit if possible) lineto command --> 26 | <path d="m 0 0 l 10 20 0.25 0.5 l 0.75 1.5 l 5 10 0.2 0.4 l 3 6 0.8 1.6 l 0 1 l 1 2 9 18"/> 27 | <!-- must not be collapsed (same slope, but different direction) --> 28 | <path d="m 0 0 10 10 -20 -20 l 10 10 -20 -20"/> 29 | <!-- first parameter pair of a moveto subpath must not be collapsed as it's not drawn on canvas --> 30 | <path d="m0 0 1 2 m 1 2 1 2l 1 2 m 1 2 1 2 1 2"/> 31 | <!-- real world example of straight path with multiple nodes --> 32 | <path d="m 6.3227953,7.1547422 10.6709787,5.9477588 9.20334,5.129731 22.977448,12.807101 30.447251,16.970601 7.898986,4.402712"/> 33 | </svg> 34 | -------------------------------------------------------------------------------- /unittests/color-formats.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg" version="1.1"> 3 | <defs> 4 | <linearGradient id="g1" x1="0" y1="0" x2="1" y2="0"> 5 | <stop offset="0.5" stop-color="rgb(50.0%, 0%, .0%)" /> 6 | </linearGradient> 7 | <solidColor id="c1" solid-color="lightgoldenrodyellow"/> 8 | </defs> 9 | <rect id="rect" width="100" height="100" fill="rgb(15,16,17)" stroke="darkgrey" /> 10 | <circle id="circle" cx="100" cy="100" r="30" fill="url(#g1)" stroke="url(#c1)" /> 11 | <ellipse id="ellipse" cx="100" cy="100" rx="30" ry="30" style="fill:#ffffff" fill="black" /> 12 | </svg> 13 | -------------------------------------------------------------------------------- /unittests/comment-beside-xml-decl.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8" standalone="yes"?> 2 | <!-- Oh look a comment --> 3 | <!-- generated by foobar version 20120503 --> 4 | <!-- And another --> 5 | <svg xmlns="http://www.w3.org/2000/svg"> 6 | <!-- This comment is meant to test whether removing a comment before <svg> 7 | messes up removing comments thereafter --> 8 | <!-- And this one is meant to test whether iteration works correctly in 9 | <svg> as well as the document element --> 10 | </svg> 11 | -------------------------------------------------------------------------------- /unittests/comments.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" ?> 2 | <!-- Empty --> 3 | <!-- Comment #2 --> 4 | <svg xmlns="http://www.w3.org/2000/svg"> 5 | </svg> 6 | <!-- After --> 7 | -------------------------------------------------------------------------------- /unittests/commonized-referenced-elements.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 2 | <g id="g"> 3 | <rect width="200" height="100" fill="#0f0"/> 4 | <rect width="200" height="100" fill="#0f0"/> 5 | <rect width="200" height="100" fill="#0f0"/> 6 | <circle id="e" r="20" fill="#0f0"/> 7 | </g> 8 | <use xlink:href="#e" /> 9 | </svg> 10 | -------------------------------------------------------------------------------- /unittests/css-reference.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 3 | 4 | <defs> 5 | <linearGradient id="g1"> 6 | <stop offset="0" stop-color="red"/> 7 | <stop offset="1" stop-color="blue"/> 8 | </linearGradient> 9 | <linearGradient id="g2"> 10 | <stop offset="0" stop-color="green"/> 11 | <stop offset="1" stop-color="yellow"/> 12 | </linearGradient> 13 | </defs> 14 | <style type="text/css"><![CDATA[ 15 | rect { 16 | stroke: red; 17 | stroke-width: 10; 18 | fill:url(#g1) 19 | } 20 | ]]></style> 21 | 22 | <style type="text/css">.circ { fill: none; stroke: url("#g2"); stroke-width: 15 }</style> 23 | 24 | <rect height="300" width="300"/> 25 | <circle class="circ" cx="350" cy="350" r="40"/> 26 | 27 | </svg> 28 | -------------------------------------------------------------------------------- /unittests/descriptive-elements-with-text.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg"> 3 | <title>This is a title element with only text node children 4 | This is a desc element with only text node children 5 | This is a metadata element with only text node children 6 | 7 | -------------------------------------------------------------------------------- /unittests/doctype.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | ]> 7 | 8 | -------------------------------------------------------------------------------- /unittests/dont-collapse-gradients.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /unittests/dont-convert-short-color-names.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/duplicate-gradient-stops-pct.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /unittests/duplicate-gradient-stops.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /unittests/duplicate-gradients-update-style.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /unittests/empty-descriptive-elements.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /unittests/empty-g.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /unittests/empty-style.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/encoding-iso-8859-15.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scour-project/scour/0609c596766ec98e4e2092b49bd03b802702ba1a/unittests/encoding-iso-8859-15.svg -------------------------------------------------------------------------------- /unittests/encoding-utf8.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello in many languages: 4 | ar: أهلا 5 | bn: হ্যালো 6 | el: Χαίρετε 7 | en: Hello 8 | hi: नमस्ते 9 | iw: שלום 10 | ja: こんにちは 11 | km: ជំរាបសួរ 12 | ml: ഹലോ 13 | ru: Здравствуйте 14 | ur: ہیلو 15 | zh: 您好 16 | “”‘’–—…‐‒°©®™•½¼¾⅓⅔†‡µ¢£€«»♠♣♥♦¿� 17 | :-×÷±∞π∅≤≥≠≈∧∨∩∪∈∀∃∄∑∏←↑→↓↔↕↖↗↘↙↺↻⇒⇔ 18 | ⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁽⁾ⁿⁱ₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎ 19 | 20 | -------------------------------------------------------------------------------- /unittests/entities.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /unittests/fill-none.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /unittests/flowtext-less.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 54 | abcd 65 | 66 | 67 | -------------------------------------------------------------------------------- /unittests/flowtext.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 54 | sfdadasdasdasdadsa abcd 77 | 78 | 79 | -------------------------------------------------------------------------------- /unittests/font-styles.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/full-descriptive-elements.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is an example SVG file 4 | Unit test for Scour's --remove-titles option 5 | 6 | 7 | This is an example SVG file 8 | Unit test for Scour's 9 | --remove-descriptions option 10 | 11 | 12 | 16 | 23 | 24 | 25 | No One 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /unittests/gradient-default-attrs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /unittests/group-creation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /unittests/group-no-creation-tspan.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | text1 5 | text2 6 | text3 7 | 8 | 9 | -------------------------------------------------------------------------------- /unittests/group-no-creation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /unittests/group-sibling-merge-crash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /unittests/group-sibling-merge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Produced by GNUPLOT 5.2 patchlevel 8 4 | 5 | 6 | 7 | 8 | 0 9 | 10 | 11 | 12 | 13 | 14 | 5000 15 | 16 | 17 | 18 | 19 | 20 | 10000 21 | 22 | 23 | 24 | 25 | 26 | 15000 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /unittests/groups-in-switch-with-id.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /unittests/groups-in-switch.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /unittests/groups-with-title-desc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 1 5 | 6 | 7 | 8 | 9 | Group 1 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /unittests/ids-protect.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Text 1 4 | Text 2 5 | Text 3 6 | Text custom 7 | My text 8 | 9 | -------------------------------------------------------------------------------- /unittests/ids-to-strip.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Fooey 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /unittests/ids.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /unittests/important-groups-in-defs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /unittests/inkscape.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /unittests/minimal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /unittests/move-common-attributes-to-grandparent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /unittests/move-common-attributes-to-parent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Hello 9 | World! 10 | Goodbye 11 | Cruel World! 12 | 13 | 14 | -------------------------------------------------------------------------------- /unittests/nested-defs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /unittests/nested-useless-groups.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /unittests/newlines.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /unittests/no-collapse-lines.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /unittests/orient-marker.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /unittests/overflow-marker.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /unittests/overflow-svg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /unittests/path-abs-to-rel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/path-bez-optimize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /unittests/path-command-rewrites.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /unittests/path-elliptical-flags.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /unittests/path-implicit-line.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/path-line-optimize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/path-no-optimize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/path-precision-control-points.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | -------------------------------------------------------------------------------- /unittests/path-precision.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /unittests/path-quad-optimize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/path-simple-triangle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /unittests/path-sn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/path-truncate-zeros-calc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/path-truncate-zeros.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/path-use-scientific-notation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/path-with-caps.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /unittests/path-with-closepath.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/polygon-coord-neg-first.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/polygon-coord-neg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/polygon-coord.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/polygon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /unittests/polyline-coord-neg-first.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/polyline-coord-neg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/polyline-coord.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/protection.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /unittests/quot-in-url.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /unittests/quotes-in-styles.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /unittests/raster-formats.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Three different formats 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /unittests/raster-paths-local.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Local files 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Local files (file: protocol) 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /unittests/raster-paths-remote.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Files from internet 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /unittests/raster.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scour-project/scour/0609c596766ec98e4e2092b49bd03b802702ba1a/unittests/raster.gif -------------------------------------------------------------------------------- /unittests/raster.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scour-project/scour/0609c596766ec98e4e2092b49bd03b802702ba1a/unittests/raster.jpg -------------------------------------------------------------------------------- /unittests/raster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scour-project/scour/0609c596766ec98e4e2092b49bd03b802702ba1a/unittests/raster.png -------------------------------------------------------------------------------- /unittests/redundant-svg-namespace.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test 6 | 7 | 8 | Hallo World 9 | 10 | -------------------------------------------------------------------------------- /unittests/referenced-elements-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Fooey 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /unittests/referenced-font.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Text 17 | 18 | -------------------------------------------------------------------------------- /unittests/refs-in-defs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /unittests/remove-default-attr-order.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | -------------------------------------------------------------------------------- /unittests/remove-default-attr-std-deviation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | -------------------------------------------------------------------------------- /unittests/remove-duplicate-gradients-master-without-id.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /unittests/remove-duplicate-gradients.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /unittests/remove-unused-attributes-on-parent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /unittests/scour-lengths.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /unittests/shorten-ids-stable-output.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /unittests/shorten-ids.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /unittests/sodipodi.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /unittests/straight-curve.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/stroke-none.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /unittests/stroke-nowidth.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/stroke-transparent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/style-cdata.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /unittests/style-to-attr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /unittests/style.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /unittests/transform-matrix-is-identity.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /unittests/transform-matrix-is-rotate-135.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/transform-matrix-is-rotate-225.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/transform-matrix-is-rotate-45.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/transform-matrix-is-rotate-90.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/transform-matrix-is-rotate-neg-45.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/transform-matrix-is-rotate-neg-90.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/transform-matrix-is-scale-2-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /unittests/transform-matrix-is-scale-neg-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/transform-matrix-is-translate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /unittests/transform-rotate-fold-3args.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /unittests/transform-rotate-is-identity.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /unittests/transform-rotate-trim-range-719.5.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /unittests/transform-rotate-trim-range-neg-540.0.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /unittests/transform-scale-is-identity.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /unittests/transform-skewX-is-identity.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/transform-skewY-is-identity.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /unittests/transform-translate-is-identity.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /unittests/unreferenced-defs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /unittests/unreferenced-font.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Text 17 | 18 | -------------------------------------------------------------------------------- /unittests/unreferenced-linearGradient.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /unittests/unreferenced-pattern.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /unittests/unreferenced-radialGradient.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /unittests/useless-defs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /unittests/viewbox-create.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /unittests/viewbox-remove.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /unittests/whitespace-defs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /unittests/whitespace.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | text1 text2 5 | text1 text2 6 | text1 text2 7 | text1 text2 8 | text1 text2 9 | text1 text2 10 | 11 | 12 | text1 13 | text2 14 | text1 15 | text2 16 | text1 17 | text2 18 | 19 | 20 | text1 text2 21 | text1 text2 22 | text1 text2 23 | text1 text2 24 | text1 text2 25 | text1 text2 26 | 27 | 28 | text1 29 | text2 30 | text1 tspan1 text2 31 | text1 tspan1 tspan2 text2 32 | 33 | 34 | text1 35 | text2 36 | text1tspantext2 37 | text1 38 | tspan 39 | text2 40 | 41 | -------------------------------------------------------------------------------- /unittests/xml-namespace-attrs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /unittests/xml-ns-decl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | image/svg+xml 6 | 7 | Open Clip Art Logo 8 | 10-01-2004 9 | 10 | 11 | Andreas Nilsson 12 | 13 | 14 | 15 | 16 | 17 | Jon Phillips, Tobias Jakobs 18 | 19 | 20 | This is one version of the official Open Clip Art Library logo. 21 | logo, open clip art library logo, logotype 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /unittests/xml-space.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Some random text. 4 | -------------------------------------------------------------------------------- /unittests/xml-well-formed.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2 < 5 5 | Peanut Butter & Jelly 6 | 7 | 8 | 9 | 10 | ΉTML & CSS 11 | 12 | --------------------------------------------------------------------------------