Monday, February 21, 2011

SVG, XML, and the Python logo

Legal notice:  the terms of use for the Python logo restrict the alteration or bastardization of the logo, including its colors.  I have contacted the Python Software Foundation and gotten permission to publish this blog entry.

The logo restrictions I violate in this post, for purposes of demonstrating working with svg, are:

   1) changing the color of the logo
   2) removal of the trademark symbol

While people are encouraged to use the logo, they are also encouraged to contact the PSF trademarks committee regarding questions of alteration.  Thank you for your consideration in this matter.

As a means of becoming more familiar with SVG (scalable vector graphics) and XML, I wanted to see if I could change the colors of the Python logo in code.  Although this is neither encouraged nor permitted (see notice above), it has been done on occasion in the past; I wanted to see how.

Since SVG is a subset of XML, I'm going to use an XML tool from the standard library (xml.etree.ElementTree) to work with the SVG image.

First, I downloaded the logo from I'm using the Java based tool Batik/Squiggle to view the SVG images:

To simplify the SVG file I removed the gray parts (text, trademark character, and shadow).  This I did by hand by looking for any gray colors of the hex form #xyxyxy in the file.

Also, I changed the name of the file I was referencing inside the SVG file to pythonlogochanged.svg.  This is important, otherwise the SVG file will continue to read whatever file is named inside it.

There are now six main elements to the file:
    1) the two shapes in the logo
    2) the two gradients for color variation across each shape
    3) the two sets of colors for start and stop in the gradation (two yellows and two blues)

It's number 3) that we're interested in.

I started out trying to use minidom from the xml standard library, but found ElementTree to be better suited to the task.  This tutorial from Effbot was helpful.

$ python2.5
Python 2.5.4 (r254:67916, Aug  9 2010, 08:57:51)
[GCC 4.2.1 20070719 ] on openbsd4
Type "help", "copyright", "credits" or "license" for more information.
>>> # open file
>>> svgobj = ET.parse('pythonlogochanged.svg')
>>> # get toplevel element
>>> rootx = svgobj.getroot()

Now it is time to drill down into the element tree.  I walked through this myself previously, so you'll have to trust that I know where the colors are in the tree.

>>> elementsx = rootx.getchildren()
>>> defsx = elementsx[2]
>>> elementsx = defsx.getchildren()
>>> yellowelement = elementsx[0]
>>> blueelement = elementsx[1]

First we'll look at the yellow color definitions.

>>> yellowchildren = yellowelement.getchildren()
>>> yellowchildren[0].items()
[('style', 'stop-color:#ffd43b;stop-opacity:1'), ('id', 'stop4673'), ('offset', '0')]
>>> yellowchildren[1].items()
[('style', 'stop-color:#ffe873;stop-opacity:1'), ('id', 'stop4675'), ('offset', '1')]

The yellow colors across the gradient are #ffd43b and #ffe873.
Now we'll look at the blue colors.

>>> bluechildren = blueelement.getchildren()
>>> bluechildren[0].items()
[('style', 'stop-color:#5a9fd4;stop-opacity:1'), ('id', 'stop4691'), ('offset', '0')]
>>> bluechildren[1].items()
[('style', 'stop-color:#306998;stop-opacity:1'), ('id', 'stop4693'), ('offset', '1')]

#5a9fd4 and #306998 are the blue colors across the gradient.

Let's try taking the color gradients out first without changing the blue and yellow colors.

>>> bluechildren[1].set('style', 'stop-color:#5a9fd4:stop-opacity:1')
>>> yellowchildren[1].set('style', 'stop-color:#ffd43b;stop-opacity:1')

Now the result needs to be written to disk.

>>> svgobj.write('pythonlogochanged.svg')

Still blue and yellow, but significantly different without the gradient.

Now let's make a black silhouette.

>>> bluechildren[0].set('style', 'stop-color:#000000:stop-opacity:1')
>>> bluechildren[1].set('style', 'stop-color:#000000:stop-opacity:1')
>>> yellowchildren[0].set('style', 'stop-color:#000000;stop-opacity:1')
>>> yellowchildren[1].set('style', 'stop-color:#000000;stop-opacity:1')
>>> svgobj.write('pythonlogochanged.svg')

The hardest part of this excercise was finding the appropriate parts of the SVG file to edit.  ElementTree makes it easy from there.

1 comment: