added pdf2pdf tool
[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     i->tempfile = strdup("tmp.pdf");
48     PDF_open_file(i->p, i->tempfile);
49     PDF_set_parameter(i->p, "usercoordinates", "true");
50     PDF_set_parameter(i->p, "topdown", "true");
51     PDF_begin_page(i->p, width, height);
52     PDF_set_parameter(i->p, "fillrule", "evenodd");
53 }
54
55 static int mkline(gfxline_t*line, PDF*p)
56 {
57     int ret = 0;
58     double x=0,y=0;
59     while(line) {
60         if(line->type == gfx_moveTo) {
61             PDF_moveto(p, line->x, line->y);
62         } else if(line->type == gfx_lineTo) {
63             PDF_lineto(p, line->x, line->y);
64             ret = 1;
65         } else {
66             /* when converting a quadratic bezier to a cubic bezier, the
67                two new control points are both 2/3 the way from the
68                endpoints to the old control point */
69             double c1x = (x + line->sx*2)/3;
70             double c1y = (y + line->sy*2)/3;
71             double c2x = (line->x + line->sx*2)/3;
72             double c2y = (line->y + line->sy*2)/3;
73             PDF_curveto(p, c1x, c1y, c2x, c2y, line->x, line->y);
74             ret = 1;
75         }
76         x = line->x;
77         y = line->y;
78         line = line->next;
79     }
80     return ret;
81 }
82
83 void pdf_startclip(gfxdevice_t*dev, gfxline_t*line)
84 {
85     internal_t*i = (internal_t*)dev->internal;
86     PDF_save(i->p);
87     PDF_set_parameter(i->p, "fillrule", "evenodd");
88     if(mkline(line, i->p))
89         PDF_clip(i->p);
90     else   
91         ; // TODO: not sure about this
92
93 }
94 void pdf_endclip(gfxdevice_t*dev)
95 {
96     internal_t*i = (internal_t*)dev->internal;
97     PDF_restore(i->p);
98 }
99 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)
100 {
101     internal_t*i = (internal_t*)dev->internal;
102     PDF_setlinewidth(i->p, width);
103     PDF_setlinecap(i->p, cap_style==gfx_capButt?0:(cap_style==gfx_capRound?1:2));
104     PDF_setlinejoin(i->p, joint_style==gfx_joinMiter?0:(joint_style==gfx_joinRound?1:2));
105     PDF_setrgbcolor_stroke(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
106     if(joint_style==gfx_joinMiter)
107         PDF_setmiterlimit(i->p, miterLimit);
108     if(mkline(line, i->p))
109         PDF_stroke(i->p);
110 }
111
112 void pdf_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
113 {
114     internal_t*i = (internal_t*)dev->internal;
115     PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
116     PDF_set_parameter(i->p, "fillrule", "evenodd");
117         
118     if(mkline(line, i->p)) {
119         PDF_fill(i->p);
120     }
121 }
122
123 void pdf_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
124 {
125     internal_t*i = (internal_t*)dev->internal;
126
127     //PDFLIB_API int PDFLIB_CALL
128     //PDF_load_image(i->pPDF *p, const char *imagetype, const char *filename, int len, const char *optlist);
129 }
130
131 void pdf_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
132 {
133     internal_t*i = (internal_t*)dev->internal;
134 }
135
136 void pdf_addfont(gfxdevice_t*dev, gfxfont_t*font)
137 {
138     internal_t*i = (internal_t*)dev->internal;
139 }
140
141 void pdf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
142 {
143     internal_t*i = (internal_t*)dev->internal;
144     if(!font)
145         return;
146     /* align characters to whole pixels */
147     matrix->tx = (int)matrix->tx;
148     matrix->ty = (int)matrix->ty;
149
150     gfxglyph_t*glyph = &font->glyphs[glyphnr];
151     gfxline_t*line2 = gfxline_clone(glyph->line);
152     gfxline_transform(line2, matrix);
153     PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
154     PDF_set_parameter(i->p, "fillrule", "evenodd");
155     
156     if(mkline(line2, i->p)) {
157         PDF_fill(i->p);
158     }
159     gfxline_free(line2);
160     return;
161 }
162
163 void pdf_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
164 {
165     internal_t*i = (internal_t*)dev->internal;
166 }
167
168 void pdf_endpage(gfxdevice_t*dev)
169 {
170     internal_t*i = (internal_t*)dev->internal;
171     PDF_end_page(i->p);
172     PDF_close(i->p);
173     PDF_delete(i->p);
174 }
175
176 typedef struct pdfresult_internal {
177     char*tempfile;
178 } pdfresult_internal_t;
179
180 void pdfresult_destroy(gfxresult_t*gfx)
181 {
182     pdfresult_internal_t*i = (pdfresult_internal_t*)gfx->internal;
183     free(i->tempfile);
184     free(gfx->internal);gfx->internal = 0;
185     free(gfx);
186 }
187
188 int pdfresult_save(gfxresult_t*gfx, const char*filename)
189 {
190     pdfresult_internal_t*i = (pdfresult_internal_t*)gfx->internal;
191     FILE*fi = fopen(i->tempfile, "rb");
192     FILE*fo = fopen(filename, "wb");
193     if(!fo) {
194         perror(filename);
195         return -1;
196     }
197     char buffer[4096];
198     int size = 0;
199     while((size = fread(buffer, 1, 4096, fi))) {
200         fwrite(buffer, 1, size, fo);
201     }
202     fclose(fi);
203     fclose(fo);
204     return 0;
205 }
206
207 void* pdfresult_get(gfxresult_t*gfx, const char*name)
208 {
209     return 0; 
210 }
211
212 gfxresult_t* pdf_finish(gfxdevice_t*dev)
213 {
214     internal_t*i = (internal_t*)dev->internal;
215
216     gfxresult_t*result = (gfxresult_t*)malloc(sizeof(gfxresult_t));
217     memset(result, 0, sizeof(gfxresult_t));
218     result->save = pdfresult_save;
219     result->get = pdfresult_get;
220     result->destroy = pdfresult_destroy;
221     result->internal = 0;
222     result->internal = malloc(sizeof(pdfresult_internal_t));
223     pdfresult_internal_t*ri = (pdfresult_internal_t*)result->internal;
224     ri->tempfile = i->tempfile;i->tempfile=0;
225     free(dev->internal);dev->internal = 0;i=0;
226     return result;
227 }
228
229 void gfxdevice_pdf_init(gfxdevice_t*dev)
230 {
231     internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
232     memset(dev, 0, sizeof(gfxdevice_t));
233
234     dev->name = "pdf";
235
236     dev->internal = i;
237
238     dev->setparameter = pdf_setparameter;
239     dev->startpage = pdf_startpage;
240     dev->startclip = pdf_startclip;
241     dev->endclip = pdf_endclip;
242     dev->stroke = pdf_stroke;
243     dev->fill = pdf_fill;
244     dev->fillbitmap = pdf_fillbitmap;
245     dev->fillgradient = pdf_fillgradient;
246     dev->addfont = pdf_addfont;
247     dev->drawchar = pdf_drawchar;
248     dev->drawlink = pdf_drawlink;
249     dev->endpage = pdf_endpage;
250     dev->finish = pdf_finish;
251
252     i->p = PDF_new();
253 }
254