summaryrefslogtreecommitdiff
path: root/lib/devices
diff options
context:
space:
mode:
authorMatthias Kramm <kramm@quiss.org>2010-02-18 17:48:00 -0800
committerMatthias Kramm <kramm@quiss.org>2010-02-18 17:48:18 -0800
commitb27d77f8a6343e60e2d3ae2c22a8096a6357a927 (patch)
tree6025ca6d57da4e8eb500b563a767dc3ab1082024 /lib/devices
parent77329c490e5346658e4878f065022abb64df5324 (diff)
added ttf support to pdf2pdf
Diffstat (limited to 'lib/devices')
-rw-r--r--lib/devices/pdf.c221
1 files changed, 180 insertions, 41 deletions
diff --git a/lib/devices/pdf.c b/lib/devices/pdf.c
index f6df3f52..5ab55fa2 100644
--- a/lib/devices/pdf.c
+++ b/lib/devices/pdf.c
@@ -28,6 +28,7 @@
#include <math.h>
#include "../os.h"
#include "../q.h"
+#include "../log.h"
#include "../jpeg.h"
#include "../types.h"
#include "../mem.h"
@@ -35,15 +36,16 @@
#include "../gfxdevice.h"
#include "../gfxtools.h"
#include "../gfximage.h"
+#include "../gfxfont.h"
typedef struct _internal {
PDF* p;
- const char*config_pdfx;
char config_addblankpages;
double config_xpad;
double config_ypad;
int config_maxdpi;
+ int config_mindpi;
int width,height;
int num_pages;
@@ -52,12 +54,39 @@ typedef struct _internal {
char*page_opts;
double lastx,lasty;
gfxfontlist_t*fontlist;
+
+ char has_matrix;
+ double m00, m01, m10, m11;
} internal_t;
-int pdf_setparameter(gfxdevice_t*dev, const char*key, const char*value)
+static void set_matrix(internal_t*i, double m00, double m01, double m10, double m11)
{
- internal_t*i = (internal_t*)dev->internal;
- return 0;
+ if(i->has_matrix) {
+ PDF_restore(i->p);
+ }
+ i->m00 = m00;
+ i->m01 = m01;
+ i->m10 = m10;
+ i->m11 = m11;
+
+ i->has_matrix = 1;
+ PDF_save(i->p);
+ PDF_setmatrix(i->p, m00, -m01, m10, -m11, 0, i->height);
+}
+static void reset_matrix(internal_t*i)
+{
+ set_matrix(i, 1.0, 0.0, 0.0, 1.0);
+}
+static void transform_back(internal_t*i, double x, double y, double *ox, double *oy)
+{
+ double det = i->m00*i->m11 - i->m10*i->m01;
+ if(!det) {
+ msg("<warning> Codependent text matrix");
+ *ox=*oy=0;
+ return;
+ }
+ *ox = (x*i->m11 - i->m10*y)/det;
+ *oy = (i->m00*y - x*i->m01)/det;
}
void pdf_startpage(gfxdevice_t*dev, int width, int height)
@@ -66,16 +95,54 @@ void pdf_startpage(gfxdevice_t*dev, int width, int height)
if(!i->tempfile) {
i->tempfile = strdup(mktempname(0));
- PDF_open_file(i->p, i->tempfile);
+
+ PDF_begin_document(i->p, i->tempfile, 0, "");
+ //PDF_set_value(i->p, "compress", 0);
PDF_set_parameter(i->p, "usercoordinates", "true");
PDF_set_parameter(i->p, "topdown", "true");
}
- PDF_begin_page(i->p, width, height);
+ int width_plus_pad = width+floor(i->config_xpad*2);
+ int height_plus_pad = height+floor(i->config_ypad*2);
+ PDF_begin_page_ext(i->p, width_plus_pad, height_plus_pad, i->page_opts);
+ PDF_set_value(i->p, "CropBox/llx", 0);
+ PDF_set_value(i->p, "CropBox/lly", 0);
+ PDF_set_value(i->p, "CropBox/urx", width_plus_pad);
+ PDF_set_value(i->p, "CropBox/ury", height_plus_pad);
+ if(i->config_xpad || i->config_ypad) {
+ PDF_set_value(i->p, "TrimBox/llx", i->config_xpad);
+ PDF_set_value(i->p, "TrimBox/lly", i->config_ypad);
+ PDF_set_value(i->p, "TrimBox/urx", i->config_xpad+width);
+ PDF_set_value(i->p, "TrimBox/ury", i->config_ypad+height);
+ }
+
PDF_set_parameter(i->p, "fillrule", "evenodd");
+ i->width = width;
+ i->height = height;
+ i->num_pages++;
+
+ reset_matrix(i);
+}
+
+int pdf_setparameter(gfxdevice_t*dev, const char*key, const char*value)
+{
+ internal_t*i = (internal_t*)dev->internal;
+ if(!strcmp(key, "addblankpages")) {
+ i->config_addblankpages = atoi(value);
+ } else if(!strcmp(key, "maxdpi")) {
+ i->config_maxdpi = atoi(value);
+ } else if(!strcmp(key, "mindpi")) {
+ i->config_mindpi = atoi(value);
+ } else if(!strcmp(key, "xpad")) {
+ i->config_xpad = atof(value);
+ } else if(!strcmp(key, "ypad")) {
+ i->config_ypad = atof(value);
+ }
+ return 0;
}
-static int mkline(gfxline_t*line, PDF*p, char fill)
+
+static int mkline(gfxline_t*line, PDF*p, double mx, double my, double scale, char fill)
{
double x=0,y=0;
char first = 1;
@@ -88,9 +155,9 @@ static int mkline(gfxline_t*line, PDF*p, char fill)
while(line) {
if(line->type == gfx_moveTo && (x!=line->x || y!=line->y || first)) {
first = 0;
- PDF_moveto(p, line->x, line->y);
+ PDF_moveto(p, line->x*scale+mx, line->y*scale+my);
} else if(line->type == gfx_lineTo) {
- PDF_lineto(p, line->x, line->y);
+ PDF_lineto(p, line->x*scale+mx, line->y*scale+my);
ret = 1;
} else {
/* when converting a quadratic bezier to a cubic bezier, the
@@ -100,7 +167,9 @@ static int mkline(gfxline_t*line, PDF*p, char fill)
double c1y = (y + line->sy*2)/3;
double c2x = (line->x + line->sx*2)/3;
double c2y = (line->y + line->sy*2)/3;
- PDF_curveto(p, c1x, c1y, c2x, c2y, line->x, line->y);
+ PDF_curveto(p, c1x*scale+mx, c1y*scale+my,
+ c2x*scale+mx, c2y*scale+my,
+ line->x*scale+mx, line->y*scale+my);
ret = 1;
}
x = line->x;
@@ -115,8 +184,9 @@ static int mkline(gfxline_t*line, PDF*p, char fill)
void pdf_startclip(gfxdevice_t*dev, gfxline_t*line)
{
internal_t*i = (internal_t*)dev->internal;
+ reset_matrix(i);
PDF_save(i->p);
- if(mkline(line, i->p, 1))
+ if(mkline(line, i->p, i->config_xpad, i->config_ypad, 1.0, 1))
PDF_clip(i->p);
else
; // TODO: strictly speaking, an empty clip clears everything
@@ -132,28 +202,34 @@ void pdf_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*co
internal_t*i = (internal_t*)dev->internal;
if(width<1e-6)
return;
+ reset_matrix(i);
PDF_setlinewidth(i->p, width);
PDF_setlinecap(i->p, cap_style==gfx_capButt?0:(cap_style==gfx_capRound?1:2));
PDF_setlinejoin(i->p, joint_style==gfx_joinMiter?0:(joint_style==gfx_joinRound?1:2));
+
PDF_setrgbcolor_stroke(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
+
if(joint_style==gfx_joinMiter)
PDF_setmiterlimit(i->p, miterLimit);
- if(mkline(line, i->p, 0))
+ if(mkline(line, i->p, i->config_xpad, i->config_ypad, 1.0, 0))
PDF_stroke(i->p);
}
void pdf_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
{
internal_t*i = (internal_t*)dev->internal;
+ reset_matrix(i);
PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
+ /*
+ pdf-x (pdf 1.3) doesn't support opacityfill
if(color->a!=255) {
char opacityfill[80];
sprintf(opacityfill, "opacityfill %f", color->a/256.0);
int gstate = PDF_create_gstate(i->p, opacityfill);
PDF_set_gstate(i->p, gstate);
- }
+ }*/
- if(mkline(line, i->p, 1)) {
+ if(mkline(line, i->p, i->config_xpad, i->config_ypad, 1.0, 1)) {
PDF_fill(i->p);
}
}
@@ -175,11 +251,6 @@ void pdf_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t
double h = sqrt(matrix->m10*matrix->m10+matrix->m11*matrix->m11);
double l1 = w*img->width;
double l2 = h*img->height;
- double r = atan2(matrix->m01, matrix->m00);
-
- /* fit_image needs the lower left corner of the image */
- double x = matrix->tx + matrix->m10*img->height;
- double y = matrix->ty + matrix->m11*img->height;
double dpi_x = 72.0 / w;
double dpi_y = 72.0 / h;
@@ -193,6 +264,11 @@ void pdf_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t
img->width, img->height, dpi, l1, l2, newwidth, newheight, i->config_maxdpi);
img = rescaled_image;
}
+ if(i->config_mindpi && dpi < i->config_mindpi && img->width>1 && img->height>1) {
+ msg("<error> Found image of size %dx%d with dpi %f, minimum allowed dpi is %d",
+ img->width, img->height, dpi, i->config_mindpi);
+ exit(1);
+ }
char tempfile[128];
mktempname(tempfile);
@@ -231,8 +307,13 @@ void pdf_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t
unlink(tempfile);
char options[80];
- sprintf(options, "boxsize {%f %f} fitmethod meet rotate %f", l1, l2, r*180/M_PI);
- PDF_fit_image(i->p, imgid, x, y, options);
+ set_matrix(i, matrix->m00, matrix->m01, matrix->m10, matrix->m11);
+ /* an image's (0,0) is at the lower left corner */
+ double x=matrix->tx + i->config_xpad + matrix->m10*img->height;
+ double y=matrix->ty + i->config_ypad + matrix->m11*img->height;
+ double tx,ty;
+ transform_back(i, x, y, &tx, &ty);
+ PDF_place_image(i->p, imgid, tx, ty, 1.0);
PDF_close_image(i->p, imgid);
if(rescaled_image)
@@ -244,7 +325,8 @@ void pdf_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, g
internal_t*i = (internal_t*)dev->internal;
}
-static char type3 = 1;
+static const char type3 = 1;
+static const char ttf = 0;
void pdf_addfont(gfxdevice_t*dev, gfxfont_t*font)
{
@@ -265,7 +347,7 @@ void pdf_addfont(gfxdevice_t*dev, gfxfont_t*font)
fontname2[t*2+1] = 0;
}
- PDF_begin_font(i->p, fontname2, l*2, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, "");
+ PDF_begin_font(i->p, fontname2, l*2, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, "");
int num = font->num_glyphs<256-32?font->num_glyphs:256-32;
for(t=0;t<num;t++) {
gfxglyph_t*g = &font->glyphs[t];
@@ -273,8 +355,8 @@ void pdf_addfont(gfxdevice_t*dev, gfxfont_t*font)
char name[32];
sprintf(name, "chr%d", t+32);
PDF_encoding_set_char(i->p, fontname, t+32, name, 0);
- PDF_begin_glyph(i->p, name, g->advance, bbox.xmin, bbox.ymin, bbox.xmax, bbox.ymax);
- if(mkline(g->line, i->p, 1))
+ PDF_begin_glyph(i->p, name, g->advance, bbox.xmin/64.0, bbox.ymin/64.0, bbox.xmax/64.0, bbox.ymax/64.0);
+ if(mkline(g->line, i->p, 0, 0, 1.0/64.0, 1))
PDF_fill(i->p);
PDF_end_glyph(i->p);
}
@@ -283,6 +365,29 @@ void pdf_addfont(gfxdevice_t*dev, gfxfont_t*font)
i->fontlist = gfxfontlist_addfont2(i->fontlist, font, (void*)(ptroff_t)fontid);
}
+ } else if(ttf) {
+ int fontid = 0;
+ if(!gfxfontlist_hasfont(i->fontlist, font)) {
+ char fontname[32],filename[32],fontname2[64];
+ static int fontnr = 1;
+ sprintf(fontname, "font%d", fontnr);
+ sprintf(filename, "font%d.ttf", fontnr);
+ fontnr++;
+ const char*old_id = font->id;
+ font->id = fontname;
+ gfxfont_save(font, filename);
+ font->id=old_id;
+
+ int l = strlen(font->id);
+ int t;
+ for(t=0;t<l+1;t++) {
+ fontname2[t*2+0] = fontname[t];
+ fontname2[t*2+1] = 0;
+ }
+ fontid = PDF_load_font(i->p, fontname2, l*2, "host", "");
+ i->fontlist = gfxfontlist_addfont2(i->fontlist, font, (void*)(ptroff_t)fontid);
+ unlink(fontname);
+ }
}
}
@@ -294,38 +399,54 @@ void pdf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color
return;
gfxglyph_t*glyph = &font->glyphs[glyphnr];
- PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
char as_shape = 0;
- if(!type3) as_shape=1;
- if(glyphnr>256-32) as_shape=1;
- if(fabs(matrix->m00 + matrix->m11) > 0.01) as_shape=1;
- if(fabs(fabs(matrix->m01) + fabs(matrix->m10)) > 0.01) as_shape=1;
- if(fabs(matrix->m00) < 1e-6) as_shape=1;
-
+ if(!type3 && !ttf) {msg("<warning> No type3 enabled. Drawing char %d as shape", glyphnr);as_shape=1;}
+ if(glyphnr>256-32) {msg("<warning> Drawing char %d as shape (not < 224)", glyphnr);as_shape=1;}
+
if(as_shape) {
+ reset_matrix(i);
+ PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
gfxline_t*line2 = gfxline_clone(glyph->line);
gfxline_transform(line2, matrix);
- if(mkline(line2, i->p, 1)) {
+ if(mkline(line2, i->p, i->config_xpad, i->config_ypad, 1.0, 1)) {
PDF_fill(i->p);
}
gfxline_free(line2);
} else {
assert(gfxfontlist_hasfont(i->fontlist, font));
int fontid = (int)(ptroff_t)gfxfontlist_getuserdata(i->fontlist, font->id);
- PDF_setfont(i->p, fontid, matrix->m00);
+
+ gfxmatrix_t m = *matrix;
+ m.m00*=64;
+ m.m01*=64;
+ m.m10*=64;
+ m.m11*=64;
+
+ if(!(fabs(m.m00 - i->m00) < 1e-6 &&
+ fabs(m.m01 - i->m01) < 1e-6 &&
+ fabs(m.m10 - i->m10) < 1e-6 &&
+ fabs(m.m11 - i->m11) < 1e-6)) {
+ set_matrix(i, m.m00, m.m01, m.m10, m.m11);
+ }
+ double tx, ty;
+ transform_back(i, m.tx+i->config_xpad, m.ty+i->config_ypad, &tx, &ty);
+
+ //PDF_setfont(i->p, fontid, 1.0/64.0); // downscaling is done in glyph itself
+ PDF_setfont(i->p, fontid, 1.0);
+ PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
+
char name[32];
sprintf(name, "%c", glyphnr+32);
- if(fabs(matrix->tx - i->lastx) > 0.001 || matrix->ty != i->lasty) {
- PDF_show_xy2(i->p, name, strlen(name), matrix->tx, matrix->ty);
+ if(fabs(tx - i->lastx) > 0.001 || ty != i->lasty) {
+ PDF_show_xy2(i->p, name, strlen(name), tx, ty);
} else {
PDF_show2(i->p, name, strlen(name));
}
- i->lastx = matrix->tx + glyph->advance*matrix->m00;
- i->lasty = matrix->ty;
+ i->lastx = tx + glyph->advance;
+ i->lasty = ty;
}
- return;
}
void pdf_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
@@ -336,6 +457,9 @@ void pdf_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
void pdf_endpage(gfxdevice_t*dev)
{
internal_t*i = (internal_t*)dev->internal;
+ if(i->has_matrix) {
+ PDF_restore(i->p); i->has_matrix = 0;
+ }
PDF_end_page(i->p);
}
@@ -379,8 +503,21 @@ void* pdfresult_get(gfxresult_t*gfx, const char*name)
gfxresult_t* pdf_finish(gfxdevice_t*dev)
{
internal_t*i = (internal_t*)dev->internal;
-
- PDF_close(i->p);
+
+ if(i->config_addblankpages) {
+ int mod = i->num_pages%i->config_addblankpages;
+ if(mod) {
+ int count = i->config_addblankpages - mod;
+ int t;
+ for(t=0;t<count;t++) {
+ dev->startpage(dev, i->width, i->height);
+ dev->endpage(dev);
+ }
+ }
+ }
+
+ PDF_end_document(i->p, "");
+ //PDF_close(i->p);
PDF_delete(i->p);
gfxresult_t*result = (gfxresult_t*)malloc(sizeof(gfxresult_t));
@@ -419,8 +556,10 @@ void gfxdevice_pdf_init(gfxdevice_t*dev)
dev->endpage = pdf_endpage;
dev->finish = pdf_finish;
+ i->page_opts = "";
i->lastx = -1e38;
i->lasty = -1e38;
+ i->has_matrix = 0;
i->p = PDF_new();
}