source: libcaca/trunk/ruby/caca-canvas.c @ 3587

Last change on this file since 3587 was 3587, checked in by sam, 5 years ago

Rename caca_get_cursor_x() and caca_get_cursor_y() to caca_wherex() and
caca_wherey(), in order to match the old <conio.h> naming scheme.

  • Property svn:eol-style set to native
File size: 17.8 KB
Line 
1/*
2 *  libcaca Ruby bindings
3 *  Copyright (c) 2007 Pascal Terjan <pterjan@linuxfr.org>
4 *
5 *  This library is free software. It comes without any warranty, to
6 *  the extent permitted by applicable law. You can redistribute it
7 *  and/or modify it under the terms of the Do What The Fuck You Want
8 *  To Public License, Version 2, as published by Sam Hocevar. See
9 *  http://sam.zoy.org/wtfpl/COPYING for more details.
10 */
11
12#include <ruby.h>
13#include <caca.h>
14#include <errno.h>
15#include "caca-dither.h"
16#include "caca-font.h"
17#include "common.h"
18
19VALUE cCanvas;
20
21#define simple_func(x)                                  \
22static VALUE x (VALUE self)                             \
23{                                                       \
24    if( caca_##x (_SELF) <0)                            \
25        rb_raise(rb_eRuntimeError, strerror(errno));    \
26                                                        \
27    return self;                                        \
28}
29
30#define get_int(x)                                      \
31static VALUE get_##x (VALUE self)                       \
32{                                                       \
33    return INT2NUM(caca_get_##x (_SELF));               \
34}
35
36static void canvas_free(void * p)
37{
38    caca_free_canvas((caca_canvas_t *)p);
39}
40
41static VALUE canvas_alloc(VALUE klass)
42{
43    VALUE obj;
44    obj = Data_Wrap_Struct(klass, NULL, canvas_free, NULL);
45    return obj;
46}
47
48VALUE canvas_create(caca_canvas_t *canvas)
49{
50    return Data_Wrap_Struct(cCanvas, NULL, NULL, canvas);
51}
52
53static VALUE canvas_initialize(VALUE self, VALUE width, VALUE height)
54{
55    caca_canvas_t *canvas;
56
57    canvas = caca_create_canvas(NUM2INT(width), NUM2INT(height));
58
59    if(canvas == NULL)
60    {
61        rb_raise(rb_eRuntimeError, strerror(errno));
62    }
63
64    _SELF = canvas;
65
66    return self;
67}
68
69get_int(canvas_height)
70get_int(canvas_width)
71
72static VALUE set_canvas_width(VALUE self, VALUE width)
73{
74    caca_set_canvas_size(_SELF, NUM2INT(width), caca_get_canvas_height(_SELF));
75    return width;
76}
77
78static VALUE set_canvas_width2(VALUE self, VALUE width)
79{
80    set_canvas_width(self, width);
81    return self;
82}
83
84static VALUE set_canvas_height(VALUE self, VALUE height)
85{
86    caca_set_canvas_size(_SELF, caca_get_canvas_width(_SELF), NUM2INT(height));
87    return height;
88}
89
90static VALUE set_canvas_height2(VALUE self, VALUE height)
91{
92    set_canvas_height(self, height);
93    return self;
94}
95
96static VALUE set_canvas_size(VALUE self, VALUE height, VALUE width)
97{
98    caca_set_canvas_size(_SELF, NUM2INT(width), NUM2INT(height));
99    return self;
100}
101
102/****/
103
104static VALUE gotoxy(VALUE self, VALUE x, VALUE y)
105{
106    if( caca_gotoxy(_SELF, NUM2INT(x), NUM2INT(y)) <0) {
107        rb_raise(rb_eRuntimeError, strerror(errno));
108    }
109    return self;
110}
111
112static VALUE wherex(VALUE self)
113{
114    return INT2NUM(caca_wherex(_SELF));
115}
116
117static VALUE wherey(VALUE self)
118{
119    return INT2NUM(caca_wherey(_SELF));
120}
121
122simple_func(clear_canvas)
123
124static VALUE put_char(VALUE self, VALUE x, VALUE y, VALUE ch)
125{
126    caca_put_char(_SELF, NUM2INT(x), NUM2INT(y), NUM2ULONG(ch));
127    return self;
128}
129
130static VALUE get_char(VALUE self, VALUE x, VALUE y)
131{
132    unsigned long int ch;
133    ch = caca_get_char(_SELF, NUM2INT(x), NUM2INT(y));
134    return INT2NUM(ch);
135}
136
137static VALUE put_str(VALUE self, VALUE x, VALUE y, VALUE str)
138{
139    caca_put_str(_SELF, NUM2INT(x), NUM2INT(y), StringValuePtr(str));
140    return self;
141}
142
143static VALUE get_attr(VALUE self, VALUE x, VALUE y)
144{
145    unsigned long int ch;
146    ch = caca_get_attr(_SELF, NUM2INT(x), NUM2INT(y));
147    return INT2NUM(ch);
148}
149
150static VALUE set_attr(VALUE self, VALUE attr)
151{
152    if(caca_set_attr(_SELF, NUM2ULONG(attr)) <0)
153        rb_raise(rb_eRuntimeError, strerror(errno));
154
155    return self;
156}
157
158static VALUE set_attr2(VALUE self, VALUE attr)
159{
160    set_attr(self, attr);
161    return self;
162}
163
164static VALUE put_attr(VALUE self, VALUE x, VALUE y, VALUE attr)
165{
166    if(caca_put_attr(_SELF, NUM2INT(x), NUM2INT(y), NUM2ULONG(attr)) <0)
167        rb_raise(rb_eRuntimeError, strerror(errno));
168
169    return self;
170}
171
172static VALUE set_color_ansi(VALUE self, VALUE fg, VALUE bg)
173{
174    if(caca_set_color_ansi(_SELF, NUM2INT(fg), NUM2INT(bg)) <0)
175        rb_raise(rb_eRuntimeError, strerror(errno));
176
177    return self;
178}
179
180static VALUE set_color_argb(VALUE self, VALUE fg, VALUE bg)
181{
182    if(caca_set_color_argb(_SELF, NUM2UINT(fg), NUM2UINT(bg)) <0) {
183        rb_raise(rb_eRuntimeError, strerror(errno));
184    }
185    return self;
186}
187
188static VALUE cprintf(int argc, VALUE* argv, VALUE self)
189{
190    int x, y;
191    VALUE rx, ry, format, rest, string;
192    rb_scan_args(argc, argv, "3*", &rx, &ry, &format, &rest);
193    x = NUM2INT(rx);
194    y = NUM2INT(ry);
195    string = rb_funcall2(rb_mKernel, rb_intern("sprintf"), argc-2, argv+2);
196    caca_put_str(_SELF, x, y, StringValuePtr(string));
197    return self;
198}
199
200
201get_int(canvas_handle_x)
202get_int(canvas_handle_y)
203
204static VALUE set_canvas_handle(VALUE self, VALUE x, VALUE y)
205{
206    caca_set_canvas_handle(_SELF, NUM2INT(x), NUM2INT(y));
207    return self;
208}
209
210static VALUE blit(int argc, VALUE* argv, VALUE self) {
211    VALUE x, y, src, mask;
212    caca_canvas_t *csrc, *cmask;
213
214    rb_scan_args(argc, argv, "31", &x, &y, &src, &mask);
215
216    Check_Type(x, T_FIXNUM);
217    Check_Type(y, T_FIXNUM);
218
219    if(CLASS_OF(src) != cCanvas)
220    {
221        rb_raise(rb_eArgError, "src is not a Caca::Canvas");
222    }
223    Data_Get_Struct(src, caca_canvas_t, csrc);
224
225    if(!NIL_P(mask))
226    {
227        if(CLASS_OF(mask) != cCanvas)
228        {
229            rb_raise(rb_eArgError, "mask is not a Caca::Canvas");
230        }
231        Data_Get_Struct(mask, caca_canvas_t, cmask);
232    }
233    else
234        cmask = NULL;
235
236    if(caca_blit(_SELF, NUM2INT(x), NUM2INT(y), csrc, cmask)<0)
237        rb_raise(rb_eRuntimeError, strerror(errno));
238
239    return self;
240}
241
242static VALUE set_canvas_boundaries(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
243{
244    if(caca_set_canvas_boundaries(_SELF, NUM2INT(x), NUM2INT(y), NUM2UINT(w), NUM2UINT(h))<0)
245    {
246        rb_raise(rb_eRuntimeError, strerror(errno));
247    }
248    return self;
249}
250
251/****/
252
253simple_func(invert)
254simple_func(flip)
255simple_func(flop)
256simple_func(rotate_180)
257simple_func(rotate_left)
258simple_func(rotate_right)
259simple_func(stretch_left)
260simple_func(stretch_right)
261
262/****/
263
264static VALUE draw_line(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE ch)
265{
266    caca_draw_line(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),NUM2ULONG(ch));
267    return self;
268}
269
270static VALUE draw_polyline(VALUE self, VALUE points, VALUE ch)
271{
272    int i, n;
273    int *ax, *ay;
274    int error = 0;
275    VALUE v, x, y;
276
277    n = RARRAY(points)->len;
278
279    ax = (int*)malloc(n*sizeof(int));
280    if(!ax)
281        rb_raise(rb_eNoMemError,"Out of memory");
282
283    ay = (int*)malloc(n*sizeof(int));
284    if(!ay)
285    {
286        free(ax);
287        rb_raise(rb_eNoMemError,"Out of memory");
288    }
289
290    for(i=0; i<n; i++)
291    {
292        v = rb_ary_entry(points, i);
293        if((TYPE(v) == T_ARRAY) && (RARRAY(v)->len == 2))
294        {
295            x = rb_ary_entry(v,0);
296            y = rb_ary_entry(v,1);
297            if(rb_obj_is_kind_of(x, rb_cInteger) &&
298               rb_obj_is_kind_of(y, rb_cInteger))
299            {
300                ax[i] = NUM2INT(x);
301                ay[i] = NUM2INT(y);
302            } else
303                error = 1;
304        }
305        else
306            error = 1;
307    }
308
309    if(error)
310    {
311        free(ax);
312        free(ay);
313        rb_raise(rb_eArgError, "Invalid list of points");
314    }
315
316    n--;
317
318    caca_draw_polyline(_SELF, ax, ay, n, NUM2ULONG(ch));
319
320    free(ax);
321    free(ay);
322
323    return self;
324}
325
326static VALUE draw_thin_line(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2)
327{
328    caca_draw_thin_line(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2));
329    return self;
330}
331
332static VALUE draw_thin_polyline(VALUE self, VALUE points)
333{
334    int i, n;
335    int *ax, *ay;
336    int error = 0;
337    VALUE v, x, y;
338
339    n = RARRAY(points)->len;
340
341    ax = (int*)malloc(n*sizeof(int));
342    if(!ax)
343        rb_raise(rb_eNoMemError,"Out of memory");
344
345    ay = (int*)malloc(n*sizeof(int));
346    if(!ay)
347    {
348        free(ax);
349        rb_raise(rb_eNoMemError,"Out of memory");
350    }
351
352    for(i=0; i<n; i++)
353    {
354        v = rb_ary_entry(points, i);
355        if((TYPE(v) == T_ARRAY) && (RARRAY(v)->len == 2))
356        {
357            x = rb_ary_entry(v,0);
358            y = rb_ary_entry(v,1);
359            if(rb_obj_is_kind_of(x, rb_cInteger) &&
360               rb_obj_is_kind_of(y, rb_cInteger))
361            {
362                ax[i] = NUM2INT(x);
363                ay[i] = NUM2INT(y);
364            } else
365                error = 1;
366        }
367        else
368            error = 1;
369    }
370
371    if(error)
372    {
373        free(ax);
374        free(ay);
375        rb_raise(rb_eArgError, "Invalid list of points");
376    }
377
378    n--;
379
380    caca_draw_thin_polyline(_SELF, ax, ay, n);
381
382    free(ax);
383    free(ay);
384
385    return self;
386}
387
388static VALUE draw_circle(VALUE self, VALUE x, VALUE y, VALUE r, VALUE ch)
389{
390    caca_draw_circle(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(r), NUM2ULONG(ch));
391    return self;
392}
393
394static VALUE draw_ellipse(VALUE self, VALUE x, VALUE y, VALUE a, VALUE b, VALUE ch)
395{
396    caca_draw_ellipse(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(a), NUM2INT(b), NUM2ULONG(ch));
397    return self;
398}
399
400static VALUE draw_thin_ellipse(VALUE self, VALUE x, VALUE y, VALUE a, VALUE b)
401{
402    caca_draw_thin_ellipse(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(a), NUM2INT(b));
403    return self;
404}
405
406static VALUE fill_ellipse(VALUE self, VALUE x, VALUE y, VALUE a, VALUE b, VALUE ch)
407{
408    caca_fill_ellipse(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(a), NUM2INT(b), NUM2ULONG(ch));
409    return self;
410}
411
412static VALUE draw_box(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h, VALUE ch)
413{
414    caca_draw_box(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h), NUM2ULONG(ch));
415    return self;
416}
417
418static VALUE draw_thin_box(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
419{
420    caca_draw_thin_box(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
421    return self;
422}
423
424static VALUE draw_cp437_box(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
425{
426    caca_draw_cp437_box(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
427    return self;
428}
429
430static VALUE fill_box(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h, VALUE ch)
431{
432    caca_fill_box(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h), NUM2ULONG(ch));
433    return self;
434}
435
436static VALUE draw_triangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3, VALUE ch)
437{
438    caca_draw_triangle(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),  NUM2INT(x3), NUM2INT(y3), NUM2ULONG(ch));
439    return self;
440}
441
442static VALUE draw_thin_triangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3)
443{
444    caca_draw_thin_triangle(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),  NUM2INT(x3), NUM2INT(y3));
445    return self;
446}
447
448static VALUE fill_triangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3, VALUE ch)
449{
450    caca_fill_triangle(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),  NUM2INT(x3), NUM2INT(y3), NUM2ULONG(ch));
451    return self;
452}
453
454static VALUE dither_bitmap(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h, VALUE d, VALUE pixels)
455{
456    if(CLASS_OF(d) != cDither)
457        rb_raise(rb_eArgError, "d is not a Caca::Dither");
458    Check_Type(pixels, T_STRING);
459
460    caca_dither_bitmap(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h), DATA_PTR(d), StringValuePtr(pixels));
461    return self;
462}
463
464/****/
465
466get_int(frame_count)
467
468static VALUE set_frame(VALUE self, VALUE id)
469{
470    if(caca_set_frame(_SELF, NUM2INT(id))<0)
471        rb_raise(rb_eArgError, strerror(errno));
472
473    return self;
474}
475
476static VALUE set_frame2(VALUE self, VALUE id)
477{
478    set_frame(self, id);
479    return self;
480}
481
482static VALUE get_frame_name(VALUE self)
483{
484    return rb_str_new2(caca_get_frame_name(_SELF));
485}
486
487static VALUE set_frame_name(VALUE self, VALUE name)
488{
489    if(caca_set_frame_name(_SELF, StringValuePtr(name))<0)
490        rb_raise(rb_eRuntimeError, strerror(errno));
491
492    return self;
493}
494
495static VALUE set_frame_name2(VALUE self, VALUE name)
496{
497    set_frame_name(self, name);
498    return self;
499}
500
501static VALUE create_frame(VALUE self, VALUE id)
502{
503    if(caca_create_frame(_SELF, NUM2INT(id))<0) {
504        rb_raise(rb_eRuntimeError, strerror(errno));
505    }
506    return self;
507}
508
509static VALUE free_frame(VALUE self, VALUE id)
510{
511    if(caca_free_frame(_SELF, NUM2INT(id))<0) {
512        rb_raise(rb_eArgError, strerror(errno));
513    }
514    return self;
515}
516
517/****/
518
519static VALUE render_canvas(VALUE self, VALUE font, VALUE width, VALUE height, VALUE pitch)
520{
521    void *buf;
522    caca_font_t *f;
523    VALUE b;
524
525    if(CLASS_OF(font) != cFont)
526    {
527        rb_raise(rb_eArgError, "First argument is not a Caca::Font");
528    }
529
530    buf = malloc(width*height*4);
531    if(buf == NULL)
532    {
533        rb_raise(rb_eNoMemError, "Out of memory");
534    }
535
536    f = DATA_PTR(font);
537    caca_render_canvas(_SELF, f, buf, NUM2UINT(width), NUM2UINT(height), NUM2UINT(pitch));
538
539    b = rb_str_new(buf, width*height*4);
540    free(buf);
541    return b;
542}
543
544static VALUE import_from_memory(VALUE self, VALUE data, VALUE format)
545{
546    long int bytes;
547    bytes = caca_import_canvas_from_memory (_SELF, StringValuePtr(data), RSTRING(StringValue(data))->len, StringValuePtr(format));
548    if(bytes <= 0)
549        rb_raise(rb_eRuntimeError, strerror(errno));
550
551    return self;
552}
553
554static VALUE import_from_file(VALUE self, VALUE filename, VALUE format)
555{
556    long int bytes;
557    bytes = caca_import_canvas_from_file (_SELF, StringValuePtr(filename), StringValuePtr(format));
558    if(bytes <= 0)
559        rb_raise(rb_eRuntimeError, strerror(errno));
560
561    return self;
562}
563
564static VALUE export_to_memory(VALUE self, VALUE format)
565{
566    size_t bytes;
567    void *result;
568    VALUE ret;
569    result = caca_export_canvas_to_memory (_SELF, StringValuePtr(format), &bytes);
570    ret = rb_str_new(result, bytes);
571    free(result);
572    return ret;
573}
574
575get_singleton_double_list(export)
576get_singleton_double_list(import)
577
578/****/
579
580void Init_caca_canvas(VALUE mCaca)
581{
582    cCanvas = rb_define_class_under(mCaca, "Canvas", rb_cObject);
583    rb_define_alloc_func(cCanvas, canvas_alloc);
584
585    rb_define_method(cCanvas, "initialize", canvas_initialize, 2);
586    rb_define_method(cCanvas, "width", get_canvas_width, 0);
587    rb_define_method(cCanvas, "width=", set_canvas_width, 1);
588    rb_define_method(cCanvas, "set_width", set_canvas_width2, 1);
589    rb_define_method(cCanvas, "height", get_canvas_height, 0);
590    rb_define_method(cCanvas, "height=", set_canvas_height, 1);
591    rb_define_method(cCanvas, "set_height", set_canvas_height2, 1);
592    rb_define_method(cCanvas, "set_size", set_canvas_size, 2);
593
594    rb_define_method(cCanvas, "gotoxy", gotoxy, 2);
595    rb_define_method(cCanvas, "wherex", wherex, 0);
596    rb_define_method(cCanvas, "wherey", wherey, 0);
597    rb_define_method(cCanvas, "handle_x", get_canvas_handle_x, 0);
598    rb_define_method(cCanvas, "handle_y", get_canvas_handle_y, 0);
599    rb_define_method(cCanvas, "set_handle", set_canvas_handle, 2);
600    rb_define_method(cCanvas, "blit", blit, -1);
601    rb_define_method(cCanvas, "set_boundaries", set_canvas_boundaries, 4);
602
603    rb_define_method(cCanvas, "clear", clear_canvas, 0);
604
605    rb_define_method(cCanvas, "put_char", put_char, 3);
606    rb_define_method(cCanvas, "get_char", get_char, 2);
607    rb_define_method(cCanvas, "put_str", put_str, 3);
608    rb_define_method(cCanvas, "printf", cprintf, -1);
609
610    rb_define_method(cCanvas, "get_attr", get_attr, 3);
611    rb_define_method(cCanvas, "attr=", set_attr, 1);
612    rb_define_method(cCanvas, "set_attr", set_attr2, 1);
613    rb_define_method(cCanvas, "put_attr", put_attr, 3);
614    rb_define_method(cCanvas, "set_color_ansi", set_color_ansi, 2);
615    rb_define_method(cCanvas, "set_color_argb", set_color_argb, 2);
616
617    rb_define_method(cCanvas, "invert", invert, 0);
618    rb_define_method(cCanvas, "flip", flip, 0);
619    rb_define_method(cCanvas, "flop", flop, 0);
620    rb_define_method(cCanvas, "rotate_180", rotate_180, 0);
621    rb_define_method(cCanvas, "rotate_left", rotate_left, 0);
622    rb_define_method(cCanvas, "rotate_right", rotate_right, 0);
623    rb_define_method(cCanvas, "stretch_left", stretch_left, 0);
624    rb_define_method(cCanvas, "stretch_right", stretch_right, 0);
625
626    rb_define_method(cCanvas, "draw_line", draw_line, 5);
627    rb_define_method(cCanvas, "draw_polyline", draw_polyline, 2);
628    rb_define_method(cCanvas, "draw_thin_line", draw_thin_line, 4);
629    rb_define_method(cCanvas, "draw_thin_polyline", draw_thin_polyline, 1);
630    rb_define_method(cCanvas, "draw_circle", draw_circle, 4);
631    rb_define_method(cCanvas, "draw_ellipse", draw_ellipse, 5);
632    rb_define_method(cCanvas, "draw_thin_ellipse", draw_thin_ellipse, 4);
633    rb_define_method(cCanvas, "fill_ellipse", fill_ellipse, 5);
634    rb_define_method(cCanvas, "draw_box", draw_box, 5);
635    rb_define_method(cCanvas, "draw_thin_box", draw_thin_box, 4);
636    rb_define_method(cCanvas, "draw_cp437_box", draw_cp437_box, 4);
637    rb_define_method(cCanvas, "fill_box", fill_box, 5);
638    rb_define_method(cCanvas, "draw_triangle", draw_triangle, 7);
639    rb_define_method(cCanvas, "draw_thin_triangle", draw_thin_triangle, 6);
640    rb_define_method(cCanvas, "fill_triangle", fill_triangle, 7);
641    rb_define_method(cCanvas, "dither_bitmap", dither_bitmap, 6);
642
643    rb_define_method(cCanvas, "frame_count", get_frame_count, 0);
644    rb_define_method(cCanvas, "frame=", set_frame, 1);
645    rb_define_method(cCanvas, "set_frame", set_frame2, 1);
646    rb_define_method(cCanvas, "frame_name", get_frame_name, 0);
647    rb_define_method(cCanvas, "frame_name=", set_frame_name, 1);
648    rb_define_method(cCanvas, "set_frame_name", set_frame_name2, 1);
649    rb_define_method(cCanvas, "create_frame", create_frame, 1);
650    rb_define_method(cCanvas, "free_frame", free_frame, 1);
651
652    rb_define_method(cCanvas, "render", render_canvas, 4);
653    rb_define_method(cCanvas, "import_from_memory", import_from_memory, 2);
654    rb_define_method(cCanvas, "import_from_file", import_from_file, 2);
655    rb_define_method(cCanvas, "export_to_memory", export_to_memory, 1);
656    rb_define_singleton_method(cCanvas, "export_list", export_list, 0);
657    rb_define_singleton_method(cCanvas, "import_list", import_list, 0);
658}
659
Note: See TracBrowser for help on using the repository browser.