A4

Merge lp:~andrea.corbellini/a4/cleanup-1 into lp:a4

Proposed by Andrea Corbellini
Status: Merged
Merged at revision: 10
Proposed branch: lp:~andrea.corbellini/a4/cleanup-1
Merge into: lp:a4
Diff against target: 200 lines (+82/-60)
1 file modified
a4lib/presentation.py (+82/-60)
To merge this branch: bzr merge lp:~andrea.corbellini/a4/cleanup-1
Reviewer Review Type Date Requested Status
Andrea Gasparini Approve
Review via email: mp+26962@code.launchpad.net

Description of the change

This branch is the first step to clean up the code, and focuses to the a4lib.presentation module. Here are the details of what I have done:

1. PEP 8: http://www.python.org/dev/peps/pep-0008/
2. PEP 257: http://www.python.org/dev/peps/pep-0257/
3. I've removed mutable objects from the default values of methods. In other words, I've changed all "def m(arg=[])" to "def m(arg=None)".
4. I've also refactored some code to enhance readability.

However, I couldn't clean up two methods: Presentation._reduce_matrix_list and Presentation._get_rotation_from_matrix_list. At a quick glance, I couldn't understand what do they do. There are some comments, but are unclear. The doc string should really be improved.

Also, I can't understand why the arguments are optional: every time these two methods are called, they do get the argument.

Finally, I think that we should create a class for the transformation matrices.

To post a comment you must log in.
Revision history for this message
Andrea Gasparini (gaspa) wrote :

IMO it's ok.
Just that numpy.dot() has to be used instead of "*" operator in reduce_matrix_list(). But I guess we can merge your changes, and then correct this.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'a4lib/presentation.py'
--- a4lib/presentation.py 2010-06-01 22:03:43 +0000
+++ a4lib/presentation.py 2010-06-07 15:46:20 +0000
@@ -3,26 +3,26 @@
33
4"""Code to deal with SVG images."""4"""Code to deal with SVG images."""
55
6import json
7import math
6import re8import re
7import json
8import rsvg9import rsvg
9import math
10
11from numpy import array, dot
12from glib import GError10from glib import GError
13from lxml import etree11from lxml import etree
1412from numpy import array
15## FIXME: get these from the svg itself, we currently care only about "svg:"13
16## namespace, the others can be ignored.14
15# FIXME Get these from the SVG itself, we currently care only about "svg:"
16# namespace, the others can be ignored.
17nsmap = {17nsmap = {
18 'sodipodi': 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd',18 'sodipodi': 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd',
19 'cc': 'http://web.resource.org/cc/',19 'cc': 'http://web.resource.org/cc/',
20 'svg': 'http://www.w3.org/2000/svg',20 'svg': 'http://www.w3.org/2000/svg',
21 'dc': 'http://purl.org/dc/elements/1.1/',21 'dc': 'http://purl.org/dc/elements/1.1/',
22 'xlink': 'http://www.w3.org/1999/xlink',22 'xlink': 'http://www.w3.org/1999/xlink',
23 'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',23 'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
24 'inkscape': 'http://www.inkscape.org/namespaces/inkscape'}24 'inkscape': 'http://www.inkscape.org/namespaces/inkscape'
2525 }
2626
27class PresentationError(StandardError):27class PresentationError(StandardError):
28 """Error raised when an operation with an image fails."""28 """Error raised when an operation with an image fails."""
@@ -43,8 +43,9 @@
4343
44 self.svgtree = etree.parse(file_name)44 self.svgtree = etree.parse(file_name)
4545
46 ## get all the text strings contained by our metadata46 # Get all the text strings contained by our metadata.
47 xpath_query = "//svg:metadata[@id='a4-presentation-information']/text()"47 xpath_query = (
48 "//svg:metadata[@id='a4-presentation-information']/text()")
48 info_strings = self.svgtree.xpath(xpath_query, namespaces=nsmap)49 info_strings = self.svgtree.xpath(xpath_query, namespaces=nsmap)
49 data = u''.join(info_strings)50 data = u''.join(info_strings)
50 try:51 try:
@@ -58,44 +59,56 @@
58 self.render_cairo = self._svg_handler.render_cairo59 self.render_cairo = self._svg_handler.render_cairo
5960
60 def _handle_transform(self, target_element=None):61 def _handle_transform(self, target_element=None):
61 """ Handle svg transform tags and build up a list of tranformations62 """Handle SVG transform tags and build a list of tranformations."""
62 given in matrix()'s terms"""
63 matrix_list = []63 matrix_list = []
64 while target_element is not None:64 while target_element is not None:
65 transform_string = target_element.attrib.get('transform')65 transform_string = target_element.attrib.get('transform')
66 if transform_string:
67 matches = re.search(
68 "matrix\((.*?),(.*?),(.*?),(.*?),(.*?),(.*?)\)",
69 transform_string)
70 if matches:
71 transform_matrix = [float(matches.group(i))
72 for i in xrange(1, 7)]
73 matrix_list.append(transform_matrix)
74 matches = re.search("translate\((.*?),(.*?)\)",
75 transform_string)
76 if matches:
77 transform_matrix = [1, 0, 0, 1, float(matches.group(1)),
78 float(matches.group(2))]
79 matrix_list.append(transform_matrix)
80 matches = re.search("scale\((.*?),(.*?)\)", transform_string)
81 if matches:
82 transform_matrix = [float(matches.group(1)), 0, 0,
83 float(matches.group(2)), 0, 0]
84 matrix_list.append(transform_matrix)
85 matches = re.search("rotate\((.*?)\)", transform_string)
86 if matches:
87 # [ cos(a) sin(a) -sin(a) cos(a) 0 0].
88 a = math.radians(int(matches.group(1)))
89 transform_matrix = [math.cos(a), math.sin(a),
90 - math.sin(a), math.cos(a), 0, 0]
91 matrix_list.append(transform_matrix)
92 target_element = target_element.getparent()66 target_element = target_element.getparent()
67 if not transform_string:
68 # This element doesn't contain a transform tag.
69 continue
70
71 # Look for a transformation matrix.
72 matches = re.search(
73 'matrix\((.*?),(.*?),(.*?),(.*?),(.*?),(.*?)\)',
74 transform_string)
75 if matches:
76 transform_matrix = [
77 float(matches.group(i)) for i in xrange(1, 7)]
78 matrix_list.append(transform_matrix)
79
80 # Look for a translation.
81 matches = re.search(
82 'translate\((.*?),(.*?)\)', transform_string)
83 if matches:
84 transform_matrix = [
85 1, 0, 0, 1, float(matches.group(1)),
86 float(matches.group(2))]
87 matrix_list.append(transform_matrix)
88
89 # Look for a scale factor.
90 matches = re.search("scale\((.*?),(.*?)\)", transform_string)
91 if matches:
92 transform_matrix = [
93 float(matches.group(1)), 0, 0,
94 float(matches.group(2)), 0, 0]
95 matrix_list.append(transform_matrix)
96
97 # Look for a rotation.
98 matches = re.search("rotate\((.*?)\)", transform_string)
99 if matches:
100 angle = math.radians(int(matches.group(1)))
101 transform_matrix = [
102 math.cos(angle), math.sin(angle), -math.sin(angle),
103 math.cos(angle), 0, 0]
104 matrix_list.append(transform_matrix)
105
93 return matrix_list106 return matrix_list
94107
95 def _reduce_matrix_list(self, mt_list=[]):108 def _reduce_matrix_list(self, mt_list=None):
96 """ Take a list of matrix(), as given by SVG code, and returns109 """Take a list of matrixes, as given by SVG code, and returns
97 a single numpy.array() representing the whole transformation"""110 a single numpy.array() representing the whole transformation"""
98 if mt_list == []:111 if not mt_list:
99 return None112 return None
100 ### reduce the matrix_list to only one.113 ### reduce the matrix_list to only one.
101 ### get the rotation angle (degree?radiants?)114 ### get the rotation angle (degree?radiants?)
@@ -108,33 +121,42 @@
108 return result121 return result
109122
110 def _get_rotation_from_matrix_list(self, matrix=None):123 def _get_rotation_from_matrix_list(self, matrix=None):
111 """ Calculate rotation angle from the transformation matrix """124 """Calculate rotation angle from the transformation matrix."""
112 if matrix == None:125 if not matrix:
113 return 0126 return 0
114 scalefactor = math.sqrt(matrix[0][0] ** 2 + matrix[0][1] ** 2)127 scalefactor = math.sqrt(matrix[0][0] ** 2 + matrix[0][1] ** 2)
115 tmp_angle = math.asin(matrix[0][1] / scalefactor)128 angle = math.asin(matrix[0][1] / scalefactor)
116 if matrix[0][0] < 0:129 if matrix[0][0] < 0:
117 return math.pi - tmp_angle130 return math.pi - angle
118 else:131 else:
119 return tmp_angle132 return angle
120133
121 def get_item_properties_by_id(self, item_id):134 def get_item_properties_by_id(self, item_id):
122 """ Returns some interesting properties ( bounding box, rotation angle,135 """Returns some properties of the SVG element with the given id.
123 etc...) given an SVG's element id """136
137 The properties returned are:
138 * the width and the height of the element;
139 * its position;
140 * the transformations and the rotations.
141 """
124 try:142 try:
125 target_element = self.svgtree.xpath("//svg:*[@id='%s']" %143 target_element = self.svgtree.xpath(
126 item_id, namespaces=nsmap)144 "//svg:*[@id='{0}']".format(item_id), namespaces=nsmap)
127 except etree.XPathEvalError:145 except etree.XPathEvalError:
128 raise PresentationError('Can find the requested item')146 raise PresentationError('Can find the requested item')
147
129 properties = {}148 properties = {}
130 if len(target_element) > 0:149 if len(target_element) > 0:
131 properties['width'] = float(target_element[0].attrib.get('width'))150 properties['width'] = float(
132 properties['height'] = float(target_element[0].attrib.get('height'))151 target_element[0].attrib.get('width'))
152 properties['height'] = float(
153 target_element[0].attrib.get('height'))
133 properties['x'] = float(target_element[0].attrib.get('x'))154 properties['x'] = float(target_element[0].attrib.get('x'))
134 properties['y'] = float(target_element[0].attrib.get('y'))155 properties['y'] = float(target_element[0].attrib.get('y'))
135 properties['transform'] = self._reduce_matrix_list(156 properties['transform'] = self._reduce_matrix_list(
136 self._handle_transform(target_element[0]))157 self._handle_transform(target_element[0]))
137 if properties['transform'] != []:158
159 if properties['transform']:
138 properties['rotation'] = self._get_rotation_from_matrix_list(160 properties['rotation'] = self._get_rotation_from_matrix_list(
139 properties['transform'])161 properties['transform'])
140 else:162 else:

Subscribers

People subscribed via source and target branches