Scour length values for most attributes. Fix removal of duplicate gradients again. Two more unittests
This commit is contained in:
parent
3371177b80
commit
6fce13b84f
4 changed files with 102 additions and 34 deletions
99
scour.py
99
scour.py
|
|
@ -63,7 +63,7 @@
|
|||
# + remove duplicate gradients
|
||||
# + remove all empty path segments
|
||||
# + scour polyline coordinates just like path coordinates
|
||||
# - enable the precision argument to affect all numbers: polygon points, lengths, coordinates
|
||||
# - enable the precision argument to affect all numbers: lengths, coordinates
|
||||
# - remove id if it matches the Inkscape-style of IDs (also provide a switch to disable this)
|
||||
# - prevent elements from being stripped if they are referenced in a <style> element
|
||||
# (for instance, filter, marker, pattern) - need a crude CSS parser
|
||||
|
|
@ -331,7 +331,22 @@ class Unit(object):
|
|||
elif str == 'in': return Unit.IN
|
||||
return Unit.INVALID
|
||||
|
||||
# @staticmethod
|
||||
def str(u):
|
||||
if u == Unit.NONE: return ''
|
||||
elif u == Unit.PCT: return '%'
|
||||
elif u == Unit.PX: return 'px'
|
||||
elif u == Unit.PT: return 'pt'
|
||||
elif u == Unit.PC: return 'pc'
|
||||
elif u == Unit.EM: return 'em'
|
||||
elif u == Unit.EX: return 'ex'
|
||||
elif u == Unit.CM: return 'cm'
|
||||
elif u == Unit.MM: return 'mm'
|
||||
elif u == Unit.IN: return 'in'
|
||||
return 'INVALID'
|
||||
|
||||
get = staticmethod(get)
|
||||
str = staticmethod(str)
|
||||
|
||||
class SVGLength(object):
|
||||
def __init__(self, str):
|
||||
|
|
@ -723,6 +738,7 @@ def removeDuplicateGradients(doc):
|
|||
num = 0
|
||||
|
||||
gradientsToRemove = {}
|
||||
duplicateToMaster = {}
|
||||
|
||||
for gradType in ['linearGradient', 'radialGradient']:
|
||||
grads = doc.getElementsByTagNameNS(NS['SVG'], gradType)
|
||||
|
|
@ -734,9 +750,13 @@ def removeDuplicateGradients(doc):
|
|||
|
||||
# compare grad to ograd (all properties, then all stops)
|
||||
# if attributes do not match, go to next gradient
|
||||
someGradAttrsDoNotMatch = False
|
||||
for attr in ['gradientUnits','spreadMethod','gradientTransform','x1','y1','x2','y2','cx','cy','fx','fy','r']:
|
||||
if grad.getAttribute(attr) != ograd.getAttribute(attr):
|
||||
continue
|
||||
someGradAttrsDoNotMatch = True
|
||||
break;
|
||||
|
||||
if someGradAttrsDoNotMatch: continue
|
||||
|
||||
# compare xlink:href values too
|
||||
if grad.getAttributeNS(NS['XLINK'], 'href') != ograd.getAttributeNS(NS['XLINK'], 'href'):
|
||||
|
|
@ -763,9 +783,11 @@ def removeDuplicateGradients(doc):
|
|||
# ograd is a duplicate of grad, we schedule it to be removed UNLESS
|
||||
# ograd is ALREADY considered a 'master' element
|
||||
if not gradientsToRemove.has_key(ograd):
|
||||
if not gradientsToRemove.has_key(grad):
|
||||
gradientsToRemove[grad] = []
|
||||
gradientsToRemove[grad].append( ograd )
|
||||
if not duplicateToMaster.has_key(ograd):
|
||||
if not gradientsToRemove.has_key(grad):
|
||||
gradientsToRemove[grad] = []
|
||||
gradientsToRemove[grad].append( ograd )
|
||||
duplicateToMaster[ograd] = grad
|
||||
|
||||
# get a collection of all elements that are referenced and their referencing elements
|
||||
referencedIDs = findReferencedElements(doc.documentElement)
|
||||
|
|
@ -809,7 +831,7 @@ def repairStyle(node, options):
|
|||
for prop in ['fill', 'stroke'] :
|
||||
if styleMap.has_key(prop) :
|
||||
chunk = styleMap[prop].split(') ')
|
||||
if len(chunk) == 2 and chunk[0][:5] == 'url(#' and chunk[1] == 'rgb(0, 0, 0)' :
|
||||
if len(chunk) == 2 and (chunk[0][:5] == 'url(#' or chunk[0][:6] == 'url("#' or chunk[0][:6] == "url('#") and chunk[1] == 'rgb(0, 0, 0)' :
|
||||
styleMap[prop] = chunk[0] + ')'
|
||||
num += 1
|
||||
|
||||
|
|
@ -1529,32 +1551,8 @@ def scourCoordinates(data):
|
|||
if data != None:
|
||||
c = 0
|
||||
for coord in data:
|
||||
# reduce to the proper number of digits
|
||||
coord = Decimal(coord) * Decimal(1)
|
||||
|
||||
# integerize if we can
|
||||
if int(coord) == coord: coord = Decimal(str(int(coord)))
|
||||
|
||||
# Decimal.trim() is available in Python 2.6+ to trim trailing zeros
|
||||
try:
|
||||
coord = coord.trim()
|
||||
except AttributeError:
|
||||
# trim it ourselves
|
||||
s = str(coord)
|
||||
dec = s.find('.')
|
||||
if dec != -1:
|
||||
while s[-1] == '0':
|
||||
s = s[:-1]
|
||||
coord = Decimal(s)
|
||||
|
||||
# Decimal.normalize() will uses scientific notation - if that
|
||||
# string is smaller, then use it
|
||||
normd = coord.normalize()
|
||||
if len(str(normd)) < len(str(coord)):
|
||||
coord = normd
|
||||
|
||||
# finally add the coordinate to the path string
|
||||
coordsStr += str(coord)
|
||||
# add the scoured coordinate to the path string
|
||||
coordsStr += scourLength(coord)
|
||||
|
||||
# only need the comma if the next number is non-negative
|
||||
if c < len(data)-1 and Decimal(data[c+1]) >= 0:
|
||||
|
|
@ -1562,6 +1560,36 @@ def scourCoordinates(data):
|
|||
c += 1
|
||||
return coordsStr
|
||||
|
||||
def scourLength(str):
|
||||
length = SVGLength(str)
|
||||
coord = length.value
|
||||
|
||||
# reduce to the proper number of digits
|
||||
coord = Decimal(unicode(coord)) * Decimal(1)
|
||||
|
||||
# integerize if we can
|
||||
if int(coord) == coord: coord = Decimal(unicode(int(coord)))
|
||||
|
||||
# Decimal.trim() is available in Python 2.6+ to trim trailing zeros
|
||||
try:
|
||||
coord = coord.trim()
|
||||
except AttributeError:
|
||||
# trim it ourselves
|
||||
s = unicode(coord)
|
||||
dec = s.find('.')
|
||||
if dec != -1:
|
||||
while s[-1] == '0':
|
||||
s = s[:-1]
|
||||
coord = Decimal(s)
|
||||
|
||||
# Decimal.normalize() will uses scientific notation - if that
|
||||
# string is smaller, then use it
|
||||
normd = coord.normalize()
|
||||
if len(unicode(normd)) < len(unicode(coord)):
|
||||
coord = normd
|
||||
|
||||
return unicode(coord)+Unit.str(length.units)
|
||||
|
||||
def embedRasters(element, options) :
|
||||
"""
|
||||
Converts raster references to inline images.
|
||||
|
|
@ -1752,6 +1780,13 @@ def scourString(in_string, options=None):
|
|||
for polyline in doc.documentElement.getElementsByTagNameNS(NS['SVG'], 'polyline') :
|
||||
cleanPolygon(polyline)
|
||||
|
||||
# scour lengths (including coordinates)
|
||||
for type in ['svg', 'image', 'rect', 'circle', 'ellipse', 'line', 'linearGradient', 'radialGradient', 'stop']:
|
||||
for elem in doc.documentElement.getElementsByTagNameNS(NS['SVG'], type):
|
||||
for attr in ['x', 'y', 'width', 'height', 'cx', 'cy', 'r', 'rx', 'ry', 'x1', 'y1', 'x2', 'y2', 'fx', 'fy', 'offset']:
|
||||
if elem.getAttribute(attr) != '':
|
||||
elem.setAttribute(attr, scourLength(elem.getAttribute(attr)))
|
||||
|
||||
# convert rasters references to base64-encoded strings
|
||||
if options.embed_rasters:
|
||||
for elem in doc.documentElement.getElementsByTagNameNS(NS['SVG'], 'image') :
|
||||
|
|
|
|||
24
testscour.py
24
testscour.py
|
|
@ -706,6 +706,30 @@ class CollapseSamePathPoints(unittest.TestCase):
|
|||
self.assertEquals(p.getAttribute('d'), "M100,100l100.12,100.12z",
|
||||
'Did not collapse same path points')
|
||||
|
||||
class ScourUnitlessLengths(unittest.TestCase):
|
||||
def runTest(self):
|
||||
r = scour.scourXmlFile('unittests/scour-lengths.svg').getElementsByTagNameNS(SVGNS, 'rect')[0];
|
||||
self.assertEquals(r.getAttribute('x'), '123.46',
|
||||
'Did not scour x attribute unitless number')
|
||||
self.assertEquals(r.getAttribute('y'), '123',
|
||||
'Did not scour y attribute unitless number')
|
||||
self.assertEquals(r.getAttribute('width'), '300',
|
||||
'Did not scour width attribute unitless number')
|
||||
self.assertEquals(r.getAttribute('height'), '100',
|
||||
'Did not scour height attribute unitless number')
|
||||
|
||||
class ScourLengthsWithUnits(unittest.TestCase):
|
||||
def runTest(self):
|
||||
r = scour.scourXmlFile('unittests/scour-lengths.svg').getElementsByTagNameNS(SVGNS, 'rect')[1];
|
||||
self.assertEquals(r.getAttribute('x'), '123.46px',
|
||||
'Did not scour x attribute with unit')
|
||||
self.assertEquals(r.getAttribute('y'), '35ex',
|
||||
'Did not scour y attribute with unit')
|
||||
self.assertEquals(r.getAttribute('width'), '300pt',
|
||||
'Did not scour width attribute with unit')
|
||||
self.assertEquals(r.getAttribute('height'), '50%',
|
||||
'Did not scour height attribute with unit')
|
||||
|
||||
# TODO; write a test for embedding rasters
|
||||
# TODO: write a test for --disable-embed-rasters
|
||||
# TODO: write tests for --keep-editor-data
|
||||
|
|
|
|||
4
unittests/collapse-same-path-points.svg
Normal file
4
unittests/collapse-same-path-points.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<path fill="green" d="M100,100 L200.12345,200.12345 C210,210 190,190 200.12,200.12 Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 235 B |
5
unittests/scour-lengths.svg
Normal file
5
unittests/scour-lengths.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="123.4567" y="123.00" width="300.00001" height="1E+02" fill="lime" />
|
||||
<rect x="123.4567px" y="35.000ex" width="300.00001pt" height="5E+01%" fill="blue" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 267 B |
Loading…
Add table
Add a link
Reference in a new issue