allow direct calling of module
This commit is contained in:
parent
8dc6137373
commit
3353500845
2 changed files with 86 additions and 7 deletions
|
|
@ -70,7 +70,7 @@ except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
APP = 'scour'
|
APP = 'scour'
|
||||||
VER = '0.26'
|
VER = '0.27'
|
||||||
COPYRIGHT = 'Copyright Jeff Schiller, Louis Simard, 2010'
|
COPYRIGHT = 'Copyright Jeff Schiller, Louis Simard, 2010'
|
||||||
|
|
||||||
NS = { 'SVG': 'http://www.w3.org/2000/svg',
|
NS = { 'SVG': 'http://www.w3.org/2000/svg',
|
||||||
|
|
@ -2099,6 +2099,8 @@ def cleanPath(element, options) :
|
||||||
numBytesSavedInPathData += ( len(oldPathStr) - len(newPathStr) )
|
numBytesSavedInPathData += ( len(oldPathStr) - len(newPathStr) )
|
||||||
element.setAttribute('d', newPathStr)
|
element.setAttribute('d', newPathStr)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def parseListOfPoints(s):
|
def parseListOfPoints(s):
|
||||||
"""
|
"""
|
||||||
Parse string into a list of points.
|
Parse string into a list of points.
|
||||||
|
|
@ -2155,6 +2157,8 @@ def parseListOfPoints(s):
|
||||||
|
|
||||||
return nums
|
return nums
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def cleanPolygon(elem, options):
|
def cleanPolygon(elem, options):
|
||||||
"""
|
"""
|
||||||
Remove unnecessary closing point of polygon points attribute
|
Remove unnecessary closing point of polygon points attribute
|
||||||
|
|
@ -2171,6 +2175,8 @@ def cleanPolygon(elem, options):
|
||||||
numPointsRemovedFromPolygon += 1
|
numPointsRemovedFromPolygon += 1
|
||||||
elem.setAttribute('points', scourCoordinates(pts, options, True))
|
elem.setAttribute('points', scourCoordinates(pts, options, True))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def cleanPolyline(elem, options):
|
def cleanPolyline(elem, options):
|
||||||
"""
|
"""
|
||||||
Scour the polyline points attribute
|
Scour the polyline points attribute
|
||||||
|
|
@ -2178,6 +2184,8 @@ def cleanPolyline(elem, options):
|
||||||
pts = parseListOfPoints(elem.getAttribute('points'))
|
pts = parseListOfPoints(elem.getAttribute('points'))
|
||||||
elem.setAttribute('points', scourCoordinates(pts, options, True))
|
elem.setAttribute('points', scourCoordinates(pts, options, True))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def serializePath(pathObj, options):
|
def serializePath(pathObj, options):
|
||||||
"""
|
"""
|
||||||
Reserializes the path data with some cleanups.
|
Reserializes the path data with some cleanups.
|
||||||
|
|
@ -2186,6 +2194,8 @@ def serializePath(pathObj, options):
|
||||||
# this fixes an issue outlined in Fix https://bugs.launchpad.net/scour/+bug/412754
|
# this fixes an issue outlined in Fix https://bugs.launchpad.net/scour/+bug/412754
|
||||||
return ''.join([cmd + scourCoordinates(data, options, (cmd == 'a')) for cmd, data in pathObj])
|
return ''.join([cmd + scourCoordinates(data, options, (cmd == 'a')) for cmd, data in pathObj])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def serializeTransform(transformObj):
|
def serializeTransform(transformObj):
|
||||||
"""
|
"""
|
||||||
Reserializes the transform data with some cleanups.
|
Reserializes the transform data with some cleanups.
|
||||||
|
|
@ -2197,6 +2207,8 @@ def serializeTransform(transformObj):
|
||||||
for command, numbers in transformObj]
|
for command, numbers in transformObj]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def scourCoordinates(data, options, forceCommaWsp = False):
|
def scourCoordinates(data, options, forceCommaWsp = False):
|
||||||
"""
|
"""
|
||||||
Serializes coordinate data with some cleanups:
|
Serializes coordinate data with some cleanups:
|
||||||
|
|
@ -2246,6 +2258,8 @@ def scourCoordinates(data, options, forceCommaWsp = False):
|
||||||
|
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def scourLength(length):
|
def scourLength(length):
|
||||||
"""
|
"""
|
||||||
Scours a length. Accepts units.
|
Scours a length. Accepts units.
|
||||||
|
|
@ -2254,6 +2268,8 @@ def scourLength(length):
|
||||||
|
|
||||||
return scourUnitlessLength(length.value) + Unit.str(length.units)
|
return scourUnitlessLength(length.value) + Unit.str(length.units)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def scourUnitlessLength(length, needsRendererWorkaround=False): # length is of a numeric type
|
def scourUnitlessLength(length, needsRendererWorkaround=False): # length is of a numeric type
|
||||||
"""
|
"""
|
||||||
Scours the numeric part of a length only. Does not accept units.
|
Scours the numeric part of a length only. Does not accept units.
|
||||||
|
|
@ -2288,6 +2304,8 @@ def scourUnitlessLength(length, needsRendererWorkaround=False): # length is of a
|
||||||
else: return nonsci
|
else: return nonsci
|
||||||
else: return nonsci
|
else: return nonsci
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def reducePrecision(element) :
|
def reducePrecision(element) :
|
||||||
"""
|
"""
|
||||||
Because opacities, letter spacings, stroke widths and all that don't need
|
Because opacities, letter spacings, stroke widths and all that don't need
|
||||||
|
|
@ -2333,6 +2351,8 @@ def reducePrecision(element) :
|
||||||
|
|
||||||
return num
|
return num
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def optimizeAngle(angle):
|
def optimizeAngle(angle):
|
||||||
"""
|
"""
|
||||||
Because any rotation can be expressed within 360 degrees
|
Because any rotation can be expressed within 360 degrees
|
||||||
|
|
@ -2355,6 +2375,7 @@ def optimizeAngle(angle):
|
||||||
return angle
|
return angle
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def optimizeTransform(transform):
|
def optimizeTransform(transform):
|
||||||
"""
|
"""
|
||||||
Optimises a series of transformations parsed from a single
|
Optimises a series of transformations parsed from a single
|
||||||
|
|
@ -2514,6 +2535,8 @@ def optimizeTransform(transform):
|
||||||
else:
|
else:
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def optimizeTransforms(element, options) :
|
def optimizeTransforms(element, options) :
|
||||||
"""
|
"""
|
||||||
Attempts to optimise transform specifications on the given node and its children.
|
Attempts to optimise transform specifications on the given node and its children.
|
||||||
|
|
@ -2544,6 +2567,8 @@ def optimizeTransforms(element, options) :
|
||||||
|
|
||||||
return num
|
return num
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def removeComments(element) :
|
def removeComments(element) :
|
||||||
"""
|
"""
|
||||||
Removes comments from the element and its children.
|
Removes comments from the element and its children.
|
||||||
|
|
@ -2566,6 +2591,8 @@ def removeComments(element) :
|
||||||
for subelement in element.childNodes:
|
for subelement in element.childNodes:
|
||||||
removeComments(subelement)
|
removeComments(subelement)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def embedRasters(element, options) :
|
def embedRasters(element, options) :
|
||||||
import base64
|
import base64
|
||||||
import urllib
|
import urllib
|
||||||
|
|
@ -2623,6 +2650,8 @@ def embedRasters(element, options) :
|
||||||
numRastersEmbedded += 1
|
numRastersEmbedded += 1
|
||||||
del b64eRaster
|
del b64eRaster
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def properlySizeDoc(docElement, options):
|
def properlySizeDoc(docElement, options):
|
||||||
# get doc width and height
|
# get doc width and height
|
||||||
w = SVGLength(docElement.getAttribute('width'))
|
w = SVGLength(docElement.getAttribute('width'))
|
||||||
|
|
@ -2663,6 +2692,8 @@ def properlySizeDoc(docElement, options):
|
||||||
docElement.removeAttribute('width')
|
docElement.removeAttribute('width')
|
||||||
docElement.removeAttribute('height')
|
docElement.removeAttribute('height')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def remapNamespacePrefix(node, oldprefix, newprefix):
|
def remapNamespacePrefix(node, oldprefix, newprefix):
|
||||||
if node == None or node.nodeType != 1: return
|
if node == None or node.nodeType != 1: return
|
||||||
|
|
||||||
|
|
@ -2698,6 +2729,8 @@ def remapNamespacePrefix(node, oldprefix, newprefix):
|
||||||
for child in node.childNodes :
|
for child in node.childNodes :
|
||||||
remapNamespacePrefix(child, oldprefix, newprefix)
|
remapNamespacePrefix(child, oldprefix, newprefix)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def makeWellFormed(str):
|
def makeWellFormed(str):
|
||||||
xml_ents = { '<':'<', '>':'>', '&':'&', "'":''', '"':'"'}
|
xml_ents = { '<':'<', '>':'>', '&':'&', "'":''', '"':'"'}
|
||||||
|
|
||||||
|
|
@ -2711,6 +2744,8 @@ def makeWellFormed(str):
|
||||||
# this list comprehension is short-form for the above for-loop:
|
# this list comprehension is short-form for the above for-loop:
|
||||||
return ''.join([xml_ents[c] if c in xml_ents else c for c in str])
|
return ''.join([xml_ents[c] if c in xml_ents else c for c in str])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# hand-rolled serialization function that has the following benefits:
|
# hand-rolled serialization function that has the following benefits:
|
||||||
# - pretty printing
|
# - pretty printing
|
||||||
# - somewhat judicious use of whitespace
|
# - somewhat judicious use of whitespace
|
||||||
|
|
@ -2809,6 +2844,8 @@ def serializeXML(element, options, ind = 0, preserveWhitespace = False):
|
||||||
|
|
||||||
return "".join(outParts)
|
return "".join(outParts)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# this is the main method
|
# this is the main method
|
||||||
# input is a string representation of the input XML
|
# input is a string representation of the input XML
|
||||||
# returns a string representation of the output XML
|
# returns a string representation of the output XML
|
||||||
|
|
@ -3020,6 +3057,8 @@ def scourString(in_string, options=None):
|
||||||
|
|
||||||
return total_output
|
return total_output
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# used mostly by unit tests
|
# used mostly by unit tests
|
||||||
# input is a filename
|
# input is a filename
|
||||||
# returns the minidom doc representation of the SVG
|
# returns the minidom doc representation of the SVG
|
||||||
|
|
@ -3028,6 +3067,8 @@ def scourXmlFile(filename, options=None):
|
||||||
out_string = scourString(in_string, options)
|
out_string = scourString(in_string, options)
|
||||||
return xml.dom.minidom.parseString(out_string.encode('utf-8'))
|
return xml.dom.minidom.parseString(out_string.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# GZ: Seems most other commandline tools don't do this, is it really wanted?
|
# GZ: Seems most other commandline tools don't do this, is it really wanted?
|
||||||
class HeaderedFormatter(optparse.IndentedHelpFormatter):
|
class HeaderedFormatter(optparse.IndentedHelpFormatter):
|
||||||
"""
|
"""
|
||||||
|
|
@ -3038,6 +3079,8 @@ class HeaderedFormatter(optparse.IndentedHelpFormatter):
|
||||||
return "%s %s\n%s\n%s" % (APP, VER, COPYRIGHT,
|
return "%s %s\n%s\n%s" % (APP, VER, COPYRIGHT,
|
||||||
optparse.IndentedHelpFormatter.format_usage(self, usage))
|
optparse.IndentedHelpFormatter.format_usage(self, usage))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# GZ: would prefer this to be in a function or class scope, but tests etc need
|
# GZ: would prefer this to be in a function or class scope, but tests etc need
|
||||||
# access to the defaults anyway
|
# access to the defaults anyway
|
||||||
_options_parser = optparse.OptionParser(
|
_options_parser = optparse.OptionParser(
|
||||||
|
|
@ -3117,12 +3160,16 @@ _options_parser.add_option("--protect-ids-prefix",
|
||||||
action="store", type="string", dest="protect_ids_prefix", default=None,
|
action="store", type="string", dest="protect_ids_prefix", default=None,
|
||||||
help="Don't change IDs starting with the given prefix")
|
help="Don't change IDs starting with the given prefix")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def maybe_gziped_file(filename, mode="r"):
|
def maybe_gziped_file(filename, mode="r"):
|
||||||
if os.path.splitext(filename)[1].lower() in (".svgz", ".gz"):
|
if os.path.splitext(filename)[1].lower() in (".svgz", ".gz"):
|
||||||
import gzip
|
import gzip
|
||||||
return gzip.GzipFile(filename, mode)
|
return gzip.GzipFile(filename, mode)
|
||||||
return file(filename, mode)
|
return file(filename, mode)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args(args=None):
|
def parse_args(args=None):
|
||||||
options, rargs = _options_parser.parse_args(args)
|
options, rargs = _options_parser.parse_args(args)
|
||||||
|
|
||||||
|
|
@ -3148,6 +3195,8 @@ def parse_args(args=None):
|
||||||
|
|
||||||
return options, [infile, outfile]
|
return options, [infile, outfile]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def getReport():
|
def getReport():
|
||||||
return ' Number of elements removed: ' + str(numElemsRemoved) + os.linesep + \
|
return ' Number of elements removed: ' + str(numElemsRemoved) + os.linesep + \
|
||||||
' Number of attributes removed: ' + str(numAttrsRemoved) + os.linesep + \
|
' Number of attributes removed: ' + str(numAttrsRemoved) + os.linesep + \
|
||||||
|
|
@ -3164,7 +3213,20 @@ def getReport():
|
||||||
' Number of bytes saved in transformations: ' + str(numBytesSavedInTransforms)
|
' Number of bytes saved in transformations: ' + str(numBytesSavedInTransforms)
|
||||||
|
|
||||||
|
|
||||||
def run():
|
|
||||||
|
def generateDefaultOptions():
|
||||||
|
## FIXME: clean up this mess/hack and refactor arg parsing to argparse
|
||||||
|
class Struct:
|
||||||
|
def __init__(self, **entries):
|
||||||
|
self.__dict__.update(entries)
|
||||||
|
|
||||||
|
d = parse_args()[0].__dict__.copy()
|
||||||
|
|
||||||
|
return Struct(**d)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def start(options, input, output):
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
from time import clock as get_tick
|
from time import clock as get_tick
|
||||||
else:
|
else:
|
||||||
|
|
@ -3174,8 +3236,6 @@ def run():
|
||||||
|
|
||||||
start = get_tick()
|
start = get_tick()
|
||||||
|
|
||||||
options, (input, output) = parse_args()
|
|
||||||
|
|
||||||
if not options.quiet:
|
if not options.quiet:
|
||||||
print >>sys.stderr, "%s %s\n%s" % (APP, VER, COPYRIGHT)
|
print >>sys.stderr, "%s %s\n%s" % (APP, VER, COPYRIGHT)
|
||||||
|
|
||||||
|
|
@ -3203,6 +3263,12 @@ def run():
|
||||||
'new file size:', newsize, 'bytes (' + str(sizediff)[:5] + '%)'
|
'new file size:', newsize, 'bytes (' + str(sizediff)[:5] + '%)'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
options, (input, output) = parse_args()
|
||||||
|
start(options, input, output)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
run()
|
run()
|
||||||
|
|
||||||
|
|
|
||||||
17
setup.py
17
setup.py
|
|
@ -18,15 +18,28 @@
|
||||||
|
|
||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
LONGDESC = """
|
||||||
|
Scour is a SVG optimizer/sanitizer that can be used to produce SVGs for Web deployment.
|
||||||
|
|
||||||
|
Website
|
||||||
|
- http://www.codedread.com/scour/ (original website)
|
||||||
|
- https://github.com/oberstet/scour (today)
|
||||||
|
|
||||||
|
Authors:
|
||||||
|
- Jeff Schiller, Louis Simard (original authors)
|
||||||
|
- Tobias Oberstein (maintainer)
|
||||||
|
"""
|
||||||
|
|
||||||
setup (
|
setup (
|
||||||
name = 'scour',
|
name = 'scour',
|
||||||
version = '0.27',
|
version = '0.27',
|
||||||
description = 'Scour SVG Optimizer',
|
description = 'Scour SVG Optimizer',
|
||||||
long_description = open("README.md").read(),
|
# long_description = open("README.md").read(),
|
||||||
|
long_description = LONGDESC,
|
||||||
license = 'Apache License 2.0',
|
license = 'Apache License 2.0',
|
||||||
author = 'Jeff Schiller',
|
author = 'Jeff Schiller',
|
||||||
author_email = 'codedread@gmail.com',
|
author_email = 'codedread@gmail.com',
|
||||||
url = 'http://blog.codedread.com/',
|
url = 'https://github.com/oberstet/scour',
|
||||||
platforms = ('Any'),
|
platforms = ('Any'),
|
||||||
install_requires = [],
|
install_requires = [],
|
||||||
packages = find_packages(),
|
packages = find_packages(),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue