"Fossies" - the Fresh Open Source Software Archive

Member "libcaca-0.99.beta20/python/caca/canvas.py" (21 Apr 2017, 58986 Bytes) of package /linux/privat/libcaca-0.99.beta20.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 # -*- coding: utf-8 -*-
    2 #
    3 # libcaca       Colour ASCII-Art library
    4 #               Python language bindings
    5 # Copyright (c) 2010 Alex Foulon <alxf@lavabit.com>
    6 #               All Rights Reserved
    7 #
    8 # This library is free software. It comes without any warranty, to
    9 # the extent permitted by applicable law. You can redistribute it
   10 # and/or modify it under the terms of the Do What the Fuck You Want
   11 # to Public License, Version 2, as published by Sam Hocevar. See
   12 # http://www.wtfpl.net/ for more details.
   13 #
   14 
   15 """ Libcaca Python bindings """
   16 
   17 import ctypes
   18 import errno
   19 
   20 from caca import _lib, utf8_to_utf32, utf32_to_utf8
   21 from caca import _PYTHON3, _str_to_bytes, _bytes_to_str
   22 from caca.font import _Font
   23 
   24 
   25 class _CanvasStruct(ctypes.Structure):
   26     pass
   27 
   28 class _Canvas(object):
   29     """ Model for Canvas objects.
   30     """
   31 
   32     def __init__(self):
   33         self._cv = None
   34 
   35     def from_param(self):
   36         """ Required by ctypes module to call object as parameter of
   37             a C function.
   38         """
   39         return self._cv
   40 
   41     def __str__(self):
   42         return "<CacaCanvas %dx%d>" % (self.get_width(), self.get_height())
   43 
   44     def __del__(self):
   45         if self._cv and _lib is not None:
   46             self._free()
   47 
   48     def _free(self):
   49         """ Free a libcaca canvas.
   50         """
   51         _lib.caca_free_canvas.argtypes = [_Canvas]
   52         _lib.caca_free_canvas.restype  = ctypes.c_int
   53 
   54         return _lib.caca_free_canvas(self)
   55 
   56 class Canvas(_Canvas):
   57     """ Canvas object, methods are libcaca functions with canvas_t as
   58         first parameter.
   59     """
   60     def __init__(self, width=0, height=0, pointer=None):
   61         """ Canvas constructor.
   62 
   63             width   -- the desired canvas width
   64             height  -- the desired canvas height
   65             pointer -- pointer to libcaca canvas
   66         """
   67         _lib.caca_create_canvas.argtypes = [ctypes.c_int, ctypes.c_int]
   68         _lib.caca_create_canvas.restype = ctypes.POINTER(_CanvasStruct)
   69 
   70         if pointer is None:
   71             try:
   72                 self._cv = _lib.caca_create_canvas(width, height)
   73             except ctypes.ArgumentError:
   74                 self._cv = 0
   75                 raise CanvasError("Specified width or height is invalid")
   76             else:
   77                 if self._cv == 0:
   78                     err = ctypes.c_int.in_dll(_lib, "errno")
   79                     if err.value == errno.EINVAL:
   80                         raise CanvasError("Specified width or height is"
   81                                           " invalid")
   82                     elif err.value == errno.ENOMEM:
   83                         raise CanvasError("Not enough memory for the requested"
   84                                           " canvas size")
   85                     else:
   86                         raise CanvasError("Unknown error: failed to create"
   87                                           " canvas")
   88         else:
   89             self._cv = pointer
   90 
   91     def manage(self, *args, **kw):
   92         """ Not implemented.
   93         """
   94         raise CanvasError("Not implemented")
   95 
   96     def unmanage(self, *args, **kw):
   97         """ Not implemented.
   98         """
   99         raise CanvasError("Not implemented")
  100 
  101     def set_size(self, width, height):
  102         """ Resize a canvas.
  103 
  104             width   -- the desired canvas width
  105             height  -- the desired canvas height
  106         """
  107         _lib.caca_set_canvas_size.argtypes  = [
  108                 _Canvas, ctypes.c_int, ctypes.c_int
  109             ]
  110         _lib.caca_set_canvas_size.restype   = ctypes.c_int
  111 
  112         try:
  113             ret = _lib.caca_set_canvas_size(self, width, height)
  114         except ctypes.ArgumentError:
  115             raise CanvasError("Specified width or height is invalid")
  116         else:
  117             if ret == -1:
  118                 err = ctypes.c_int.in_dll(_lib, "errno")
  119                 if err.value == errno.EINVAL:
  120                     raise CanvasError("Specified width or height is invalid")
  121                 elif err.value == errno.EBUSY:
  122                     raise CanvasError("The canvas is in use by a display driver"
  123                                       " and cannot be resized")
  124                 elif err.value == errno.ENOMEM:
  125                     raise CanvasError("Not enough memory for the requested"
  126                                       " canvas size")
  127             else:
  128                 return ret
  129 
  130     def get_width(self):
  131         """ Get the canvas width.
  132         """
  133         _lib.caca_get_canvas_width.argtypes = [_Canvas]
  134         _lib.caca_get_canvas_width.restype  = ctypes.c_int
  135 
  136         return _lib.caca_get_canvas_width(self)
  137 
  138     def get_height(self):
  139         """ Get the canvas height.
  140         """
  141         _lib.caca_get_canvas_height.argtypes = [_Canvas]
  142         _lib.caca_get_canvas_height.restype  = ctypes.c_int
  143 
  144         return _lib.caca_get_canvas_height(self)
  145 
  146     def get_chars(self, *args, **kw):
  147         """ Not implemented.
  148         """
  149         raise CanvasError("Not implemented")
  150 
  151     def get_attrs(self, *args, **kw):
  152         """ Not implemented.
  153         """
  154         raise CanvasError("Not implemented")
  155 
  156     def gotoxy(self, x, y):
  157         """ Set cursor position. Setting the cursor position outside the canvas
  158             is legal but the cursor will not be shown.
  159 
  160             x   -- X cursor coordinate
  161             y   -- Y cursor coordinate
  162         """
  163         _lib.caca_gotoxy.argtypes = [_Canvas, ctypes.c_int, ctypes.c_int]
  164         _lib.caca_gotoxy.restyoe  = ctypes.c_int
  165 
  166         try:
  167             ret = _lib.caca_gotoxy(self, x, y)
  168         except ctypes.ArgumentError:
  169             raise CanvasError("specified coordinate X or Y is invalid")
  170         else:
  171             return ret
  172 
  173     def wherex(self):
  174         """ Get X cursor position.
  175         """
  176         _lib.caca_wherex.argtypes = [_Canvas]
  177         _lib.caca_wherex.restype  = ctypes.c_int
  178 
  179         return _lib.caca_wherex(self)
  180 
  181     def wherey(self):
  182         """ Get Y cursor position.
  183         """
  184         _lib.caca_wherey.argtypes = [_Canvas]
  185         _lib.caca_wherey.restype  = ctypes.c_int
  186 
  187         return _lib.caca_wherey(self)
  188 
  189     def put_char(self, x, y, ch):
  190         """ Print an ASCII or Unicode character. Return the width of the
  191             printed character: 2 for a fullwidth character, 1 otherwise.
  192 
  193             x   -- X coordinate
  194             y   -- Y coordinate
  195             ch  -- the character to print
  196         """
  197         _lib.caca_put_char.argtypes = [
  198                 _Canvas, ctypes.c_int, ctypes.c_int, ctypes.c_uint32
  199             ]
  200         _lib.caca_put_char.restype  = ctypes.c_int
  201 
  202         if not isinstance(ch, str):
  203             raise CanvasError("Specified character is invalid")
  204         else:
  205             try:
  206                 ch = ord(ch)
  207             except TypeError:
  208                 ch = utf8_to_utf32(ch)
  209 
  210             try:
  211                 ret =  _lib.caca_put_char(self, x, y, ch)
  212             except ctypes.ArgumentError:
  213                 raise CanvasError("specified coordinate X or Y is invalid")
  214             else:
  215                 return ret
  216 
  217     def get_char(self, x, y):
  218         """ Get the Unicode character at the given coordinates.
  219 
  220             x   -- X coordinate
  221             y   -- Y coordinate
  222         """
  223         _lib.caca_get_char.argtypes = [
  224                 _Canvas, ctypes.c_int, ctypes.c_int
  225             ]
  226         _lib.caca_get_char.restype  = ctypes.c_uint32
  227 
  228         try:
  229             ch = _lib.caca_get_char(self, x, y)
  230         except ctypes.ArgumentError:
  231             raise CanvasError("specified coordinate X or Y is invalid")
  232         else:
  233             try:
  234                 ch = ord(ch)
  235             except TypeError:
  236                 ch = utf32_to_utf8(ch)
  237 
  238             return ch
  239 
  240     def put_str(self, x, y, s):
  241         """ Print a string.
  242 
  243             x   -- X coordinate
  244             y   -- Y coordinate
  245             s   -- the string to print
  246         """
  247         _lib.caca_put_str.argtypes = [
  248                 _Canvas, ctypes.c_int, ctypes.c_int, ctypes.c_char_p
  249             ]
  250         _lib.caca_put_str.restype  = ctypes.c_int
  251 
  252         if _PYTHON3 and isinstance(s, str):
  253             s = _str_to_bytes(s)
  254 
  255         try:
  256             ret = _lib.caca_put_str(self, x, y, s)
  257         except ctypes.ArgumentError:
  258             raise CanvasError("Invalid argument")
  259         else:
  260             return ret
  261 
  262     def printf(self, x, y, fmt, *args):
  263         """ Print a formated string.
  264 
  265             x       -- X coordinate
  266             y       -- Y coordinate
  267             fmt     -- the format string to print
  268             args    -- Arguments to the format string
  269         """
  270         _lib.caca_printf.argtypes = [
  271                 _Canvas, ctypes.c_int, ctypes.c_int, ctypes.c_char_p
  272             ]
  273         _lib.caca_printf.restype  = ctypes.c_int
  274 
  275         if _PYTHON3 and isinstance(fmt, str):
  276             fmt = _str_to_bytes(fmt)
  277 
  278         if _PYTHON3:
  279             nargs = []
  280             for arg in args[:]:
  281                 if isinstance(arg, str):
  282                     nargs.append(_str_to_bytes(arg))
  283                 else:
  284                     nargs.append(arg)
  285         else:
  286             nargs = args
  287 
  288         try:
  289             ret = _lib.caca_printf(self, x, y, fmt, *nargs)
  290         except ctypes.ArgumentError:
  291             raise CanvasError("Specified coordinate X or Y is invalid")
  292         else:
  293             return ret
  294 
  295     def vprintf(self, *args, **kw):
  296         """ Not implemented.
  297         """
  298         raise CanvasError("Not implemented")
  299 
  300     def clear(self):
  301         """ Clear the canvas.
  302         """
  303         _lib.caca_clear_canvas.argtypes = [_Canvas]
  304         _lib.caca_clear_canvas.restype  = ctypes.c_int
  305 
  306         return _lib.caca_clear_canvas(self)
  307 
  308     def set_handle(self, x, y):
  309         """ Set cursor handle. Blitting method will use the handle value to
  310             put the canvas at the proper coordinates.
  311 
  312             x   -- X handle coordinate
  313             y   -- Y handle coordinate
  314         """
  315         _lib.caca_set_canvas_handle.argtypes = [
  316                 _Canvas, ctypes.c_int, ctypes.c_int
  317             ]
  318         _lib.caca_set_canvas_handle.restype  = ctypes.c_int
  319 
  320         try:
  321             ret = _lib.caca_set_canvas_handle(self, x, y)
  322         except ctypes.ArgumentError:
  323             raise CanvasError("Specified coordinate X or Y is invalid")
  324         else:
  325             return ret
  326 
  327     def get_handle_x(self):
  328         """ Get X handle position.
  329         """
  330         _lib.caca_get_canvas_handle_x.argtypes = [_Canvas]
  331         _lib.caca_get_canvas_handle_x.restype  = ctypes.c_int
  332 
  333         return _lib.caca_get_canvas_handle_x(self)
  334 
  335     def get_handle_y(self):
  336         """ Get Y handle position.
  337         """
  338         _lib.caca_get_canvas_handle_y.argtypes = [_Canvas]
  339         _lib.caca_get_canvas_handle_y.restype  = ctypes.c_int
  340 
  341         return _lib.caca_get_canvas_handle_y(self)
  342 
  343     def blit(self, x, y, cv, mask=None):
  344         """ Blit canvas onto another one.
  345 
  346             x       -- X coordinate
  347             y       -- Y coordinate
  348             cv      -- the source canvas
  349             mask    -- the mask canvas
  350         """
  351         _lib.caca_blit.argtypes = [
  352                 _Canvas, ctypes.c_int, ctypes.c_int, _Canvas, _Canvas
  353             ]
  354         _lib.caca_blit.restype  = ctypes.c_int
  355 
  356         if not isinstance(cv, Canvas):
  357             raise CanvasError("Specified mask canvas is invalid")
  358         else:
  359             if mask is None:
  360                 mask = NullCanvas()
  361             else:
  362                 if not isinstance(mask, _Canvas):
  363                     raise CanvasError("Specified mask canvas is invalid")
  364 
  365         try:
  366             ret = _lib.caca_blit(self, x, y, cv, mask)
  367         except ctypes.ArgumentError:
  368             raise CanvasError("Specified coordinate X or Y is invalid")
  369         else:
  370             if ret == -1:
  371                 err = ctypes.c_int.in_dll(_lib, "errno")
  372                 if err.value == errno.EINVAL:
  373                     raise CanvasError("A mask was specified but the mask size"
  374                                       " and source canvas size do not match")
  375             else:
  376                 return ret
  377 
  378     def set_boundaries(self, x, y, width, height):
  379         """ Set a canvas' new boundaries.
  380 
  381             x       -- X coordinate of the top-left corner
  382             y       -- Y coordinate of the top-left corner
  383             width   -- width of the box
  384             height  -- height of the box
  385         """
  386         _lib.caca_set_canvas_boundaries.argtypes = [
  387               _Canvas, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int
  388             ]
  389         _lib.caca_set_canvas_boundaries.restype  = ctypes.c_int
  390 
  391         try:
  392             ret = _lib.caca_set_canvas_boundaries(self, x, y, width, height)
  393         except ctypes.ArgumentError:
  394             raise CanvasError("Specified coordinate or size is invalid")
  395         else:
  396             if ret == -1:
  397                 err = ctypes.c_int.in_dll(_lib, "errno")
  398                 if err.value == errno.EINVAL:
  399                     raise CanvasError("Specified width or height is invalid")
  400                 elif err.value == errno.EBUSY:
  401                     raise CanvasError("The canvas is in use by a display driver"
  402                                       " and cannot be resized")
  403                 elif err.value == errno.ENOMEM:
  404                     raise CanvasError("Not enough memory for the requested"
  405                                       " canvas size")
  406             else:
  407                 return ret
  408 
  409     def disable_dirty_rect(self):
  410         """ Disable dirty rectangles.
  411         """
  412         _lib.caca_disable_dirty_rect.argtypes = [_Canvas]
  413         _lib.caca_disable_dirty_rect.restype  = ctypes.c_int
  414 
  415         return _lib.caca_disable_dirty_rect(self)
  416 
  417     def enable_dirty_rect(self):
  418         """ Enable dirty rectangles.
  419         """
  420         _lib.caca_enable_dirty_rect.argtypes = [_Canvas]
  421         _lib.caca_enable_dirty_rect.restype  = ctypes.c_int
  422 
  423         ret = _lib.caca_enable_dirty_rect(self)
  424         if ret == -1:
  425             err = ctypes.c_int.in_dll(_lib, "errno")
  426             if err.value == errno.EINVAL:
  427                 raise CanvasError("Dirty rectangles were not disabled")
  428         else:
  429             return ret
  430 
  431     def get_dirty_rect_count(self):
  432         """ Get the number of dirty rectangles in the canvas.
  433         """
  434         _lib.caca_get_dirty_rect_count.argtypes = [_Canvas]
  435         _lib.caca_get_dirty_rect_count.restype  = ctypes.c_int
  436 
  437         return _lib.caca_get_dirty_rect_count(self)
  438 
  439     def get_dirty_rect(self, idx):
  440         """ Get a canvas's dirty rectangle. Return python dictionnary with
  441             coords as keys: x, y, width, height.
  442 
  443             idx -- the requested rectangle index
  444         """
  445         dct = None
  446         x = ctypes.c_int()
  447         y = ctypes.c_int()
  448         width  = ctypes.c_int()
  449         height = ctypes.c_int()
  450 
  451         _lib.caca_get_dirty_rect.argtypes = [
  452                 _Canvas, ctypes.c_int,
  453                 ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int),
  454                 ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)
  455             ]
  456         _lib.caca_get_dirty_rect.restype  = ctypes.c_int
  457 
  458         try:
  459             ret = _lib.caca_get_dirty_rect(self, idx, x, y, width, height)
  460         except ctypes.ArgumentError:
  461             raise CanvasError("Specified rectangle index is invalid")
  462         else:
  463             if ret == -1:
  464                 err = ctypes.c_int.in_dll(_lib, "errno")
  465                 if err.value == errno.EINVAL:
  466                     raise CanvasError("Specified rectangle index is out of"
  467                                       " bounds")
  468             else:
  469                 dct = {
  470                     'x': x.value, 'y': y.value,
  471                     'width': width.value, 'height': height.value,
  472                 }
  473                 return dct
  474 
  475     def add_dirty_rect(self, x, y, width, height):
  476         """ Add an area to the canvas's dirty rectangle list.
  477 
  478             x       -- the leftmost edge of the additional dirty rectangle
  479             y       -- the topmost edge of the additional dirty rectangle
  480             width   -- the width of the additional dirty rectangle
  481             height  -- the height of the additional dirty rectangle
  482         """
  483         _lib.caca_add_dirty_rect.argtypes = [
  484                 _Canvas, ctypes.c_int, ctypes.c_int,
  485                 ctypes.c_int, ctypes.c_int
  486             ]
  487         _lib.caca_add_dirty_rect.restype  = ctypes.c_int
  488 
  489         try:
  490             ret =_lib.caca_add_dirty_rect(self, x, y, width, height)
  491         except ctypes.ArgumentError:
  492             raise CanvasError("Specified coordinate or size is invalid")
  493         else:
  494             if ret == -1:
  495                 err = ctypes.c_int.in_dll(_lib, "errno")
  496                 if err.value == errno.EINVAL:
  497                     raise CanvasError("Specified rectangle coordinates are out"
  498                                       " of bounds")
  499             else:
  500                 return ret
  501 
  502     def remove_dirty_rect(self, x, y, width, height):
  503         """ Remove an area from the dirty rectangle list.
  504 
  505             x       -- the leftmost edge of the additional dirty rectangle
  506             y       -- the topmost edge of the additional dirty rectangle
  507             width   -- the width of the additional rectangle
  508             height  -- the height of the additional dirty rectangle
  509         """
  510         _lib.caca_remove_dirty_rect.argtypes = [
  511                 _Canvas, ctypes.c_int, ctypes.c_int,
  512                 ctypes.c_int, ctypes.c_int
  513             ]
  514         _lib.caca_remove_dirty_rect.restype  = ctypes.c_int
  515 
  516         try:
  517             ret = _lib.caca_remove_dirty_rect(self, x, y, width, height)
  518         except ctypes.ArgumentError:
  519             raise CanvasError("Specified coordinate or size is invalid")
  520         else:
  521             if ret == -1:
  522                 err = ctypes.c_int.in_dll(_lib, "errno")
  523                 if err.value == errno.EINVAL:
  524                     raise CanvasError("Specified rectangle coordinates are out"
  525                                       " of bounds")
  526             else:
  527                 return ret
  528 
  529     def clear_dirty_rect_list(self):
  530         """ Clear a canvas's dirty rectangle list.
  531         """
  532         _lib.caca_clear_dirty_rect_list.argtypes = [_Canvas]
  533         _lib.caca_clear_dirty_rect_list.restype  = ctypes.c_int
  534 
  535         return _lib.caca_clear_dirty_rect_list(self)
  536 
  537     def invert(self):
  538         """ Invert a canvas' colours.
  539         """
  540         _lib.caca_invert.argtypes = [_Canvas]
  541         _lib.caca_invert.restype  = ctypes.c_int
  542 
  543         return _lib.caca_invert(self)
  544 
  545     def flip(self):
  546         """ Flip a canvas horizontally.
  547         """
  548         _lib.caca_flip.argtypes = [_Canvas]
  549         _lib.caca_flip.restype  = ctypes.c_int
  550 
  551         return _lib.caca_flip(self)
  552 
  553     def flop(self):
  554         """ Flip a canvas vertically.
  555         """
  556         _lib.caca_flop.argtypes = [_Canvas]
  557         _lib.caca_flop.restype  = ctypes.c_int
  558 
  559         return _lib.caca_flop(self)
  560 
  561     def rotate_180(self):
  562         """ Rotate a canvas.
  563         """
  564         _lib.caca_rotate_180.argtypes = [_Canvas]
  565         _lib.caca_rotate_180.restype  = ctypes.c_int
  566 
  567         return _lib.caca_rotate_180(self)
  568 
  569     def rotate_left(self):
  570         """ Rotate a canvas, 90 degrees counterclockwise.
  571         """
  572         _lib.caca_rotate_left.argtypes = [_Canvas]
  573         _lib.caca_rotate_left.restype  = ctypes.c_int
  574 
  575         ret = _lib.caca_rotate_left(self)
  576         if ret == -1:
  577             err = ctypes.c_int.in_dll(_lib, "errno")
  578             if err.value == errno.EBUSY:
  579                 raise CanvasError("The canvas is in use by a display driver"
  580                                   " and cannot be rotated")
  581             elif err.value == errno.ENOMEM:
  582                 raise CanvasError("Not enough memory to allocate the new"
  583                                   " canvas size")
  584         else:
  585             return ret
  586 
  587     def rotate_right(self):
  588         """ Rotate a canvas, 90 degrees clockwise.
  589         """
  590         _lib.caca_rotate_right.argtypes = [_Canvas]
  591         _lib.caca_rotate_right.restype  = ctypes.c_int
  592 
  593         ret = _lib.caca_rotate_right(self)
  594         if ret == -1:
  595             err = ctypes.c_int.in_dll(_lib, "errno")
  596             if err.value == errno.EBUSY:
  597                 raise CanvasError("The canvas is in use by a display driver"
  598                                   " and cannot be rotated")
  599             elif err.value == errno.ENOMEM:
  600                 raise CanvasError("Not enough memory to allocate the new"
  601                                   " canvas size")
  602         else:
  603             return ret
  604 
  605     def stretch_left(self):
  606         """ Rotate and stretch a canvas, 90 degrees counterclockwise.
  607         """
  608         _lib.caca_stretch_left.argtypes = [_Canvas]
  609         _lib.caca_stretch_left.restype  = ctypes.c_int
  610 
  611         ret = _lib.caca_stretch_left(self)
  612         if ret == -1:
  613             err = ctypes.c_int.in_dll(_lib, "errno")
  614             if err.value == errno.EBUSY:
  615                 raise CanvasError("The canvas is in use by a display driver"
  616                                   " and cannot be rotated")
  617             elif err.value == errno.ENOMEM:
  618                 raise CanvasError("Not enough memory to allocate the new"
  619                                   " canvas size")
  620         else:
  621             return ret
  622 
  623     def stretch_right(self):
  624         """ Rotate and stretch a canvas, 90 degrees clockwise.
  625         """
  626         _lib.caca_stretch_right.argtypes = [_Canvas]
  627         _lib.caca_stretch_right.restype  = ctypes.c_int
  628 
  629         ret = _lib.caca_stretch_right(self)
  630         if ret == -1:
  631             err = ctypes.c_int.in_dll(_lib, "errno")
  632             if err.value == errno.EBUSY:
  633                 raise CanvasError("The canvas is in use by a display driver"
  634                                   " and cannot be rotated")
  635             elif err.value == errno.ENOMEM:
  636                 raise CanvasError("Not enough memory to allocate the new"
  637                                   " canvas size")
  638         else:
  639             return ret
  640 
  641     def get_attr(self, x, y):
  642         """ Get the text attribute at the given coordinates.
  643 
  644             x   -- X coordinate
  645             y   -- Y coordinate
  646         """
  647         _lib.caca_get_attr.argtypes = [_Canvas, ctypes.c_int, ctypes.c_int]
  648         _lib.caca_get_attr.restype  = ctypes.c_uint32
  649 
  650         try:
  651             ret = _lib.caca_get_attr(self, x, y)
  652         except ctypes.ArgumentError:
  653             raise CanvasError("Specified coordinate X or Y is invalid")
  654         else:
  655             return ret
  656 
  657     def set_attr(self, attr):
  658         """ Set the default character attribute.
  659 
  660             attr    -- the requested attribute value
  661         """
  662         _lib.caca_set_attr.argtypes = [_Canvas, ctypes.c_uint32]
  663         _lib.caca_set_attr.restype  = ctypes.c_int
  664 
  665         try:
  666             ret = _lib.caca_set_attr(self, attr)
  667         except ctypes.ArgumentError:
  668             raise CanvasError("Specified attribute is invalid")
  669         else:
  670             return ret
  671 
  672     def unset_attr(self, attr):
  673         """ Unset the default character attribute.
  674 
  675             attr    -- the requested attribute value
  676         """
  677         _lib.caca_unset_attr.argtypes = [_Canvas, ctypes.c_uint32]
  678         _lib.caca_unset_attr.restype  = ctypes.c_int
  679 
  680         try:
  681             ret = _lib.caca_unset_attr(self, attr)
  682         except ctypes.ArgumentError:
  683             raise CanvasError("Specified attribute is invalid")
  684         else:
  685             return ret
  686 
  687     def toggle_attr(self, attr):
  688         """ Toggle the default character attribute.
  689 
  690             attr -- the requested attribute value
  691         """
  692         _lib.caca_toggle_attr.argtypes = [_Canvas, ctypes.c_uint32]
  693         _lib.caca_toggle_attr.restype  = ctypes.c_int
  694 
  695         try:
  696             ret = _lib.caca_toggle_attr(self, attr)
  697         except ctypes.ArgumentError:
  698             raise CanvasError("Specified attribute is invalid")
  699         else:
  700             return ret
  701 
  702     def put_attr(self, x, y, attr):
  703         """ Set the character attribute at the given coordinates.
  704 
  705             x       -- X coordinate
  706             y       -- Y coordinate
  707             attr    -- the requested attribute value
  708         """
  709         _lib.caca_put_attr.argtypes = [
  710             _Canvas, ctypes.c_int, ctypes.c_int, ctypes.c_uint32
  711         ]
  712         _lib.caca_put_attr.restype  = ctypes.c_int
  713 
  714         try:
  715             ret = _lib.caca_put_attr(self, x, y, attr)
  716         except ctypes.ArgumentError:
  717             raise CanvasError("Specified coordinate or attribute is invalid")
  718         else:
  719             return ret
  720 
  721     def set_color_ansi(self, fg, bg):
  722         """ Set the default colour pair for text (ANSI version).
  723 
  724             fg  -- the requested ANSI foreground colour.
  725             bg  -- the requested ANSI background colour.
  726         """
  727         _lib.caca_set_color_ansi.argtypes = [
  728                 _Canvas, ctypes.c_uint8, ctypes.c_uint8
  729             ]
  730         _lib.caca_set_color_ansi.restype  = ctypes.c_int
  731 
  732         try:
  733             ret = _lib.caca_set_color_ansi(self, fg, bg)
  734         except ctypes.ArgumentError:
  735             raise CanvasError("At least one of the colour values is invalid")
  736         else:
  737             if ret == -1:
  738                 err = ctypes.c_int.in_dll(_lib, "errno")
  739                 if err.value == errno.EINVAL:
  740                     raise CanvasError("At least one of the colour values"
  741                                       " is invalid")
  742             else:
  743                 return ret
  744 
  745     def set_color_argb(self, fg, bg):
  746         """ Set the default colour pair for text (truecolor version).
  747 
  748             fg  -- the requested ARGB foreground colour.
  749             bg  -- the requested ARGB background colour.
  750         """
  751         _lib.caca_set_color_argb.argtypes = [
  752             _Canvas, ctypes.c_uint16, ctypes.c_uint16
  753         ]
  754         _lib.caca_set_color_argb.restype  = ctypes.c_int
  755 
  756         try:
  757             ret = _lib.caca_set_color_argb(self, fg, bg)
  758         except ctypes.ArgumentError:
  759             raise CanvasError("At least one of the colour values is invalid")
  760         else:
  761             return ret
  762 
  763     def draw_line(self, x1, y1, x2, y2, ch):
  764         """ Draw a line on the canvas using the given character.
  765 
  766             x1  -- X coordinate of the first point
  767             y1  -- Y coordinate of the first point
  768             x2  -- X coordinate of the second point
  769             y2  -- Y coordinate of the second point
  770             ch  -- character to be used to draw the line
  771         """
  772         _lib.caca_draw_line.argtypes = [
  773                 _Canvas, ctypes.c_int, ctypes.c_int,
  774                 ctypes.c_int, ctypes.c_int, ctypes.c_uint32
  775             ]
  776         _lib.caca_draw_line.restype  = ctypes.c_int
  777 
  778         if not isinstance(ch, str):
  779             raise CanvasError("Specified character is invalid")
  780         else:
  781             try:
  782                 ch = ord(ch)
  783             except TypeError:
  784                 ch = utf8_to_utf32(ch)
  785 
  786             try:
  787                 ret = _lib.caca_draw_line(self, x1, y1, x2, y2, ch)
  788             except ctypes.ArgumentError:
  789                 raise CanvasError("specified coordinate is invalid")
  790             else:
  791                 return ret
  792 
  793     def draw_polyline(self, array_xy, ch):
  794         """ Draw a polyline.
  795 
  796             array_xy -- List of (X, Y) coordinates
  797             ch       -- character to be used to draw the line
  798         """
  799         if not isinstance(array_xy, list) or len(array_xy) < 2:
  800             raise CanvasError("Specified array of coordinates is invalid")
  801         else:
  802             for item in array_xy:
  803                 if not isinstance(item, list) and \
  804                    not isinstance(item, tuple):
  805                     raise CanvasError("Specified array of coordinates"
  806                                       " is invalid")
  807 
  808         ax = ctypes.c_int * len(array_xy)
  809         ay = ctypes.c_int * len(array_xy)
  810 
  811         _lib.caca_draw_polyline.argtypes = [
  812                 _Canvas, ax, ay, ctypes.c_int, ctypes.c_uint32
  813             ]
  814         _lib.caca_draw_polyline.restype  = ctypes.c_int
  815 
  816         if not isinstance(ch, str):
  817             raise CanvasError("Specified character is invalid")
  818         else:
  819             try:
  820                 ch = ord(ch)
  821             except TypeError:
  822                 ch = utf8_to_utf32(ch)
  823 
  824             try:
  825                 ax = ax(*[x[0] for x in array_xy])
  826                 ay = ay(*[y[1] for y in array_xy])
  827             except IndexError:
  828                 raise CanvasError("Specified array coordinates is invalid")
  829 
  830             try:
  831                 ret = _lib.caca_draw_polyline(self, ax, ay,
  832                                               len(array_xy) - 1, ch)
  833             except ctypes.ArgumentError:
  834                 raise CanvasError("specified array of coordinates is invalid")
  835             else:
  836                 return ret
  837 
  838     def draw_thin_line(self, x1, y1, x2, y2):
  839         """ Draw a thin line on the canvas, using ASCII art.
  840 
  841             x1  -- X coordinate of the first point
  842             y1  -- Y coordinate of the first point
  843             x2  -- X coordinate of the second point
  844             y2  -- Y coordinate of the second point
  845         """
  846         _lib.caca_draw_thin_line.argtypes = [
  847                 _Canvas, ctypes.c_int, ctypes.c_int,
  848                 ctypes.c_int, ctypes.c_int
  849             ]
  850         _lib.caca_draw_thin_line.restype  = ctypes.c_int
  851 
  852         try:
  853             ret = _lib.caca_draw_thin_line(self, x1, y1, x2, y2)
  854         except ctypes.ArgumentError:
  855             raise CanvasError("specified coordinate is invalid")
  856         else:
  857             return ret
  858 
  859     def draw_thin_polyline(self, array_xy):
  860         """ Draw an ASCII art thin polyline.
  861 
  862             array_xy -- Array of (X, Y) coordinates
  863         """
  864         if not isinstance(array_xy, list) or len(array_xy) < 2:
  865             raise CanvasError("Specified array of coordinates is invalid")
  866         else:
  867             for item in array_xy:
  868                 if not isinstance(item, list) and \
  869                    not isinstance(item, tuple):
  870                     raise CanvasError("Specified array of coordinates"
  871                                       " is invalid")
  872 
  873         ax = ctypes.c_int * len(array_xy)
  874         ay = ctypes.c_int * len(array_xy)
  875 
  876         _lib.caca_draw_thin_polyline.argtypes = [
  877                Canvas, ax, ay, ctypes.c_int
  878             ]
  879         _lib.caca_draw_thin_polyline.restype  = ctypes.c_int
  880 
  881         try:
  882             ax = ax(*[x[0] for x in array_xy])
  883             ay = ay(*[y[1] for y in array_xy])
  884         except IndexError:
  885             raise CanvasError("Specified array coordinates is invalid")
  886 
  887         try:
  888             ret = _lib.caca_draw_thin_polyline(self, ax, ay, len(array_xy) - 1)
  889         except ctypes.ArgumentError:
  890             raise CanvasError("specified array of coordinates is invalid")
  891         else:
  892             return ret
  893 
  894     def draw_circle(self, x, y, r, ch):
  895         """ Draw a circle on the canvas using the given character.
  896 
  897             x   -- center X coordinate
  898             y   -- center Y coordinate
  899             r   -- circle radius
  900             ch  -- the UTF-32 character to be used to draw the circle outline
  901         """
  902         _lib.caca_draw_circle.argtypes = [
  903             _Canvas, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_uint32
  904         ]
  905         _lib.caca_draw_circle.restype  = ctypes.c_int
  906 
  907         if not isinstance(ch, str):
  908             raise CanvasError("Specified character is invalid")
  909         else:
  910             try:
  911                 ch = ord(ch)
  912             except TypeError:
  913                 ch = utf8_to_utf32(ch)
  914 
  915         try:
  916             ret = _lib.caca_draw_circle(self, x, y, r, ch)
  917         except ctypes.ArgumentError:
  918             raise CanvasError("Specified circle coordinate or radius is"
  919                               " invalid")
  920         else:
  921             return ret
  922 
  923     def draw_ellipse(self, xo, yo, a, b, ch):
  924         """ Draw an ellipse on the canvas using the given character.
  925 
  926             xo  -- center X coordinate
  927             yo  -- center Y coordinate
  928             a   -- ellipse x radius
  929             b   -- ellipse y radius
  930             ch  -- UTF-32 character to be used to draw the ellipse outline
  931         """
  932         _lib.caca_draw_ellipse.argtypes = [
  933                 _Canvas, ctypes.c_int, ctypes.c_int,
  934                 ctypes.c_int, ctypes.c_int, ctypes.c_uint32
  935             ]
  936         _lib.caca_draw_ellipse.restype  = ctypes.c_int
  937 
  938         if not isinstance(ch, str):
  939             raise CanvasError("Specified character is invalid")
  940         else:
  941             try:
  942                 ch = ord(ch)
  943             except TypeError:
  944                 ch = utf8_to_utf32(ch)
  945 
  946         try:
  947             ret = _lib.caca_draw_ellipse(self, xo, yo, a, b, ch)
  948         except ctypes.ArgumentError:
  949             raise CanvasError("Specified ellipse coordinate or radius is"
  950                               " invalid")
  951         else:
  952             return ret
  953 
  954     def draw_thin_ellipse(self, xo, yo, a, b):
  955         """ Draw a thin ellipse on the canvas.
  956 
  957             xo  -- center X coordinate
  958             yo  -- center Y coordinate
  959             a   -- ellipse X radius
  960             b   -- ellipse Y radius
  961         """
  962         _lib.caca_draw_thin_ellipse.argtypes = [
  963                 _Canvas, ctypes.c_int, ctypes.c_int,
  964                 ctypes.c_int, ctypes.c_int
  965             ]
  966         _lib.caca_draw_thin_ellipse.restype  = ctypes.c_int
  967 
  968         try:
  969             ret = _lib.caca_draw_thin_ellipse(self, xo, yo, a, b)
  970         except ctypes.ArgumentError:
  971             raise CanvasError("Specified ellipse coordinate or radius is"
  972                               " invalid")
  973         else:
  974             return ret
  975 
  976     def fill_ellipse(self, xo, yo, a, b, ch):
  977         """ Fill an ellipse on the canvas using the given character.
  978 
  979             xo  -- center X coordinate
  980             yo  -- center Y coordinate
  981             a   -- ellipse X radius
  982             b   -- ellipse Y radius
  983             ch  -- UTF-32 character to be used to fill the ellipse
  984         """
  985         _lib.caca_fill_ellipse.argtypes = [
  986                 _Canvas, ctypes.c_int, ctypes.c_int,
  987                 ctypes.c_int, ctypes.c_int, ctypes.c_uint32
  988             ]
  989         _lib.caca_fill_ellipse.restype  = ctypes.c_int
  990 
  991         if not isinstance(ch, str):
  992             raise CanvasError("Specified character is invalid")
  993         else:
  994             try:
  995                 ch = ord(ch)
  996             except TypeError:
  997                 ch = utf8_to_utf32(ch)
  998 
  999         try:
 1000             ret = _lib.caca_fill_ellipse(self, xo, yo, a, b, ch)
 1001         except ctypes.ArgumentError:
 1002             raise CanvasError("Specified ellipse coordinate or radius is"
 1003                               " invalid")
 1004         else:
 1005             return ret
 1006 
 1007     def draw_box(self, x, y, width, height, ch):
 1008         """ Draw a box on the canvas using the given character.
 1009 
 1010             x       -- X coordinate of the upper-left corner of the box
 1011             y       -- Y coordinate of the upper-left corner of the box
 1012             width   -- width of the box
 1013             height  -- height of the box
 1014             ch      -- character to be used to draw the box
 1015         """
 1016         _lib.caca_draw_box.argtypes = [
 1017                 Canvas, ctypes.c_int, ctypes.c_int,
 1018                 ctypes.c_int, ctypes.c_int, ctypes.c_uint32
 1019             ]
 1020         _lib.caca_draw_box.restype  = ctypes.c_int
 1021 
 1022         if not isinstance(ch, str):
 1023             raise CanvasError("Specified character is invalid")
 1024         else:
 1025             try:
 1026                 ch = ord(ch)
 1027             except TypeError:
 1028                 ch = utf8_to_utf32(ch)
 1029 
 1030         try:
 1031             ret = _lib.caca_draw_box(self, x, y, width, height, ch)
 1032         except ctypes.ArgumentError:
 1033             raise CanvasError("specified box coordinate is invalid")
 1034         else:
 1035             return ret
 1036 
 1037     def draw_thin_box(self, x, y, width, height):
 1038         """ Draw a thin box on the canvas.
 1039 
 1040             x       -- X coordinate of the upper-left corner of the box
 1041             y       -- Y coordinate of the upper-left corner of the box
 1042             width   -- width of the box
 1043             height  -- height of the box
 1044         """
 1045         _lib.caca_draw_thin_box.argtypes = [
 1046                 _Canvas, ctypes.c_int, ctypes.c_int,
 1047                 ctypes.c_int, ctypes.c_int
 1048             ]
 1049         _lib.caca_draw_thin_box.restype  = ctypes.c_int
 1050 
 1051         try:
 1052             ret = _lib.caca_draw_thin_box(self, x, y, width, height)
 1053         except ctypes.ArgumentError:
 1054             raise CanvasError("specified box coordinate is invalid")
 1055         else:
 1056             return ret
 1057 
 1058     def draw_cp437_box(self, x, y, width, height):
 1059         """ Draw a box on the canvas using CP437 characters.
 1060 
 1061             x       -- X coordinate of the upper-left corner box
 1062             y       -- Y coordinate of the upper-left corner box
 1063             width   -- width of the box
 1064             height  -- height of the box
 1065         """
 1066         _lib.caca_draw_cp437_box.argtypes = [
 1067                 _Canvas, ctypes.c_int, ctypes.c_int,
 1068                 ctypes.c_int, ctypes.c_int
 1069             ]
 1070         _lib.caca_draw_cp437_box.restype  = ctypes.c_int
 1071 
 1072         try:
 1073             ret = _lib.caca_draw_cp437_box(self, x, y, width, height)
 1074         except ctypes.ArgumentError:
 1075             raise CanvasError("specified box coordinate is invalid")
 1076         else:
 1077             return ret
 1078 
 1079     def fill_box(self, x, y, width, height, ch):
 1080         """ Fill a box on the canvas using the given character.
 1081 
 1082             x       -- X coordinate of the upper-left corner of the box
 1083             y       -- Y coordinate of the upper-left corner of the box
 1084             width   -- width of the box
 1085             height  -- height of the box
 1086             ch      -- UFT-32 character to be used to fill the box
 1087         """
 1088         _lib.caca_fill_box.argtypes = [
 1089             _Canvas, ctypes.c_int, ctypes.c_int,
 1090             ctypes.c_int, ctypes.c_int, ctypes.c_uint32
 1091         ]
 1092         _lib.caca_fill_box.restype  = ctypes.c_int
 1093 
 1094         if not isinstance(ch, str):
 1095             raise CanvasError("Specified character is invalid")
 1096         else:
 1097             try:
 1098                 ch = ord(ch)
 1099             except TypeError:
 1100                 ch = utf8_to_utf32(ch)
 1101 
 1102         try:
 1103             ret = _lib.caca_fill_box(self, x, y, width, height, ch)
 1104         except ctypes.ArgumentError:
 1105             raise CanvasError("specified box coordinate is invalid")
 1106         else:
 1107             return ret
 1108 
 1109     def draw_triangle(self, x1, y1, x2, y2, x3, y3, ch):
 1110         """ Draw a triangle on the canvas using the given character.
 1111 
 1112             x1  -- X coordinate of the first point
 1113             y1  -- Y coordinate of the first point
 1114             x2  -- X coordinate of the second point
 1115             y2  -- Y coordinate of the second point
 1116             x3  -- X coordinate of the third point
 1117             y3  -- Y coordinate of the third point
 1118             ch  -- UTF-32 character to be used to draw the triangle outline
 1119         """
 1120         _lib.caca_draw_triangle.argtypes = [
 1121             _Canvas, ctypes.c_int, ctypes.c_int, ctypes.c_int,
 1122             ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_uint32
 1123         ]
 1124         _lib.caca_draw_triangle.restype  = ctypes.c_int
 1125 
 1126         if not isinstance(ch, str):
 1127             raise CanvasError("Specified character is invalid")
 1128         else:
 1129             try:
 1130                 ch = ord(ch)
 1131             except TypeError:
 1132                 ch = utf8_to_utf32(ch)
 1133 
 1134         try:
 1135             ret = _lib.caca_draw_triangle(self, x1, y1, x2, y2, x3, y3, ch)
 1136         except ctypes.ArgumentError:
 1137             raise CanvasError("specified triangle coordinate is invalid")
 1138         else:
 1139             return ret
 1140 
 1141     def draw_thin_triangle(self, x1, y1, x2, y2, x3, y3):
 1142         """ Draw a thin triangle on the canvas.
 1143 
 1144             x1  -- X coordinate of the first point
 1145             y1  -- Y coordinate of the first point
 1146             x2  -- X coordinate of the second point
 1147             y2  -- Y coordinate of the second point
 1148             x3  -- X coordinate of the third point
 1149             y3  -- Y coordinate of the third point
 1150         """
 1151         _lib.caca_draw_thin_triangle.argtypes = [
 1152             _Canvas, ctypes.c_int, ctypes.c_int, ctypes.c_int,
 1153             ctypes.c_int, ctypes.c_int, ctypes.c_int
 1154         ]
 1155         _lib.caca_draw_thin_triangle.restype  = ctypes.c_int
 1156 
 1157         try:
 1158             ret = _lib.caca_draw_thin_triangle(self, x1, y1, x2, y2, x3, y3)
 1159         except ctypes.ArgumentError:
 1160             raise CanvasError("specified triangle coordinate is invalid")
 1161         else:
 1162             return ret
 1163 
 1164     def fill_triangle(self, x1, y1, x2, y2, x3, y3, ch):
 1165         """ Fill a triangle on the canvas using the given character.
 1166 
 1167             x1  -- X coordinate of the first point
 1168             y1  -- Y coordinate of the first point
 1169             x2  -- X coordinate of the second point
 1170             y2  -- Y coordinate of the second point
 1171             x3  -- X coordinate of the second point
 1172             y3  -- Y coordinate of the second point
 1173             ch  -- UTF-32 character to be used to fill the triangle
 1174         """
 1175         _lib.caca_fill_triangle.argtypes = [
 1176             _Canvas, ctypes.c_int, ctypes.c_int, ctypes.c_int,
 1177             ctypes.c_int, ctypes.c_int, ctypes.c_int
 1178         ]
 1179         _lib.caca_fill_triangle.restype  = ctypes.c_int
 1180 
 1181         if not isinstance(ch, str):
 1182             raise CanvasError("Specified character is invalid")
 1183         else:
 1184             try:
 1185                 ch = ord(ch)
 1186             except TypeError:
 1187                 ch = utf8_to_utf32(ch)
 1188 
 1189         try:
 1190             ret = _lib.caca_fill_triangle(self, x1, y1, x2, y2, x3, y3, ch)
 1191         except ctypes.ArgumentError:
 1192             raise CanvasError("specified triangle coordinate is invalid")
 1193         else:
 1194             return ret
 1195 
 1196     def fill_triangle_textured(self, coords, tex, uv):
 1197         """ Fill a triangle on the canvas using an arbitrary-sized texture.
 1198 
 1199             coords  -- coordinates of the triangle (3{x,y})
 1200             tex     -- the handle of the canvas texture
 1201             uv      -- coordinates of the texture  (3{u,v})
 1202         """
 1203         _lib.caca_fill_triangle_textured.argtypes = [
 1204             _Canvas, ctypes.c_int * 6, _Canvas, ctypes.c_int * 6
 1205         ]
 1206         _lib.caca_fill_triangle_textured.restype  = ctypes.c_int
 1207 
 1208         return _lib.caca_fill_triangle_textured(self, coords, tex, uv)
 1209 
 1210     def get_frame_count(self):
 1211         """ Get the number of frames in a canvas.
 1212         """
 1213         _lib.caca_get_frame_count.argtypes = [_Canvas]
 1214         _lib.caca_get_frame_count.restype  = ctypes.c_int
 1215 
 1216         return _lib.caca_get_frame_count(self)
 1217 
 1218     def set_frame(self, idx):
 1219         """ Activate a given canvas frame.
 1220 
 1221             idx -- the canvas frame to activate
 1222         """
 1223         _lib.caca_set_frame.argtypes = [_Canvas, ctypes.c_int]
 1224         _lib.caca_set_frame.restype  = ctypes.c_int
 1225 
 1226         try:
 1227             ret = _lib.caca_set_frame(self, idx)
 1228         except ctypes.ArgumentError:
 1229             raise CanvasError("specified index is invalid")
 1230         else:
 1231             err = ctypes.c_int.in_dll(_lib, "errno")
 1232             if err.value == errno.EINVAL:
 1233                 raise CanvasError("Requested frame is out of range")
 1234             else:
 1235                 return ret
 1236 
 1237     def get_frame_name(self):
 1238         """ Get the current frame's name.
 1239         """
 1240         _lib.caca_get_frame_name.argtypes = [_Canvas]
 1241         _lib.caca_get_frame_name.restype  = ctypes.c_char_p
 1242 
 1243         if _PYTHON3:
 1244             return _bytes_to_str(_lib.caca_get_frame_name(self))
 1245         else:
 1246             return _lib.caca_get_frame_name(self)
 1247 
 1248     def set_frame_name(self, name):
 1249         """ Set the current frame's name.
 1250 
 1251             name    -- the name to give to the current frame
 1252         """
 1253         _lib.caca_set_frame_name.argtypes = [_Canvas, ctypes.c_char_p]
 1254         _lib.caca_set_frame_name.restype  = ctypes.c_int
 1255 
 1256         if _PYTHON3 and isinstance(name, str):
 1257             name = _str_to_bytes(name)
 1258 
 1259         try:
 1260             ret = _lib.caca_set_frame_name(self, name)
 1261         except ctypes.ArgumentError:
 1262             raise CanvasError("Specified name is invalid")
 1263         else:
 1264             err = ctypes.c_int.in_dll(_lib, "errno")
 1265             if err.value == errno.ENOMEM:
 1266                 raise CanvasError("Not enough memory to allocate new frame")
 1267             else:
 1268                 return ret
 1269 
 1270     def create_frame(self, idx):
 1271         """ Add a frame to a canvas.
 1272 
 1273             idx -- the index where to insert the new frame
 1274         """
 1275         _lib.caca_create_frame.argtypes = [_Canvas, ctypes.c_int]
 1276         _lib.caca_create_frame.restype  = ctypes.c_int
 1277 
 1278         try:
 1279             ret = _lib.caca_create_frame(self, idx)
 1280         except ctypes.ArgumentError:
 1281             raise CanvasError("specified index is invalid")
 1282         else:
 1283             err = ctypes.c_int.in_dll(_lib, "errno")
 1284             if err.value == errno.ENOMEM:
 1285                 raise CanvasError("Not enough memory to allocate new frame")
 1286             else:
 1287                 return ret
 1288 
 1289     def free_frame(self, idx):
 1290         """ Remove a frame from a canvas.
 1291 
 1292             idx -- the index of the frame to delete
 1293         """
 1294         _lib.caca_free_frame.argtypes = [_Canvas, ctypes.c_int]
 1295         _lib.caca_free_frame.restype  = ctypes.c_int
 1296 
 1297         try:
 1298             ret = _lib.caca_free_frame(self, idx)
 1299         except ctypes.ArgumentError:
 1300             raise CanvasError("specified index is invalid")
 1301         else:
 1302             err = ctypes.c_int.in_dll(_lib, "errno")
 1303             if err.value == errno.EINVAL:
 1304                 raise CanvasError("Requested frame is out of range, or attempt"
 1305                                   " to delete the last frame of the canvas")
 1306             else:
 1307                 return ret
 1308 
 1309     def import_from_memory(self, data, fmt):
 1310         """ Import a memory buffer into a canvas.
 1311 
 1312             data -- a memory area containing the data to be loaded into
 1313                     the canvas
 1314             fmt  -- a string describing the input format
 1315 
 1316             Valid values for format are:
 1317               - "": attempt to autodetect the file format.
 1318               - caca: import native libcaca files.
 1319               - text: import ASCII text files.
 1320               - ansi: import ANSI files.
 1321               - utf8: import UTF-8 files with ANSI colour codes.
 1322         """
 1323 
 1324         _lib.caca_import_canvas_from_memory.argtypes = [
 1325                 Canvas, ctypes.c_char_p,
 1326                 ctypes.c_size_t, ctypes.c_char_p
 1327             ]
 1328         _lib.caca_import_canvas_from_memory.restype  = ctypes.c_int
 1329 
 1330         if _PYTHON3 and isinstance(data, str):
 1331             data = _str_to_bytes(data)
 1332         if _PYTHON3 and isinstance(fmt, str):
 1333             fmt = _str_to_bytes(fmt)
 1334 
 1335         length = ctypes.c_size_t(len(data))
 1336 
 1337         try:
 1338             ret = _lib.caca_import_canvas_from_memory(self, data, length, fmt)
 1339         except ctypes.ArgumentError:
 1340             raise CanvasError("Given data are invalid")
 1341         else:
 1342             err = ctypes.c_int.in_dll(_lib, "errno")
 1343             if ret == -1:
 1344                 if err.value == errno.ENOMEM:
 1345                     raise CanvasError("Not enough memory to allocate canvas")
 1346                 elif err.value == errno.EINVAL:
 1347                     raise CanvasError("Invalid format requested")
 1348             else:
 1349                 return ret
 1350 
 1351     def import_from_file(self, filename, fmt):
 1352         """ Import a file into a canvas.
 1353 
 1354             filename -- the name of the file to load
 1355             fmt      -- a string describing the input format
 1356 
 1357             Valid values for format are:
 1358               - "": attempt to autodetect the file format.
 1359               - caca: import native libcaca files.
 1360               - text: import ASCII text files.
 1361               - ansi: import ANSI files.
 1362               - utf8: import UTF-8 files with ANSI colour codes.
 1363         """
 1364         _lib.caca_import_canvas_from_file.argtypes = [
 1365             _Canvas, ctypes.c_char_p, ctypes.c_char_p
 1366         ]
 1367         _lib.caca_import_canvas_from_file.restype  = ctypes.c_int
 1368 
 1369         if _PYTHON3 and isinstance(filename, str):
 1370             filename = _str_to_bytes(filename)
 1371         if _PYTHON3 and isinstance(fmt, str):
 1372             fmt = _str_to_bytes(fmt)
 1373 
 1374         try:
 1375             ret = _lib.caca_import_canvas_from_file(self, filename, fmt)
 1376         except ctypes.ArgumentError:
 1377             raise CanvasError("Specified filename is invalid")
 1378         else:
 1379             err = ctypes.c_int.in_dll(_lib, "errno")
 1380             if ret == -1:
 1381                 if err.value == errno.ENOSYS:
 1382                     raise CanvasError("File access is not implemented on this"
 1383                                       " system")
 1384                 elif err.value == errno.ENOMEM:
 1385                     raise CanvasError("Not enough memory to allocate canvas")
 1386                 elif err.value == errno.EINVAL:
 1387                     raise CanvasError("Invalid format requested")
 1388             else:
 1389                 return ret
 1390 
 1391     def import_area_from_memory(self, x, y, data, fmt):
 1392         """ Import a memory buffer into a canvas area.
 1393 
 1394             x    -- the leftmost coordinate of the area to import to
 1395             y    -- the topmost coordinate of the area to import to
 1396             data -- a memory area containing the data to be loaded into
 1397                     the canvas
 1398             fmt  -- a string describing the input format
 1399 
 1400             Valid values for format are:
 1401               - "": attempt to autodetect the file format.
 1402               - caca: import native libcaca files.
 1403               - text: import ASCII text files.
 1404               - ansi: import ANSI files.
 1405               - utf8: import UTF-8 files with ANSI colour codes.
 1406         """
 1407         length = ctypes.c_size_t(len(data))
 1408 
 1409         _lib.caca_import_area_from_memory.argtypes = [
 1410                 _Canvas, ctypes.c_int, ctypes.c_int,
 1411                 ctypes.c_char_p, ctypes.c_size_t, ctypes.c_char_p
 1412             ]
 1413         _lib.caca_import_area_from_memory.restype  = ctypes.c_int
 1414 
 1415         if _PYTHON3 and isinstance(data, str):
 1416             data = _str_to_bytes(data)
 1417         if _PYTHON3 and isinstance(fmt, str):
 1418             fmt = _str_to_bytes(fmt)
 1419 
 1420         try:
 1421             ret = _lib.caca_import_area_from_memory(self, x, y,
 1422                                                     data, length, fmt)
 1423         except ctypes.ArgumentError:
 1424             raise CanvasError("Specified coordinate X or Y is invalid")
 1425         else:
 1426             if ret == -1:
 1427                 err = ctypes.c_int.in_dll(_lib, "errno")
 1428                 if err.value == errno.EINVAL:
 1429                     raise CanvasError("Unsupported format requested or"
 1430                                       " invalid coordinates")
 1431                 elif err.value == errno.ENOMEM:
 1432                     raise CanvasError("Not enough memory to allocate canvas")
 1433             else:
 1434                 return ret
 1435 
 1436     def import_area_from_file(self, x, y, filename, fmt):
 1437         """ Import a file into a canvas area.
 1438 
 1439             x        -- the leftmost coordinate of the area to import to
 1440             y        -- the topmost coordinate of the area to import to
 1441             filename -- the name of the file to be load
 1442             fmt      -- a string describing the input format
 1443 
 1444             Valid values for format are:
 1445               - "": attempt to autodetect the file format.
 1446               - caca: import native libcaca files.
 1447               - text: import ASCII text files.
 1448               - ansi: import ANSI files.
 1449               - utf8: import UTF-8 files with ANSI colour codes.
 1450         """
 1451         _lib.caca_import_area_from_file.argtypes = [
 1452                 _Canvas, ctypes.c_int, ctypes.c_int,
 1453                 ctypes.c_char_p, ctypes.c_char_p
 1454             ]
 1455         _lib.caca_import_area_from_file.restype  = ctypes.c_int
 1456 
 1457         if _PYTHON3 and isinstance(filename, str):
 1458             filename = _str_to_bytes(filename)
 1459         if _PYTHON3 and isinstance(fmt, str):
 1460             fmt = _str_to_bytes(fmt)
 1461 
 1462         try:
 1463             ret = _lib.caca_import_area_from_file(self, x, y, filename, fmt)
 1464         except ctypes.ArgumentError:
 1465             raise CanvasError("Specified coordinate X or Y is invalid")
 1466         else:
 1467             if ret == -1:
 1468                 err = ctypes.c_int.in_dll(_lib, "errno")
 1469                 if err.value == errno.ENOSYS:
 1470                     raise CanvasError("File access is not implemented on this"
 1471                                       " system")
 1472                 elif err.value == errno.ENOMEM:
 1473                     raise CanvasError("Not enough memory to allocate canvas")
 1474                 elif err.value == errno.EINVAL:
 1475                     raise CanvasError("Unsupported format requested or"
 1476                                       " invalid coordinates")
 1477             else:
 1478                 return ret
 1479 
 1480     def export_to_memory(self, fmt):
 1481         """ Export a canvas into a foreign format.
 1482 
 1483             fmt -- a string describing the output format
 1484 
 1485             Valid values for format are:
 1486               - caca: export native libcaca files.
 1487               - ansi: export ANSI art (CP437 charset with ANSI colour codes).
 1488               - html: export an HTML page with CSS information.
 1489               - html3: export an HTML table that should be compatible with
 1490                        most navigators, including textmode ones.
 1491               - irc: export UTF-8 text with mIRC colour codes.
 1492               - ps: export a PostScript document.
 1493               - svg: export an SVG vector image.
 1494               - tga: export a TGA image.
 1495         """
 1496         p_size_t = ctypes.POINTER(ctypes.c_size_t)
 1497         _lib.caca_export_canvas_to_memory.argtypes = [
 1498                 _Canvas, ctypes.c_char_p, p_size_t
 1499             ]
 1500         _lib.caca_export_canvas_to_memory.restype  = ctypes.POINTER(
 1501                                                         ctypes.c_char_p)
 1502 
 1503         p = ctypes.c_size_t()
 1504 
 1505         if _PYTHON3 and isinstance(fmt, str):
 1506             fmt = _str_to_bytes(fmt)
 1507 
 1508         try:
 1509             ret = _lib.caca_export_canvas_to_memory(self, fmt, p)
 1510         except ctypes.ArgumentError:
 1511             raise CanvasError("Invalid format requested")
 1512         else:
 1513             if not ret:
 1514                 err = ctypes.c_int.in_dll(_lib, "errno")
 1515                 if err.value == errno.EINVAL:
 1516                     raise CanvasError("Invalid format requested")
 1517                 elif err.value == errno.ENOMEM:
 1518                     raise CanvasError("Not enough memory to allocate output"
 1519                                       " buffer")
 1520             else:
 1521                 if _PYTHON3:
 1522                     return _bytes_to_str(ctypes.string_at(ret, p.value))
 1523                 else:
 1524                     return ctypes.string_at(ret, p.value)
 1525 
 1526     def export_area_to_memory(self, x, y, width, height, fmt):
 1527         """ Export a canvas portion into a foreign format.
 1528 
 1529             x       -- the leftmost coordinate of the area to export
 1530             y       -- the topmost coordinate of the area to export
 1531             width   -- the width of the area to export
 1532             height  -- the height of the area to export
 1533             fmt     -- a string describing the output format
 1534 
 1535             Valid values for format are:
 1536               - caca: export native libcaca files.
 1537               - ansi: export ANSI art (CP437 charset with ANSI colour codes).
 1538               - html: export an HTML page with CSS information.
 1539               - html3: export an HTML table that should be compatible with
 1540                        most navigators, including textmode ones.
 1541               - irc: export UTF-8 text with mIRC colour codes.
 1542               - ps: export a PostScript document.
 1543               - svg: export an SVG vector image.
 1544               - tga: export a TGA image.
 1545         """
 1546         p_size_t = ctypes.POINTER(ctypes.c_size_t)
 1547 
 1548         _lib.caca_export_area_to_memory.argtypes = [
 1549                 _Canvas, ctypes.c_int, ctypes.c_int, ctypes.c_int,
 1550                 ctypes.c_int, ctypes.c_char_p, p_size_t
 1551             ]
 1552         _lib.caca_export_area_to_memory.restype  = ctypes.POINTER(ctypes.c_char_p)
 1553 
 1554         p = ctypes.c_size_t()
 1555 
 1556         if _PYTHON3 and isinstance(fmt, str):
 1557             fmt = _str_to_bytes(fmt)
 1558 
 1559         try:
 1560             ret = _lib.caca_export_area_to_memory(self, x, y, width, height,
 1561                                                   fmt, p)
 1562         except ctypes.ArgumentError:
 1563             raise CanvasError("Requested area coordinate is invalid")
 1564         else:
 1565             if not ret:
 1566                 err = ctypes.c_int.in_dll(_lib, "errno")
 1567                 if err.value == errno.EINVAL:
 1568                     raise CanvasError("Invalid format requested")
 1569                 elif err.value == errno.ENOMEM:
 1570                     raise CanvasError("Not enough memory to allocate output"
 1571                                       " buffer")
 1572             else:
 1573                 if _PYTHON3:
 1574                     return _bytes_to_str(ctypes.string_at(ret, p.value))
 1575                 else:
 1576                     return ctypes.string_at(ret, p.value)
 1577 
 1578     def set_figfont(self, filename):
 1579         """ Load a figfont and attach it to a canvas.
 1580 
 1581             filename    -- the figfont file to load.
 1582         """
 1583         _lib.caca_canvas_set_figfont.argtypes = [_Canvas, ctypes.c_char_p]
 1584         _lib.caca_canvas_set_figfont.restype  = ctypes.c_int
 1585 
 1586         if _PYTHON3 and isinstance(filename, str):
 1587             filename = _str_to_bytes(filename)
 1588 
 1589         return _lib.caca_canvas_set_figfont(self, filename)
 1590 
 1591     def put_figchar(self, ch):
 1592         """ Paste a character using the current figfont.
 1593 
 1594             ch  -- the character to paste
 1595         """
 1596         _lib.caca_put_figchar.argtypes = [_Canvas, ctypes.c_uint32]
 1597         _lib.caca_put_figchar.restype  = ctypes.c_int
 1598 
 1599         if _PYTHON3 and isinstance(ch, str):
 1600             ch = _str_to_bytes(ch)
 1601 
 1602         try:
 1603             ch = ord(ch)
 1604         except TypeError:
 1605             ch = utf8_to_utf32(ch)
 1606 
 1607         return _lib.caca_put_figchar(self, ch)
 1608 
 1609     def flush_figlet(self):
 1610         """ Flush the figlet context
 1611         """
 1612         _lib.caca_flush_figlet.argtypes = [_Canvas]
 1613         _lib.caca_flush_figlet.restype  = ctypes.c_int
 1614 
 1615         return _lib.caca_flush_figlet(self)
 1616 
 1617     def render(self, font, buf, width, height, pitch):
 1618         """ Render the canvas onto an image buffer.
 1619 
 1620             font    -- a Font() object
 1621             buf     -- the image buffer
 1622             width   -- the width (in pixels) of the image
 1623             heigth  -- the height (in pixels) of the image
 1624             pitch   -- the pitch (in bytes) of the image
 1625         """
 1626         _lib.caca_render_canvas.argtypes = [
 1627             _Canvas, _Font, ctypes.c_char_p,
 1628             ctypes.c_int, ctypes.c_int, ctypes.c_int
 1629         ]
 1630         _lib.caca_render_canvas.restype  = ctypes.c_int
 1631 
 1632         return _lib.caca_render_canvas(self, font, buf, width, height, pitch)
 1633 
 1634 class NullCanvas(_Canvas):
 1635     """ Represent a NULL canvas_t, eg to use as canvas mask for blit operations.
 1636     """
 1637     def __str__(self):
 1638         return "<NullCanvas>"
 1639 
 1640 class CanvasError(Exception):
 1641     pass
 1642