multi-page fix
[swftools.git] / lib / devices / pdf.c
1 /* pdf.c
2
3    Part of the swftools package.
4
5    Copyright (c) 2007 Matthias Kramm <kramm@quiss.org> 
6  
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <unistd.h>
25 #include <memory.h>
26 #include <pdflib.h>
27 #include "../types.h"
28 #include "../mem.h"
29 #include "../gfxdevice.h"
30 #include "../gfxtools.h"
31
32 typedef struct _internal {
33     PDF* p;
34     char*tempfile;
35 } internal_t;
36
37 int pdf_setparameter(gfxdevice_t*dev, const char*key, const char*value)
38 {
39     internal_t*i = (internal_t*)dev->internal;
40     return 0;
41 }
42
43 void pdf_startpage(gfxdevice_t*dev, int width, int height)
44 {
45     internal_t*i = (internal_t*)dev->internal;
46
47     if(!i->tempfile) {
48         i->tempfile = strdup("tmp.pdf");
49         PDF_open_file(i->p, i->tempfile);
50         PDF_set_parameter(i->p, "usercoordinates", "true");
51         PDF_set_parameter(i->p, "topdown", "true");
52     }
53
54     PDF_begin_page(i->p, width, height);
55     PDF_set_parameter(i->p, "fillrule", "evenodd");
56 }
57
58 static int mkline(gfxline_t*line, PDF*p)
59 {
60     int ret = 0;
61     double x=0,y=0;
62     while(line) {
63         if(line->type == gfx_moveTo) {
64             PDF_moveto(p, line->x, line->y);
65         } else if(line->type == gfx_lineTo) {
66             PDF_lineto(p, line->x, line->y);
67             ret = 1;
68         } else {
69             /* when converting a quadratic bezier to a cubic bezier, the
70                two new control points are both 2/3 the way from the
71                endpoints to the old control point */
72             double c1x = (x + line->sx*2)/3;
73             double c1y = (y + line->sy*2)/3;
74             double c2x = (line->x + line->sx*2)/3;
75             double c2y = (line->y + line->sy*2)/3;
76             PDF_curveto(p, c1x, c1y, c2x, c2y, line->x, line->y);
77             ret = 1;
78         }
79         x = line->x;
80         y = line->y;
81         line = line->next;
82     }
83     return ret;
84 }
85
86 void pdf_startclip(gfxdevice_t*dev, gfxline_t*line)
87 {
88     internal_t*i = (internal_t*)dev->internal;
89     PDF_save(i->p);
90     PDF_set_parameter(i->p, "fillrule", "evenodd");
91     if(mkline(line, i->p))
92         PDF_clip(i->p);
93     else   
94         ; // TODO: not sure about this
95
96 }
97 void pdf_endclip(gfxdevice_t*dev)
98 {
99     internal_t*i = (internal_t*)dev->internal;
100     PDF_restore(i->p);
101 }
102 void pdf_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit)
103 {
104     internal_t*i = (internal_t*)dev->internal;
105     PDF_setlinewidth(i->p, width);
106     PDF_setlinecap(i->p, cap_style==gfx_capButt?0:(cap_style==gfx_capRound?1:2));
107     PDF_setlinejoin(i->p, joint_style==gfx_joinMiter?0:(joint_style==gfx_joinRound?1:2));
108     PDF_setrgbcolor_stroke(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
109     if(joint_style==gfx_joinMiter)
110         PDF_setmiterlimit(i->p, miterLimit);
111     if(mkline(line, i->p))
112         PDF_stroke(i->p);
113 }
114
115 void pdf_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
116 {
117     internal_t*i = (internal_t*)dev->internal;
118     PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
119     PDF_set_parameter(i->p, "fillrule", "evenodd");
120         
121     if(mkline(line, i->p)) {
122         PDF_fill(i->p);
123     }
124 }
125
126 void pdf_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
127 {
128     internal_t*i = (internal_t*)dev->internal;
129
130     //PDFLIB_API int PDFLIB_CALL
131     //PDF_load_image(i->pPDF *p, const char *imagetype, const char *filename, int len, const char *optlist);
132 }
133
134 void pdf_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
135 {
136     internal_t*i = (internal_t*)dev->internal;
137 }
138
139 void pdf_addfont(gfxdevice_t*dev, gfxfont_t*font)
140 {
141     internal_t*i = (internal_t*)dev->internal;
142 }
143
144 void pdf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
145 {
146     internal_t*i = (internal_t*)dev->internal;
147     if(!font)
148         return;
149     /* align characters to whole pixels */
150     matrix->tx = (int)matrix->tx;
151     matrix->ty = (int)matrix->ty;
152
153     gfxglyph_t*glyph = &font->glyphs[glyphnr];
154     gfxline_t*line2 = gfxline_clone(glyph->line);
155     gfxline_transform(line2, matrix);
156     PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
157     PDF_set_parameter(i->p, "fillrule", "evenodd");
158     
159     if(mkline(line2, i->p)) {
160         PDF_fill(i->p);
161     }
162     gfxline_free(line2);
163     return;
164 }
165
166 void pdf_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
167 {
168     internal_t*i = (internal_t*)dev->internal;
169 }
170
171 void pdf_endpage(gfxdevice_t*dev)
172 {
173     internal_t*i = (internal_t*)dev->internal;
174     PDF_end_page(i->p);
175 }
176
177 typedef struct pdfresult_internal {
178     char*tempfile;
179 } pdfresult_internal_t;
180
181 void pdfresult_destroy(gfxresult_t*gfx)
182 {
183     pdfresult_internal_t*i = (pdfresult_internal_t*)gfx->internal;
184     free(i->tempfile);
185     free(gfx->internal);gfx->internal = 0;
186     free(gfx);
187 }
188
189 int pdfresult_save(gfxresult_t*gfx, const char*filename)
190 {
191     pdfresult_internal_t*i = (pdfresult_internal_t*)gfx->internal;
192     FILE*fi = fopen(i->tempfile, "rb");
193     FILE*fo = fopen(filename, "wb");
194     if(!fo) {
195         perror(filename);
196         return -1;
197     }
198     char buffer[4096];
199     int size = 0;
200     while((size = fread(buffer, 1, 4096, fi))) {
201         fwrite(buffer, 1, size, fo);
202     }
203     fclose(fi);
204     fclose(fo);
205     return 0;
206 }
207
208 void* pdfresult_get(gfxresult_t*gfx, const char*name)
209 {
210     return 0; 
211 }
212
213 gfxresult_t* pdf_finish(gfxdevice_t*dev)
214 {
215     internal_t*i = (internal_t*)dev->internal;
216     
217     PDF_close(i->p);
218     PDF_delete(i->p);
219
220     gfxresult_t*result = (gfxresult_t*)malloc(sizeof(gfxresult_t));
221     memset(result, 0, sizeof(gfxresult_t));
222     result->save = pdfresult_save;
223     result->get = pdfresult_get;
224     result->destroy = pdfresult_destroy;
225     result->internal = 0;
226     result->internal = malloc(sizeof(pdfresult_internal_t));
227     pdfresult_internal_t*ri = (pdfresult_internal_t*)result->internal;
228     ri->tempfile = i->tempfile;i->tempfile=0;
229     free(dev->internal);dev->internal = 0;i=0;
230     return result;
231 }
232
233 void gfxdevice_pdf_init(gfxdevice_t*dev)
234 {
235     internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
236     memset(dev, 0, sizeof(gfxdevice_t));
237
238     dev->name = "pdf";
239
240     dev->internal = i;
241
242     dev->setparameter = pdf_setparameter;
243     dev->startpage = pdf_startpage;
244     dev->startclip = pdf_startclip;
245     dev->endclip = pdf_endclip;
246     dev->stroke = pdf_stroke;
247     dev->fill = pdf_fill;
248     dev->fillbitmap = pdf_fillbitmap;
249     dev->fillgradient = pdf_fillgradient;
250     dev->addfont = pdf_addfont;
251     dev->drawchar = pdf_drawchar;
252     dev->drawlink = pdf_drawlink;
253     dev->endpage = pdf_endpage;
254     dev->finish = pdf_finish;
255
256     i->p = PDF_new();
257 }
258