static void ps_closepage(struct termp *p) { int i; size_t len, base; /* * Close out a page that we've already flushed to output. In * PostScript, we simply note that the page must be showed. In * PDF, we must now create the Length, Resource, and Page node * for the page contents. */ assert(p->ps->psmarg && p->ps->psmarg[0]); ps_printf(p, "%s", p->ps->psmarg); if (TERMTYPE_PS != p->type) { ps_printf(p, "ET\n"); len = p->ps->pdfbytes - p->ps->pdflastpg; base = p->ps->pages * 4 + p->ps->pdfbody; ps_printf(p, "endstream\nendobj\n"); /* Length of content. */ pdf_obj(p, base + 1); ps_printf(p, "%zu\nendobj\n", len); /* Resource for content. */ pdf_obj(p, base + 2); ps_printf(p, "<<\n/ProcSet [/PDF /Text]\n"); ps_printf(p, "/Font <<\n"); for (i = 0; i < (int)TERMFONT__MAX; i++) ps_printf(p, "/F%d %d 0 R\n", i, 3 + i); ps_printf(p, ">>\n>>\n"); /* Page node. */ pdf_obj(p, base + 3); ps_printf(p, "<<\n"); ps_printf(p, "/Type /Page\n"); ps_printf(p, "/Parent 2 0 R\n"); ps_printf(p, "/Resources %zu 0 R\n", base + 2); ps_printf(p, "/Contents %zu 0 R\n", base); ps_printf(p, ">>\nendobj\n"); } else ps_printf(p, "showpage\n"); p->ps->pages++; p->ps->psrow = p->ps->top; assert( ! (PS_NEWPAGE & p->ps->flags)); p->ps->flags |= PS_NEWPAGE; }
/* read and dereference an indirect reference */ int pdf_ref(char *pdf, int len, int pos) { int obj, rev; if (pdf_obj(pdf, len, pos, &obj, &rev)) return -1; return pdf_find(pdf, len, obj, rev); }
/* retrieve and dereference a dictionary entry */ int pdf_dval_val(char *pdf, int len, int pos, char *key) { int val = pdf_dval(pdf, len, pos, key); int val_obj, val_rev; if (val < 0) return -1; if (pdf_type(pdf, len, val) == 'r') { pdf_obj(pdf, len, val, &val_obj, &val_rev); return pdf_find(pdf, len, val_obj, val_rev); } return val; }
static void ps_pletter(struct termp *p, int c) { int f; /* * If we haven't opened a page context, then output that we're * in a new page and make sure the font is correctly set. */ if (PS_NEWPAGE & p->ps->flags) { if (TERMTYPE_PS == p->type) { ps_printf(p, "%%%%Page: %zu %zu\n", p->ps->pages + 1, p->ps->pages + 1); ps_printf(p, "/%s %zu selectfont\n", fonts[(int)p->ps->lastf].name, p->ps->scale); } else { pdf_obj(p, p->ps->pdfbody + p->ps->pages * 4); ps_printf(p, "<<\n"); ps_printf(p, "/Length %zu 0 R\n", p->ps->pdfbody + 1 + p->ps->pages * 4); ps_printf(p, ">>\nstream\n"); } p->ps->pdflastpg = p->ps->pdfbytes; p->ps->flags &= ~PS_NEWPAGE; } /* * If we're not in a PostScript "word" context, then open one * now at the current cursor. */ if ( ! (PS_INLINE & p->ps->flags)) { if (TERMTYPE_PS != p->type) { ps_printf(p, "BT\n/F%d %zu Tf\n", (int)p->ps->lastf, p->ps->scale); ps_printf(p, "%.3f %.3f Td\n(", AFM2PNT(p, p->ps->pscol), AFM2PNT(p, p->ps->psrow)); } else ps_printf(p, "%.3f %.3f moveto\n(", AFM2PNT(p, p->ps->pscol), AFM2PNT(p, p->ps->psrow)); p->ps->flags |= PS_INLINE; } assert( ! (PS_NEWPAGE & p->ps->flags)); /* * We need to escape these characters as per the PostScript * specification. We would also escape non-graphable characters * (like tabs), but none of them would get to this point and * it's superfluous to abort() on them. */ switch (c) { case ('('): /* FALLTHROUGH */ case (')'): /* FALLTHROUGH */ case ('\\'): ps_putchar(p, '\\'); break; default: break; } /* Write the character and adjust where we are on the page. */ f = (int)p->ps->lastf; if (c <= 32 || (c - 32 >= MAXCHAR)) { ps_putchar(p, ' '); p->ps->pscol += (size_t)fonts[f].gly[0].wx; return; } ps_putchar(p, (char)c); c -= 32; p->ps->pscol += (size_t)fonts[f].gly[c].wx; }
static void ps_begin(struct termp *p) { time_t t; int i; /* * Print margins into margin buffer. Nothing gets output to the * screen yet, so we don't need to initialise the primary state. */ if (p->ps->psmarg) { assert(p->ps->psmargsz); p->ps->psmarg[0] = '\0'; } /*p->ps->pdfbytes = 0;*/ p->ps->psmargcur = 0; p->ps->flags = PS_MARGINS; p->ps->pscol = p->ps->left; p->ps->psrow = p->ps->header; ps_setfont(p, TERMFONT_NONE); (*p->headf)(p, p->argf); (*p->endline)(p); p->ps->pscol = p->ps->left; p->ps->psrow = p->ps->footer; (*p->footf)(p, p->argf); (*p->endline)(p); p->ps->flags &= ~PS_MARGINS; assert(0 == p->ps->flags); assert(p->ps->psmarg); assert('\0' != p->ps->psmarg[0]); /* * Print header and initialise page state. Following this, * stuff gets printed to the screen, so make sure we're sane. */ t = time(NULL); if (TERMTYPE_PS == p->type) { ps_printf(p, "%%!PS-Adobe-3.0\n"); ps_printf(p, "%%%%CreationDate: %s", ctime(&t)); ps_printf(p, "%%%%DocumentData: Clean7Bit\n"); ps_printf(p, "%%%%Orientation: Portrait\n"); ps_printf(p, "%%%%Pages: (atend)\n"); ps_printf(p, "%%%%PageOrder: Ascend\n"); ps_printf(p, "%%%%DocumentMedia: " "Default %zu %zu 0 () ()\n", (size_t)AFM2PNT(p, p->ps->width), (size_t)AFM2PNT(p, p->ps->height)); ps_printf(p, "%%%%DocumentNeededResources: font"); for (i = 0; i < (int)TERMFONT__MAX; i++) ps_printf(p, " %s", fonts[i].name); ps_printf(p, "\n%%%%EndComments\n"); } else { ps_printf(p, "%%PDF-1.1\n"); pdf_obj(p, 1); ps_printf(p, "<<\n"); ps_printf(p, ">>\n"); ps_printf(p, "endobj\n"); for (i = 0; i < (int)TERMFONT__MAX; i++) { pdf_obj(p, (size_t)i + 3); ps_printf(p, "<<\n"); ps_printf(p, "/Type /Font\n"); ps_printf(p, "/Subtype /Type1\n"); ps_printf(p, "/Name /F%zu\n", i); ps_printf(p, "/BaseFont /%s\n", fonts[i].name); ps_printf(p, ">>\n"); } } p->ps->pdfbody = (size_t)TERMFONT__MAX + 3; p->ps->pscol = p->ps->left; p->ps->psrow = p->ps->top; p->ps->flags |= PS_NEWPAGE; ps_setfont(p, TERMFONT_NONE); }
/* ARGSUSED */ static void ps_end(struct termp *p) { size_t i, xref, base; /* * At the end of the file, do one last showpage. This is the * same behaviour as groff(1) and works for multiple pages as * well as just one. */ if ( ! (PS_NEWPAGE & p->ps->flags)) { assert(0 == p->ps->flags); assert('\0' == p->ps->last); ps_closepage(p); } if (TERMTYPE_PS == p->type) { ps_printf(p, "%%%%Trailer\n"); ps_printf(p, "%%%%Pages: %zu\n", p->ps->pages); ps_printf(p, "%%%%EOF\n"); return; } pdf_obj(p, 2); ps_printf(p, "<<\n/Type /Pages\n"); ps_printf(p, "/MediaBox [0 0 %zu %zu]\n", (size_t)AFM2PNT(p, p->ps->width), (size_t)AFM2PNT(p, p->ps->height)); ps_printf(p, "/Count %zu\n", p->ps->pages); ps_printf(p, "/Kids ["); for (i = 0; i < p->ps->pages; i++) ps_printf(p, " %zu 0 R", i * 4 + p->ps->pdfbody + 3); base = (p->ps->pages - 1) * 4 + p->ps->pdfbody + 4; ps_printf(p, "]\n>>\nendobj\n"); pdf_obj(p, base); ps_printf(p, "<<\n"); ps_printf(p, "/Type /Catalog\n"); ps_printf(p, "/Pages 2 0 R\n"); ps_printf(p, ">>\n"); xref = p->ps->pdfbytes; ps_printf(p, "xref\n"); ps_printf(p, "0 %zu\n", base + 1); ps_printf(p, "0000000000 65535 f \n"); for (i = 0; i < base; i++) ps_printf(p, "%.10zu 00000 n \n", p->ps->pdfobjs[(int)i]); ps_printf(p, "trailer\n"); ps_printf(p, "<<\n"); ps_printf(p, "/Size %zu\n", base + 1); ps_printf(p, "/Root %zu 0 R\n", base); ps_printf(p, "/Info 1 0 R\n"); ps_printf(p, ">>\n"); ps_printf(p, "startxref\n"); ps_printf(p, "%zu\n", xref); ps_printf(p, "%%%%EOF\n"); }