Fixes to globals used for tracking statistics (#118)
- Collect globals in `scourString()` and make sure they're all properly initialized to zero. Before statistics were wrong when scouring multiple files/strings because initialization was only done once when loading the module. - harmonize names - adjust according to PEP 8 while at it (including leading underscore to mark as non-public) - include one missing variable in statistics output (number of comments removed)
This commit is contained in:
parent
4410f91dad
commit
2487f4433b
1 changed files with 105 additions and 95 deletions
200
scour/scour.py
200
scour/scour.py
|
|
@ -534,8 +534,8 @@ def findElementsWithId(node, elems=None):
|
||||||
findElementsWithId(child, elems)
|
findElementsWithId(child, elems)
|
||||||
return elems
|
return elems
|
||||||
|
|
||||||
referencingProps = ['fill', 'stroke', 'filter', 'clip-path', 'mask', 'marker-start',
|
|
||||||
'marker-end', 'marker-mid']
|
referencingProps = ['fill', 'stroke', 'filter', 'clip-path', 'mask', 'marker-start', 'marker-end', 'marker-mid']
|
||||||
|
|
||||||
|
|
||||||
def findReferencedElements(node, ids=None):
|
def findReferencedElements(node, ids=None):
|
||||||
|
|
@ -625,20 +625,6 @@ def findReferencingProperty(node, prop, val, ids):
|
||||||
else:
|
else:
|
||||||
ids[id] = [1, [node]]
|
ids[id] = [1, [node]]
|
||||||
|
|
||||||
numIDsRemoved = 0
|
|
||||||
numElemsRemoved = 0
|
|
||||||
numAttrsRemoved = 0
|
|
||||||
numRastersEmbedded = 0
|
|
||||||
numPathSegmentsReduced = 0
|
|
||||||
numCurvesStraightened = 0
|
|
||||||
numBytesSavedInPathData = 0
|
|
||||||
numBytesSavedInColors = 0
|
|
||||||
numBytesSavedInIDs = 0
|
|
||||||
numBytesSavedInLengths = 0
|
|
||||||
numBytesSavedInTransforms = 0
|
|
||||||
numPointsRemovedFromPolygon = 0
|
|
||||||
numCommentBytes = 0
|
|
||||||
|
|
||||||
|
|
||||||
def removeUnusedDefs(doc, defElem, elemsToRemove=None):
|
def removeUnusedDefs(doc, defElem, elemsToRemove=None):
|
||||||
if elemsToRemove is None:
|
if elemsToRemove is None:
|
||||||
|
|
@ -668,7 +654,7 @@ def removeUnreferencedElements(doc, keepDefs):
|
||||||
|
|
||||||
Returns the number of unreferenced elements removed from the document.
|
Returns the number of unreferenced elements removed from the document.
|
||||||
"""
|
"""
|
||||||
global numElemsRemoved
|
global _num_elements_removed
|
||||||
num = 0
|
num = 0
|
||||||
|
|
||||||
# Remove certain unreferenced elements outside of defs
|
# Remove certain unreferenced elements outside of defs
|
||||||
|
|
@ -684,7 +670,7 @@ def removeUnreferencedElements(doc, keepDefs):
|
||||||
and goner.parentNode.tagName != 'defs'):
|
and goner.parentNode.tagName != 'defs'):
|
||||||
goner.parentNode.removeChild(goner)
|
goner.parentNode.removeChild(goner)
|
||||||
num += 1
|
num += 1
|
||||||
numElemsRemoved += 1
|
_num_elements_removed += 1
|
||||||
|
|
||||||
if not keepDefs:
|
if not keepDefs:
|
||||||
# Remove most unreferenced elements inside defs
|
# Remove most unreferenced elements inside defs
|
||||||
|
|
@ -693,7 +679,7 @@ def removeUnreferencedElements(doc, keepDefs):
|
||||||
elemsToRemove = removeUnusedDefs(doc, aDef)
|
elemsToRemove = removeUnusedDefs(doc, aDef)
|
||||||
for elem in elemsToRemove:
|
for elem in elemsToRemove:
|
||||||
elem.parentNode.removeChild(elem)
|
elem.parentNode.removeChild(elem)
|
||||||
numElemsRemoved += 1
|
_num_elements_removed += 1
|
||||||
num += 1
|
num += 1
|
||||||
return num
|
return num
|
||||||
|
|
||||||
|
|
@ -868,20 +854,20 @@ def removeUnreferencedIDs(referencedIDs, identifiedElements):
|
||||||
|
|
||||||
Returns the number of ID attributes removed
|
Returns the number of ID attributes removed
|
||||||
"""
|
"""
|
||||||
global numIDsRemoved
|
global _num_ids_removed
|
||||||
keepTags = ['font']
|
keepTags = ['font']
|
||||||
num = 0
|
num = 0
|
||||||
for id in list(identifiedElements.keys()):
|
for id in list(identifiedElements.keys()):
|
||||||
node = identifiedElements[id]
|
node = identifiedElements[id]
|
||||||
if id not in referencedIDs and node.nodeName not in keepTags:
|
if id not in referencedIDs and node.nodeName not in keepTags:
|
||||||
node.removeAttribute('id')
|
node.removeAttribute('id')
|
||||||
numIDsRemoved += 1
|
_num_ids_removed += 1
|
||||||
num += 1
|
num += 1
|
||||||
return num
|
return num
|
||||||
|
|
||||||
|
|
||||||
def removeNamespacedAttributes(node, namespaces):
|
def removeNamespacedAttributes(node, namespaces):
|
||||||
global numAttrsRemoved
|
global _num_attributes_removed
|
||||||
num = 0
|
num = 0
|
||||||
if node.nodeType == 1:
|
if node.nodeType == 1:
|
||||||
# remove all namespace'd attributes from this element
|
# remove all namespace'd attributes from this element
|
||||||
|
|
@ -893,7 +879,7 @@ def removeNamespacedAttributes(node, namespaces):
|
||||||
attrsToRemove.append(attr.nodeName)
|
attrsToRemove.append(attr.nodeName)
|
||||||
for attrName in attrsToRemove:
|
for attrName in attrsToRemove:
|
||||||
num += 1
|
num += 1
|
||||||
numAttrsRemoved += 1
|
_num_attributes_removed += 1
|
||||||
node.removeAttribute(attrName)
|
node.removeAttribute(attrName)
|
||||||
|
|
||||||
# now recurse for children
|
# now recurse for children
|
||||||
|
|
@ -903,7 +889,7 @@ def removeNamespacedAttributes(node, namespaces):
|
||||||
|
|
||||||
|
|
||||||
def removeNamespacedElements(node, namespaces):
|
def removeNamespacedElements(node, namespaces):
|
||||||
global numElemsRemoved
|
global _num_elements_removed
|
||||||
num = 0
|
num = 0
|
||||||
if node.nodeType == 1:
|
if node.nodeType == 1:
|
||||||
# remove all namespace'd child nodes from this element
|
# remove all namespace'd child nodes from this element
|
||||||
|
|
@ -914,7 +900,7 @@ def removeNamespacedElements(node, namespaces):
|
||||||
childrenToRemove.append(child)
|
childrenToRemove.append(child)
|
||||||
for child in childrenToRemove:
|
for child in childrenToRemove:
|
||||||
num += 1
|
num += 1
|
||||||
numElemsRemoved += 1
|
_num_elements_removed += 1
|
||||||
node.removeChild(child)
|
node.removeChild(child)
|
||||||
|
|
||||||
# now recurse for children
|
# now recurse for children
|
||||||
|
|
@ -937,7 +923,7 @@ def removeDescriptiveElements(doc, options):
|
||||||
if not elementTypes:
|
if not elementTypes:
|
||||||
return
|
return
|
||||||
|
|
||||||
global numElemsRemoved
|
global _num_elements_removed
|
||||||
num = 0
|
num = 0
|
||||||
elementsToRemove = []
|
elementsToRemove = []
|
||||||
for elementType in elementTypes:
|
for elementType in elementTypes:
|
||||||
|
|
@ -946,7 +932,7 @@ def removeDescriptiveElements(doc, options):
|
||||||
for element in elementsToRemove:
|
for element in elementsToRemove:
|
||||||
element.parentNode.removeChild(element)
|
element.parentNode.removeChild(element)
|
||||||
num += 1
|
num += 1
|
||||||
numElemsRemoved += 1
|
_num_elements_removed += 1
|
||||||
|
|
||||||
return num
|
return num
|
||||||
|
|
||||||
|
|
@ -957,7 +943,7 @@ def removeNestedGroups(node):
|
||||||
which do not have any attributes or a title/desc child and
|
which do not have any attributes or a title/desc child and
|
||||||
promoting their children up one level
|
promoting their children up one level
|
||||||
"""
|
"""
|
||||||
global numElemsRemoved
|
global _num_elements_removed
|
||||||
num = 0
|
num = 0
|
||||||
|
|
||||||
groupsToRemove = []
|
groupsToRemove = []
|
||||||
|
|
@ -978,7 +964,7 @@ def removeNestedGroups(node):
|
||||||
while g.childNodes.length > 0:
|
while g.childNodes.length > 0:
|
||||||
g.parentNode.insertBefore(g.firstChild, g)
|
g.parentNode.insertBefore(g.firstChild, g)
|
||||||
g.parentNode.removeChild(g)
|
g.parentNode.removeChild(g)
|
||||||
numElemsRemoved += 1
|
_num_elements_removed += 1
|
||||||
num += 1
|
num += 1
|
||||||
|
|
||||||
# now recurse for children
|
# now recurse for children
|
||||||
|
|
@ -1084,7 +1070,7 @@ def createGroupsForCommonAttributes(elem):
|
||||||
This function acts recursively on the given element.
|
This function acts recursively on the given element.
|
||||||
"""
|
"""
|
||||||
num = 0
|
num = 0
|
||||||
global numElemsRemoved
|
global _num_elements_removed
|
||||||
|
|
||||||
# TODO perhaps all of the Presentation attributes in http://www.w3.org/TR/SVG/struct.html#GElement
|
# TODO perhaps all of the Presentation attributes in http://www.w3.org/TR/SVG/struct.html#GElement
|
||||||
# could be added here
|
# could be added here
|
||||||
|
|
@ -1183,7 +1169,7 @@ def createGroupsForCommonAttributes(elem):
|
||||||
group.parentNode = elem
|
group.parentNode = elem
|
||||||
num += 1
|
num += 1
|
||||||
curChild = runStart - 1
|
curChild = runStart - 1
|
||||||
numElemsRemoved -= 1
|
_num_elements_removed -= 1
|
||||||
else:
|
else:
|
||||||
curChild -= 1
|
curChild -= 1
|
||||||
else:
|
else:
|
||||||
|
|
@ -1253,7 +1239,7 @@ def removeUnusedAttributesOnParent(elem):
|
||||||
|
|
||||||
|
|
||||||
def removeDuplicateGradientStops(doc):
|
def removeDuplicateGradientStops(doc):
|
||||||
global numElemsRemoved
|
global _num_elements_removed
|
||||||
num = 0
|
num = 0
|
||||||
|
|
||||||
for gradType in ['linearGradient', 'radialGradient']:
|
for gradType in ['linearGradient', 'radialGradient']:
|
||||||
|
|
@ -1287,14 +1273,14 @@ def removeDuplicateGradientStops(doc):
|
||||||
for stop in stopsToRemove:
|
for stop in stopsToRemove:
|
||||||
stop.parentNode.removeChild(stop)
|
stop.parentNode.removeChild(stop)
|
||||||
num += 1
|
num += 1
|
||||||
numElemsRemoved += 1
|
_num_elements_removed += 1
|
||||||
|
|
||||||
# linear gradients
|
# linear gradients
|
||||||
return num
|
return num
|
||||||
|
|
||||||
|
|
||||||
def collapseSinglyReferencedGradients(doc):
|
def collapseSinglyReferencedGradients(doc):
|
||||||
global numElemsRemoved
|
global _num_elements_removed
|
||||||
num = 0
|
num = 0
|
||||||
|
|
||||||
identifiedElements = findElementsWithId(doc.documentElement)
|
identifiedElements = findElementsWithId(doc.documentElement)
|
||||||
|
|
@ -1346,13 +1332,13 @@ def collapseSinglyReferencedGradients(doc):
|
||||||
|
|
||||||
# now delete elem
|
# now delete elem
|
||||||
elem.parentNode.removeChild(elem)
|
elem.parentNode.removeChild(elem)
|
||||||
numElemsRemoved += 1
|
_num_elements_removed += 1
|
||||||
num += 1
|
num += 1
|
||||||
return num
|
return num
|
||||||
|
|
||||||
|
|
||||||
def removeDuplicateGradients(doc):
|
def removeDuplicateGradients(doc):
|
||||||
global numElemsRemoved
|
global _num_elements_removed
|
||||||
num = 0
|
num = 0
|
||||||
|
|
||||||
gradientsToRemove = {}
|
gradientsToRemove = {}
|
||||||
|
|
@ -1446,7 +1432,7 @@ def removeDuplicateGradients(doc):
|
||||||
# now that all referencing elements have been re-mapped to the master
|
# now that all referencing elements have been re-mapped to the master
|
||||||
# it is safe to remove this gradient from the document
|
# it is safe to remove this gradient from the document
|
||||||
dupGrad.parentNode.removeChild(dupGrad)
|
dupGrad.parentNode.removeChild(dupGrad)
|
||||||
numElemsRemoved += 1
|
_num_elements_removed += 1
|
||||||
num += 1
|
num += 1
|
||||||
return num
|
return num
|
||||||
|
|
||||||
|
|
@ -2051,9 +2037,8 @@ def cleanPath(element, options):
|
||||||
"""
|
"""
|
||||||
Cleans the path string (d attribute) of the element
|
Cleans the path string (d attribute) of the element
|
||||||
"""
|
"""
|
||||||
global numBytesSavedInPathData
|
global _num_bytes_saved_in_path_data
|
||||||
global numPathSegmentsReduced
|
global _num_path_segments_removed
|
||||||
global numCurvesStraightened
|
|
||||||
|
|
||||||
# this gets the parser object from svg_regex.py
|
# this gets the parser object from svg_regex.py
|
||||||
oldPathStr = element.getAttribute('d')
|
oldPathStr = element.getAttribute('d')
|
||||||
|
|
@ -2183,40 +2168,40 @@ def cleanPath(element, options):
|
||||||
# 'm0,0 x,y' can be replaces with 'lx,y',
|
# 'm0,0 x,y' can be replaces with 'lx,y',
|
||||||
# except the first m which is a required absolute moveto
|
# except the first m which is a required absolute moveto
|
||||||
path[pathIndex] = ('l', data[2:])
|
path[pathIndex] = ('l', data[2:])
|
||||||
numPathSegmentsReduced += 1
|
_num_path_segments_removed += 1
|
||||||
else: # else skip move coordinate
|
else: # else skip move coordinate
|
||||||
i = 2
|
i = 2
|
||||||
while i < len(data):
|
while i < len(data):
|
||||||
if data[i] == data[i + 1] == 0:
|
if data[i] == data[i + 1] == 0:
|
||||||
del data[i:i + 2]
|
del data[i:i + 2]
|
||||||
numPathSegmentsReduced += 1
|
_num_path_segments_removed += 1
|
||||||
else:
|
else:
|
||||||
i += 2
|
i += 2
|
||||||
elif cmd == 'c':
|
elif cmd == 'c':
|
||||||
while i < len(data):
|
while i < len(data):
|
||||||
if data[i] == data[i + 1] == data[i + 2] == data[i + 3] == data[i + 4] == data[i + 5] == 0:
|
if data[i] == data[i + 1] == data[i + 2] == data[i + 3] == data[i + 4] == data[i + 5] == 0:
|
||||||
del data[i:i + 6]
|
del data[i:i + 6]
|
||||||
numPathSegmentsReduced += 1
|
_num_path_segments_removed += 1
|
||||||
else:
|
else:
|
||||||
i += 6
|
i += 6
|
||||||
elif cmd == 'a':
|
elif cmd == 'a':
|
||||||
while i < len(data):
|
while i < len(data):
|
||||||
if data[i + 5] == data[i + 6] == 0:
|
if data[i + 5] == data[i + 6] == 0:
|
||||||
del data[i:i + 7]
|
del data[i:i + 7]
|
||||||
numPathSegmentsReduced += 1
|
_num_path_segments_removed += 1
|
||||||
else:
|
else:
|
||||||
i += 7
|
i += 7
|
||||||
elif cmd == 'q':
|
elif cmd == 'q':
|
||||||
while i < len(data):
|
while i < len(data):
|
||||||
if data[i] == data[i + 1] == data[i + 2] == data[i + 3] == 0:
|
if data[i] == data[i + 1] == data[i + 2] == data[i + 3] == 0:
|
||||||
del data[i:i + 4]
|
del data[i:i + 4]
|
||||||
numPathSegmentsReduced += 1
|
_num_path_segments_removed += 1
|
||||||
else:
|
else:
|
||||||
i += 4
|
i += 4
|
||||||
elif cmd in ['h', 'v']:
|
elif cmd in ['h', 'v']:
|
||||||
oldLen = len(data)
|
oldLen = len(data)
|
||||||
path[pathIndex] = (cmd, [coord for coord in data if coord != 0])
|
path[pathIndex] = (cmd, [coord for coord in data if coord != 0])
|
||||||
numPathSegmentsReduced += len(path[pathIndex][1]) - oldLen
|
_num_path_segments_removed += len(path[pathIndex][1]) - oldLen
|
||||||
|
|
||||||
# fixup: Delete subcommands having no coordinates.
|
# fixup: Delete subcommands having no coordinates.
|
||||||
path = [elem for elem in path if len(elem[1]) > 0 or elem[0] == 'z']
|
path = [elem for elem in path if len(elem[1]) > 0 or elem[0] == 'z']
|
||||||
|
|
@ -2254,7 +2239,6 @@ def cleanPath(element, options):
|
||||||
newData = []
|
newData = []
|
||||||
# now create a straight line segment
|
# now create a straight line segment
|
||||||
newPath.append(('l', [dx, dy]))
|
newPath.append(('l', [dx, dy]))
|
||||||
numCurvesStraightened += 1
|
|
||||||
else:
|
else:
|
||||||
newData.extend(data[i:i + 6])
|
newData.extend(data[i:i + 6])
|
||||||
|
|
||||||
|
|
@ -2306,14 +2290,14 @@ def cleanPath(element, options):
|
||||||
lineTuples = []
|
lineTuples = []
|
||||||
# append the v and then the remaining line coords
|
# append the v and then the remaining line coords
|
||||||
newPath.append(('v', [data[i + 1]]))
|
newPath.append(('v', [data[i + 1]]))
|
||||||
numPathSegmentsReduced += 1
|
_num_path_segments_removed += 1
|
||||||
elif data[i + 1] == 0:
|
elif data[i + 1] == 0:
|
||||||
if lineTuples:
|
if lineTuples:
|
||||||
# flush the line command, then append the h and then the remaining line coords
|
# flush the line command, then append the h and then the remaining line coords
|
||||||
newPath.append(('l', lineTuples))
|
newPath.append(('l', lineTuples))
|
||||||
lineTuples = []
|
lineTuples = []
|
||||||
newPath.append(('h', [data[i]]))
|
newPath.append(('h', [data[i]]))
|
||||||
numPathSegmentsReduced += 1
|
_num_path_segments_removed += 1
|
||||||
else:
|
else:
|
||||||
lineTuples.extend(data[i:i + 2])
|
lineTuples.extend(data[i:i + 2])
|
||||||
i += 2
|
i += 2
|
||||||
|
|
@ -2333,7 +2317,7 @@ def cleanPath(element, options):
|
||||||
cmd = 'l' # dealing with linetos now
|
cmd = 'l' # dealing with linetos now
|
||||||
# append the v and then the remaining line coords
|
# append the v and then the remaining line coords
|
||||||
newPath.append(('v', [data[i + 1]]))
|
newPath.append(('v', [data[i + 1]]))
|
||||||
numPathSegmentsReduced += 1
|
_num_path_segments_removed += 1
|
||||||
elif data[i + 1] == 0:
|
elif data[i + 1] == 0:
|
||||||
if lineTuples:
|
if lineTuples:
|
||||||
# flush the m/l command, then append the h and then the remaining line coords
|
# flush the m/l command, then append the h and then the remaining line coords
|
||||||
|
|
@ -2341,7 +2325,7 @@ def cleanPath(element, options):
|
||||||
lineTuples = []
|
lineTuples = []
|
||||||
cmd = 'l' # dealing with linetos now
|
cmd = 'l' # dealing with linetos now
|
||||||
newPath.append(('h', [data[i]]))
|
newPath.append(('h', [data[i]]))
|
||||||
numPathSegmentsReduced += 1
|
_num_path_segments_removed += 1
|
||||||
else:
|
else:
|
||||||
lineTuples.extend(data[i:i + 2])
|
lineTuples.extend(data[i:i + 2])
|
||||||
i += 2
|
i += 2
|
||||||
|
|
@ -2370,7 +2354,7 @@ def cleanPath(element, options):
|
||||||
curveTuples = []
|
curveTuples = []
|
||||||
# append the s command
|
# append the s command
|
||||||
newPath.append(('s', [data[i + 2], data[i + 3], data[i + 4], data[i + 5]]))
|
newPath.append(('s', [data[i + 2], data[i + 3], data[i + 4], data[i + 5]]))
|
||||||
numPathSegmentsReduced += 1
|
_num_path_segments_removed += 1
|
||||||
else:
|
else:
|
||||||
j = 0
|
j = 0
|
||||||
while j <= 5:
|
while j <= 5:
|
||||||
|
|
@ -2395,7 +2379,7 @@ def cleanPath(element, options):
|
||||||
curveTuples = []
|
curveTuples = []
|
||||||
# append the t command
|
# append the t command
|
||||||
newPath.append(('t', [data[i + 2], data[i + 3]]))
|
newPath.append(('t', [data[i + 2], data[i + 3]]))
|
||||||
numPathSegmentsReduced += 1
|
_num_path_segments_removed += 1
|
||||||
else:
|
else:
|
||||||
j = 0
|
j = 0
|
||||||
while j <= 3:
|
while j <= 3:
|
||||||
|
|
@ -2424,7 +2408,7 @@ def cleanPath(element, options):
|
||||||
if isSameSign(data[coordIndex - 1], data[coordIndex]):
|
if isSameSign(data[coordIndex - 1], data[coordIndex]):
|
||||||
data[coordIndex - 1] += data[coordIndex]
|
data[coordIndex - 1] += data[coordIndex]
|
||||||
del data[coordIndex]
|
del data[coordIndex]
|
||||||
numPathSegmentsReduced += 1
|
_num_path_segments_removed += 1
|
||||||
else:
|
else:
|
||||||
coordIndex += 1
|
coordIndex += 1
|
||||||
|
|
||||||
|
|
@ -2459,7 +2443,7 @@ def cleanPath(element, options):
|
||||||
# if for whatever reason we actually made the path longer don't use it
|
# if for whatever reason we actually made the path longer don't use it
|
||||||
# TODO: maybe we could compare path lengths after each optimization step and use the shortest
|
# TODO: maybe we could compare path lengths after each optimization step and use the shortest
|
||||||
if len(newPathStr) <= len(oldPathStr):
|
if len(newPathStr) <= len(oldPathStr):
|
||||||
numBytesSavedInPathData += (len(oldPathStr) - len(newPathStr))
|
_num_bytes_saved_in_path_data += (len(oldPathStr) - len(newPathStr))
|
||||||
element.setAttribute('d', newPathStr)
|
element.setAttribute('d', newPathStr)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2527,7 +2511,7 @@ def cleanPolygon(elem, options):
|
||||||
"""
|
"""
|
||||||
Remove unnecessary closing point of polygon points attribute
|
Remove unnecessary closing point of polygon points attribute
|
||||||
"""
|
"""
|
||||||
global numPointsRemovedFromPolygon
|
global _num_points_removed_from_polygon
|
||||||
|
|
||||||
pts = parseListOfPoints(elem.getAttribute('points'))
|
pts = parseListOfPoints(elem.getAttribute('points'))
|
||||||
N = len(pts) / 2
|
N = len(pts) / 2
|
||||||
|
|
@ -2536,7 +2520,7 @@ def cleanPolygon(elem, options):
|
||||||
(endx, endy) = pts[-2:]
|
(endx, endy) = pts[-2:]
|
||||||
if startx == endx and starty == endy:
|
if startx == endx and starty == endy:
|
||||||
del pts[-2:]
|
del pts[-2:]
|
||||||
numPointsRemovedFromPolygon += 1
|
_num_points_removed_from_polygon += 1
|
||||||
elem.setAttribute('points', scourCoordinates(pts, options, True))
|
elem.setAttribute('points', scourCoordinates(pts, options, True))
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2944,10 +2928,10 @@ def removeComments(element):
|
||||||
"""
|
"""
|
||||||
Removes comments from the element and its children.
|
Removes comments from the element and its children.
|
||||||
"""
|
"""
|
||||||
global numCommentBytes
|
global _num_bytes_saved_in_comments
|
||||||
|
|
||||||
if isinstance(element, xml.dom.minidom.Comment):
|
if isinstance(element, xml.dom.minidom.Comment):
|
||||||
numCommentBytes += len(element.data)
|
_num_bytes_saved_in_comments += len(element.data)
|
||||||
element.parentNode.removeChild(element)
|
element.parentNode.removeChild(element)
|
||||||
else:
|
else:
|
||||||
for subelement in element.childNodes[:]:
|
for subelement in element.childNodes[:]:
|
||||||
|
|
@ -2961,7 +2945,7 @@ def embedRasters(element, options):
|
||||||
Converts raster references to inline images.
|
Converts raster references to inline images.
|
||||||
NOTE: there are size limits to base64-encoding handling in browsers
|
NOTE: there are size limits to base64-encoding handling in browsers
|
||||||
"""
|
"""
|
||||||
global numRastersEmbedded
|
global _num_rasters_embedded
|
||||||
|
|
||||||
href = element.getAttributeNS(NS['XLINK'], 'href')
|
href = element.getAttributeNS(NS['XLINK'], 'href')
|
||||||
|
|
||||||
|
|
@ -3009,7 +2993,7 @@ def embedRasters(element, options):
|
||||||
ext = 'jpeg'
|
ext = 'jpeg'
|
||||||
|
|
||||||
element.setAttributeNS(NS['XLINK'], 'href', 'data:image/' + ext + ';base64,' + b64eRaster)
|
element.setAttributeNS(NS['XLINK'], 'href', 'data:image/' + ext + ';base64,' + b64eRaster)
|
||||||
numRastersEmbedded += 1
|
_num_rasters_embedded += 1
|
||||||
del b64eRaster
|
del b64eRaster
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3253,14 +3237,37 @@ def scourString(in_string, options=None):
|
||||||
global scouringContext
|
global scouringContext
|
||||||
scouringContext = Context(prec=options.digits)
|
scouringContext = Context(prec=options.digits)
|
||||||
|
|
||||||
global numAttrsRemoved
|
# globals for tracking statistics
|
||||||
global numStylePropsFixed
|
# TODO: get rid of these globals...
|
||||||
global numElemsRemoved
|
global _num_elements_removed
|
||||||
global numBytesSavedInColors
|
global _num_attributes_removed
|
||||||
global numCommentsRemoved
|
global _num_ids_removed
|
||||||
global numBytesSavedInIDs
|
global _num_comments_removed
|
||||||
global numBytesSavedInLengths
|
global _num_style_properties_fixed
|
||||||
global numBytesSavedInTransforms
|
global _num_rasters_embedded
|
||||||
|
global _num_path_segments_removed
|
||||||
|
global _num_points_removed_from_polygon
|
||||||
|
global _num_bytes_saved_in_path_data
|
||||||
|
global _num_bytes_saved_in_colors
|
||||||
|
global _num_bytes_saved_in_comments
|
||||||
|
global _num_bytes_saved_in_ids
|
||||||
|
global _num_bytes_saved_in_lengths
|
||||||
|
global _num_bytes_saved_in_transforms
|
||||||
|
_num_elements_removed = 0
|
||||||
|
_num_attributes_removed = 0
|
||||||
|
_num_ids_removed = 0
|
||||||
|
_num_comments_removed = 0
|
||||||
|
_num_style_properties_fixed = 0
|
||||||
|
_num_rasters_embedded = 0
|
||||||
|
_num_path_segments_removed = 0
|
||||||
|
_num_points_removed_from_polygon = 0
|
||||||
|
_num_bytes_saved_in_path_data = 0
|
||||||
|
_num_bytes_saved_in_colors = 0
|
||||||
|
_num_bytes_saved_in_comments = 0
|
||||||
|
_num_bytes_saved_in_ids = 0
|
||||||
|
_num_bytes_saved_in_lengths = 0
|
||||||
|
_num_bytes_saved_in_transforms = 0
|
||||||
|
|
||||||
doc = xml.dom.minidom.parseString(in_string)
|
doc = xml.dom.minidom.parseString(in_string)
|
||||||
|
|
||||||
# determine number of flowRoot elements in input document
|
# determine number of flowRoot elements in input document
|
||||||
|
|
@ -3295,7 +3302,7 @@ def scourString(in_string, options=None):
|
||||||
|
|
||||||
for attr in xmlnsDeclsToRemove:
|
for attr in xmlnsDeclsToRemove:
|
||||||
doc.documentElement.removeAttribute(attr)
|
doc.documentElement.removeAttribute(attr)
|
||||||
numAttrsRemoved += 1
|
_num_attributes_removed += 1
|
||||||
|
|
||||||
# ensure namespace for SVG is declared
|
# ensure namespace for SVG is declared
|
||||||
# TODO: what if the default namespace is something else (i.e. some valid namespace)?
|
# TODO: what if the default namespace is something else (i.e. some valid namespace)?
|
||||||
|
|
@ -3330,24 +3337,24 @@ def scourString(in_string, options=None):
|
||||||
|
|
||||||
for attrName in xmlnsDeclsToRemove:
|
for attrName in xmlnsDeclsToRemove:
|
||||||
doc.documentElement.removeAttribute(attrName)
|
doc.documentElement.removeAttribute(attrName)
|
||||||
numAttrsRemoved += 1
|
_num_attributes_removed += 1
|
||||||
|
|
||||||
for prefix in redundantPrefixes:
|
for prefix in redundantPrefixes:
|
||||||
remapNamespacePrefix(doc.documentElement, prefix, '')
|
remapNamespacePrefix(doc.documentElement, prefix, '')
|
||||||
|
|
||||||
if options.strip_comments:
|
if options.strip_comments:
|
||||||
numCommentsRemoved = removeComments(doc)
|
_num_comments_removed = removeComments(doc)
|
||||||
|
|
||||||
if options.strip_xml_space_attribute and doc.documentElement.hasAttribute('xml:space'):
|
if options.strip_xml_space_attribute and doc.documentElement.hasAttribute('xml:space'):
|
||||||
doc.documentElement.removeAttribute('xml:space')
|
doc.documentElement.removeAttribute('xml:space')
|
||||||
numAttrsRemoved += 1
|
_num_attributes_removed += 1
|
||||||
|
|
||||||
# repair style (remove unnecessary style properties and change them into XML attributes)
|
# repair style (remove unnecessary style properties and change them into XML attributes)
|
||||||
numStylePropsFixed = repairStyle(doc.documentElement, options)
|
_num_style_properties_fixed = repairStyle(doc.documentElement, options)
|
||||||
|
|
||||||
# convert colors to #RRGGBB format
|
# convert colors to #RRGGBB format
|
||||||
if options.simple_colors:
|
if options.simple_colors:
|
||||||
numBytesSavedInColors = convertColors(doc.documentElement)
|
_num_bytes_saved_in_colors = convertColors(doc.documentElement)
|
||||||
|
|
||||||
# remove unreferenced gradients/patterns outside of defs
|
# remove unreferenced gradients/patterns outside of defs
|
||||||
# and most unreferenced elements inside of defs
|
# and most unreferenced elements inside of defs
|
||||||
|
|
@ -3369,7 +3376,7 @@ def scourString(in_string, options=None):
|
||||||
removeElem = True
|
removeElem = True
|
||||||
if removeElem:
|
if removeElem:
|
||||||
elem.parentNode.removeChild(elem)
|
elem.parentNode.removeChild(elem)
|
||||||
numElemsRemoved += 1
|
_num_elements_removed += 1
|
||||||
|
|
||||||
if options.strip_ids:
|
if options.strip_ids:
|
||||||
bContinueLooping = True
|
bContinueLooping = True
|
||||||
|
|
@ -3401,10 +3408,10 @@ def scourString(in_string, options=None):
|
||||||
# doesn't accept fill=, stroke= etc.!
|
# doesn't accept fill=, stroke= etc.!
|
||||||
referencedIds = findReferencedElements(doc.documentElement)
|
referencedIds = findReferencedElements(doc.documentElement)
|
||||||
for child in doc.documentElement.childNodes:
|
for child in doc.documentElement.childNodes:
|
||||||
numAttrsRemoved += moveCommonAttributesToParentGroup(child, referencedIds)
|
_num_attributes_removed += moveCommonAttributesToParentGroup(child, referencedIds)
|
||||||
|
|
||||||
# remove unused attributes from parent
|
# remove unused attributes from parent
|
||||||
numAttrsRemoved += removeUnusedAttributesOnParent(doc.documentElement)
|
_num_attributes_removed += removeUnusedAttributesOnParent(doc.documentElement)
|
||||||
|
|
||||||
# Collapse groups LAST, because we've created groups. If done before
|
# Collapse groups LAST, because we've created groups. If done before
|
||||||
# moveAttributesToParentGroup, empty <g>'s may remain.
|
# moveAttributesToParentGroup, empty <g>'s may remain.
|
||||||
|
|
@ -3429,7 +3436,7 @@ def scourString(in_string, options=None):
|
||||||
|
|
||||||
# shorten ID names as much as possible
|
# shorten ID names as much as possible
|
||||||
if options.shorten_ids:
|
if options.shorten_ids:
|
||||||
numBytesSavedInIDs += shortenIDs(doc, options.shorten_ids_prefix, unprotected_ids(doc, options))
|
_num_bytes_saved_in_ids += shortenIDs(doc, options.shorten_ids_prefix, unprotected_ids(doc, options))
|
||||||
|
|
||||||
# scour lengths (including coordinates)
|
# scour lengths (including coordinates)
|
||||||
for type in ['svg', 'image', 'rect', 'circle', 'ellipse', 'line',
|
for type in ['svg', 'image', 'rect', 'circle', 'ellipse', 'line',
|
||||||
|
|
@ -3441,13 +3448,13 @@ def scourString(in_string, options=None):
|
||||||
elem.setAttribute(attr, scourLength(elem.getAttribute(attr)))
|
elem.setAttribute(attr, scourLength(elem.getAttribute(attr)))
|
||||||
|
|
||||||
# more length scouring in this function
|
# more length scouring in this function
|
||||||
numBytesSavedInLengths = reducePrecision(doc.documentElement)
|
_num_bytes_saved_in_lengths = reducePrecision(doc.documentElement)
|
||||||
|
|
||||||
# remove default values of attributes
|
# remove default values of attributes
|
||||||
numAttrsRemoved += removeDefaultAttributeValues(doc.documentElement, options)
|
_num_attributes_removed += removeDefaultAttributeValues(doc.documentElement, options)
|
||||||
|
|
||||||
# reduce the length of transformation attributes
|
# reduce the length of transformation attributes
|
||||||
numBytesSavedInTransforms = optimizeTransforms(doc.documentElement, options)
|
_num_bytes_saved_in_transforms = optimizeTransforms(doc.documentElement, options)
|
||||||
|
|
||||||
# convert rasters references to base64-encoded strings
|
# convert rasters references to base64-encoded strings
|
||||||
if options.embed_rasters:
|
if options.embed_rasters:
|
||||||
|
|
@ -3734,19 +3741,22 @@ def getInOut(options):
|
||||||
|
|
||||||
|
|
||||||
def getReport():
|
def getReport():
|
||||||
return ' Number of elements removed: ' + str(numElemsRemoved) + os.linesep + \
|
return (
|
||||||
' Number of attributes removed: ' + str(numAttrsRemoved) + os.linesep + \
|
' Number of elements removed: ' + str(_num_elements_removed) + os.linesep +
|
||||||
' Number of unreferenced id attributes removed: ' + str(numIDsRemoved) + os.linesep + \
|
' Number of attributes removed: ' + str(_num_attributes_removed) + os.linesep +
|
||||||
' Number of style properties fixed: ' + str(numStylePropsFixed) + os.linesep + \
|
' Number of unreferenced IDs removed: ' + str(_num_ids_removed) + os.linesep +
|
||||||
' Number of raster images embedded inline: ' + str(numRastersEmbedded) + os.linesep + \
|
' Number of comments removed: ' + str(_num_comments_removed) + os.linesep +
|
||||||
' Number of path segments reduced/removed: ' + str(numPathSegmentsReduced) + os.linesep + \
|
' Number of style properties fixed: ' + str(_num_style_properties_fixed) + os.linesep +
|
||||||
' Number of bytes saved in path data: ' + str(numBytesSavedInPathData) + os.linesep + \
|
' Number of raster images embedded: ' + str(_num_rasters_embedded) + os.linesep +
|
||||||
' Number of bytes saved in colors: ' + str(numBytesSavedInColors) + os.linesep + \
|
' Number of path segments reduced/removed: ' + str(_num_path_segments_removed) + os.linesep +
|
||||||
' Number of points removed from polygons: ' + str(numPointsRemovedFromPolygon) + os.linesep + \
|
' Number of points removed from polygons: ' + str(_num_points_removed_from_polygon) + os.linesep +
|
||||||
' Number of bytes saved in comments: ' + str(numCommentBytes) + os.linesep + \
|
' Number of bytes saved in path data: ' + str(_num_bytes_saved_in_path_data) + os.linesep +
|
||||||
' Number of bytes saved in id attributes: ' + str(numBytesSavedInIDs) + os.linesep + \
|
' Number of bytes saved in colors: ' + str(_num_bytes_saved_in_colors) + os.linesep +
|
||||||
' Number of bytes saved in lengths: ' + str(numBytesSavedInLengths) + os.linesep + \
|
' Number of bytes saved in comments: ' + str(_num_bytes_saved_in_comments) + os.linesep +
|
||||||
' Number of bytes saved in transformations: ' + str(numBytesSavedInTransforms)
|
' Number of bytes saved in IDs: ' + str(_num_bytes_saved_in_ids) + os.linesep +
|
||||||
|
' Number of bytes saved in lengths: ' + str(_num_bytes_saved_in_lengths) + os.linesep +
|
||||||
|
' Number of bytes saved in transformations: ' + str(_num_bytes_saved_in_transforms)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def start(options, input, output):
|
def start(options, input, output):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue