| # Liblouis Python ctypes bindings |
| # |
| # Copyright (C) 2009, 2010 James Teh <jamie@jantrid.net> |
| # |
| # This file is part of liblouis. |
| # |
| # liblouis is free software: you can redistribute it and/or modify it |
| # under the terms of the GNU Lesser General Public License as published |
| # by the Free Software Foundation, either version 2.1 of the License, or |
| # (at your option) any later version. |
| # |
| # liblouis is distributed in the hope that it will be useful, but |
| # WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| # Lesser General Public License for more details. |
| # |
| # You should have received a copy of the GNU Lesser General Public |
| # License along with liblouis. If not, see <http://www.gnu.org/licenses/>. |
| # |
| |
| """Liblouis Python ctypes bindings |
| These bindings allow you to use the liblouis braille translator and back-translator library from within Python. |
| This documentation is only a Python helper. |
| Please see the liblouis documentation for more information. |
| |
| Most of these functions take a C{tableList} argument which specifies |
| a list of translation tables to use. Please see the liblouis documentation |
| concerning the C{tableList} parameter to the C{lou_translateString} |
| function for information about how liblouis searches for these tables. |
| |
| @author: Michael Curran <mick@kulgan.net> |
| @author: James Teh <jamie@jantrid.net> |
| @author: Eitan Isaacson <eitan@ascender.com> |
| @author: Michael Whapples <mwhapples@aim.com> |
| @author: Davy Kager <mail@davykager.nl> |
| """ |
| |
| from ctypes import * |
| import struct |
| import atexit |
| import sys |
| |
| # Some general utility functions |
| def _createTablesString(tablesList): |
| """Creates a tables string for liblouis calls""" |
| return b",".join([x.encode("ASCII") if isinstance(x, str) else bytes(x) for x in tablesList]) |
| |
| def _createTypeformbuf(length, typeform=None): |
| """Creates a typeform buffer for liblouis calls""" |
| return (c_ushort*length)(*typeform) if typeform else (c_ushort*length)() |
| |
| createStr = None |
| if sys.version_info[0] == 2: |
| createStr = lambda x: unicode(x) |
| else: |
| createStr = lambda x: str(x) |
| |
| #{ Module Configuration |
| #: Specifies the number by which the input length should be multiplied |
| #: to calculate the maximum output length. |
| #: @type: int |
| # This default will handle the case where every input character is |
| # undefined in the translation table. |
| outlenMultiplier = 4 + sizeof(c_wchar) * 2 |
| #} |
| |
| try: |
| # Native win32 |
| _loader = windll |
| except NameError: |
| # Unix/Cygwin |
| _loader = cdll |
| liblouis = _loader["###LIBLOUIS_SONAME###"] |
| |
| atexit.register(liblouis.lou_free) |
| |
| liblouis.lou_version.restype = c_char_p |
| |
| liblouis.lou_charSize.restype = c_int |
| |
| liblouis.lou_translateString.argtypes = ( |
| c_char_p, c_wchar_p, POINTER(c_int), c_wchar_p, |
| POINTER(c_int), POINTER(c_ushort), POINTER(c_char), c_int) |
| |
| liblouis.lou_translate.argtypes = ( |
| c_char_p, c_wchar_p, POINTER(c_int), c_wchar_p, |
| POINTER(c_int), POINTER(c_ushort), POINTER(c_char), |
| POINTER(c_int), POINTER(c_int), POINTER(c_int), c_int) |
| |
| liblouis.lou_backTranslateString.argtypes = ( |
| c_char_p, c_wchar_p, POINTER(c_int), c_wchar_p, |
| POINTER(c_int), POINTER(c_ushort), POINTER(c_char), c_int) |
| |
| liblouis.lou_backTranslate.argtypes = ( |
| c_char_p, c_wchar_p, POINTER(c_int), c_wchar_p, POINTER(c_int), |
| POINTER(c_ushort), POINTER(c_char), POINTER(c_int), POINTER(c_int), |
| POINTER(c_int), c_int) |
| |
| liblouis.lou_hyphenate.argtypes = ( |
| c_char_p, c_wchar_p, c_int, POINTER(c_char), c_int) |
| |
| liblouis.lou_checkTable.argtypes = (c_char_p,) |
| |
| liblouis.lou_compileString.argtypes = (c_char_p, c_char_p) |
| |
| liblouis.lou_getTypeformForEmphClass.argtypes = (c_char_p, c_char_p) |
| |
| def version(): |
| """Obtain version information for liblouis. |
| @return: The version of liblouis, plus other information, such as |
| the release date and perhaps notable changes. |
| @rtype: str |
| """ |
| return liblouis.lou_version().decode("ASCII") |
| |
| def charSize(): |
| """Obtain charSize information for liblouis. |
| @return: The size of the widechar with which liblouis was compiled. |
| @rtype: int |
| """ |
| return liblouis.lou_charSize() |
| |
| def translate(tableList, inbuf, typeform=None, cursorPos=0, mode=0): |
| """Translate a string of characters, providing position information. |
| @param tableList: A list of translation tables. |
| @type tableList: list of str |
| @param inbuf: The string to translate. |
| @type inbuf: str |
| @param typeform: A list of typeform constants indicating the typeform for each position in inbuf, |
| C{None} for no typeform information. |
| @type typeform: list of int |
| @param cursorPos: The position of the cursor in inbuf. |
| @type cursorPos: int |
| @param mode: The translation mode; add multiple values for a combined mode. |
| @type mode: int |
| @return: A tuple of: the translated string, |
| a list of input positions for each position in the output, |
| a list of output positions for each position in the input, and |
| the position of the cursor in the output. |
| @rtype: (str, list of int, list of int, int) |
| @raise RuntimeError: If a complete translation could not be done. |
| @see: lou_translate in the liblouis documentation |
| """ |
| tablesString = _createTablesString(tableList) |
| inbuf = createStr(inbuf) |
| inlen = c_int(len(inbuf)) |
| outlen = c_int(inlen.value*outlenMultiplier) |
| outbuf = create_unicode_buffer(outlen.value) |
| typeformbuf = None |
| if typeform: |
| typeformbuf = _createTypeformbuf(outlen.value, typeform) |
| inPos = (c_int*outlen.value)() |
| outPos = (c_int*inlen.value)() |
| cursorPos = c_int(cursorPos) |
| if not liblouis.lou_translate(tablesString, inbuf, byref(inlen), |
| outbuf, byref(outlen), typeformbuf, |
| None, outPos, inPos, byref(cursorPos), mode): |
| raise RuntimeError("Can't translate: tables %s, inbuf %s, typeform %s, cursorPos %s, mode %s"%(tableList, inbuf, typeform, cursorPos, mode)) |
| if isinstance(typeform, list): |
| typeform[:] = list(typeformbuf) |
| return outbuf.value, inPos[:outlen.value], outPos[:inlen.value], cursorPos.value |
| |
| def translateString(tableList, inbuf, typeform=None, mode=0): |
| """Translate a string of characters. |
| @param tableList: A list of translation tables. |
| @type tableList: list of str |
| @param inbuf: The string to translate. |
| @type inbuf: str |
| @param typeform: A list of typeform constants indicating the typeform for each position in inbuf, |
| C{None} for no typeform information. |
| @type typeform: list of int |
| @param mode: The translation mode; add multiple values for a combined mode. |
| @type mode: int |
| @return: The translated string. |
| @rtype: str |
| @raise RuntimeError: If a complete translation could not be done. |
| @see: lou_translateString in the liblouis documentation |
| """ |
| tablesString = _createTablesString(tableList) |
| inbuf = createStr(inbuf) |
| inlen = c_int(len(inbuf)) |
| outlen = c_int(inlen.value*outlenMultiplier) |
| outbuf = create_unicode_buffer(outlen.value) |
| typeformbuf = None |
| if typeform: |
| typeformbuf = _createTypeformbuf(outlen.value, typeform) |
| if not liblouis.lou_translateString(tablesString, inbuf, byref(inlen), |
| outbuf, byref(outlen), typeformbuf, |
| None, mode): |
| raise RuntimeError("Can't translate: tables %s, inbuf %s, typeform %s, mode %s"%(tableList, inbuf, typeform, mode)) |
| if isinstance(typeform, list): |
| typeform[:] = list(typeformbuf) |
| return outbuf.value |
| |
| def backTranslate(tableList, inbuf, typeform=None, cursorPos=0, mode=0): |
| """Back translates a string of characters, providing position information. |
| @param tableList: A list of translation tables. |
| @type tableList: list of str |
| @param inbuf: Braille to back translate. |
| @type inbuf: str |
| @param typeform: List where typeform constants will be placed. |
| @type typeform: list |
| @param cursorPos: Position of cursor. |
| @type cursorPos: int |
| @param mode: Translation mode. |
| @type mode: int |
| @return: A tuple: A string of the back translation, |
| a list of input positions for each position in the output, |
| a list of the output positions for each position in the input and |
| the position of the cursor in the output. |
| @rtype: (str, list of int, list of int, int) |
| @raise RuntimeError: If a complete back translation could not be done. |
| @see: lou_backTranslate in the liblouis documentation. |
| """ |
| tablesString = _createTablesString(tableList) |
| inbuf = createStr(inbuf) |
| inlen = c_int(len(inbuf)) |
| outlen = c_int(inlen.value * outlenMultiplier) |
| outbuf = create_unicode_buffer(outlen.value) |
| typeformbuf = None |
| if isinstance(typeform, list): |
| typeformbuf = _createTypeformbuf(outlen.value) |
| inPos = (c_int*outlen.value)() |
| outPos = (c_int*inlen.value)() |
| cursorPos = c_int(cursorPos) |
| if not liblouis.lou_backTranslate(tablesString, inbuf, byref(inlen), |
| outbuf, byref(outlen), typeformbuf, None, |
| outPos, inPos, byref(cursorPos), mode): |
| raise RuntimeError("Can't back translate: tables %s, inbuf %s, typeform %s, cursorPos %d, mode %d"%(tableList, inbuf, typeform, cursorPos, mode)) |
| if isinstance(typeform, list): |
| typeform[:] = list(typeformbuf) |
| return outbuf.value, inPos[:outlen.value], outPos[:inlen.value], cursorPos.value |
| |
| def backTranslateString(tableList, inbuf, typeform=None, mode=0): |
| """Back translate from Braille. |
| @param tableList: A list of translation tables. |
| @type tableList: list of str |
| @param inbuf: The Braille to back translate. |
| @type inbuf: str |
| @param typeform: List for typeform constants to be put in. |
| If you don't want typeform data then give None |
| @type typeform: list |
| @param mode: The translation mode |
| @type mode: int |
| @return: The back translation of inbuf. |
| @rtype: str |
| @raise RuntimeError: If a complete back translation could not be done. |
| @see: lou_backTranslateString in the liblouis documentation. |
| """ |
| tablesString = _createTablesString(tableList) |
| inbuf = createStr(inbuf) |
| inlen = c_int(len(inbuf)) |
| outlen = c_int(inlen.value * outlenMultiplier) |
| outbuf = create_unicode_buffer(outlen.value) |
| typeformbuf = None |
| if isinstance(typeform, list): |
| typeformbuf = _createTypeformbuf(outlen.value) |
| if not liblouis.lou_backTranslateString(tablesString, inbuf, byref(inlen), outbuf, |
| byref(outlen), typeformbuf, None, mode): |
| raise RuntimeError("Can't back translate: tables %s, inbuf %s, mode %d"%(tableList, inbuf, mode)) |
| if isinstance(typeform, list): |
| typeform[:] = list(typeformbuf) |
| return outbuf.value |
| |
| def hyphenate(tableList, inbuf, mode=0): |
| """Get information for hyphenation. |
| @param tableList: A list of translation tables and hyphenation |
| dictionaries. |
| @type tableList: list of str |
| @param inbuf: The text to get hyphenation information about. |
| This should be a single word and leading/trailing whitespace |
| and punctuation is ignored. |
| @type inbuf: str |
| @param mode: Lets liblouis know if inbuf is plain text or Braille. |
| Set to 0 for text and anyother value for Braille. |
| @type mode: int |
| @return: A string with '1' at the beginning of every syllable |
| and '0' elsewhere. |
| @rtype: str |
| @raise RuntimeError: If hyphenation data could not be produced. |
| @see: lou_hyphenate in the liblouis documentation. |
| """ |
| tablesString = _createTablesString(tableList) |
| inbuf = createStr(inbuf) |
| inlen = c_int(len(inbuf)) |
| hyphen_string = create_string_buffer(inlen.value + 1) |
| if not liblouis.lou_hyphenate(tablesString, inbuf, inlen, hyphen_string, mode): |
| raise RuntimeError("Can't hyphenate: tables %s, inbuf %s, mode %d"%(tableList, inbuf, mode)) |
| return hyphen_string.value.decode("ASCII") |
| |
| def checkTable(tableList): |
| """Check if the specified tables can be found and compiled. |
| This can be used to check if a list of tables contains errors |
| before sending it to other liblouis functions |
| that accept a list of tables. |
| @param tableList: A list of translation tables. |
| @type tableList: list of str |
| @raise RuntimeError: If compilation failed. |
| @see: lou_checkTable in the liblouis documentation |
| """ |
| tablesString = _createTablesString(tableList) |
| if not liblouis.lou_checkTable(tablesString): |
| raise RuntimeError("Can't compile: tables %s"%tableList) |
| |
| def compileString(tableList, inString): |
| """Compile a table entry on the fly at run-time. |
| @param tableList: A list of translation tables. |
| @type tableList: list of str |
| @param inString: The table entry to be added. |
| @type inString: str |
| @raise RuntimeError: If compilation of the entry failed. |
| @see: lou_compileString in the liblouis documentation |
| """ |
| tablesString = _createTablesString(tableList) |
| inBytes = inString.encode("ASCII") if isinstance(inString, str) else bytes(inString) |
| if not liblouis.lou_compileString(tablesString, inString): |
| raise RuntimeError("Can't compile entry: tables %s, inString %s"%(tableList, inString)) |
| |
| def getTypeformForEmphClass(tableList, emphClass): |
| """Get the typeform bit for the named emphasis class. |
| @param tableList: A list of translation tables. |
| @type tableList: list of str |
| @param emphClass: An emphasis class name. |
| @type emphClass: str |
| @see: lou_getTypeformForEmphClass in the liblouis documentation |
| """ |
| tablesString = _createTablesString(tableList) |
| return liblouis.lou_getTypeformForEmphClass(tablesString, emphClass) |
| |
| #{ Typeforms |
| plain_text = 0x0000 |
| italic = 0x0001 # emph_1 |
| underline = 0x0002 # emph_2 |
| bold = 0x0004 # emph_3 |
| emph_4 = 0x0008 |
| emph_5 = 0x0010 |
| emph_6 = 0x0020 |
| emph_7 = 0x0040 |
| emph_8 = 0x0080 |
| emph_9 = 0x0100 |
| emph_10 = 0x0200 |
| computer_braille = 0x0400 |
| no_translate = 0x0800 |
| no_contract = 0x1000 |
| #} |
| |
| #{ Translation modes |
| noContractions = 1 |
| compbrlAtCursor = 2 |
| dotsIO = 4 |
| comp8Dots = 8 |
| pass1Only = 16 |
| compbrlLeftCursor = 32 |
| ucBrl = 64 |
| noUndefinedDots = 128 |
| partialTrans = 256 |
| #} |
| |
| if charSize() == 2 and sys.maxunicode != 65535: |
| raise Exception("mismatch in Unicode width: liblouis is 2 and python isn't") |
| elif charSize() == 4 and sys.maxunicode != 1114111: |
| raise Exception("mismatch in Unicode width: liblouis is 4 and python isn't") |
| |
| if __name__ == '__main__': |
| # Just some common tests. |
| print(version()) |
| print(translate([b'../tables/en-us-g2.ctb'], 'Hello world!', cursorPos=5)) |