Handle stop offsets in percentages. Convert stop offsets into floating point (or integer if possible)

This commit is contained in:
JSCHILL1 2009-04-27 19:19:05 -05:00
parent efbdd3a027
commit 321f16c46d
3 changed files with 117 additions and 86 deletions

185
scour.py
View file

@ -45,6 +45,7 @@
# * Put id attributes first in the serialization (or make the d attribute last)
# Next Up:
# - deal with gradient stops with offsets in percentages
# - implement command-line option to output svgz
# - Remove unnecessary units of precision on attributes (use decimal: http://docs.python.org/library/decimal.html)
# - Convert all colors to #RRGGBB format
@ -123,6 +124,92 @@ svgAttributes = [
'visibility'
]
coord = re.compile("\\-?\\d+\\.?\\d*")
scinumber = re.compile("[\\-\\+]?(\\d*\\.?)?\\d+[eE][\\-\\+]?\\d+")
number = re.compile("[\\-\\+]?(\\d*\\.?)?\\d+")
sciExponent = re.compile("[eE]([\\-\\+]?\\d+)")
unit = re.compile("(em|ex|px|pt|pc|cm|mm|in|\\%){1,1}$")
class Unit:
INVALID = -1
NONE = 0
PCT = 1
PX = 2
PT = 3
PC = 4
EM = 5
EX = 6
CM = 7
MM = 8
IN = 9
@staticmethod
def get(str):
if str == None or str == '': return Unit.NONE
elif str == '%': return Unit.PCT
elif str == 'px': return Unit.PX
elif str == 'pt': return Unit.PT
elif str == 'pc': return Unit.PC
elif str == 'em': return Unit.EM
elif str == 'ex': return Unit.EX
elif str == 'cm': return Unit.CM
elif str == 'mm': return Unit.MM
elif str == 'in': return Unit.IN
return Unit.INVALID
class SVGLength:
def __init__(self, str):
# print "Parsing '%s'" % str
try: # simple unitless and no scientific notation
self.value = string.atof(str)
self.units = Unit.NONE
# print " Value =", self.value
except ValueError:
# we know that the length string has an exponent, a unit, both or is invalid
# TODO: parse out number, exponent and unit
unitBegin = 0
scinum = scinumber.match(str)
if scinum != None:
# this will always match, no need to check it
numMatch = number.match(str)
expMatch = sciExponent.search(str, numMatch.start(0))
self.value = string.atof(numMatch.group(0)) * math.pow(10, string.atof(expMatch.group(1)))
unitBegin = expMatch.end(1)
else:
# unit or invalid
numMatch = number.match(str)
if numMatch != None:
self.value = string.atof(numMatch.group(0))
unitBegin = numMatch.end(0)
if unitBegin != 0 :
# print " Value =", self.value
unitMatch = unit.search(str, unitBegin)
if unitMatch != None :
self.units = Unit.get(unitMatch.group(0))
# print " Units =", self.units
# invalid
else:
# TODO: this needs to set the default for the given attribute (how?)
# print " Invalid: ", str
self.value = 0
self.units = Unit.INVALID
# returns the length of a property
# TODO: eventually use the above class once it is complete
def getSVGLength(value):
try:
v = string.atof(value)
except ValueError:
coordMatch = coord.match(value)
if coordMatch != None:
unitMatch = unit.search(value, coordMatch.start(0))
v = value
return v
def findElementById(node, id):
if node == None or node.nodeType != 1: return None
if node.getAttribute('id') == id: return node
@ -330,7 +417,18 @@ def removeDuplicateGradientStops(doc):
stops = {}
stopsToRemove = []
for stop in grad.getElementsByTagNameNS(NS['SVG'], 'stop'):
offset = string.atof(stop.getAttribute('offset'))
# convert percentages into a floating point number
offsetU = SVGLength(stop.getAttribute('offset'))
if offsetU.units == Unit.PCT:
offset = offsetU.value / 100.0
elif offsetU.units == Unit.NONE:
offset = offsetU.value
else:
offset = 0
# set the stop offset value to the integer or floating point equivalent
if int(offset) == offset: stop.setAttribute('offset', str(int(offset)))
else: stop.setAttribute('offset', str(offset))
color = stop.getAttribute('stop-color')
opacity = stop.getAttribute('stop-opacity')
if stops.has_key(offset) :
@ -401,91 +499,6 @@ def collapseSinglyReferencedGradients(doc):
num += 1
return num
coord = re.compile("\\-?\\d+\\.?\\d*")
scinumber = re.compile("[\\-\\+]?(\\d*\\.?)?\\d+[eE][\\-\\+]?\\d+")
number = re.compile("[\\-\\+]?(\\d*\\.?)?\\d+")
sciExponent = re.compile("[eE]([\\-\\+]?\\d+)")
unit = re.compile("(em|ex|px|pt|pc|cm|mm|in|\\%){1,1}$")
class Unit:
INVALID = -1
NONE = 0
PCT = 1
PX = 2
PT = 3
PC = 4
EM = 5
EX = 6
CM = 7
MM = 8
IN = 9
@staticmethod
def get(str):
if str == None or str == '': return Unit.NONE
elif str == '%': return Unit.PCT
elif str == 'px': return Unit.PX
elif str == 'pt': return Unit.PT
elif str == 'pc': return Unit.PC
elif str == 'em': return Unit.EM
elif str == 'ex': return Unit.EX
elif str == 'cm': return Unit.CM
elif str == 'mm': return Unit.MM
elif str == 'in': return Unit.IN
return Unit.INVALID
class SVGLength:
def __init__(self, str):
# print "Parsing '%s'" % str
try: # simple unitless and no scientific notation
self.value = string.atof(str)
self.units = Unit.NONE
# print " Value =", self.value
except ValueError:
# we know that the length string has an exponent, a unit, both or is invalid
# TODO: parse out number, exponent and unit
unitBegin = 0
scinum = scinumber.match(str)
if scinum != None:
# this will always match, no need to check it
numMatch = number.match(str)
expMatch = sciExponent.search(str, numMatch.start(0))
self.value = string.atof(numMatch.group(0)) * math.pow(10, string.atof(expMatch.group(1)))
unitBegin = expMatch.end(1)
else:
# unit or invalid
numMatch = number.match(str)
if numMatch != None:
self.value = string.atof(numMatch.group(0))
unitBegin = numMatch.end(0)
if unitBegin != 0 :
# print " Value =", self.value
unitMatch = unit.search(str, unitBegin)
if unitMatch != None :
self.units = Unit.get(unitMatch.group(0))
# print " Units =", self.units
# invalid
else:
# TODO: this needs to set the default for the given attribute (how?)
# print " Invalid: ", str
self.value = 0
self.units = Unit.INVALID
# returns the length of a property
# TODO: eventually use the above class once it is complete
def getSVGLength(value):
try:
v = string.atof(value)
except ValueError:
coordMatch = coord.match(value)
if coordMatch != None:
unitMatch = unit.search(value, coordMatch.start(0))
v = value
return v
def repairStyle(node):
num = 0