Use decimals for path data and limit to 6 digits of precision
This commit is contained in:
parent
ec4e7b3594
commit
29fdd5ba66
4 changed files with 44 additions and 20 deletions
41
scour.py
41
scour.py
|
|
@ -37,7 +37,6 @@
|
||||||
# * Eliminate empty path segments
|
# * Eliminate empty path segments
|
||||||
# * Eliminate last segment in a polygon
|
# * Eliminate last segment in a polygon
|
||||||
# * Collapse straight curves.
|
# * Collapse straight curves.
|
||||||
# * Convert absolute path segments to relative ones.
|
|
||||||
# * Process Transformations
|
# * Process Transformations
|
||||||
# * Process quadratic Bezier curves
|
# * Process quadratic Bezier curves
|
||||||
# * Collapse all group based transformations
|
# * Collapse all group based transformations
|
||||||
|
|
@ -50,6 +49,7 @@
|
||||||
# + Sanitize path data (remove unnecessary whitespace
|
# + Sanitize path data (remove unnecessary whitespace
|
||||||
# + Move from absolute to relative path data
|
# + Move from absolute to relative path data
|
||||||
# + Remove trailing zeroes from path data
|
# + Remove trailing zeroes from path data
|
||||||
|
# + Limit to no more than 6 digits of precision
|
||||||
# - Remove unnecessary units of precision on attributes (use decimal: http://docs.python.org/library/decimal.html)
|
# - Remove unnecessary units of precision on attributes (use decimal: http://docs.python.org/library/decimal.html)
|
||||||
# - Remove unnecessary units of precision on path coordinates
|
# - Remove unnecessary units of precision on path coordinates
|
||||||
# - Convert all colors to #RRGGBB format
|
# - Convert all colors to #RRGGBB format
|
||||||
|
|
@ -69,6 +69,10 @@ import base64
|
||||||
import os.path
|
import os.path
|
||||||
import urllib
|
import urllib
|
||||||
from svg_regex import svg_parser
|
from svg_regex import svg_parser
|
||||||
|
from decimal import *
|
||||||
|
|
||||||
|
# set precision to 6 decimal places
|
||||||
|
getcontext().prec = 6
|
||||||
|
|
||||||
APP = 'scour'
|
APP = 'scour'
|
||||||
VER = '0.10'
|
VER = '0.10'
|
||||||
|
|
@ -619,15 +623,16 @@ def cleanPath(element) :
|
||||||
# one or more tuples, each containing two numbers
|
# one or more tuples, each containing two numbers
|
||||||
nums = []
|
nums = []
|
||||||
for t in dataset:
|
for t in dataset:
|
||||||
nums.append(t[0])
|
# convert to a Decimal and ensure precision
|
||||||
nums.append(t[1])
|
nums.append(Decimal(str(t[0])) * Decimal(1))
|
||||||
|
nums.append(Decimal(str(t[1])) * Decimal(1))
|
||||||
path.append( (cmd, nums) )
|
path.append( (cmd, nums) )
|
||||||
|
|
||||||
elif cmd in ['V','v','H','h']:
|
elif cmd in ['V','v','H','h']:
|
||||||
# one or more numbers
|
# one or more numbers
|
||||||
nums = []
|
nums = []
|
||||||
for n in dataset:
|
for n in dataset:
|
||||||
nums.append(n)
|
nums.append(Decimal(str(n)))
|
||||||
path.append( (cmd, nums) )
|
path.append( (cmd, nums) )
|
||||||
|
|
||||||
elif cmd in ['C','c']:
|
elif cmd in ['C','c']:
|
||||||
|
|
@ -635,8 +640,8 @@ def cleanPath(element) :
|
||||||
nums = []
|
nums = []
|
||||||
for t in dataset:
|
for t in dataset:
|
||||||
for pair in t:
|
for pair in t:
|
||||||
nums.append(pair[0])
|
nums.append(Decimal(str(pair[0])) * Decimal(1))
|
||||||
nums.append(pair[1])
|
nums.append(Decimal(str(pair[1])) * Decimal(1))
|
||||||
path.append( (cmd, nums) )
|
path.append( (cmd, nums) )
|
||||||
|
|
||||||
elif cmd in ['S','s','Q','q']:
|
elif cmd in ['S','s','Q','q']:
|
||||||
|
|
@ -644,8 +649,8 @@ def cleanPath(element) :
|
||||||
nums = []
|
nums = []
|
||||||
for t in dataset:
|
for t in dataset:
|
||||||
for pair in t:
|
for pair in t:
|
||||||
nums.append(pair[0])
|
nums.append(Decimal(str(pair[0])) * Decimal(1))
|
||||||
nums.append(pair[1])
|
nums.append(Decimal(str(pair[1])) * Decimal(1))
|
||||||
path.append( (cmd, nums) )
|
path.append( (cmd, nums) )
|
||||||
|
|
||||||
elif cmd in ['A','a']:
|
elif cmd in ['A','a']:
|
||||||
|
|
@ -653,18 +658,18 @@ def cleanPath(element) :
|
||||||
# another boolean, and a tuple of two numbers
|
# another boolean, and a tuple of two numbers
|
||||||
nums = []
|
nums = []
|
||||||
for t in dataset:
|
for t in dataset:
|
||||||
nums.append( t[0][0] )
|
nums.append( Decimal(str(t[0][0])) * Decimal(1) )
|
||||||
nums.append( t[0][1] )
|
nums.append( Decimal(str(t[0][1])) * Decimal(1) )
|
||||||
nums.append( t[1] )
|
nums.append( Decimal(str(t[1])) * Decimal(1))
|
||||||
|
|
||||||
if t[2]: nums.append( 1 )
|
if t[2]: nums.append( Decimal(1) )
|
||||||
else: nums.append( 0 )
|
else: nums.append( Decimal(0) )
|
||||||
|
|
||||||
if t[3]: nums.append( 1 )
|
if t[3]: nums.append( Decimal(1) )
|
||||||
else: nums.append( 0 )
|
else: nums.append( Decimal(0) )
|
||||||
|
|
||||||
nums.append( t[4][0] )
|
nums.append( Decimal(str(t[4][0])) * Decimal(1) )
|
||||||
nums.append( t[4][1] )
|
nums.append( Decimal(str(t[4][1])) * Decimal(1) )
|
||||||
path.append( (cmd, nums) )
|
path.append( (cmd, nums) )
|
||||||
|
|
||||||
elif cmd in ['Z','z']:
|
elif cmd in ['Z','z']:
|
||||||
|
|
@ -741,7 +746,7 @@ def cleanPath(element) :
|
||||||
|
|
||||||
# - reserialize the path data with some cleanups:
|
# - reserialize the path data with some cleanups:
|
||||||
# - removes scientific notation (exponents)
|
# - removes scientific notation (exponents)
|
||||||
# - removes trailing zeros after the decimal
|
# - removes all trailing zeros after the decimal
|
||||||
# - removes extraneous whitespace
|
# - removes extraneous whitespace
|
||||||
# - adds commas between all values in a subcommand
|
# - adds commas between all values in a subcommand
|
||||||
def serializePath(pathObj):
|
def serializePath(pathObj):
|
||||||
|
|
|
||||||
18
testscour.py
18
testscour.py
|
|
@ -443,6 +443,22 @@ class ConvertAbsoluteToRelativePathCommands(unittest.TestCase):
|
||||||
'Absolute V command not converted to relative v command')
|
'Absolute V command not converted to relative v command')
|
||||||
self.assertEquals(path[1][1][0], -20.0,
|
self.assertEquals(path[1][1][0], -20.0,
|
||||||
'Absolute V value not converted to relative v value')
|
'Absolute V value not converted to relative v value')
|
||||||
|
|
||||||
|
class RoundPathData(unittest.TestCase):
|
||||||
|
def runTest(self):
|
||||||
|
doc = scour.scourXmlFile('unittests/path-precision.svg')
|
||||||
|
path = svg_parser.parse(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d'))
|
||||||
|
self.assertEquals(path[0][1][0][0], 100.0,
|
||||||
|
'Not rounding down' )
|
||||||
|
self.assertEquals(path[0][1][0][1], 100.0,
|
||||||
|
'Not rounding up' )
|
||||||
|
|
||||||
|
class LimitPrecisionInPathData(unittest.TestCase):
|
||||||
|
def runTest(self):
|
||||||
|
doc = scour.scourXmlFile('unittests/path-precision.svg')
|
||||||
|
path = svg_parser.parse(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d'))
|
||||||
|
self.assertEquals(path[1][1][0], 100.001,
|
||||||
|
'Not correctly limiting precision on path data' )
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg">
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M 385.88362,201.47812 V181.47812 l100,-50 h20 C 505.43501,223.44223 659.42238,164.82405 714.32160,-0.0015300000 C 649.90356,227.13187 497.48814,312.46353 371.30643,277.40123 C 245.12472,242.33893 157.17674,250.88268 121.69357,12.440270 C 211.69357,149.44027 323.87473,190.08578 385.88362,201.47812 z " fill="blue"/>
|
<path d="M 385,201 V181 l100,-50 h20 C 505.43501,223.44223 659.42238,164.82405 714.32160,-0.0015300000 C 649.90356,227.13187 497.48814,312.46353 371.30643,277.40123 C 245.12472,242.33893 157.17674,250.88268 121.69357,12.440270 C 211.69357,149.44027 323.87473,190.08578 385.88362,201.47812 z " fill="blue"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 378 B After Width: | Height: | Size: 360 B |
3
unittests/path-precision.svg
Normal file
3
unittests/path-precision.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||||||
|
<path d="M 100.0000001 99.9999999 h100.001 v100 h-100 z" fill="red" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 157 B |
Loading…
Add table
Add a link
Reference in a new issue