void ps_printer::begin_page(int n) { out.begin_comment("Page:") .comment_arg(i_to_a(n)); out.comment_arg(i_to_a(++pages_output)) .end_comment(); output_style.f = 0; output_space_code = 32; output_draw_point_size = -1; output_line_thickness = -1; output_hpos = output_vpos = -1; ndefined_styles = 0; out.simple_comment("BeginPageSetup"); #if 0 /* * NOTE: * may decide to do this once per page */ media_set(); #endif out.put_symbol("BP") .simple_comment("EndPageSetup"); if (sbuf_color != default_color) set_color(&sbuf_color); }
void resource_manager::import_file(const char *filename, ps_output &out) { out.end_line(); string name(filename); resource *r = lookup_resource(RESOURCE_FILE, name); supply_resource(r, -1, out.get_file(), 1); }
void resource_manager::output_prolog(ps_output &out) { FILE *outfp = out.get_file(); out.end_line(); char *path; if (!getenv("GROPS_PROLOGUE")) { string e = "GROPS_PROLOGUE"; e += '='; e += GROPS_PROLOGUE; e += '\0'; if (putenv(strsave(e.contents()))) fatal("putenv failed"); } char *prologue = getenv("GROPS_PROLOGUE"); FILE *fp = font::open_file(prologue, &path); if (!fp) fatal("can't find `%1'", prologue); fputs("%%BeginResource: ", outfp); procset_resource->print_type_and_name(outfp); putc('\n', outfp); process_file(-1, fp, path, outfp); fclose(fp); a_delete path; fputs("%%EndResource\n", outfp); }
void ps_printer::do_file(char *arg, const environment *env) { while (csspace(*arg)) arg++; if (*arg == '\0') { error("missing argument to X file command"); return; } const char *filename = arg; do { ++arg; } while (*arg != '\0' && *arg != ' ' && *arg != '\n'); out.put_fix_number(env->hpos) .put_fix_number(env->vpos) .put_symbol("EBEGIN"); rm.import_file(filename, out); out.put_symbol("EEND"); output_hpos = output_vpos = -1; output_style.f = 0; output_draw_point_size = -1; output_line_thickness = -1; ndefined_styles = 0; if (!ndefs) ndefs = 1; }
void resource_manager::print_header_comments(ps_output &out) { for (resource *r = resource_list; r; r = r->next) if (r->type == RESOURCE_FONT && (r->flags & resource::FONT_NEEDED)) supply_resource(r, 0, 0); print_resources_comment(resource::NEEDED, out.get_file()); print_resources_comment(resource::SUPPLIED, out.get_file()); print_language_level_comment(out.get_file()); print_extensions_comment(out.get_file()); }
void ps_printer::set_style(const style &sty) { char buf[1 + INT_DIGITS + 1]; for (int i = 0; i < ndefined_styles; i++) if (sty == defined_styles[i]) { sprintf(buf, "F%d", i); out.put_symbol(buf); return; } if (ndefined_styles >= MAX_DEFINED_STYLES) ndefined_styles = 0; sprintf(buf, "F%d", ndefined_styles); out.put_literal_symbol(buf); const char *psname = sty.f->get_internal_name(); if (psname == 0) fatal("no internalname specified for font `%1'", sty.f->get_name()); char *encoding = ((ps_font *)sty.f)->encoding; if (sty.sub == 0) { if (encoding != 0) { char *s = ((ps_font *)sty.f)->reencoded_name; if (s == 0) { int ei = set_encoding_index((ps_font *)sty.f); char *tem = new char[strlen(psname) + 1 + INT_DIGITS + 1]; sprintf(tem, "%s@%d", psname, ei); psname = tem; ((ps_font *)sty.f)->reencoded_name = tem; } else psname = s; } } else psname = get_subfont(sty.sub, psname); out.put_fix_number((font::res/(72*font::sizescale))*sty.point_size); if (sty.height != 0 || sty.slant != 0) { int h = sty.height == 0 ? sty.point_size : sty.height; h *= font::res/(72*font::sizescale); int c = int(h*tan(radians(sty.slant)) + .5); out.put_fix_number(c) .put_fix_number(h) .put_literal_symbol(psname) .put_symbol("MF"); } else { out.put_literal_symbol(psname) .put_symbol("SF"); } defined_styles[ndefined_styles++] = sty; }
void ps_printer::encode_subfont(subencoding *sub) { assert(sub->glyphs != 0); out.put_literal_symbol(make_subencoding_name(sub->idx)) .put_delimiter('['); for (int i = 0; i < 256; i++) { if (sub->glyphs[i]) out.put_literal_symbol(sub->glyphs[i]); else out.put_literal_symbol(".notdef"); } out.put_delimiter(']') .put_symbol("def"); }
void ps_printer::reencode_font(ps_font *f) { out.put_literal_symbol(f->reencoded_name) .put_symbol(make_encoding_name(f->encoding_index)) .put_literal_symbol(f->get_internal_name()) .put_symbol("RE"); }
void ps_printer::fill_path(const environment *env) { if (sbuf_color == *env->fill) out.put_symbol("FL"); else set_color(env->fill, 1); }
void ps_printer::do_exec(char *arg, const environment *env) { flush_sbuf(); while (csspace(*arg)) arg++; if (*arg == '\0') { error("missing argument to X exec command"); return; } if (!check_line_lengths(arg)) { error("lines in X exec command must not be more than 255 characters long"); return; } out.put_fix_number(env->hpos) .put_fix_number(env->vpos) .put_symbol("EBEGIN") .special(arg) .put_symbol("EEND"); output_hpos = output_vpos = -1; output_style.f = 0; output_draw_point_size = -1; output_line_thickness = -1; ndefined_styles = 0; if (!ndefs) ndefs = 1; }
void ps_printer::media_set() { /* * The setpagedevice implies an erasepage and initgraphics, and * must thus precede any descriptions for a particular page. * * NOTE: * This does not work with ps2pdf when there are included eps * segments that contain PageSize/setpagedevice. * This might be a bug in ghostscript -- must be investigated. * Using setpagedevice in an .eps is really the wrong concept, anyway. * * NOTE: * For the future, this is really the place to insert other * media selection features, like: * MediaColor * MediaPosition * MediaType * MediaWeight * MediaClass * TraySwitch * ManualFeed * InsertSheet * Duplex * Collate * ProcessColorModel * etc. */ if (!(broken_flags & (USE_PS_ADOBE_2_0|NO_PAPERSIZE))) { out.begin_comment("BeginFeature:") .comment_arg("*PageSize") .comment_arg(media_name()) .end_comment(); int w = media_width(); int h = media_height(); if (w > 0 && h > 0) // warning to user is done elsewhere fprintf(out.get_file(), "<< /PageSize [ %d %d ] /ImagingBBox null >> setpagedevice\n", w, h); out.simple_comment("EndFeature"); } }
void ps_printer::end_page(int) { flush_sbuf(); set_color(&default_color); out.put_symbol("EP"); if (invis_count != 0) { error("missing `endinvis' command"); invis_count = 0; } }
void ps_printer::define_encoding(const char *encoding, int encoding_index) { char *vec[256]; int i; for (i = 0; i < 256; i++) vec[i] = 0; char *path; FILE *fp = font::open_file(encoding, &path); if (fp == 0) fatal("can't open encoding file `%1'", encoding); int lineno = 1; const int BUFFER_SIZE = 512; char buf[BUFFER_SIZE]; while (fgets(buf, BUFFER_SIZE, fp) != 0) { char *p = buf; while (csspace(*p)) p++; if (*p != '#' && *p != '\0' && (p = strtok(buf, WS)) != 0) { char *q = strtok(0, WS); int n = 0; // pacify compiler if (q == 0 || sscanf(q, "%d", &n) != 1 || n < 0 || n >= 256) fatal_with_file_and_line(path, lineno, "bad second field"); vec[n] = new char[strlen(p) + 1]; strcpy(vec[n], p); } lineno++; } a_delete path; out.put_literal_symbol(make_encoding_name(encoding_index)) .put_delimiter('['); for (i = 0; i < 256; i++) { if (vec[i] == 0) out.put_literal_symbol(".notdef"); else { out.put_literal_symbol(vec[i]); a_delete vec[i]; } } out.put_delimiter(']') .put_symbol("def"); fclose(fp); }
void ps_printer::set_line_thickness_and_color(const environment *env) { if (line_thickness < 0) { if (output_draw_point_size != env->size) { // we ought to check for overflow here int lw = ((font::res/(72*font::sizescale))*linewidth*env->size)/1000; out.put_fix_number(lw) .put_symbol("LW"); output_draw_point_size = env->size; output_line_thickness = -1; } } else { if (output_line_thickness != line_thickness) { out.put_fix_number(line_thickness) .put_symbol("LW"); output_line_thickness = line_thickness; output_draw_point_size = -1; } } if (sbuf_color != *env->col) set_color(env->col); }
void ps_printer::set_color(color *col, int fill) { sbuf_color = *col; unsigned int components[4]; char s[3]; color_scheme cs = col->get_components(components); s[0] = fill ? 'F' : 'C'; s[2] = 0; switch (cs) { case DEFAULT: // black out.put_symbol("0"); s[1] = 'g'; break; case RGB: out.put_color(Red) .put_color(Green) .put_color(Blue); s[1] = 'r'; break; case CMY: col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black); // fall through case CMYK: out.put_color(Cyan) .put_color(Magenta) .put_color(Yellow) .put_color(Black); s[1] = 'k'; cmyk_flag = 1; break; case GRAY: out.put_color(Gray); s[1] = 'g'; break; } out.put_symbol(s); }
void resource_manager::document_setup(ps_output &out) { int nranks = 0; resource *r; for (r = resource_list; r; r = r->next) if (r->rank >= nranks) nranks = r->rank + 1; if (nranks > 0) { // Sort resource_list in reverse order of rank. Presource *head = new Presource[nranks + 1]; Presource **tail = new Presource *[nranks + 1]; int i; for (i = 0; i < nranks + 1; i++) { head[i] = 0; tail[i] = &head[i]; } for (r = resource_list; r; r = r->next) { i = r->rank < 0 ? 0 : r->rank + 1; *tail[i] = r; tail[i] = &(*tail[i])->next; } resource_list = 0; for (i = 0; i < nranks + 1; i++) if (head[i]) { *tail[i] = resource_list; resource_list = head[i]; } a_delete head; a_delete tail; // check it for (r = resource_list; r; r = r->next) if (r->next) assert(r->rank >= r->next->rank); for (r = resource_list; r; r = r->next) if (r->type == RESOURCE_FONT && r->rank >= 0) supply_resource(r, -1, out.get_file()); } }
void ps_printer::flush_sbuf() { enum { NONE, RELATIVE_H, RELATIVE_V, RELATIVE_HV, ABSOLUTE } motion = NONE; int space_flag = 0; if (sbuf_len == 0) return; if (output_style != sbuf_style) { set_style(sbuf_style); output_style = sbuf_style; } int extra_space = 0; if (output_hpos < 0 || output_vpos < 0) motion = ABSOLUTE; else { if (output_hpos != sbuf_start_hpos) motion = RELATIVE_H; if (output_vpos != sbuf_vpos) { if (motion != NONE) motion = RELATIVE_HV; else motion = RELATIVE_V; } } if (sbuf_space_code >= 0) { int w = sbuf_style.f->get_width(space_glyph, sbuf_style.point_size); if (w + sbuf_kern != sbuf_space_width) { if (sbuf_space_code != output_space_code) { set_space_code(sbuf_space_code); output_space_code = sbuf_space_code; } space_flag = 1; extra_space = sbuf_space_width - w - sbuf_kern; if (sbuf_space_diff_count > sbuf_space_count/2) extra_space++; else if (sbuf_space_diff_count < -(sbuf_space_count/2)) extra_space--; } } if (space_flag) out.put_fix_number(extra_space); if (sbuf_kern != 0) out.put_fix_number(sbuf_kern); out.put_string(sbuf, sbuf_len); char command_array[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'}; char sym[2]; sym[0] = command_array[motion*4 + space_flag + 2*(sbuf_kern != 0)]; sym[1] = '\0'; switch (motion) { case NONE: break; case ABSOLUTE: out.put_fix_number(sbuf_start_hpos) .put_fix_number(sbuf_vpos); break; case RELATIVE_H: out.put_fix_number(sbuf_start_hpos - output_hpos); break; case RELATIVE_V: out.put_fix_number(sbuf_vpos - output_vpos); break; case RELATIVE_HV: out.put_fix_number(sbuf_start_hpos - output_hpos) .put_fix_number(sbuf_vpos - output_vpos); break; default: assert(0); } out.put_symbol(sym); output_hpos = sbuf_end_hpos; output_vpos = sbuf_vpos; sbuf_len = 0; }
void ps_printer::set_space_code(unsigned char c) { out.put_literal_symbol("SC") .put_number(c) .put_symbol("def"); }
void ps_printer::draw(int code, int *p, int np, const environment *env) { if (invis_count > 0) return; flush_sbuf(); int fill_flag = 0; switch (code) { case 'C': fill_flag = 1; // fall through case 'c': // troff adds an extra argument to C if (np != 1 && !(code == 'C' && np == 2)) { error("1 argument required for circle"); break; } out.put_fix_number(env->hpos + p[0]/2) .put_fix_number(env->vpos) .put_fix_number(p[0]/2) .put_symbol("DC"); if (fill_flag) fill_path(env); else { set_line_thickness_and_color(env); out.put_symbol("ST"); } break; case 'l': if (np != 2) { error("2 arguments required for line"); break; } set_line_thickness_and_color(env); out.put_fix_number(p[0] + env->hpos) .put_fix_number(p[1] + env->vpos) .put_fix_number(env->hpos) .put_fix_number(env->vpos) .put_symbol("DL"); break; case 'E': fill_flag = 1; // fall through case 'e': if (np != 2) { error("2 arguments required for ellipse"); break; } out.put_fix_number(p[0]) .put_fix_number(p[1]) .put_fix_number(env->hpos + p[0]/2) .put_fix_number(env->vpos) .put_symbol("DE"); if (fill_flag) fill_path(env); else { set_line_thickness_and_color(env); out.put_symbol("ST"); } break; case 'P': fill_flag = 1; // fall through case 'p': { if (np & 1) { error("even number of arguments required for polygon"); break; } if (np == 0) { error("no arguments for polygon"); break; } out.put_fix_number(env->hpos) .put_fix_number(env->vpos) .put_symbol("MT"); for (int i = 0; i < np; i += 2) out.put_fix_number(p[i]) .put_fix_number(p[i+1]) .put_symbol("RL"); out.put_symbol("CL"); if (fill_flag) fill_path(env); else { set_line_thickness_and_color(env); out.put_symbol("ST"); } break; } case '~': { if (np & 1) { error("even number of arguments required for spline"); break; } if (np == 0) { error("no arguments for spline"); break; } out.put_fix_number(env->hpos) .put_fix_number(env->vpos) .put_symbol("MT"); out.put_fix_number(p[0]/2) .put_fix_number(p[1]/2) .put_symbol("RL"); /* tnum/tden should be between 0 and 1; the closer it is to 1 the tighter the curve will be to the guiding lines; 2/3 is the standard value */ const int tnum = 2; const int tden = 3; for (int i = 0; i < np - 2; i += 2) { out.put_fix_number((p[i]*tnum)/(2*tden)) .put_fix_number((p[i + 1]*tnum)/(2*tden)) .put_fix_number(p[i]/2 + (p[i + 2]*(tden - tnum))/(2*tden)) .put_fix_number(p[i + 1]/2 + (p[i + 3]*(tden - tnum))/(2*tden)) .put_fix_number((p[i] - p[i]/2) + p[i + 2]/2) .put_fix_number((p[i + 1] - p[i + 1]/2) + p[i + 3]/2) .put_symbol("RC"); } out.put_fix_number(p[np - 2] - p[np - 2]/2) .put_fix_number(p[np - 1] - p[np - 1]/2) .put_symbol("RL"); set_line_thickness_and_color(env); out.put_symbol("ST"); } break; case 'a': { if (np != 4) { error("4 arguments required for arc"); break; } set_line_thickness_and_color(env); double c[2]; if (adjust_arc_center(p, c)) out.put_fix_number(env->hpos + int(c[0])) .put_fix_number(env->vpos + int(c[1])) .put_fix_number(int(sqrt(c[0]*c[0] + c[1]*c[1]))) .put_float(degrees(atan2(-c[1], -c[0]))) .put_float(degrees(atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]))) .put_symbol("DA"); else out.put_fix_number(p[0] + p[2] + env->hpos) .put_fix_number(p[1] + p[3] + env->vpos) .put_fix_number(env->hpos) .put_fix_number(env->vpos) .put_symbol("DL"); } break; case 't': if (np == 0) line_thickness = -1; else { // troff gratuitously adds an extra 0 if (np != 1 && np != 2) { error("0 or 1 argument required for thickness"); break; } line_thickness = p[0]; } break; default: error("unrecognised drawing command `%1'", char(code)); break; } output_hpos = output_vpos = -1; }
void ps_printer::do_import(char *arg, const environment *env) { while (*arg == ' ' || *arg == '\n') arg++; char *p; for (p = arg; *p != '\0' && *p != ' ' && *p != '\n'; p++) ; if (*p != '\0') *p++ = '\0'; int parms[6]; int nparms = 0; while (nparms < 6) { char *end; long n = strtol(p, &end, 10); if (n == 0 && end == p) break; parms[nparms++] = int(n); p = end; } if (csalpha(*p) && (p[1] == '\0' || p[1] == ' ' || p[1] == '\n')) { error("scaling indicators not allowed in arguments for X import command"); return; } while (*p == ' ' || *p == '\n') p++; if (nparms < 5) { if (*p == '\0') error("too few arguments for X import command"); else error("invalid argument `%1' for X import command", p); return; } if (*p != '\0') { error("superfluous argument `%1' for X import command", p); return; } int llx = parms[0]; int lly = parms[1]; int urx = parms[2]; int ury = parms[3]; int desired_width = parms[4]; int desired_height = parms[5]; if (desired_width <= 0) { error("bad width argument `%1' for X import command: must be > 0", desired_width); return; } if (nparms == 6 && desired_height <= 0) { error("bad height argument `%1' for X import command: must be > 0", desired_height); return; } if (llx == urx) { error("llx and urx arguments for X import command must not be equal"); return; } if (lly == ury) { error("lly and ury arguments for X import command must not be equal"); return; } if (nparms == 5) { int old_wid = urx - llx; int old_ht = ury - lly; if (old_wid < 0) old_wid = -old_wid; if (old_ht < 0) old_ht = -old_ht; desired_height = int(desired_width*(double(old_ht)/double(old_wid)) + .5); } if (env->vpos - desired_height < 0) warning("top of imported graphic is above the top of the page"); out.put_number(llx) .put_number(lly) .put_fix_number(desired_width) .put_number(urx - llx) .put_fix_number(-desired_height) .put_number(ury - lly) .put_fix_number(env->hpos) .put_fix_number(env->vpos) .put_symbol("PBEGIN"); rm.import_file(arg, out); // do this here just in case application defines PEND out.put_symbol("end") .put_symbol("PEND"); }