aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plpprint/.cvsignore1
-rw-r--r--plpprint/Makefile.am4
-rw-r--r--plpprint/plpprintd.cc571
-rw-r--r--plpprint/prolog.ps.in159
4 files changed, 702 insertions, 33 deletions
diff --git a/plpprint/.cvsignore b/plpprint/.cvsignore
index 067f1e1..c5361f5 100644
--- a/plpprint/.cvsignore
+++ b/plpprint/.cvsignore
@@ -3,3 +3,4 @@ Makefile
.libs
.deps
plpprintd
+prolog.ps
diff --git a/plpprint/Makefile.am b/plpprint/Makefile.am
index f0d0a4e..9d44b15 100644
--- a/plpprint/Makefile.am
+++ b/plpprint/Makefile.am
@@ -6,5 +6,7 @@ sbin_PROGRAMS = plpprintd
plpprintd_LDADD = $(top_srcdir)/lib/libplp.la
plpprintd_SOURCES = plpprintd.cc
+pkgdata_DATA = prolog.ps
+
maintainer-clean-local:
- rm -f Makefile.in
+ rm -f Makefile.in prolog.ps
diff --git a/plpprint/plpprintd.cc b/plpprint/plpprintd.cc
index 7cf4006..9f32c22 100644
--- a/plpprint/plpprintd.cc
+++ b/plpprint/plpprintd.cc
@@ -36,6 +36,7 @@
#include <ppsocket.h>
#include <wprt.h>
+#include <psibitmap.h>
#define _GNU_SOURCE
#include <getopt.h>
@@ -113,58 +114,564 @@ infolog(char *fmt, ...)
return 0;
}
+static int minx, maxx, miny, maxy;
+string usedfonts;
+
+typedef struct {
+ char *psifont;
+ bool bold;
+ bool italic;
+ char *psfont;
+} fontmap_entry;
+
+#define FALLBACK_FONT "Courier"
+
+static fontmap_entry fontmap[] = {
+ { "Times New Roman", false, false, "Times-Roman"},
+ { "Times New Roman", true, false, "Times-Bold"},
+ { "Times New Roman", false, true, "Times-Italic"},
+ { "Times New Roman", true, true, "Times-BoldItalic"},
+ { "Arial", false, false, "Helvetica"},
+ { "Arial", true, false, "Helvetica-Bold"},
+ { "Arial", false, true, "Helvetica-Oblique"},
+ { "Arial", true, true, "Helvetica-BoldOblique"},
+ { "Courier New", false, false, "Courier"},
+ { "Courier New", true, false, "Courier-Bold"},
+ { "Courier New", false, true, "Courier-Oblique"},
+ { "Courier New", true, true, "Courier-BoldOblique"},
+ { "Swiss", false, false, "Courier"},
+ { "Swiss", true, false, "Courier-Bold"},
+ { "Swiss", false, true, "Courier-Oblique"},
+ { "Swiss", true, true, "Courier-BoldOblique"},
+ { NULL, false, false, NULL}
+};
+
+static void
+ps_setfont(FILE *f, const char *fname, bool bold, bool italic,
+ unsigned long fsize)
+{
+ fontmap_entry *fe = fontmap;
+ char *psf = NULL;
+ while (fe->psifont) {
+ if ((!strcmp(fe->psifont, fname)) &&
+ (fe->bold == bold) &&
+ (fe->italic == italic)) {
+ psf = fe->psfont;
+ break;
+ }
+ fe++;
+ }
+ if (!psf) {
+ psf = FALLBACK_FONT;
+ errorlog("No font mapping for '%s' (%s%s%s); fallback to %s\n",
+ fname, (bold) ? "Bold" : "", (italic) ? "Italic" : "",
+ (bold || italic) ? "" : "Regular", psf);
+ }
+ if (usedfonts.find(psf) == usedfonts.npos) {
+ usedfonts += "%%+ font ";
+ usedfonts += psf;
+ usedfonts += "\n";
+ }
+ fprintf(f, "%d /%s F\n", fsize, psf);
+}
+
static void
-convert_job(const char *jobname)
+ps_escape(string &text)
{
- // ... To be done ...
- unlink(jobname);
+ int pos = 0;
+ while ((pos = text.find_first_of("()", pos)) != text.npos) {
+ text.insert(pos, "\\");
+ pos += 2;
+ }
+}
+
+static void
+ps_bitmap(FILE *f, int llx, int lly, int urx, int ury, const char *buf)
+{
+ bufferStore out;
+ int width, height;
+ if (decodeBitmap((const unsigned char *)buf, width, height, out)) {
+ fprintf(f, "%d %d %d %d I\n");
+ const char *p = out.getString(0);
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++)
+ fprintf(f, "%02x", *p++);
+ fprintf(f, "\n");
+ }
+ } else
+ errorlog("Corrupted bitmap data");
+}
+
+static void
+convertPage(FILE *f, int page, bool last, bufferStore buf)
+{
+ int len = buf.getLen();
+ int i = 0;
+ long boffset = 0;
+ unsigned long left = 0;
+ unsigned long top = 0;
+ unsigned long right = 0;
+ unsigned long bottom = 0;
+ int lmargin = -1;
+
+#ifdef DEBUG
+ char dumpname[128];
+ sprintf(dumpname, "/tmp/pdump_%d", page);
+ FILE *df = fopen(dumpname, "w");
+ fwrite(buf.getString(0), 1, len, df);
+ fclose(df);
+ debuglog("Saved page input to %s\n", dumpname);
+#endif
+ if (page == 0) {
+ time_t now = time(NULL);
+ fputs(
+ "%!PS-Adobe-3.0\n"
+ "%%Creator: plpprintd " VERSION "\n"
+ "%%CreationDate: ", f);
+ fputs(ctime(&now), f);
+ fputs(
+ "%%Pages: (atend)\n"
+ "%%BoundingBox: (atend)\n"
+ "%%DocumentNeededResources: (atend)\n"
+ "%%LanguageLvel: 2\n"
+ "%%EndComments\n"
+ "%%BeginProlog\n", f);
+ char pbuf[1024];
+ FILE *pf = fopen(PKGDATA "/prolog.ps", "r");
+ while (fgets(pbuf, sizeof(pbuf), pf))
+ fputs(pbuf, f);
+ fclose(pf);
+ fputs(
+ "%%EndProlog\n"
+ "%%BeginSetup\n"
+ "currentpagedevice /PageSize get 1 get /top exch def\n"
+ "%%EndSetup\n", f);
+ minx = miny = 9999;
+ maxx = maxy = 0;
+ usedfonts = "";
+ }
+ fprintf(f, "%%%%Page: %d %d\n", page+1, page+1);
+ while (i < len) {
+ unsigned char opcode = buf.getByte(i);
+ switch (opcode) {
+ case 0x00: {
+ // Start of section
+ unsigned long section = buf.getDWord(i+1);
+ fprintf(f, "%% @%d: Section %d\n", i, section);
+ // (section & 3) =
+ // 0 = Header, 1 = Body, 2 = Footer, 3 = Footer
+ i += 5;
+ }
+ break;
+ case 0x01: {
+ // End of page
+ i = len + 1;
+ }
+ break;
+ case 0x03: {
+ // ???
+ fprintf(f, "%% @%d: U03 %d\n", i, buf.getByte(i+1));
+ debuglog("@%d: U03 %d", i, buf.getByte(i+1));
+ i += 2;
+ }
+ break;
+ case 0x04: {
+ // Bounding box
+ left = buf.getDWord(i+1);
+ top = buf.getDWord(i+5);
+ right = buf.getDWord(i+9);
+ bottom = buf.getDWord(i+13);
+ if (lmargin == -1)
+ lmargin = left;
+ if (left < minx)
+ minx = left;
+ if (right > maxx)
+ maxx = right;
+ if (top < miny)
+ miny = top;
+ if (bottom > maxy)
+ maxy = bottom;
+ i += 17;
+ fprintf(f, "%% @%d: bbox %d %d %d %d\n", i, left, top, right,
+ bottom);
+ }
+ break;
+ case 0x05: {
+ // ???
+ fprintf(f, "%% @%d: U05\n", i);
+ debuglog("@%d: U05", i);
+ i++;
+ }
+ break;
+ case 0x06: {
+ // ???
+ fprintf(f, "%% @%d: U06 %d 0x%08x\n", i,
+ buf.getByte(i+1), buf.getDWord(i+2));
+ debuglog("@%d: U06 %d 0x%08x", i,
+ buf.getByte(i+1), buf.getDWord(i+2));
+ i += 6;
+ }
+ break;
+ case 0x07: {
+ // Font
+ int namelen;
+ int ofs;
+ if (buf.getByte(i+1) & 1) {
+ namelen = buf.getWord(i+1) >> 3;
+ ofs = i + 3;
+ } else {
+ namelen = buf.getByte(i+1) >> 2;
+ ofs = i + 2;
+ }
+ string fname(buf.getString(ofs), namelen);
+ ofs += namelen;
+ int screenfont = buf.getByte(ofs);
+ int basesize = buf.getWord(ofs+1);
+ unsigned long style = buf.getDWord(ofs+3);
+ bool italic = ((style & 1) != 0);
+ bool bold = ((style & 2) != 0);
+ unsigned long fontsize = buf.getDWord(ofs+7);
+ boffset = (long)buf.getDWord(ofs+11);
+ fprintf(f, "%% @%d: Font '%s' %d %s%s%s\n", i, fname.c_str(),
+ fontsize, bold ? "Bold" : "", italic ? "Italic" : "",
+ (bold || italic) ? "" : "Regular");
+ ps_setfont(f, fname.c_str(), bold, italic, fontsize);
+ i = ofs + 15;
+ }
+ break;
+ case 0x08: {
+ // ???
+ fprintf(f, "%% @%d: U08\n", i);
+ debuglog("@%d: U08", i);
+ i++;
+ }
+ break;
+ case 0x09: {
+ // underline
+ fprintf(f, "%% @%d: Underline %d\n", i, buf.getByte(i+1));
+ fprintf(f, "%d UL\n", buf.getByte(i+1));
+ i += 2;
+ }
+ break;
+ case 0x0a: {
+ // strikethru
+ fprintf(f, "%% @%d: Strikethru %d\n", i, buf.getByte(i+1));
+ fprintf(f, "%d ST\n", buf.getByte(i+1));
+ i += 2;
+ }
+ break;
+ case 0x0b: {
+ // newline
+ fprintf(f, "%% @%d: Newline %d %d\n", i, buf.getDWord(i+1),
+ buf.getDWord(i+5));
+ i += 9;
+ }
+ break;
+ case 0x0c: {
+ // cr
+ fprintf(f, "%% @%d: CR %d %d\n", i, buf.getDWord(i+1),
+ buf.getDWord(i+5));
+ i += 9;
+ }
+ break;
+ case 0x0d: {
+ // foreground color
+ fprintf(f, "%% @%d: Foreground %d %d %d\n", i, buf.getByte(i+1),
+ buf.getByte(i+2), buf.getByte(i+3));
+ fprintf(f, "%d %d %d FG\n", buf.getByte(i+1),
+ buf.getByte(i+2), buf.getByte(i+3));
+ i += 4;
+ }
+ break;
+ case 0x0e: {
+ // ???
+ fprintf(f, "%% @%d: U0e %d\n", i, buf.getByte(i+1));
+ debuglog("@%d: U0e %d", i, buf.getByte(i+1));
+ i += 2;
+ }
+ break;
+ case 0x0f: {
+ // ???
+ fprintf(f, "%% @%d: U0f %d %d\n", i, buf.getDWord(i+1),
+ buf.getDWord(i+5));
+ debuglog("@%d: U0f %d %d", i, buf.getDWord(i+1),
+ buf.getDWord(i+5));
+ i += 9;
+ }
+ break;
+ case 0x10: {
+ // background color
+ fprintf(f, "%% @%d: Background %d %d %d\n", i, buf.getByte(i+1),
+ buf.getByte(i+2), buf.getByte(i+3));
+ fprintf(f, "%d %d %d BG\n", buf.getByte(i+1),
+ buf.getByte(i+2), buf.getByte(i+3));
+ i += 4;
+ }
+ break;
+ case 0x11: {
+ // ???
+ fprintf(f, "%% @%d: U11 %d\n", i, buf.getByte(i+1));
+ debuglog("@%d: U11 %d", i, buf.getByte(i+1));
+ i += 2;
+ }
+ break;
+ case 0x17: {
+ // ???
+ fprintf(f, "%% @%d: U17 %d %d\n", i, buf.getDWord(i+1),
+ buf.getDWord(i+5));
+ debuglog("@%d: U17 %d %d", i, buf.getDWord(i+1),
+ buf.getDWord(i+5));
+ i += 9;
+ }
+ break;
+ case 0x19: {
+ // Draw line
+ fprintf(f, "%% @%d: Line %d %d %d %d\n", i,
+ buf.getDWord(i+1), buf.getDWord(i+5),
+ buf.getDWord(i+9), buf.getDWord(i+13));
+ fprintf(f, "%d %d %d %d L\n",
+ buf.getDWord(i+1), buf.getDWord(i+5),
+ buf.getDWord(i+9), buf.getDWord(i+13));
+ i += 17;
+ }
+ break;
+ case 0x1b: {
+ // ???
+ fprintf(f, "%% @%d: U1b %d %d\n", i, buf.getDWord(i+1),
+ buf.getDWord(i+5));
+ debuglog("@%d: U1b %d %d", i, buf.getDWord(i+1),
+ buf.getDWord(i+5));
+ i += 9;
+ }
+ break;
+ case 0x1f: {
+ // Draw ellipse
+ fprintf(f, "%% @%d: Ellipse %d %d %d %d\n", i,
+ buf.getDWord(i+1), buf.getDWord(i+5),
+ buf.getDWord(i+9), buf.getDWord(i+13));
+ fprintf(f, "%d %d %d %d E\n",
+ buf.getDWord(i+1), buf.getDWord(i+5),
+ buf.getDWord(i+9), buf.getDWord(i+13));
+ i += 17;
+ }
+ break;
+ case 0x20: {
+ // Draw rectangle
+ fprintf(f, "%% @%d: Rectangle %d %d %d %d\n", i,
+ buf.getDWord(i+1), buf.getDWord(i+5),
+ buf.getDWord(i+9), buf.getDWord(i+13));
+ fprintf(f, "%d %d %d %d R\n",
+ buf.getDWord(i+1), buf.getDWord(i+5),
+ buf.getDWord(i+9), buf.getDWord(i+13));
+ i += 17;
+ }
+ break;
+
+ case 0x23: {
+ // Draw polygon
+ unsigned long count = buf.getDWord(i+1);
+ int o = i + 5;
+ fprintf(f, "%% @%d: Polygon (%d segments)\n", i, count);
+ fprintf(f, "[\n");
+ for (int j = 0; j < count; j++) {
+ fprintf(f, "%d %d\n", buf.getDWord(o),
+ buf.getDWord(o+4));
+ o += 8;
+ }
+ fprintf(f, "] P\n");
+ i = o + 1;
+ }
+ break;
+ case 0x25: {
+ // Draw bitmap
+ // skip for now
+ unsigned long blen = buf.getDWord(i+17);
+ fprintf(f, "%% @%d: U25\n", i);
+ debuglog("@%d: U25 len=%d ofs=%d", i, blen, buf.getDWord(i+21));
+ i += (17 + blen);
+ }
+ break;
+ case 0x26: {
+ // Draw bitmap
+ unsigned long llx = buf.getDWord(i+1);
+ unsigned long lly = buf.getDWord(i+13);
+ unsigned long urx = buf.getDWord(i+9);
+ unsigned long ury = buf.getDWord(i+5);
+ unsigned long bw = buf.getDWord(i+25);
+ unsigned long bh = buf.getDWord(i+29);
+ unsigned long blen = buf.getDWord(i+17);
+ unsigned long bofs = buf.getDWord(i+21);
+ unsigned long bits = buf.getDWord(i+41);
+ bool rle = (buf.getDWord(i+53) == 1);
+ fprintf(f, "%% @%d: Bitmap\n", i);
+ ps_bitmap(f, llx, lly, urx, ury, buf.getString(17));
+ debuglog("Bitmap len=%d ofs=%d", blen, bofs);
+ i += (17 + blen + 16);
+ }
+ break;
+ case 0x27: {
+ // Draw label
+ int tlen;
+ int ofs;
+ if (buf.getByte(i+1) & 1) {
+ tlen = buf.getWord(i+1) >> 3;
+ ofs = i + 3;
+ } else {
+ tlen = buf.getByte(i+1) >> 2;
+ ofs = i + 2;
+ }
+ string text(buf.getString(ofs), tlen);
+ ofs += tlen;
+ ps_escape(text);
+ fprintf(f, "(%s) %d %d 0 0 false T\n", text.c_str(),
+ buf.getDWord(ofs), buf.getDWord(ofs+4) + boffset);
+ i = ofs + 8;
+ }
+ break;
+ case 0x28: {
+ // Draw text
+ int tlen;
+ int ofs;
+ if (buf.getByte(i+1) & 1) {
+ tlen = buf.getWord(i+1) >> 3;
+ ofs = i + 3;
+ } else {
+ tlen = buf.getByte(i+1) >> 2;
+ ofs = i + 2;
+ }
+ string text(buf.getString(ofs), tlen);
+ ofs += tlen;
+ int x = buf.getDWord(ofs);
+ fprintf(f, "%% @%d: Text '%s' %d %d %d %d ?%d ?%d\n", i,
+ text.c_str(), x, buf.getDWord(ofs+12) + boffset,
+ buf.getDWord(ofs+4), buf.getDWord(ofs+8),
+ buf.getByte(ofs+16), buf.getDWord(ofs+17));
+ ps_escape(text);
+ if ((x == 0) && (lmargin != -1))
+ x = lmargin;
+ fprintf(f, "(%s) %d %d %d %d true T\n", text.c_str(),
+ x, buf.getDWord(ofs+12) + boffset,
+ buf.getDWord(ofs+4), buf.getDWord(ofs+8));
+ i = ofs + 25;
+ }
+ break;
+ default:
+ debuglog("@%d: UNHANDLED OPCODE %02x", i, opcode);
+ i++;
+ break;
+ }
+ }
+ fprintf(f, "showpage\n");
+ if (last) {
+ fputs(
+ "%%Trailer\n"
+ "%%DocumentNeededResources: ", f);
+ if (usedfonts.empty())
+ fputs("none\n", f);
+ else {
+ usedfonts.erase(0, 4);
+ fputs(usedfonts.c_str(), f);
+ }
+ fprintf(f, "%%%%Pages: %d\n", page + 1);
+ fprintf(f, "%%%%BoundingBox: %d %d %d %d\n",
+ minx / 20, miny / 20, maxx / 20, maxy / 20);
+ fputs("%%EOF\n", f);
+ }
}
+static unsigned char fakePage[15] = {
+ 0x2a, 0x2a, 0x09, 0x00, 0x00, 0x00, 0x82, 0x2e,
+ 0x00, 0x00, 0xc6, 0x41, 0x00, 0x00, 0x00,
+};
+
+const
static void
service_loop()
{
serviceLoop = true;
while (serviceLoop) {
bool spoolOpen = false;
- bufferStore c;
+ bool pageStart = true;
+ bool cancelled = false;
+ unsigned long plen;
+ int pageCount;
+ bufferStore buf;
+ bufferStore pageBuf;
int fd;
+ FILE *f;
+ unsigned char b;
char *jname =
(char *)malloc(strlen(spooldir) +
strlen(TEMPLATE) + 2);
while (1) {
/* Job loop */
- c.init();
- if (wPrt->getData(c) != rfsv::E_PSI_GEN_NONE) {
- if (spoolOpen) {
- unlink(jname);
- close(fd);
- errorlog("Job aborted");
+ buf.init();
+ if (wPrt->getData(buf) == rfsv::E_PSI_GEN_NONE) {
+ if ((buf.getLen() == 15) &&
+ (!memcmp(buf.getString(0), fakePage, 15))) {
+ cancelled = false;
+ if (spoolOpen) {
+ fclose(f);
+ infolog("Cancelled job %s", jname);
+ unlink(jname);
+ break;
+ }
+ continue;
+ }
+ if (!spoolOpen && !cancelled) {
+ sprintf(jname, "%s/%s", spooldir, TEMPLATE);
+ if ((fd = mkstemp(jname)) != -1) {
+ infolog("Receiving new job %s", jname);
+ spoolOpen = true;
+ pageStart = true;
+ pageCount = 0;
+ } else {
+ errorlog("Could not create spool file.");
+ cancelled = true;
+ wPrt->cancelJob();
+ }
+ f = fdopen(fd, "w");
+ plen = 0;
+ }
+ b = buf.getByte(0);
+ if ((b != 0x2a) && (b != 0xff)) {
+ errorlog("Invalid packet type 0x%02x.", b);
+ cancelled = true;
+ wPrt->cancelJob();
+ }
+ bool jobEnd = (b == 0xff);
+ if (!cancelled) {
+ buf.discardFirstBytes(1);
+ if (pageStart) {
+ b = buf.getByte(0);
+ plen = buf.getDWord(1) - 8;
+ buf.discardFirstBytes(5+8);
+ pageStart = false;
+ pageBuf.init();
+ }
+ pageBuf.addBuff(buf);
+ plen -= buf.getLen();
+ if (plen <= 0) {
+ convertPage(f, pageCount++, jobEnd, pageBuf);
+ pageBuf.init();
+ pageStart = true;
+ }
+ }
+ if (jobEnd) {
+ if (spoolOpen)
+ fclose(f);
+ if (!cancelled) {
+ if (pageCount > 0) {
+ infolog("Spooling %d pages", pageCount);
+ // TODO: print it...
+ }
+ } else
+ unlink(jname);
+ spoolOpen = false;
}
- free(jname);
- return;
- }
- if ((c.getLen() == 15) && (c.getWord(0) == 0x2a2a)) {
- sprintf(jname, "%s/%s", spooldir, TEMPLATE);
- if ((fd = mkstemp(jname)) != -1) {
- debuglog("Receiving new job %s", jname);
- write(fd, c.getString(0), c.getLen());
- spoolOpen = true;
- } else
- errorlog("Could not create spool file.");
- } else {
- if (spoolOpen)
- write(fd, c.getString(0), c.getLen());
- if (c.getWord(0) == 0xffff)
- break;
}
}
- if (spoolOpen) {
- close(fd);
- spoolOpen = false;
- debuglog("Job received, start conversion ...");
- convert_job(jname);
- }
free(jname);
}
}
diff --git a/plpprint/prolog.ps.in b/plpprint/prolog.ps.in
new file mode 100644
index 0000000..4321eaf
--- /dev/null
+++ b/plpprint/prolog.ps.in
@@ -0,0 +1,159 @@
+%%BeginResource: plpprint_prolog @VERSION@ 0
+% $Id$
+/ul false def
+/st false def
+/bg [0 0 0] def
+/fg [0 0 0] def
+/twips{1440 div 72 mul}bind def
+/EpocEncoding ISOLatin1Encoding 256 array copy dup 128
+[/Euro/.notdef/quotesinglbase/florin/quotedblbase/ellipsis/dagger/daggerdbl
+/circumflex/perthousand/Scaron/guilsinglleft/OE/.notdef/Zcaron/.notdef
+/.notdef/quoteleft/quoteright/quotedblleft/quotedblright/bullet/endash
+/emdash/tilde/trademark/scaron/guilsinglright/oe/.notdef/zcaron/ydieresis]
+putinterval def
+/fs{ % fontvalue fs pointvalue
+ 1000 div 24 mul
+}bind def
+/m{
+ top exch sub moveto
+}bind def
+/l{
+ top exch sub lineto
+}bind def
+/UL{
+ 1 eq /ul exch def
+}bind def
+/ST{
+ 1 eq /st exch def
+}bind def
+/BG{ % r g b BG - (store background color)
+ mark 4 1 roll ] /bg exch def
+}bind def
+/FG{ % r g b FG - (store foreground color)
+ mark 4 1 roll ] /fg exch def
+}bind def
+/SC{ % colorarray SC - (set stored color)
+ dup 0 get 255 div exch
+ dup 1 get 255 div exch
+ 2 get 255 div
+ setrgbcolor
+}bind def
+/F{
+ findfont
+ % reencode for ISOLatin1. (From redbook sec. 5.6.1) and add some
+ % special symbols, resulting in an EPOC encoding
+ dup length dict begin
+ {
+ 1 index dup /FID ne {
+ /CharStrings ne {
+ def
+ } {
+ % must copy CharStrings dict to make it writeable
+ dup length dict begin {def} forall
+ % copy /Euro charstring from Symbol font
+ /Euro /Symbol findfont /CharStrings get /Euro get def
+ currentdict end def
+ } ifelse
+ } {
+ pop pop pop
+ } ifelse
+ } forall
+ % Replace encoding
+ /Encoding EpocEncoding def
+ currentdict
+ end dup /FontName get 80 string cvs (-EPOCLatin15) concatstrings cvn
+ exch definefont
+ % end of reencoding
+ exch twips scalefont setfont
+}bind def
+/L{ % x1 y1 x2 y2 L - (draw line from x1,y1 to x2,y2)
+ 4 -1 roll twips 4 -1 roll twips m
+ twips exch twips exch l fg SC stroke
+}bind def
+/R{ % left top right bottom R - (draw rectangle)
+ 4 dict begin
+ twips /y2 exch def
+ twips /x2 exch def
+ twips /y1 exch def
+ twips /x1 exch def
+ newpath
+ x1 y1 m x2 y1 l x2 y2 l x1 y2 l closepath
+ gsave bg SC fill grestore fg SC stroke
+ end
+}bind def
+/E { % ulx uly llx lly E - (draw ellipse)
+ 6 dict begin
+ twips /lly exch def
+ twips /llx exch def
+ twips /uly exch def
+ twips /ulx exch def
+ /wx llx ulx sub def
+ /wy lly uly sub def
+ gsave
+ newpath
+ ulx wx 2 div add top uly sub wy 2 div sub translate
+ 1 wy wx div scale
+ newpath wx 2 div 0 moveto
+ 0 0 wx 2 div 0 360 arc closepath
+ gsave bg SC fill grestore fg SC stroke
+ grestore
+ end
+}bind def
+/P{ % pointarray P - (draw polygon)
+ 4 dict begin
+ /points exch def
+ 0 2 points length 1 sub {
+ /idx exch def
+ points idx get twips
+ points idx 1 add get twips
+ idx 0 eq {m}{l} ifelse
+ } for
+ gsave bg SC fill grestore fg SC stroke
+ end
+}bind def
+/T{ % string left bottom top right justify T - (draw text)
+ 5 dict begin
+ /just exch def
+ twips /x2 exch def
+ twips /y2 exch def
+ twips /y1 exch def
+ twips /x1 exch def
+ x1 y1 m
+ gsave
+ just pop false {
+ gsave
+ newpath 0 0 moveto dup false charpath pathbbox
+ grestore
+ 4 1 roll exch sub 3 1 roll sub % width height
+ y2 y1 sub exch div exch % yscale width
+ x2 x1 sub exch div exch % xscale yscale
+ scale
+ } if
+ ul {
+ gsave
+ currentfont /FontInfo known {
+ currentfont /FontInfo get begin
+ 0 UnderlinePosition fs rmoveto
+ UnderlineThickness fs setlinewidth
+ end
+ } {
+ 0 -10 rmoveto 0.5 setlinewidth
+ } ifelse
+ dup stringwidth rlineto stroke
+ grestore
+ } if
+ st {
+ gsave
+ newpath 0 0 moveto (I) false charpath pathbbox
+ exch pop exch sub exch pop 2 div 0 exch
+ grestore
+ gsave
+ rmoveto
+ dup stringwidth rlineto stroke
+ grestore
+ } if
+ show
+ grestore
+ end
+}bind def
+%%EndResource