Added code to convert colors to #RRGGBB format

This commit is contained in:
JSCHILL1 2009-05-17 14:34:08 -05:00
parent 823c8c45e3
commit a7d2593a58
4 changed files with 250 additions and 18 deletions

238
scour.py
View file

@ -30,9 +30,6 @@
# * Specify a limit to the precision of all positional elements.
# * Clean up Definitions
# * Collapse duplicate gradient definitions
# * Clean up CSS
# * Convert RGB colours from RGB(r,g,b) to #RRGGBB format
# * Convert RGB colours from #RRGGBB to #RGB if possible
# * Clean up paths
# * Eliminate last segment in a polygon
# * Collapse straight curves.
@ -46,10 +43,10 @@
# Next Up:
# + Up-revved enthought's path parser for integer coords with sci notation:
# https://svn.enthought.com/enthought/changeset/23583?format=diff&new=23583
# + Convert rgb() into #RRGGBB
# + Convert #RRGGBB into #RGB where possible
# - prevent elements from being stripped if they are referenced in a <style> element
# (for instance, filter, marker, pattern) - need a crude CSS parser
# - Convert all colors to #RRGGBB format
# - Reduce #RRGGBB format to #RGB format when possible
# - Remove any unused glyphs from font elements?
# necessary to get true division
@ -125,7 +122,156 @@ svgAttributes = [
'visibility'
]
colors = {
'aliceblue': 'rgb(240, 248, 255)',
'antiquewhite': 'rgb(250, 235, 215)',
'aqua': 'rgb( 0, 255, 255)',
'aquamarine': 'rgb(127, 255, 212)',
'azure': 'rgb(240, 255, 255)',
'beige': 'rgb(245, 245, 220)',
'bisque': 'rgb(255, 228, 196)',
'black': 'rgb( 0, 0, 0)',
'blanchedalmond': 'rgb(255, 235, 205)',
'blue': 'rgb( 0, 0, 255)',
'blueviolet': 'rgb(138, 43, 226)',
'brown': 'rgb(165, 42, 42)',
'burlywood': 'rgb(222, 184, 135)',
'cadetblue': 'rgb( 95, 158, 160)',
'chartreuse': 'rgb(127, 255, 0)',
'chocolate': 'rgb(210, 105, 30)',
'coral': 'rgb(255, 127, 80)',
'cornflowerblue': 'rgb(100, 149, 237)',
'cornsilk': 'rgb(255, 248, 220)',
'crimson': 'rgb(220, 20, 60)',
'cyan': 'rgb( 0, 255, 255)',
'darkblue': 'rgb( 0, 0, 139)',
'darkcyan': 'rgb( 0, 139, 139)',
'darkgoldenrod': 'rgb(184, 134, 11)',
'darkgray': 'rgb(169, 169, 169)',
'darkgreen': 'rgb( 0, 100, 0)',
'darkgrey': 'rgb(169, 169, 169)',
'darkkhaki': 'rgb(189, 183, 107)',
'darkmagenta': 'rgb(139, 0, 139)',
'darkolivegreen': 'rgb( 85, 107, 47)',
'darkorange': 'rgb(255, 140, 0)',
'darkorchid': 'rgb(153, 50, 204)',
'darkred': 'rgb(139, 0, 0)',
'darksalmon': 'rgb(233, 150, 122)',
'darkseagreen': 'rgb(143, 188, 143)',
'darkslateblue': 'rgb( 72, 61, 139)',
'darkslategray': 'rgb( 47, 79, 79)',
'darkslategrey': 'rgb( 47, 79, 79)',
'darkturquoise': 'rgb( 0, 206, 209)',
'darkviolet': 'rgb(148, 0, 211)',
'deeppink': 'rgb(255, 20, 147)',
'deepskyblue': 'rgb( 0, 191, 255)',
'dimgray': 'rgb(105, 105, 105)',
'dimgrey': 'rgb(105, 105, 105)',
'dodgerblue': 'rgb( 30, 144, 255)',
'firebrick': 'rgb(178, 34, 34)',
'floralwhite': 'rgb(255, 250, 240)',
'forestgreen': 'rgb( 34, 139, 34)',
'fuchsia': 'rgb(255, 0, 255)',
'gainsboro': 'rgb(220, 220, 220)',
'ghostwhite': 'rgb(248, 248, 255)',
'gold': 'rgb(255, 215, 0)',
'goldenrod': 'rgb(218, 165, 32)',
'gray': 'rgb(128, 128, 128)',
'grey': 'rgb(128, 128, 128)',
'green': 'rgb( 0, 128, 0)',
'greenyellow': 'rgb(173, 255, 47)',
'honeydew': 'rgb(240, 255, 240)',
'hotpink': 'rgb(255, 105, 180)',
'indianred': 'rgb(205, 92, 92)',
'indigo': 'rgb( 75, 0, 130)',
'ivory': 'rgb(255, 255, 240)',
'khaki': 'rgb(240, 230, 140)',
'lavender': 'rgb(230, 230, 250)',
'lavenderblush': 'rgb(255, 240, 245)',
'lawngreen': 'rgb(124, 252, 0)',
'lemonchiffon': 'rgb(255, 250, 205)',
'lightblue': 'rgb(173, 216, 230)',
'lightcoral': 'rgb(240, 128, 128)',
'lightcyan': 'rgb(224, 255, 255)',
'lightgoldenrodyellow': 'rgb(250, 250, 210)',
'lightgray': 'rgb(211, 211, 211)',
'lightgreen': 'rgb(144, 238, 144)',
'lightgrey': 'rgb(211, 211, 211)',
'lightpink': 'rgb(255, 182, 193)',
'lightsalmon': 'rgb(255, 160, 122)',
'lightseagreen': 'rgb( 32, 178, 170)',
'lightskyblue': 'rgb(135, 206, 250)',
'lightslategray': 'rgb(119, 136, 153)',
'lightslategrey': 'rgb(119, 136, 153)',
'lightsteelblue': 'rgb(176, 196, 222)',
'lightyellow': 'rgb(255, 255, 224)',
'lime': 'rgb( 0, 255, 0)',
'limegreen': 'rgb( 50, 205, 50)',
'linen': 'rgb(250, 240, 230)',
'magenta': 'rgb(255, 0, 255)',
'maroon': 'rgb(128, 0, 0)',
'mediumaquamarine': 'rgb(102, 205, 170)',
'mediumblue': 'rgb( 0, 0, 205)',
'mediumorchid': 'rgb(186, 85, 211)',
'mediumpurple': 'rgb(147, 112, 219)',
'mediumseagreen': 'rgb( 60, 179, 113)',
'mediumslateblue': 'rgb(123, 104, 238)',
'mediumspringgreen': 'rgb( 0, 250, 154)',
'mediumturquoise': 'rgb( 72, 209, 204)',
'mediumvioletred': 'rgb(199, 21, 133)',
'midnightblue': 'rgb( 25, 25, 112)',
'mintcream': 'rgb(245, 255, 250)',
'mistyrose': 'rgb(255, 228, 225)',
'moccasin': 'rgb(255, 228, 181)',
'navajowhite': 'rgb(255, 222, 173)',
'navy': 'rgb( 0, 0, 128)',
'oldlace': 'rgb(253, 245, 230)',
'olive': 'rgb(128, 128, 0)',
'olivedrab': 'rgb(107, 142, 35)',
'orange': 'rgb(255, 165, 0)',
'orangered': 'rgb(255, 69, 0)',
'orchid': 'rgb(218, 112, 214)',
'palegoldenrod': 'rgb(238, 232, 170)',
'palegreen': 'rgb(152, 251, 152)',
'paleturquoise': 'rgb(175, 238, 238)',
'palevioletred': 'rgb(219, 112, 147)',
'papayawhip': 'rgb(255, 239, 213)',
'peachpuff': 'rgb(255, 218, 185)',
'peru': 'rgb(205, 133, 63)',
'pink': 'rgb(255, 192, 203)',
'plum': 'rgb(221, 160, 221)',
'powderblue': 'rgb(176, 224, 230)',
'purple': 'rgb(128, 0, 128)',
'red': 'rgb(255, 0, 0)',
'rosybrown': 'rgb(188, 143, 143)',
'royalblue': 'rgb( 65, 105, 225)',
'saddlebrown': 'rgb(139, 69, 19)',
'salmon': 'rgb(250, 128, 114)',
'sandybrown': 'rgb(244, 164, 96)',
'seagreen': 'rgb( 46, 139, 87)',
'seashell': 'rgb(255, 245, 238)',
'sienna': 'rgb(160, 82, 45)',
'silver': 'rgb(192, 192, 192)',
'skyblue': 'rgb(135, 206, 235)',
'slateblue': 'rgb(106, 90, 205)',
'slategray': 'rgb(112, 128, 144)',
'slategrey': 'rgb(112, 128, 144)',
'snow': 'rgb(255, 250, 250)',
'springgreen': 'rgb( 0, 255, 127)',
'steelblue': 'rgb( 70, 130, 180)',
'tan': 'rgb(210, 180, 140)',
'teal': 'rgb( 0, 128, 128)',
'thistle': 'rgb(216, 191, 216)',
'tomato': 'rgb(255, 99, 71)',
'turquoise': 'rgb( 64, 224, 208)',
'violet': 'rgb(238, 130, 238)',
'wheat': 'rgb(245, 222, 179)',
'white': 'rgb(255, 255, 255)',
'whitesmoke': 'rgb(245, 245, 245)',
'yellow': 'rgb(255, 255, 0)',
'yellowgreen': 'rgb(154, 205, 50)',
}
coord = re.compile("\\-?\\d+\\.?\\d*")
scinumber = re.compile("[\\-\\+]?(\\d*\\.?)?\\d+[eE][\\-\\+]?\\d+")
number = re.compile("[\\-\\+]?(\\d*\\.?)?\\d+")
@ -281,6 +427,7 @@ numAttrsRemoved = 0
numRastersEmbedded = 0
numPathSegmentsReduced = 0
numBytesSavedInPathData = 0
numBytesSavedInColors = 0
# removes all unreferenced elements except for <svg>, <font>, <metadata>, <title>, and <desc>
# also vacuums the defs of any non-referenced renderable elements
@ -643,12 +790,78 @@ def repairStyle(node, options):
node.setAttribute('style', fixedStyle)
else:
node.removeAttribute('style')
# recurse for our child elements
for child in node.childNodes :
num += repairStyle(child,options)
return num
# convert blue to rgb(r,g,b)
# convert rgb(r%,g%,b%) to rgb(r,g,b)
# convert rgb(r,g,b) to #RRGGBB
# finally convert #RRGGBB to #RGB if possible
rgb = re.compile("\\s*rgb\\(\\s*(\\d+)\\s*\\,\\s*(\\d+)\\s*\\,\\s*(\\d+)\\s*\\)\\s*")
rgbp = re.compile("\\s*rgb\\(\\s*(\\d*\\.?\\d+)\\%\\s*\\,\\s*(\\d*\\.?\\d+)\\%\\s*\\,\\s*(\\d*\\.?\\d+)\\%\\s*\\)\\s*")
def convertColor(value):
s = value
if s in colors.keys():
s = colors[s]
rgbpMatch = rgbp.match(s)
if rgbpMatch != None :
r = int( string.atof( rgbpMatch.group(1) ) * 255.0 / 100.0 )
g = int( string.atof( rgbpMatch.group(2) ) * 255.0 / 100.0 )
b = int( string.atof( rgbpMatch.group(3) ) * 255.0 / 100.0 )
s = 'rgb(%d,%d,%d)' % (r,g,b)
rgbMatch = rgb.match(s)
if rgbMatch != None :
r = hex( int( rgbMatch.group(1) ) )[2:].upper()
g = hex( int( rgbMatch.group(2) ) )[2:].upper()
b = hex( int( rgbMatch.group(3) ) )[2:].upper()
if len(r) == 1: r='0'+r
if len(g) == 1: g='0'+g
if len(b) == 1: b='0'+b
s = '#'+r+g+b
if s[0] == '#' and s[1]==s[2] and s[3]==s[4] and s[5]==s[6]:
s = s.upper()
s = '#'+s[1]+s[3]+s[5]
return s
def convertColors(element) :
numBytes = 0
if element.nodeType != 1: return 0
# set up list of color attributes for each element type
attrsToConvert = []
if element.nodeName in ['rect', 'circle', 'ellipse', 'polygon', \
'line', 'polyline', 'path', 'g', 'a']:
attrsToConvert = ['fill', 'stroke']
elif element.nodeName in ['stop']:
attrsToConvert = ['stop-color']
elif element.nodeName in ['solidColor']:
attrsToConvert = ['solid-color']
# now convert all the color formats
for attr in attrsToConvert:
val = element.getAttribute(attr)
oldBytes = len(val)
if val != '':
element.setAttribute(attr, convertColor(val))
numBytes += (oldBytes - len(element.getAttribute(attr)))
# now recurse for our child elements
for child in element.childNodes :
numBytes += convertColors(child)
return numBytes
def cleanPath(element) :
global numBytesSavedInPathData
global numPathSegmentsReduced
@ -981,6 +1194,7 @@ def scourString(in_string, options=[]):
global numAttrsRemoved
global numStylePropsFixed
global numElemsRemoved
global numBytesSavedInColors
doc = xml.dom.minidom.parseString(in_string)
# for whatever reason this does not always remove all inkscape/sodipodi attributes/elements
@ -1005,8 +1219,9 @@ def scourString(in_string, options=[]):
# repair style (remove unnecessary style properties and change them into XML attributes)
numStylePropsFixed = repairStyle(doc.documentElement, options)
# TODO: change color properties to #RRGGBB format
# TODO: change color properties to #RGB where possible
# convert colors to #RRGGBB format
if not '--disable-simplify-colors' in options:
numBytesSavedInColors = convertColors(doc.documentElement)
# remove empty defs, metadata, g
# NOTE: these elements will be removed even if they have (invalid) text nodes
@ -1098,6 +1313,7 @@ def printSyntaxAndQuit():
print 'If the output file is not specified, stdout is used.'
print 'If an option is not available below that means it occurs automatically'
print 'when scour is invoked. Available OPTIONS:\n'
print ' --disable-simplify-colors : Scour will not convert all colors to #RRGGBB format'
print ' --disable-style-to-xml : Scour will not convert style properties into XML attributes'
print ' --disable-group-collapsing : Scour will not collapse <g> elements'
print ' --enable-id-stripping : Scour will remove all un-referenced ID attributes'
@ -1116,6 +1332,7 @@ def parseCLA():
output = sys.stdout
options = []
validOptions = [
'--disable-simplify-colors',
'--disable-style-to-xml',
'--disable-group-collapsing',
'--enable-id-stripping',
@ -1191,7 +1408,10 @@ if __name__ == '__main__':
print ' Number of raster images embedded inline:', numRastersEmbedded
print ' Number of path segments reduced/removed:', numPathSegmentsReduced
print ' Number of bytes saved in path data:', numBytesSavedInPathData
print ' Number of bytes saved in colors:', numBytesSavedInColors
oldsize = os.path.getsize(inputfilename)
newsize = os.path.getsize(outputfilename)
sizediff = (newsize / oldsize);
print ' Original file size:', oldsize, 'bytes; new file size:', newsize, 'bytes (' + str(sizediff)[:5] + 'x)'