From 4e333e4605a3ac27a920f1079021f02f2167940b Mon Sep 17 00:00:00 2001 From: Elie Le Vaillant Date: Sat, 14 Sep 2024 15:23:40 +0000 Subject: [PATCH] pdf&ps: Add support for line control This includes line thickness, line cap and line join. This was added to ps using \X'set' commands. A new drawing primitive, mirroring groff's, was introduced: \D't'. It allows directly setting line width using units. \D't 1i' has expected results (a line width of an inch), whereas .nr a 1i .dv set linewidth \na does not, because the argument of linewidth is in thousandths of ems. It's also arguably more cumbersome. --- pdf.c | 9 +++++++-- post.c | 3 +++ post.h | 1 + ps.c | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/pdf.c b/pdf.c index d881266..e34414f 100644 --- a/pdf.c +++ b/pdf.c @@ -879,8 +879,8 @@ void drawend(int close, int fill) fill = !fill ? 2 : fill; if (l_page != page_n || l_size != o_s || l_wid != pdf_linewid || l_cap != pdf_linecap || l_join != pdf_linejoin) { - int lwid = pdf_linewid * o_s; - sbuf_printf(pg, "%d.%03d w\n", lwid / 1000, lwid % 1000); + int lwid = pdf_linewid; + sbuf_printf(pg, "%d.%02d w\n", lwid / 100, lwid % 100); sbuf_printf(pg, "%d J %d j\n", pdf_linecap, pdf_linejoin); l_page = page_n; l_size = o_s; @@ -979,6 +979,11 @@ void draws(int h1, int v1, int h2, int v2) outrel(h1, v1); } +void drawt(int w) +{ + pdf_linewid = w * 7200 / dev_res; +} + void docheader(char *title, int pagewidth, int pageheight, int linewidth) { if (title) diff --git a/post.c b/post.c index fb52a65..11bce12 100644 --- a/post.c +++ b/post.c @@ -232,6 +232,9 @@ static void postdraw(void) int c = next(); drawbeg(); switch (tolower(c)) { + case 't': + drawt(nextnum()); + break; case 'l': h1 = nextnum(); v1 = nextnum(); diff --git a/post.h b/post.h index 0f30569..67e5740 100644 --- a/post.h +++ b/post.h @@ -77,6 +77,7 @@ void drawc(int c); void drawe(int h, int v); void drawa(int h1, int v1, int h2, int v2); void draws(int h1, int v1, int h2, int v2); +void drawt(int w); void docheader(char *title, int pagewidth, int pageheight, int linewidth); void doctrailer(int pages); diff --git a/ps.c b/ps.c index 33336f8..30e2c6a 100644 --- a/ps.c +++ b/ps.c @@ -8,6 +8,7 @@ static char ps_title[256]; /* document title */ static char ps_author[256]; /* document author */ static int ps_height; /* document height in basic units */ +static int page_n = 0; /* number of pages */ static int o_f, o_s, o_m; /* font and size */ static int o_h, o_v; /* current user position */ static int p_f, p_s, p_m; /* output postscript font */ @@ -16,6 +17,10 @@ static int o_qv, o_qh, o_qend; /* queued character position */ static int o_rh, o_rv, o_rdeg; /* previous rotation position and degree */ static int o_gname; /* use glyphshow for all glyphs */ +static int ps_linewid; /* line width in basic units */ +static int ps_linecap = 1; /* line cap style: 0 (butt), 1 (round), 2 (projecting square) */ +static int ps_linejoin = 1; /* line join style: 0 (miter), 1 (round), 2 (bevel) */ + static char o_fonts[FNLEN * NFONTS] = " "; static void outvf(char *s, va_list ap) @@ -200,10 +205,24 @@ void drawmend(char *s) outf("%s grestore\n", s); } +static int l_page, l_size, l_wid, l_cap, l_join; /* drawing line properties */ + void drawbeg(void) { o_flush(); out_fontup(o_f); + if (l_page != page_n || l_size != o_s || l_wid != ps_linewid || + l_cap != ps_linecap || l_join != ps_linejoin) { + outf("%d setlinewidth ", ps_linewid); + outf("%d setlinecap ", ps_linecap); + outf("%d setlinejoin\n", ps_linejoin); + o_flush(); + l_page = page_n; + l_size = o_s; + l_wid = ps_linewid; + l_cap = ps_linecap; + l_join = ps_linejoin; + } if (draw_path) return; outf("newpath "); @@ -258,6 +277,11 @@ void draws(int h1, int v1, int h2, int v2) outrel(h1, v1); } +void drawt(int w) +{ + ps_linewid = w; +} + void outeps(char *eps, int hwid, int vwid) { char buf[1 << 12]; @@ -371,10 +395,17 @@ void outinfo(char *kwd, char *val) void outset(char *var, char *val) { + if (!strcmp("linewidth", var)) + ps_linewid = atoi(val); + if (!strcmp("linecap", var)) + ps_linecap = atoi(val); + if (!strcmp("linejoin", var)) + ps_linejoin = atoi(val); } void docpagebeg(int n) { + page_n = n; out("%%%%Page: %d %d\n", n, n); out("/saveobj save def\n"); out("mark\n"); @@ -506,6 +537,7 @@ static char *prolog = /* pagewidth and pageheight are in tenths of a millimetre */ void docheader(char *title, int pagewidth, int pageheight, int linewidth) { + ps_linewid = linewidth * dev_res / 7200; ps_height = pageheight * dev_res / 254; out("%%!PS-Adobe-2.0\n"); out("%%%%Version: 1.0\n");