added ttf support to ruby module
[swftools.git] / lib / ruby / gfx.c
1 #include <ruby.h>
2 #include "../gfxdevice.h"
3 #include "../gfxsource.h"
4 #include "../gfxtools.h"
5 #include "../gfximage.h"
6 #include "../gfxfont.h"
7 #include "../devices/pdf.h"
8 #include "../readers/swf.h"
9 #include "../readers/image.h"
10 #include "../pdf/pdf.h"
11 #include "../mem.h"
12 #include "../types.h"
13 #include "../log.h"
14
15 #define RUBY_GFX_VERSION  "0.9.0"
16
17 static VALUE GFX;
18 static VALUE Font, Glyph, Bitmap, Document, DocumentPage, PDFClass, SWFClass, ImageClass, Device;
19 static ID id_doc;
20
21 typedef struct doc_internal {
22     VALUE self;
23     gfxsource_t*driver; // filled by alloc
24     gfxdocument_t*doc;
25     gfxfontlist_t*fontlist;
26 } doc_internal_t;
27
28 typedef struct page_internal {
29     doc_internal_t*doc;
30     gfxpage_t*page;
31 } page_internal_t;
32
33 typedef struct image_internal {
34     doc_internal_t*doc;
35     gfximage_t*image;
36 } image_internal_t;
37
38 typedef struct font_internal {
39     VALUE self;
40     VALUE glyph_array;
41     gfxfont_t*font;
42 } font_internal_t;
43
44 typedef struct glyph_internal {
45     font_internal_t*font;
46     int nr;
47 } glyph_internal_t;
48
49 static gfxsource_t* pdfdriver = 0;
50 static gfxsource_t* imagedriver = 0;
51 static gfxsource_t* swfdriver = 0;
52
53 #define Get_Doc(doc,cls) doc_internal_t*doc=0;Data_Get_Struct(cls, doc_internal_t, doc);
54 #define Get_Page(page,cls) page_internal_t*page=0;Data_Get_Struct(cls, page_internal_t, page);
55
56 static VALUE doc_allocate(VALUE cls, gfxsource_t*driver);
57 static VALUE page_allocate(VALUE cls);
58
59 // ------------------------ documents ---------------------------------------
60
61 static VALUE doc_initialize(VALUE cls, VALUE _filename)
62 {
63     Check_Type(_filename, T_STRING);
64     Get_Doc(doc,cls);
65     const char*filename = StringValuePtr(_filename);
66     doc->fontlist = gfxfontlist_create();
67     doc->doc = pdfdriver->open(pdfdriver, filename);
68     if(!doc->doc) {
69         rb_raise(rb_eIOError, "couldn't open %s", filename);
70     }
71     return cls;
72 }
73
74 static VALUE doc_num_pages(VALUE cls)
75 {
76     Get_Doc(doc,cls)
77     return INT2FIX(doc->doc->num_pages);
78 }
79
80 static VALUE doc_get_page(VALUE cls, VALUE _nr)
81 {
82     Check_Type(_nr, T_FIXNUM);
83     int nr = FIX2INT(_nr);
84     Get_Doc(doc,cls);
85
86     VALUE v = page_allocate(DocumentPage);
87     Get_Page(page,v)
88     page->page = doc->doc->getpage(doc->doc, nr);
89     page->doc = doc;
90     if(!page->page) {
91         rb_raise(rb_eArgError, "No page %d in document", nr);
92         return Qnil;
93     }
94     return v;
95 }
96
97 static VALUE doc_each_page(VALUE cls)
98 {
99     Get_Doc(doc,cls);
100     int t;
101     for(t=1;t<=doc->doc->num_pages;t++) {
102         VALUE v = page_allocate(DocumentPage);
103         Get_Page(page,v)
104         page->page = doc->doc->getpage(doc->doc, t);
105         page->doc = doc;
106         rb_yield(v);
107     }
108     return cls;
109 }
110
111 static void doc_mark(doc_internal_t*doc)
112 {
113     gfxfontlist_t*l = doc->fontlist;
114     while(l) {
115         if(l->user) 
116             rb_gc_mark((VALUE)l->user);
117         l = l->next;
118     }
119 }
120
121 static void doc_free(doc_internal_t*doc)
122 {
123     gfxfontlist_free(doc->fontlist, 0);
124     doc->doc->destroy(doc->doc);
125     free(doc);
126 }
127
128 static VALUE doc_allocate(VALUE cls, gfxsource_t*driver)
129 {
130     doc_internal_t*doc = 0;
131     VALUE v = Data_Make_Struct(cls, doc_internal_t, doc_mark, doc_free, doc);
132     doc->self = v;
133     memset(doc, 0, sizeof(doc_internal_t));
134     doc->driver = driver;
135     return v;
136 }
137
138 static VALUE pdf_allocate(VALUE cls) {return doc_allocate(cls, pdfdriver);}
139 static VALUE swf_allocate(VALUE cls) {return doc_allocate(cls, swfdriver);}
140 static VALUE imgdrv_allocate(VALUE cls) {return doc_allocate(cls, imagedriver);}
141
142 // ------------------------ doc pages ---------------------------------------
143
144 static void page_free(page_internal_t*page)
145 {
146     if(!page) return;
147     if(page->page) {
148         page->page->destroy(page->page);
149         page->page = 0;
150     }
151     free(page);
152 }
153 static void page_mark(page_internal_t*page)
154 {
155     rb_gc_mark(page->doc->self);
156 }
157 static VALUE page_allocate(VALUE cls)
158 {
159     page_internal_t*page = 0;
160     VALUE v = Data_Make_Struct(cls, page_internal_t, page_mark, page_free, page);
161     memset(page, 0, sizeof(page_internal_t));
162     return v;
163 }
164 static VALUE page_nr(VALUE cls)
165 {
166     Get_Page(page,cls)
167     return INT2FIX(page->page->nr);
168 }
169 static VALUE page_width(VALUE cls)
170 {
171     Get_Page(page,cls)
172     return INT2FIX(page->page->width);
173 }
174 static VALUE page_height(VALUE cls)
175 {
176     Get_Page(page,cls)
177     return INT2FIX(page->page->height);
178 }
179
180 // ------------------------ image -------------------------------------------
181
182 #define Get_Image(image,cls) image_internal_t*image=0;Data_Get_Struct(cls, image_internal_t, image);
183
184 static void image_free(image_internal_t*image)
185 {
186     free(image);
187 }
188 static void image_mark(image_internal_t*image)
189 {
190     rb_gc_mark(image->doc->self);
191 }
192 static VALUE image_allocate(VALUE cls)
193 {
194     image_internal_t*image = 0;
195     VALUE v = Data_Make_Struct(cls, image_internal_t, image_mark, image_free, image);
196     memset(image, 0, sizeof(image_internal_t));
197     return v;
198 }
199 static VALUE image_width(VALUE cls)
200 {
201     Get_Image(image,cls)
202     return INT2FIX(image->image->width);
203 }
204 static VALUE image_height(VALUE cls)
205 {
206     Get_Image(image,cls)
207     return INT2FIX(image->image->height);
208 }
209 static VALUE image_rescale(VALUE cls, VALUE _width, VALUE _height)
210 {
211     Get_Image(image,cls)
212     Check_Type(_width, T_FIXNUM);
213     Check_Type(_height, T_FIXNUM);
214     int width = FIX2INT(_width);
215     int height = FIX2INT(_height);
216     volatile VALUE v_image2 = image_allocate(Bitmap);
217     Get_Image(image2,v_image2)
218     image2->doc = image->doc;
219     image2->image = gfximage_rescale(image->image, width, height);
220     if(!image2->image) {
221         rb_raise(rb_eArgError, "Can't rescale to size %dx%d", width, height);
222     }
223     return v_image2;
224 }
225 static VALUE image_has_alpha(VALUE cls)
226 {
227     Get_Image(image,cls)
228     int size = image->image->width * image->image->height;
229     gfxcolor_t*data = image->image->data;
230     int t;
231     for(t=0;t<size;t++) {
232         if(data->a!=255) 
233             return Qtrue;
234     }
235     return Qfalse;
236 }
237 static VALUE image_save_jpeg(VALUE cls, VALUE _filename, VALUE quality)
238 {
239     Get_Image(image,cls)
240     Check_Type(_filename, T_STRING);
241     Check_Type(quality, T_FIXNUM);
242     const char*filename = StringValuePtr(_filename);
243     gfximage_save_jpeg(image->image, filename, FIX2INT(quality));
244     return cls;
245 }
246 static VALUE image_save_png(VALUE cls, VALUE _filename)
247 {
248     Get_Image(image,cls)
249     Check_Type(_filename, T_STRING);
250     const char*filename = StringValuePtr(_filename);
251     gfximage_save_png(image->image, filename);
252     return cls;
253 }
254 VALUE convert_image(doc_internal_t*doc,gfximage_t*_image)
255 {
256     VALUE v = image_allocate(Bitmap);
257     Get_Image(image,v)
258     image->image = _image;
259     image->doc = doc;
260     return v;
261 }
262 void invalidate_image(VALUE v)
263 {
264     Get_Image(image,v)
265     image->image = 0;
266 }
267
268 // ------------------------ glyphs ------------------------------------------
269
270 static VALUE convert_line(gfxline_t*line);
271
272 #define Get_Glyph(glyph,cls) glyph_internal_t*glyph=0;Data_Get_Struct(cls, glyph_internal_t, glyph);
273
274 static void glyph_free(glyph_internal_t*glyph)
275 {
276     free(glyph);
277 }
278
279 static void glyph_mark(glyph_internal_t*glyph)
280 {
281     rb_gc_mark(glyph->font->self);
282 }
283
284 static VALUE glyph_allocate(VALUE cls)
285 {
286     glyph_internal_t*glyph = 0;
287     VALUE v = Data_Make_Struct(cls, glyph_internal_t, glyph_mark, glyph_free, glyph);
288     memset(glyph, 0, sizeof(glyph_internal_t));
289     return v;
290 }
291
292 static VALUE glyph_polygon(VALUE cls)
293 {
294     Get_Glyph(glyph,cls);
295     return convert_line(glyph->font->font->glyphs[glyph->nr].line);
296 }
297
298 static VALUE glyph_advance(VALUE cls)
299 {
300     Get_Glyph(glyph,cls);
301     return rb_float_new(glyph->font->font->glyphs[glyph->nr].advance);
302 }
303
304 static VALUE glyph_bbox(VALUE cls)
305 {
306     Get_Glyph(glyph,cls);
307     gfxbbox_t bbox = gfxline_getbbox(glyph->font->font->glyphs[glyph->nr].line);
308     return rb_ary_new3(4, rb_float_new(bbox.xmin), 
309                           rb_float_new(bbox.ymin), 
310                           rb_float_new(bbox.xmax), 
311                           rb_float_new(bbox.ymax));
312 }
313
314 static VALUE glyph_unicode(VALUE cls)
315 {
316     Get_Glyph(glyph,cls);
317     return INT2FIX(glyph->font->font->glyphs[glyph->nr].unicode);
318 }
319
320 // ------------------------ font --------------------------------------------
321
322 #define Get_Font(font,cls) font_internal_t*font=0;Data_Get_Struct(cls, font_internal_t, font);
323
324 static void font_mark(font_internal_t*font)
325 {
326     rb_gc_mark(font->glyph_array);
327 }
328
329 static void font_free(font_internal_t*font)
330 {
331     free(font);
332 }
333
334 static VALUE font_allocate(VALUE cls)
335 {
336     font_internal_t*font = 0;
337     VALUE v = Data_Make_Struct(cls, font_internal_t, font_mark, font_free, font);
338     memset(font, 0, sizeof(font_internal_t));
339     font->self = v;
340     return v;
341 }
342
343 static VALUE font_ascent(VALUE cls)
344 {
345     Get_Font(font,cls);
346     return rb_float_new(font->font->ascent);
347 }
348
349 static VALUE font_descent(VALUE cls)
350 {
351     Get_Font(font,cls);
352     return rb_float_new(font->font->descent);
353 }
354
355 static VALUE font_name(VALUE cls)
356 {
357     Get_Font(font,cls);
358     return rb_tainted_str_new2(font->font->id);
359 }
360
361 static VALUE font_glyphs(VALUE cls)
362 {
363     Get_Font(font,cls);
364     return font->glyph_array;
365 }
366
367 static VALUE font_save_ttf(VALUE cls, VALUE _filename)
368 {
369     Get_Font(font,cls);
370     Check_Type(_filename, T_STRING);
371     const char*filename = StringValuePtr(_filename);
372     gfxfont_save(font->font, filename);
373     return Qnil;
374 }
375
376 static VALUE font_kerning(VALUE cls)
377 {
378     Get_Font(font,cls);
379     gfxkerning_t*kerning = font->font->kerning;
380     int kerning_size = font->font->kerning_size;
381     volatile VALUE a = rb_ary_new2(kerning_size);
382     int t;
383     for(t=0;t<kerning_size;t++) {
384         volatile VALUE tuple = rb_ary_new2(3);
385         rb_ary_store(tuple, 0, INT2FIX(kerning[t].c1));
386         rb_ary_store(tuple, 1, INT2FIX(kerning[t].c2));
387         rb_ary_store(tuple, 2, INT2FIX(kerning[t].advance));
388         rb_ary_store(a, t, tuple);
389     }
390     return a;
391 }
392
393 // ------------------------ gfx device --------------------------------------
394
395 typedef struct device_internal {
396     doc_internal_t*doc;
397     VALUE v;
398 } device_internal_t;
399
400 static ID id_setparameter = 0;
401 static ID id_startpage = 0;
402 static ID id_startclip = 0;
403 static ID id_endclip = 0;
404 static ID id_stroke = 0;
405 static ID id_fill = 0;
406 static ID id_fillbitmap = 0;
407 static ID id_fillgradient = 0;
408 static ID id_addfont = 0;
409 static ID id_drawchar = 0;
410 static ID id_drawlink = 0;
411 static ID id_endpage = 0;
412 static ID id_geterror = 0;
413 static ID id_finish = 0;
414 static ID id_butt = 0;
415 static ID id_round = 0;
416 static ID id_square = 0;
417 static ID id_bevel = 0;
418 static ID id_miter = 0;
419 static ID id_move = 0;
420 static ID id_line = 0;
421 static ID id_spline = 0;
422 static ID id_radial = 0;
423 static ID id_linear = 0;
424
425 static VALUE noop(int argc, VALUE *argv, VALUE obj) {return obj;}
426
427 #define forward(v,id,args...) rb_respond_to((v), (id))?rb_funcall((v), (id), args):0
428
429 VALUE convert_line(gfxline_t*line)
430 {
431     int len = 0;
432     gfxline_t*l = line;
433     while(l) {l=l->next;len++;}
434
435     volatile VALUE array = rb_ary_new2(len);
436
437     int pos = 0;
438     l = line;
439     while(l) {
440         volatile VALUE e;
441         if(l->type == gfx_moveTo) {
442             e = rb_ary_new3(3, ID2SYM(id_move), Qfalse, Qfalse);
443             rb_ary_store(array, pos, e);
444             rb_ary_store(e, 1, rb_float_new(l->x));
445             rb_ary_store(e, 2, rb_float_new(l->y));
446         } else if(l->type == gfx_lineTo) {
447             e = rb_ary_new3(3, ID2SYM(id_line), Qfalse, Qfalse);
448             rb_ary_store(array, pos, e);
449             rb_ary_store(e, 1, rb_float_new(l->x));
450             rb_ary_store(e, 2, rb_float_new(l->y));
451         } else {
452             e = rb_ary_new3(5, ID2SYM(id_spline), Qfalse, Qfalse, Qfalse, Qfalse);
453             rb_ary_store(array, pos, e);
454             rb_ary_store(e, 1, rb_float_new(l->x));
455             rb_ary_store(e, 2, rb_float_new(l->y));
456             rb_ary_store(e, 3, rb_float_new(l->sx));
457             rb_ary_store(e, 4, rb_float_new(l->sy));
458         }
459         pos++;
460         l=l->next;
461     }
462     return array;
463 }
464 VALUE convert_color(gfxcolor_t*color)
465 {
466     return rb_ary_new3(4, INT2FIX(color->a), INT2FIX(color->r), INT2FIX(color->g), INT2FIX(color->b));
467 }
468 VALUE convert_matrix(gfxmatrix_t*matrix)
469 {
470     volatile VALUE array = rb_ary_new2(3);
471     volatile VALUE a = rb_ary_new2(2);
472     rb_ary_store(array, 0, a);
473     rb_ary_store(a, 0, rb_float_new(matrix->m00));
474     rb_ary_store(a, 1, rb_float_new(matrix->m01));
475     a = rb_ary_new2(2);
476     rb_ary_store(array, 1, a);
477     rb_ary_store(a, 0, rb_float_new(matrix->m10));
478     rb_ary_store(a, 1, rb_float_new(matrix->m11));
479     a = rb_ary_new2(2);
480     rb_ary_store(array, 2, a);
481     rb_ary_store(a, 0, rb_float_new(matrix->tx));
482     rb_ary_store(a, 1, rb_float_new(matrix->ty));
483     return array;
484 }
485 static VALUE font_is_cached(device_internal_t*i, gfxfont_t*font)
486 {
487     return (VALUE)gfxfontlist_getuserdata(i->doc->fontlist, font->id);
488 }
489 static void cache_font(device_internal_t*i, gfxfont_t*font, VALUE v)
490 {
491     i->doc->fontlist = gfxfontlist_addfont2(i->doc->fontlist, font, (void*)v);
492 }
493 static VALUE convert_font(gfxfont_t*font)
494 {
495     volatile VALUE v2 = font_allocate(Font);
496     Get_Font(f, v2);
497     f->font = font;
498     f->glyph_array = rb_ary_new2(font->num_glyphs);
499
500     int t;
501     for(t=0;t<font->num_glyphs;t++) {
502         volatile VALUE a = glyph_allocate(Glyph);
503         rb_ary_store(f->glyph_array, t, a);
504         Get_Glyph(g, a);
505         g->font = f;
506         g->nr = t;
507     }
508     return v2;
509 }
510 static VALUE convert_gradient(gfxgradient_t*gradient)
511 {
512     return Qnil; //TODO
513 }
514 #define HEAD \
515     device_internal_t*i = (device_internal_t*)dev->internal; \
516     VALUE v = i->v;
517 int rb_setparameter(gfxdevice_t*dev, const char*key, const char*value)
518 {
519     HEAD
520     volatile VALUE v_key = rb_tainted_str_new2(key);
521     volatile VALUE v_value = rb_tainted_str_new2(value);
522     VALUE ret = forward(v,id_setparameter,2,v_key,v_value);
523     return 0;
524 }
525 void rb_startpage(gfxdevice_t*dev, int width, int height)
526 {
527     HEAD
528     VALUE ret = forward(v,id_startpage,2,INT2FIX(width),INT2FIX(height));
529 }
530 void rb_startclip(gfxdevice_t*dev, gfxline_t*line)
531 {
532     HEAD
533     volatile VALUE v_line = convert_line(line);
534     VALUE ret = forward(v,id_startclip,1,v_line);
535 }
536 void rb_endclip(gfxdevice_t*dev)
537 {
538     HEAD
539     VALUE ret = forward(v,id_endclip,0);
540 }
541 void rb_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit)
542 {
543     HEAD
544     
545     ID cap = 0;
546     if(cap_style == gfx_capButt) cap = id_butt;
547     else if(cap_style == gfx_capRound) cap = id_round;
548     else if(cap_style == gfx_capSquare) cap = id_square;
549     
550     ID joint = 0;
551     if(joint_style == gfx_joinRound) joint = id_round;
552     else if(joint_style == gfx_joinMiter) joint = id_miter;
553     else if(joint_style == gfx_joinBevel) joint = id_bevel;
554
555     volatile VALUE v_line = convert_line(line);
556     volatile VALUE v_width = rb_float_new(width);
557     volatile VALUE v_color = convert_color(color);
558     volatile VALUE v_miter = rb_float_new(miterLimit);
559     forward(v, id_stroke, 6, v_line, v_width, v_color, ID2SYM(cap), ID2SYM(joint), v_miter);
560 }
561 void rb_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
562 {
563     HEAD
564     
565     volatile VALUE v_line = convert_line(line);
566     volatile VALUE v_color = convert_color(color);
567     forward(v, id_fill, 2, v_line, v_color);
568 }
569 void rb_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
570 {
571     HEAD
572     volatile VALUE v_image = convert_image(i->doc, img);
573     volatile VALUE v_line = convert_line(line);
574     volatile VALUE v_matrix = convert_matrix(matrix);
575     forward(v, id_fillbitmap, 4, v_line, v_image, v_matrix, Qnil);
576     invalidate_image(v_image);
577 }
578 void rb_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
579 {
580     HEAD
581     ID typeid = (type == gfxgradient_linear)? id_linear : id_radial;
582     
583     volatile VALUE v_line = convert_line(line);
584     volatile VALUE v_matrix = convert_matrix(matrix);
585     volatile VALUE v_gradient = convert_gradient(gradient);
586     forward(v, id_fillgradient, 4, v_line, v_gradient, ID2SYM(typeid), v_matrix);
587 }
588 void rb_addfont(gfxdevice_t*dev, gfxfont_t*font)
589 {
590     HEAD
591
592     volatile VALUE f = font_is_cached(i, font);
593     if(!f) {f=convert_font(font);cache_font(i,font,f);}
594
595     forward(v, id_addfont, 1, f);
596 }
597 void rb_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
598 {
599     HEAD
600     volatile VALUE f = font_is_cached(i, font);
601     if(!f) {f=convert_font(font);cache_font(i,font,f);}
602
603     volatile VALUE v_color = convert_color(color);
604     volatile VALUE v_matrix = convert_matrix(matrix);
605     forward(v, id_drawchar, 4, f, INT2FIX(glyphnr), v_color, v_matrix);
606 }
607 void rb_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
608 {
609     HEAD
610     volatile VALUE v_line = convert_line(line);
611     volatile VALUE v_action = rb_tainted_str_new2(action);
612     forward(v, id_drawlink, v_line, v_action);
613 }
614 void rb_endpage(gfxdevice_t*dev)
615 {
616     HEAD
617     forward(v, id_endpage, 0);
618 }
619 gfxresult_t* rb_finish(gfxdevice_t*dev)
620 {
621     HEAD
622     VALUE ret = forward(v, id_endpage, 0);
623     gfxresult_t*r = (gfxresult_t*)rfx_calloc(sizeof(gfxresult_t));
624     r->internal = (void*)(ptroff_t)ret;
625     return r;
626 }
627
628 static VALUE page_render(VALUE cls, VALUE device)
629 {
630     Check_Type(device, T_OBJECT);
631     Get_Page(page,cls)
632
633     gfxdevice_t dev;
634     device_internal_t i;
635     i.v = device;
636     i.doc = page->doc;
637
638     dev.internal = &i;
639     dev.setparameter = rb_setparameter;
640     dev.startpage = rb_startpage;
641     dev.startclip = rb_startclip;
642     dev.endclip = rb_endclip;
643     dev.stroke = rb_stroke;
644     dev.fill = rb_fill;
645     dev.fillbitmap = rb_fillbitmap;
646     dev.fillgradient = rb_fillgradient;
647     dev.addfont = rb_addfont;
648     dev.drawchar = rb_drawchar;
649     dev.drawlink = rb_drawlink;
650     dev.endpage = rb_endpage;
651     dev.finish = rb_finish;
652
653     dev.startpage(&dev, page->page->width, page->page->height);
654     page->page->render(page->page, &dev);
655     dev.endpage(&dev);
656
657     return cls;
658 }
659
660 static VALUE doc_prepare(VALUE cls, VALUE device)
661 {
662     Get_Doc(doc,cls);
663
664     gfxdevice_t dev;
665     device_internal_t i;
666     i.v = device;
667     i.doc = doc;
668
669     dev.internal = &i;
670     dev.setparameter = rb_setparameter;
671     dev.startpage = rb_startpage;
672     dev.startclip = rb_startclip;
673     dev.endclip = rb_endclip;
674     dev.stroke = rb_stroke;
675     dev.fill = rb_fill;
676     dev.fillbitmap = rb_fillbitmap;
677     dev.fillgradient = rb_fillgradient;
678     dev.addfont = rb_addfont;
679     dev.drawchar = rb_drawchar;
680     dev.drawlink = rb_drawlink;
681     dev.endpage = rb_endpage;
682     dev.finish = rb_finish;
683
684     doc->doc->prepare(doc->doc, &dev);
685     return cls;
686 }
687
688
689 // ---------------------- global functions ----------------------------------
690
691 VALUE gfx_setparameter(VALUE module, VALUE _key, VALUE _value)
692 {
693     Check_Type(_key, T_STRING);
694     Check_Type(_value, T_STRING);
695     const char*key = StringValuePtr(_key);
696     const char*value = StringValuePtr(_value);
697     pdfdriver->setparameter(pdfdriver, key, value);
698     swfdriver->setparameter(swfdriver, key, value);
699     imagedriver->setparameter(imagedriver, key, value);
700     return GFX;
701 }
702
703 // --------------------------------------------------------------------------
704
705 void Init_gfx()
706 {
707     initLog(0,0,0,0,0,2);
708     pdfdriver = gfxsource_pdf_create();
709     swfdriver = gfxsource_swf_create();
710     imagedriver = gfxsource_image_create();
711
712     GFX = rb_define_module("GFX");
713     
714     rb_define_module_function(GFX, "setparameter", gfx_setparameter, 2);
715     
716     DocumentPage = rb_define_class_under(GFX, "DocumentPage", rb_cObject);
717     rb_define_method(DocumentPage, "width", page_width, 0);
718     rb_define_method(DocumentPage, "height", page_height, 0);
719     rb_define_method(DocumentPage, "nr", page_nr, 0);
720     rb_define_method(DocumentPage, "render", page_render, 1);
721
722     Document = rb_define_class_under(GFX, "Document", rb_cObject);
723     rb_define_method(Document, "initialize", doc_initialize, 1);
724     rb_define_method(Document, "page", doc_get_page, 1);
725     rb_define_method(Document, "each_page", doc_each_page, 0);
726     rb_define_method(Document, "prepare", doc_prepare, 1);
727     
728     Bitmap = rb_define_class_under(GFX, "Bitmap", rb_cObject);
729     rb_define_method(Bitmap, "save_jpeg", image_save_jpeg, 2);
730     rb_define_method(Bitmap, "save_png", image_save_png, 1);
731     rb_define_method(Bitmap, "width", image_width, 0);
732     rb_define_method(Bitmap, "height", image_height, 0);
733     rb_define_method(Bitmap, "rescale", image_rescale, 2);
734     rb_define_method(Bitmap, "has_alpha", image_has_alpha, 0);
735     
736     Glyph = rb_define_class_under(GFX, "Glyph", rb_cObject);
737     rb_define_method(Glyph, "polygon", glyph_polygon, 0);
738     rb_define_method(Glyph, "unicode", glyph_unicode, 0);
739     rb_define_method(Glyph, "advance", glyph_advance, 0);
740     rb_define_method(Glyph, "bbox", glyph_bbox, 0);
741     
742     Font = rb_define_class_under(GFX, "Font", rb_cObject);
743     rb_define_method(Font, "name", font_name, 0);
744     rb_define_method(Font, "ascent", font_ascent, 0);
745     rb_define_method(Font, "descent", font_descent, 0);
746     rb_define_method(Font, "glyphs", font_glyphs, 0);
747     rb_define_method(Font, "kerning", font_kerning, 0);
748     rb_define_method(Font, "get_kerning_table", font_kerning, 0);
749     rb_define_method(Font, "save_ttf", font_save_ttf, 1);
750     
751     Device = rb_define_class_under(GFX, "Device", rb_cObject);
752     rb_define_method(Device, "startpage", noop, -1);
753     rb_define_method(Device, "endpage", noop, -1);
754     rb_define_method(Device, "startclip", noop, -1);
755     rb_define_method(Device, "endclip", noop, -1);
756     rb_define_method(Device, "stroke", noop, -1);
757     rb_define_method(Device, "fill", noop, -1);
758     rb_define_method(Device, "fillbitmap", noop, -1);
759     rb_define_method(Device, "fillgradient", noop, -1);
760     rb_define_method(Device, "addfont", noop, -1);
761     rb_define_method(Device, "drawchar", noop, -1);
762     rb_define_method(Device, "drawlink", noop, -1);
763     rb_define_method(Device, "endpage", noop, -1);
764
765     PDFClass = rb_define_class_under(GFX, "PDF", Document);
766     rb_define_alloc_func(PDFClass, pdf_allocate);
767     
768     SWFClass = rb_define_class_under(GFX, "SWF", Document);
769     rb_define_alloc_func(SWFClass, swf_allocate);
770     
771     ImageClass = rb_define_class_under(GFX, "ImageRead", Document);
772     rb_define_alloc_func(ImageClass, imgdrv_allocate);
773
774     id_setparameter = rb_intern("setparameter");
775     id_startpage = rb_intern("startpage") ;
776     id_startclip = rb_intern("startclip") ;
777     id_endclip = rb_intern("endclip") ;
778     id_stroke = rb_intern("stroke") ;
779     id_fill = rb_intern("fill") ;
780     id_fillbitmap = rb_intern("fillbitmap") ;
781     id_fillgradient = rb_intern("fillgradient") ;
782     id_addfont = rb_intern("addfont") ;
783     id_drawchar = rb_intern("drawchar") ;
784     id_drawlink = rb_intern("drawlink") ;
785     id_endpage = rb_intern("endpage") ;
786     id_geterror = rb_intern("geterror") ;
787     id_finish = rb_intern("finish") ;
788     id_butt = rb_intern("butt");
789     id_round = rb_intern("round");
790     id_square = rb_intern("square");
791     id_miter = rb_intern("miter");
792     id_bevel = rb_intern("bevel");
793     id_move = rb_intern("move");
794     id_line = rb_intern("line");
795     id_spline = rb_intern("spline");
796     id_radial = rb_intern("radial");
797     id_linear = rb_intern("linear");
798 }
799