// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I // surface class for laserwriter #include #include #include #include // constructor laserwriter::laserwriter(const int x0, const int y0, const int x1, const int y1, const int ofsx, const int ofsy) : last_dot(0, 0, 0) { x_ofs = ofsx; y_ofs = ofsy; use_left = x0; use_right = x1; use_top = y0; use_bottom = y1; _dotsize = 1; printing_in_progress = false; n_writes = 0; heap_check(gflwp = new grey_font_laserwriter(0, 0)); gfp = gflwp; _init(); } // copy constructor laserwriter::laserwriter(laserwriter& l) : last_dot(l.last_dot) { x_ofs = l.x_ofs; y_ofs = l.y_ofs; use_left = l.use_left; use_right = l.use_right; use_top = l.use_top; use_bottom = l.use_bottom; font = l.font; im_top = l.im_top; im_bottom = l.im_bottom; im_left = l.im_left; im_right = l.im_right; printing_in_progress = false; tmpnam(postscript_filename); l._flush(); const char* command_string = (const char*)(DREstring("cp ") + (DREstring)l.postscript_filename + DREstring(" ") + (DREstring)postscript_filename); system(command_string); postscript_file = fopen(postscript_filename, "a+"); if (!postscript_file) then fatal_error("laserwriter copy constructor"); } // destructor laserwriter::~laserwriter(void) { fclose(postscript_file); // may fail if already closed if (!printing_in_progress) then { const char* command_string = DREstring("rm ") + (DREstring)postscript_filename; system(command_string); } } // private function void laserwriter::prologue(void) { *this << "%!PS-Adobe-1.0" << // transform to correct system "72 300 div dup scale" << "-90 rotate" << "-3300 0 translate" << // define dot operator -- goes in with x, y, size on stack "/D" << "{ newpath" << " /DotSize exch 1 sub def" << " 2 copy 4 copy moveto" << " exch DotSize sub exch lineto" << " DotSize sub exch DotSize sub exch lineto" << " DotSize sub lineto" << " fill" << "} def"; _flush(); } // private function void laserwriter::_init(void) { tmpnam(postscript_filename); postscript_file = fopen(postscript_filename, "w+"); prologue(); } // laserwriter << LINE surface& laserwriter::operator<<(LINE& rhs) { return (*this < DREstring(rhs.x1() + x_ofs, 10) < " " < DREstring(height() - rhs.y1() + y_ofs, 10) < " moveto\n" < DREstring(rhs.x2() + x_ofs, 10) < " " < DREstring(height() - rhs.y2() + y_ofs, 10) < " lineto stroke\n"); } surface& laserwriter::operator<<(dot& rhs) { if (last_dot != rhs) then { last_dot = rhs; return (*this < DREstring(rhs.x() + x_ofs, 10) < " " < DREstring(height() - rhs.y() + y_ofs, 10) < " " < DREstring((rhs.size() == -1) ? _dotsize : rhs.size(), 10) < " D\n"); } else return *this; } surface& laserwriter::operator<<(text& rhs) { if (rhs.length()) then { DREstring ps_font_name; ps_font_name = font; if (font == (DREstring)"ROMAN") then ps_font_name = "Times-Roman"; *this < "/" < ps_font_name < " findfont " < DREstring10(rhs.height()) < " scalefont setfont\n"; if (rhs.x() < 0) then { *this < DREstring(im_left, 10) < " " < DREstring((int)((abs(rhs.x())/100.0) * image_width()) + x_ofs, 10) < " add\n"; *this < "(" < rhs.words() < ")" < " stringwidth\n"; *this < "pop 2 div sub " < DREstring10(height() - rhs.y() + y_ofs) < " moveto\n"; } else *this < DREstring10(rhs.x() + x_ofs) < " " < DREstring10(height() - rhs.y() + y_ofs) < " moveto\n"; *this < "(" < rhs.words() < ") show\n"; } return *this; } int laserwriter::width(void) { return 3276; } int laserwriter::height(void) { return 2400; } void laserwriter::set_font(DREstring& fontname, const int size) { font = fontname; if (size) then font_height = size; DREstring t_fontname = fontname; if (t_fontname == (DREstring)"ROMAN") then t_fontname = "Times-Roman"; *this < "/" < t_fontname < " findfont " < DREstring10(font_height) < " scalefont setfont\n"; } void laserwriter::set_font_height(const int size) { DREstring fontname = DREstring("FONT") + DREstring10(gfp->number()); font = fontname; if (size) then font_height = size; *this < "/" < fontname < " findfont " < DREstring10(font_height) < " scalefont setfont\n"; _save(); } void laserwriter::_print(const char* printer_name) { *this << "showpage"; #if 0 *this << "serverdict begin" << "statusdict begin" << "0 checkpassword " << " { 0 exitserver }" << " {(Incorrect Server Password!!)= flush }" << "ifelse" << "statusdict begin" << "800 800 setmargins" << "end"; #endif _flush().close(); // Special for PORTRAIT and LANDSCAPE printers if (DREstring(printer_name) == (DREstring)"PORTRAIT") then { const char* command_string = DREstring("cat ") + (DREstring)postscript_filename + (DREstring) " | " + (DREstring)"/usr/local/bin/postscript -c A4 -"; system(command_string); return; } if (DREstring(printer_name) == (DREstring)"LANDSCAPE") then { const char* command_string = DREstring("cat ") + (DREstring)postscript_filename + (DREstring)" | " + (DREstring)"/usr/local/bin/postscript -c M4 -"; system(command_string); return; } const char* command_string = DREstring("lpr -P") + (DREstring)printer_name + (DREstring)" -r -s " + (DREstring)postscript_filename; printing_in_progress = true; system(command_string); } void laserwriter::clear(void) { // delete the file fclose(postscript_file); const char* command_string = DREstring("rm ") + (DREstring)postscript_filename; system(command_string); postscript_file = fopen(postscript_filename, "a+"); prologue(); } void laserwriter::print(const char* printer_name) { laserwriter temp(*this); temp._print(printer_name); // clear as well; in general, this may not be a good thing to do; if // that turns out to be the case, then we should declare a seperate // print_with_clear function and use pointers to members to select // the correct version at run-time clear(); } // detach and reattach to a new file void laserwriter::detach(void) { *this << "showpage"; _flush().close(); _init(); } // detach and reattach to a new file void laserwriter::detach(const char* filename) { *this << "showpage"; _flush().close(); const char* command_string = DREstring("cp ") + (DREstring)postscript_filename + (DREstring)" " + (DREstring)filename; system(command_string); _init(); } // detach and reattach to a new file void laserwriter::detach(ostream& ostr) { *this << "showpage"; _flush().close(); // copy the file to the output stream ifstream PSfile(postscript_filename, ios::in); DREstring postscript_line; while (PSfile.good()) { PSfile >> postscript_line; ostr << postscript_line << endl; } _init(); } // resize a laserwriter font int laserwriter::resize_font(const int width, const int height) { gfp->resize(width, height); *this << "9 dict dup begin" << "/FontType 3 def" << "/FontMatrix [1 0 0 1 0 0] def" << "/FontBBox [0 0 0 0] def" << "/Encoding 256 array def" << "0 1 255 { Encoding exch /.notdef put } for" << "Encoding"; const int max_char_nr = gfp->width() * gfp->height(), bias = (max_char_nr < 50 ? 65 : 0); for (int char_nr = 0; char_nr <= max_char_nr; char_nr++) { const int n = char_nr + bias, n1 = n % 26, n2 = (n / 26) % 26; DREstring id; id += (char)(65 + n2); id += (char)(65 + n1); DREstring temp_string = (DREstring)((char_nr == max_char_nr) ? " " : "dup ") + (DREstring10(char_nr + bias) + (DREstring)" /C" + id + (DREstring)" put"); *this << temp_string; } *this << "/BuildChar" << "{ 0 begin" << " /char exch def" << " /fontdict exch def" << " /charname fontdict /Encoding get char get def" << " /charinfo fontdict /CharData get charname get def" << " /wx charinfo 0 get def" << " /charbbox charinfo 1 4 getinterval def" << // BEWARE -- I use "width" to mean "y-width", i. e. "height" !! " 0 wx neg charbbox aload pop setcachedevice" << " charinfo 5 get charinfo 6 get true" << " fontdict /imagemaskmatrix get" << " dup 4 charinfo 7 get put" << " dup 5 charinfo 8 get put" << " charinfo 9 1 getinterval cvx" << " imagemask" << " end" << "} def" << "/BuildChar load 0 6 dict put"; DREstring height_string(gfp->height(), 10); *this < "/imagemaskmatrix [" < height_string < " 0 0 " < height_string < " 0 0] def\n" < "/CharData 260 dict def\n" < "CharData begin\n"; for (char_nr = 0; char_nr <= max_char_nr; char_nr++) *this << gflwp->_ps_character(char_nr); *this << "end" << "/UniqueID 2 def" << "end" << ((DREstring)"/FONT" + DREstring10(gfp->number()) + (DREstring)" exch definefont pop") << ((DREstring)"/FONT" + DREstring10(gfp->number()) + (DREstring)" findfont " + height_string + (DREstring)" scalefont setfont"); _flush(); return (width * height); } // write the internal buffer void laserwriter::flush(void) { char out_chars[GREY_FONT_BUFFER_SIZE]; int out_index = 0; if (!(gfp->null())) then { for (int n = 0; n < gfp->length(); n++) { if ((gfp->element(n) <= 127) && (isalnum(gfp->element(n)))) then out_chars[out_index++] = char(gfp->element(n)); else { out_chars[out_index++] = 92; // back slash DREstring t_string = left_fill(DREstring(gfp->element(n), 8), 3, "0"); for (int k = 1; k <= 3; k++) out_chars[out_index++] = t_string.chr(k); } } out_chars[out_index] = '\0'; *this < '('; *this < out_chars; *this << ") show"; if (++n_writes == VM_trigger) then { _restore(); _save(); n_writes = 0; } } gfp->length(0); // when I have it working, try a _flush() here. } // move current point void laserwriter::moveto(const int x, const int y) { *this < DREstring(x, 10); *this < ' '; *this < DREstring(y, 10); *this << " moveto"; } // ---------------------- portrait_laserwriter ------------------- // default constructor portrait_laserwriter::portrait_laserwriter(int x0, int y0, int x1, int y1, int ofsx, int ofsy) : laserwriter(x0, y0, x1, y1, ofsx, ofsy) { // transform back to portrait mode *this << "3300 0 translate" << "90 rotate"; _flush(); } int portrait_laserwriter::width(void) { return 2400; } int portrait_laserwriter::height(void) { return 3276; }