3 Part of the swftools package.
5 Copyright (c) 2007 Matthias Kramm <kramm@quiss.org>
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.
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.
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 */
35 #include "../gfxdevice.h"
36 #include "../gfxtools.h"
37 #include "../gfximage.h"
39 typedef struct _internal {
42 const char*config_pdfx;
43 char config_addblankpages;
54 gfxfontlist_t*fontlist;
57 int pdf_setparameter(gfxdevice_t*dev, const char*key, const char*value)
59 internal_t*i = (internal_t*)dev->internal;
63 void pdf_startpage(gfxdevice_t*dev, int width, int height)
65 internal_t*i = (internal_t*)dev->internal;
68 i->tempfile = strdup(mktempname(0));
69 PDF_open_file(i->p, i->tempfile);
70 PDF_set_parameter(i->p, "usercoordinates", "true");
71 PDF_set_parameter(i->p, "topdown", "true");
74 PDF_begin_page(i->p, width, height);
75 PDF_set_parameter(i->p, "fillrule", "evenodd");
78 static int mkline(gfxline_t*line, PDF*p, char fill)
83 gfxline_t*free_line = 0;
85 line = gfxline_restitch(gfxline_clone(line));
89 if(line->type == gfx_moveTo && (x!=line->x || y!=line->y || first)) {
91 PDF_moveto(p, line->x, line->y);
92 } else if(line->type == gfx_lineTo) {
93 PDF_lineto(p, line->x, line->y);
96 /* when converting a quadratic bezier to a cubic bezier, the
97 two new control points are both 2/3 the way from the
98 endpoints to the old control point */
99 double c1x = (x + line->sx*2)/3;
100 double c1y = (y + line->sy*2)/3;
101 double c2x = (line->x + line->sx*2)/3;
102 double c2y = (line->y + line->sy*2)/3;
103 PDF_curveto(p, c1x, c1y, c2x, c2y, line->x, line->y);
111 gfxline_free(free_line);
115 void pdf_startclip(gfxdevice_t*dev, gfxline_t*line)
117 internal_t*i = (internal_t*)dev->internal;
119 if(mkline(line, i->p, 1))
122 ; // TODO: strictly speaking, an empty clip clears everything
125 void pdf_endclip(gfxdevice_t*dev)
127 internal_t*i = (internal_t*)dev->internal;
130 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)
132 internal_t*i = (internal_t*)dev->internal;
135 PDF_setlinewidth(i->p, width);
136 PDF_setlinecap(i->p, cap_style==gfx_capButt?0:(cap_style==gfx_capRound?1:2));
137 PDF_setlinejoin(i->p, joint_style==gfx_joinMiter?0:(joint_style==gfx_joinRound?1:2));
138 PDF_setrgbcolor_stroke(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
139 if(joint_style==gfx_joinMiter)
140 PDF_setmiterlimit(i->p, miterLimit);
141 if(mkline(line, i->p, 0))
145 void pdf_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
147 internal_t*i = (internal_t*)dev->internal;
148 PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
150 char opacityfill[80];
151 sprintf(opacityfill, "opacityfill %f", color->a/256.0);
152 int gstate = PDF_create_gstate(i->p, opacityfill);
153 PDF_set_gstate(i->p, gstate);
156 if(mkline(line, i->p, 1)) {
161 void pdf_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
163 internal_t*i = (internal_t*)dev->internal;
165 int t,size=img->width*img->height;
167 for(t=0;t<size;t++) {
168 if(img->data[t].a!=255) {
174 double w = sqrt(matrix->m00*matrix->m00+matrix->m01*matrix->m01);
175 double h = sqrt(matrix->m10*matrix->m10+matrix->m11*matrix->m11);
176 double l1 = w*img->width;
177 double l2 = h*img->height;
178 double r = atan2(matrix->m01, matrix->m00);
180 /* fit_image needs the lower left corner of the image */
181 double x = matrix->tx + matrix->m10*img->height;
182 double y = matrix->ty + matrix->m11*img->height;
184 double dpi_x = 72.0 / w;
185 double dpi_y = 72.0 / h;
186 double dpi = dpi_x>dpi_y?dpi_x:dpi_y;
187 gfximage_t*rescaled_image = 0;
188 if(i->config_maxdpi && dpi > i->config_maxdpi) {
189 int newwidth = img->width*i->config_maxdpi/dpi;
190 int newheight = img->height*i->config_maxdpi/dpi;
191 rescaled_image = gfximage_rescale(img, newwidth, newheight);
192 msg("<notice> Downscaling %dx%d image (dpi %f, %.0fx%.0f on page) to %dx%d (dpi %d)",
193 img->width, img->height, dpi, l1, l2, newwidth, newheight, i->config_maxdpi);
194 img = rescaled_image;
198 mktempname(tempfile);
200 gfximage_save_jpeg(img, tempfile, 96);
205 mktempname(tempfile2);
207 int size = img->width*img->height;
208 unsigned char*alpha = malloc(size);
209 for(t=0;t<size;t++) {
210 alpha[t] = img->data[t].a;
212 jpeg_save_gray(alpha, img->width, img->height, 97, tempfile2);
214 int maskid = PDF_load_image(i->p, "jpeg", tempfile2, 0, "mask");
218 msg("<error> Couldn't process mask jpeg of size %dx%d: error code %d", img->width, img->height, maskid);
221 sprintf(masked, "masked %d", maskid);
222 imgid = PDF_load_image(i->p, "jpeg", tempfile, 0, masked);
224 imgid = PDF_load_image(i->p, "jpeg", tempfile, 0, "");
228 msg("<error> Couldn't process jpeg of size %dx%d: error code %d, file %s", img->width, img->height, imgid, tempfile);
234 sprintf(options, "boxsize {%f %f} fitmethod meet rotate %f", l1, l2, r*180/M_PI);
235 PDF_fit_image(i->p, imgid, x, y, options);
236 PDF_close_image(i->p, imgid);
239 gfximage_free(rescaled_image);
242 void pdf_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
244 internal_t*i = (internal_t*)dev->internal;
247 static char type3 = 1;
249 void pdf_addfont(gfxdevice_t*dev, gfxfont_t*font)
251 internal_t*i = (internal_t*)dev->internal;
255 if(!gfxfontlist_hasfont(i->fontlist, font)) {
257 static int fontnr = 1;
259 sprintf(fontname, "font%d", fontnr++);
260 int l = strlen(fontname);
264 fontname2[t*2+0] = fontname[t];
265 fontname2[t*2+1] = 0;
268 PDF_begin_font(i->p, fontname2, l*2, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, "");
269 int num = font->num_glyphs<256-32?font->num_glyphs:256-32;
271 gfxglyph_t*g = &font->glyphs[t];
272 gfxbbox_t bbox = gfxline_getbbox(g->line);
274 sprintf(name, "chr%d", t+32);
275 PDF_encoding_set_char(i->p, fontname, t+32, name, 0);
276 PDF_begin_glyph(i->p, name, g->advance, bbox.xmin, bbox.ymin, bbox.xmax, bbox.ymax);
277 if(mkline(g->line, i->p, 1))
282 fontid = PDF_load_font(i->p, fontname2, l*2, fontname, "");
284 i->fontlist = gfxfontlist_addfont2(i->fontlist, font, (void*)(ptroff_t)fontid);
289 void pdf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
291 internal_t*i = (internal_t*)dev->internal;
296 gfxglyph_t*glyph = &font->glyphs[glyphnr];
297 PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
299 if(!type3) as_shape=1;
300 if(glyphnr>256-32) as_shape=1;
301 if(fabs(matrix->m00 + matrix->m11) > 0.01) as_shape=1;
302 if(fabs(fabs(matrix->m01) + fabs(matrix->m10)) > 0.01) as_shape=1;
303 if(fabs(matrix->m00) < 1e-6) as_shape=1;
306 gfxline_t*line2 = gfxline_clone(glyph->line);
307 gfxline_transform(line2, matrix);
308 if(mkline(line2, i->p, 1)) {
313 assert(gfxfontlist_hasfont(i->fontlist, font));
314 int fontid = (int)(ptroff_t)gfxfontlist_getuserdata(i->fontlist, font->id);
315 PDF_setfont(i->p, fontid, matrix->m00);
317 sprintf(name, "%c", glyphnr+32);
319 if(fabs(matrix->tx - i->lastx) > 0.001 || matrix->ty != i->lasty) {
320 PDF_show_xy2(i->p, name, strlen(name), matrix->tx, matrix->ty);
322 PDF_show2(i->p, name, strlen(name));
325 i->lastx = matrix->tx + glyph->advance*matrix->m00;
326 i->lasty = matrix->ty;
331 void pdf_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
333 internal_t*i = (internal_t*)dev->internal;
336 void pdf_endpage(gfxdevice_t*dev)
338 internal_t*i = (internal_t*)dev->internal;
342 typedef struct pdfresult_internal {
344 } pdfresult_internal_t;
346 void pdfresult_destroy(gfxresult_t*gfx)
348 pdfresult_internal_t*i = (pdfresult_internal_t*)gfx->internal;
351 free(gfx->internal);gfx->internal = 0;
355 int pdfresult_save(gfxresult_t*gfx, const char*filename)
357 pdfresult_internal_t*i = (pdfresult_internal_t*)gfx->internal;
358 FILE*fi = fopen(i->tempfile, "rb");
359 FILE*fo = fopen(filename, "wb");
366 while((size = fread(buffer, 1, 4096, fi))) {
367 fwrite(buffer, 1, size, fo);
374 void* pdfresult_get(gfxresult_t*gfx, const char*name)
379 gfxresult_t* pdf_finish(gfxdevice_t*dev)
381 internal_t*i = (internal_t*)dev->internal;
386 gfxresult_t*result = (gfxresult_t*)malloc(sizeof(gfxresult_t));
387 memset(result, 0, sizeof(gfxresult_t));
388 result->save = pdfresult_save;
389 result->get = pdfresult_get;
390 result->destroy = pdfresult_destroy;
391 result->internal = 0;
392 result->internal = malloc(sizeof(pdfresult_internal_t));
393 pdfresult_internal_t*ri = (pdfresult_internal_t*)result->internal;
394 ri->tempfile = i->tempfile;i->tempfile=0;
395 free(dev->internal);dev->internal = 0;i=0;
399 void gfxdevice_pdf_init(gfxdevice_t*dev)
401 internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
402 memset(dev, 0, sizeof(gfxdevice_t));
408 dev->setparameter = pdf_setparameter;
409 dev->startpage = pdf_startpage;
410 dev->startclip = pdf_startclip;
411 dev->endclip = pdf_endclip;
412 dev->stroke = pdf_stroke;
413 dev->fill = pdf_fill;
414 dev->fillbitmap = pdf_fillbitmap;
415 dev->fillgradient = pdf_fillgradient;
416 dev->addfont = pdf_addfont;
417 dev->drawchar = pdf_drawchar;
418 dev->drawlink = pdf_drawlink;
419 dev->endpage = pdf_endpage;
420 dev->finish = pdf_finish;