1 # Liblouis Python ctypes bindings
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Library General Public
5 # License as published by the Free Software Foundation; either
6 # version 2 of the License, or (at your option) any later version.
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # Library General Public License for more details.
13 # You should have received a copy of the GNU Library General Public
14 # License along with this library; if not, write to the
15 # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
16 # Boston MA 02110-1301 USA.
18 """Liblouis Python ctypes bindings
19 These bindings allow you to use the liblouis braille translator and back-translator library from within Python.
20 This documentation is only a Python helper.
21 Please see the liblouis documentation for more information.
23 Most of these functions take a C{tableList} argument which specifies
24 a list of translation tables to use. Please see the liblouis documentation
25 concerning the C{tableList} parameter to the C{lou_translateString}
26 function for information about how liblouis searches for these tables.
28 @author: Michael Curran <mick@kulgan.net>
29 @author: James Teh <jamie@jantrid.net>
30 @author: Eitan Isaacson <eitan@ascender.com>
31 @author: Michael Whapples <mwhapples@aim.com>
39 # Some general utility functions
40 def _createTablesString(tablesList):
41 """Creates a tables string for liblouis calls"""
42 return b",".join([x.encode("ASCII") if isinstance(x, str) else bytes(x) for x in tablesList])
45 if sys.version_info[0] == 2:
46 createStr = lambda x: unicode(x)
48 createStr = lambda x: str(x)
50 #{ Module Configuration
51 #: Specifies the number by which the input length should be multiplied
52 #: to calculate the maximum output length.
54 # This default will handle the case where every input character is
55 # undefined in the translation table.
56 outlenMultiplier = 4 + sizeof(c_wchar) * 2
65 liblouis = _loader["###LIBLOUIS_SONAME###"]
67 atexit.register(liblouis.lou_free)
69 liblouis.lou_version.restype = c_char_p
71 liblouis.lou_translateString.argtypes = (
72 c_char_p, c_wchar_p, POINTER(c_int), c_wchar_p,
73 POINTER(c_int), POINTER(c_char), POINTER(c_char), c_int)
75 liblouis.lou_translate.argtypes = (
76 c_char_p, c_wchar_p, POINTER(c_int), c_wchar_p,
77 POINTER(c_int), POINTER(c_char), POINTER(c_char),
78 POINTER(c_int), POINTER(c_int), POINTER(c_int), c_int)
80 liblouis.lou_backTranslateString.argtypes = (
81 c_char_p, c_wchar_p, POINTER(c_int), c_wchar_p,
82 POINTER(c_int), POINTER(c_char), POINTER(c_char), c_int)
84 liblouis.lou_backTranslate.argtypes = (
85 c_char_p, c_wchar_p, POINTER(c_int), c_wchar_p, POINTER(c_int),
86 POINTER(c_char), POINTER(c_char), POINTER(c_int), POINTER(c_int),
87 POINTER(c_int), c_int)
89 liblouis.lou_hyphenate.argtypes = (
90 c_char_p, c_wchar_p, c_int, POINTER(c_char), c_int)
92 liblouis.lou_compileString.argtypes = (c_char_p, c_char_p)
95 """Obtain version information for liblouis.
96 @return: The version of liblouis, plus other information, such as
97 the release date and perhaps notable changes.
100 return liblouis.lou_version().decode("ASCII")
102 def translate(tableList, inbuf, typeform=None,cursorPos=0, mode=0):
103 """Translate a string of characters, providing position information.
104 @param tableList: A list of translation tables.
105 @type tableList: list of str
106 @param inbuf: The string to translate.
108 @param typeform: A list of typeform constants indicating the typeform for each position in inbuf,
109 C{None} for no typeform information.
110 @type typeform: list of int
111 @param cursorPos: The position of the cursor in inbuf.
113 @param mode: The translation mode; add multiple values for a combined mode.
115 @return: A tuple of: the translated string,
116 a list of input positions for each position in the output,
117 a list of output positions for each position in the input, and
118 the position of the cursor in the output.
119 @rtype: (str, list of int, list of int, int)
120 @raise RuntimeError: If a complete translation could not be done.
121 @see: lou_translate in the liblouis documentation
123 tablesString = _createTablesString(tableList)
124 inbuf = createStr(inbuf)
125 inlen = c_int(len(inbuf))
126 outlen = c_int(inlen.value*outlenMultiplier)
127 outbuf = create_unicode_buffer(outlen.value)
130 typeformbuf = create_string_buffer(struct.pack('B'*len(typeform),*typeform), size=outlen.value)
131 inPos = (c_int*outlen.value)()
132 outPos = (c_int*inlen.value)()
133 cursorPos = c_int(cursorPos)
134 if not liblouis.lou_translate(tablesString, inbuf, byref(inlen),
135 outbuf, byref(outlen), typeformbuf,
136 None, outPos, inPos, byref(cursorPos), mode):
137 raise RuntimeError("can't translate: tables %s, inbuf %s, typeform %s, cursorPos %s, mode %s"%(tableList, inbuf, typeform, cursorPos, mode))
138 if isinstance(typeform, list):
139 typeform[:] = typeformbuf.value
140 return outbuf.value, inPos[:outlen.value], outPos[:inlen.value], cursorPos.value
142 def translateString(tableList, inbuf, typeform = None, mode = 0):
143 """Translate a string of characters.
144 @param tableList: A list of translation tables.
145 @type tableList: list of str
146 @param inbuf: The string to translate.
148 @param typeform: A list of typeform constants indicating the typeform for each position in inbuf,
149 C{None} for no typeform information.
150 @type typeform: list of int
151 @param mode: The translation mode; add multiple values for a combined mode.
153 @return: The translated string.
155 @raise RuntimeError: If a complete translation could not be done.
156 @see: lou_translateString in the liblouis documentation
158 tablesString = _createTablesString(tableList)
159 inbuf = createStr(inbuf)
160 inlen = c_int(len(inbuf))
161 outlen = c_int(inlen.value*outlenMultiplier)
162 outbuf = create_unicode_buffer(outlen.value)
165 typeformbuf = create_string_buffer(struct.pack('B'*len(typeform),*typeform), size=outlen.value)
166 if not liblouis.lou_translateString(tablesString, inbuf, byref(inlen),
167 outbuf, byref(outlen), typeformbuf,
169 raise RuntimeError("can't translate: tables %s, inbuf %s, typeform %s, mode %s"%(tableList, inbuf, typeform, mode))
170 if isinstance(typeform, list):
171 typeform[:] = typeformbuf.value
174 def backTranslate(tableList, inbuf, typeform=None, cursorPos=0, mode=0):
175 """Back translates a string of characters, providing position information.
176 @param tableList: A list of translation tables.
177 @type tableList: list of str
178 @param inbuf: Braille to back translate.
180 @param typeform: List where typeform constants will be placed.
182 @param cursorPos: Position of cursor.
184 @param mode: Translation mode.
186 @return: A tuple: A string of the back translation,
187 a list of input positions for each position in the output,
188 a list of the output positions for each position in the input and
189 the position of the cursor in the output.
190 @rtype: (str, list of int, list of int, int)
191 @raises RuntimeError: If back translation could not be completed.
192 @see: lou_backTranslate in the liblouis documentation.
194 tablestring = _createTablesString(tableList)
195 inbuf = createStr(inbuf)
196 inlen = c_int(len(inbuf))
197 outlen = c_int(inlen.value * outlenMultiplier)
198 outbuf = create_unicode_buffer(outlen.value)
200 if isinstance(typeform, list):
201 typeformbuf = create_string_buffer(outlen.value)
202 inPos = (c_int*outlen.value)()
203 outPos = (c_int*inlen.value)()
204 cursorPos = c_int(cursorPos)
205 if not liblouis.lou_backTranslate(tablestring, inbuf, byref(inlen),
206 outbuf, byref(outlen), typeformbuf, None,
207 outPos, inPos, byref(cursorPos), mode):
208 raise RuntimeError("Can't back translate tableList %s, inbuf %s, typeform %s, cursorPos %d, mode %d" % (tableList, inbuf, typeform, cursorPos, mode))
209 if isinstance(typeform, list):
210 typeform[:] = typeformbuf.value
211 return outbuf.value, inPos[:outlen.value], outPos[:inlen.value], cursorPos.value
213 def backTranslateString(tableList, inbuf, typeform=None, mode=0):
214 """Back translate from Braille.
215 @param tableList: A list of translation tables.
216 @type tableList: list of str
217 @param inbuf: The Braille to back translate.
219 @param typeform: List for typeform constants to be put in.
220 If you don't want typeform data then give None
222 @param mode: The translation mode
224 @return: The back translation of inbuf.
226 @raises RuntimeError: If a full back translation could not be done.
227 @see: lou_backTranslateString in the liblouis documentation.
229 tablestring = _createTablesString(tableList)
230 inbuf = createStr(inbuf)
231 inlen = c_int(len(inbuf))
232 outlen = c_int(inlen.value * outlenMultiplier)
233 outbuf = create_unicode_buffer(outlen.value)
235 if isinstance(typeform, list):
236 typeformbuf = create_string_buffer(outlen.value)
237 if not liblouis.lou_backTranslateString(tablestring, inbuf, byref(inlen), outbuf,
238 byref(outlen), typeformbuf, None, mode):
239 raise RuntimeError("Can't back translate tables %s, inbuf %s, mode %d" %(tablestring, inbuf, mode))
240 if isinstance(typeform, list):
241 typeform[:] = typeformbuf.value[:outlen.value]
244 def hyphenate(tableList, inbuf, mode=0):
245 """Get information for hyphenation.
246 @param tableList: A list of translation tables and hyphenation
248 @type tableList: list of str
249 @param inbuf: The text to get hyphenation information about.
250 This should be a single word and leading/trailing whitespace
251 and punctuation is ignored.
253 @param mode: Lets liblouis know if inbuf is plain text or Braille.
254 Set to 0 for text and anyother value for Braille.
256 @return: A string with '1' at the beginning of every syllable
259 @raises RuntimeError: If hyphenation data could not be produced.
260 @see: lou_hyphenate in the liblouis documentation.
262 tablesString = _createTablesString(tableList)
263 inbuf = createStr(inbuf)
264 inlen = c_int(len(inbuf))
265 hyphen_string = create_string_buffer(inlen.value + 1)
266 if not liblouis.lou_hyphenate(tablesString, inbuf, inlen, hyphen_string, mode):
267 raise RuntimeError("Can't hyphenate tables %s, inbuf %s, mode %d" %(tablesString, inbuf, mode))
268 return hyphen_string.value.decode("ASCII")
270 def compileString(tableList, inString):
271 """Compile a table entry on the fly at run-time.
272 @param tableList: A list of translation tables.
273 @type tableList: list of str
274 @param inString: The table entry to be added.
276 @raise RuntimeError: If compilation of the entry failed.
277 @see: lou_compileString in the liblouis documentation
279 tablesString = _createTablesString(tableList)
280 inBytes = inString.encode("ASCII") if isinstance(inString, str) else bytes(inString)
281 if not liblouis.lou_compileString(tablesString, inString):
282 raise RuntimeError("Can't compile entry: tables %s, inString %s" % (tableList, inString))
297 compbrlLeftCursor = 32
302 if __name__ == '__main__':
303 # Just some common tests.
305 print(translate([b'../tables/en-us-g2.ctb'], 'Hello world!', cursorPos=5))