source: libcaca/trunk/python/caca/canvas.py @ 4800

Last change on this file since 4800 was 4800, checked in by alxf, 3 years ago

Drop tabs and trailing spaces.

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