Scour length values for most attributes. Fix removal of duplicate gradients again. Two more unittests

This commit is contained in:
JSCHILL1 2009-08-03 12:23:41 -05:00
parent 3371177b80
commit 6fce13b84f
4 changed files with 102 additions and 34 deletions

View file

@ -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 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,18 +1551,31 @@ def scourCoordinates(data):
if data != None:
c = 0
for coord in data:
# 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:
coordsStr += ','
c += 1
return coordsStr
def scourLength(str):
length = SVGLength(str)
coord = length.value
# reduce to the proper number of digits
coord = Decimal(coord) * Decimal(1)
coord = Decimal(unicode(coord)) * Decimal(1)
# integerize if we can
if int(coord) == coord: coord = Decimal(str(int(coord)))
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 = str(coord)
s = unicode(coord)
dec = s.find('.')
if dec != -1:
while s[-1] == '0':
@ -1550,17 +1585,10 @@ def scourCoordinates(data):
# Decimal.normalize() will uses scientific notation - if that
# string is smaller, then use it
normd = coord.normalize()
if len(str(normd)) < len(str(coord)):
if len(unicode(normd)) < len(unicode(coord)):
coord = normd
# finally add the coordinate to the path string
coordsStr += str(coord)
# only need the comma if the next number is non-negative
if c < len(data)-1 and Decimal(data[c+1]) >= 0:
coordsStr += ','
c += 1
return coordsStr
return unicode(coord)+Unit.str(length.units)
def embedRasters(element, options) :
"""
@ -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') :

View file

@ -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

View 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

View 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