2
/******************************************************************************
4
* DESCRIPTION: Abstract device for printing post-script graphics
5
* COPYRIGHT : (C) 1999 Joris van der Hoeven
6
*******************************************************************************
7
* This software falls under the GNU general public license and comes WITHOUT
8
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
9
* If you don't have this file, write to the Free Software Foundation, Inc.,
10
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11
******************************************************************************/
13
#include "PsDevice/printer.hpp"
15
#include "image_files.hpp"
16
#include "tex_files.hpp"
17
#include "analyze.hpp"
18
#include "iterator.hpp"
19
#include "merge_sort.hpp"
22
string PS_LINE ("ln");
23
string PS_FILL ("fl");
25
string PS_POL_START ("sp");
26
string PS_POL_NEXT ("np");
27
string PS_POL_END ("ep");
31
/******************************************************************************
32
* constructors and destructors
33
******************************************************************************/
35
printer_rep::printer_rep (
36
display dis2, url ps_file_name2, int dpi2, int nr_pages2,
37
string page_type2, bool landscape2, double paper_w2, double paper_h2):
38
dis (dis2), ps_file_name (ps_file_name2), dpi (dpi2),
39
nr_pages (nr_pages2), page_type (page_type2),
40
landscape (landscape2), paper_w (paper_w2), paper_h (paper_h2),
41
linelen (0), fg (-1), bg (-1), ncols (0),
42
lw (-1), nwidths (0), cfn (""), nfonts (0),
43
xpos (0), ypos (0), tex_flag (false),
44
defs ("?"), tex_chars ("?"), tex_width ("?"),
45
tex_fonts ("?"), tex_font_chars (array<int>(0))
48
as_string (call ("get-preference", string ("font type"))) == "True type";
56
magenta = dis->magenta;
60
light_grey= dis->light_grey;
62
dark_grey = dis->dark_grey;
64
string tex_pro, special_pro, color_pro, texps_pro;
65
load_string ("$TEXMACS_PATH/misc/convert/tex.pro", tex_pro, true);
66
load_string ("$TEXMACS_PATH/misc/convert/special.pro", special_pro, true);
67
load_string ("$TEXMACS_PATH/misc/convert/color.pro", color_pro, true);
68
load_string ("$TEXMACS_PATH/misc/convert/texps.pro", texps_pro, true);
69
set_clipping (0, (int) (-(dpi*PIXEL*paper_h)/2.54),
70
(int) ((dpi*PIXEL*paper_w)/2.54), 0);
72
prologue << "%!PS-Adobe-2.0\n"
73
<< "%%Creator: TeXmacs-" TEXMACS_VERSION "\n"
74
<< "%%Title: " << as_string (ps_file_name) << "\n"
75
<< "%%Pages: " << as_string (nr_pages) << "\n"
76
<< "%%PageOrder: Ascend\n";
77
if (page_type != "user")
78
prologue << "%%DocumentPaperSizes: " << page_type << "\n";
80
prologue << "%%BoundingBox: 0 0 "
81
<< as_string ((int) (28.36*paper_h+ 0.5)) << " "
82
<< as_string ((int) (28.36*paper_w+ 0.5)) << "\n"
83
<< "%%Orientation: Landscape\n";
85
prologue << "%%BoundingBox: 0 0 "
86
<< as_string ((int) (28.36*paper_w+ 0.5)) << " "
87
<< as_string ((int) (28.36*paper_h+ 0.5)) << "\n";
88
prologue << "%%EndComments\n\n"
90
<< special_pro << "\n"
93
<< as_string ((int) (1864680.0*paper_w+ 0.5)) << " "
94
<< as_string ((int) (1864680.0*paper_h+ 0.5)) << " 1000 "
95
<< as_string (dpi) << " " << as_string (dpi)
96
<< " (TeXmacs) @start\n";
98
define (PS_LINE, string ("/pt4 X /pt3 X /pt2 X /pt1 X\n") *
99
string ("newpath pt1 pt2 moveto pt3 pt4 lineto stroke"));
100
define (PS_FILL, string ("/pt4 X /pt3 X /pt2 X /pt1 X\n") *
101
string ("newpath pt1 pt2 moveto pt3 pt2 lineto ") *
102
string ("pt3 pt4 lineto pt1 pt4 lineto pt1 pt2 eofill stroke"));
103
define (PS_ARC, string ("/a2 X /a1 X /r2 X /r1 X /pt2 X /pt1 X\n") *
104
string ("newpath pt1 pt2 r1 r2 a1 a2 ellipse stroke"));
105
define (PS_POL_START, string ("/pt2 X /pt1 X\n") *
106
string ("newpath pt1 pt2 moveto"));
107
define (PS_POL_NEXT, string ("/pt2 X /pt1 X\n") *
108
string ("pt1 pt2 lineto"));
109
define (PS_POL_END, string ("closepath eofill"));
110
define (PS1, string ("gsave"));
111
define (PS2, string ("1 -1 scale show grestore"));
117
printer_rep::~printer_rep () {
119
body << "\n%%Trailer\n"
121
<< "userdict /end-hook known{end-hook} if\n"
124
generate_tex_fonts ();
128
<< "%%Feature: *Resolution " << as_string (dpi) << "dpi\n"
129
<< "TeXDict begin\n";
130
if (page_type != "user")
131
prologue << "%%PaperSize: " << page_type << "\n";
133
prologue << "@landscape\n";
134
prologue << "%%EndSetup\n";
136
string ps_text= prologue * "\n" * body;
137
save_string (ps_file_name, ps_text);
141
printer_rep::get_type () {
142
return PS_DEVICE_PRINTER;
145
/******************************************************************************
146
* subroutines for printing
147
******************************************************************************/
150
printer_rep::next_page () {
151
if (cur_page > 0) print ("eop\n");
152
if (cur_page >= nr_pages) return;
154
body << "\n%%Page: " << as_string (cur_page) << " "
155
<< as_string (cur_page) << "\n"
156
<< as_string (cur_page) << " "
157
<< as_string (cur_page-1) << " bop\n";
168
printer_rep::define (string s, string defn) {
169
if (defs->contains (s)) return;
171
prologue << "/" << s << " {" << defn << "} N\n";
175
printer_rep::sep () {
177
(body [N(body)-1] != ')') &&
178
(body [N(body)-1] != '\n')) {
193
printer_rep::print (string s) {
195
if ((linelen>0) && (linelen+N(s)>79)) {
200
else if (s[0]!='(') sep ();
201
if (tex_flag && (s[0]=='(')) {
202
body->resize (N(body)-2);
212
printer_rep::print (SI x, SI y) {
214
if (x>=0) x= x/PIXEL; else x= (x-PIXEL+1)/PIXEL;
215
if (y>=0) y= y/PIXEL; else y= (y-PIXEL+1)/PIXEL;
216
print (as_string (x-dpi));
217
print (as_string (-y-dpi));
221
printer_rep::move_to (SI x, SI y) {
223
if (x>=0) x= x/PIXEL; else x= (x-PIXEL+1)/PIXEL;
224
if (y>=0) y= y/PIXEL; else y= (y-PIXEL+1)/PIXEL;
225
if (tex_flag && (xpos==x) && (ypos==y)) return;
226
if (tex_flag && (ypos==y)) {
227
body->resize (N(body)-1);
232
if ((diff>=-4) && (diff<=4)) print (string ((char) ('p'+diff)));
234
print (as_string (diff));
241
print (as_string (x-dpi));
242
print (as_string (-y-dpi));
247
printer_rep::select_color (color c) {
249
dis->get_rgb (c, r, g, b);
250
r= 10000+ ((r*1000)/255);
251
g= 10000+ ((g*1000)/255);
252
b= 10000+ ((b*1000)/255);
253
string rr= as_string (r); rr= rr(1,2) * "." * rr(2,5);
254
string gg= as_string (g); gg= gg(1,2) * "." * gg(2,5);
255
string bb= as_string (b); bb= bb(1,2) * "." * bb(2,5);
256
string s = rr * " " * gg * " " * bb * " setrgbcolor";
257
if (!defs->contains (s)) {
258
define ("C" * as_string (ncols), s);
265
printer_rep::select_line_width (SI w) {
266
w= w/PIXEL; if (w<1) w=1;
267
string s = as_string (w) * " setlinewidth";
268
if (!defs->contains (s)) {
269
define ("W" * as_string (nwidths), s);
275
/******************************************************************************
276
* subroutines for fonts
277
******************************************************************************/
280
prepare_text (string s) {
283
for (i=0; i<N(s); i++) {
284
int c= ((unsigned char) s[i]);
285
if ((s[i]=='(') || (s[i]==')') || (s[i]=='\\'))
287
else if ((c <= 32) || (c >= 128)) {
289
r << ('0' + (c >> 6));
290
r << ('0' + ((c >> 3) & 7));
291
r << ('0' + (c & 7));
299
printer_rep::select_tex_font (string name) {
300
if (cfn==name) return;
302
print (tex_fonts [name]);
305
/******************************************************************************
306
* make tex characters and fonts
307
******************************************************************************/
309
static char* hex_string= "0123456789ABCDEF";
312
printer_rep::make_tex_char (string name, unsigned char c, bitmap_char bmc) {
313
string char_name (name * "-" * as_string ((int) c));
314
if (tex_chars->contains (char_name)) return;
315
if (!tex_fonts->contains (name)) {
316
tex_fonts (name)= "F" * as_string (nfonts);
317
tex_font_chars (name)= array<int> (0);
320
tex_font_chars (name) << ((int) c);
323
int i, j, count=0, cur= 0;
324
for (j=0; j < bmc->height; j++)
325
for (i=0; i < ((bmc->width+7) & (-8)); i++) {
327
if ((i<bmc->width) && (bmc->get_x(i,j)>0)) cur++;
330
hex_code << hex_string[cur];
338
int d3= 130+ bmc->xoff;
339
int d4= 126+ bmc->yoff;
341
if ((d1<256) && (d2<256) && (d3<256) && (d4<256) && (d5<256)) {
342
hex_code << as_hexadecimal (d1, 2) << as_hexadecimal (d2, 2)
343
<< as_hexadecimal (d3, 2) << as_hexadecimal (d4, 2)
344
<< as_hexadecimal (d5, 2);
345
hex_code= "<" * hex_code * ">";
348
hex_code= "[<" * hex_code * ">";
349
hex_code << as_string (d1) << " " << as_string (d2) << " "
350
<< as_string (d3) << " " << as_string (d4) << " "
351
<< as_string (d5) << " ";
354
tex_chars (char_name)= hex_code;
355
tex_width (char_name)= as_string (d5);
359
printer_rep::generate_tex_fonts () {
360
hashset<string> done;
361
iterator<string> it= iterate (tex_fonts);
362
while (it->busy ()) {
363
string fn_name= it->next ();
364
array<int> a= tex_font_chars [fn_name];
368
string name = tex_fonts [fn_name], ttf;
369
int pos = search_forwards (".", fn_name);
370
string root = (pos==-1? fn_name: fn_name (0, pos));
371
if (true_type && (pos!=-1) && ends (fn_name, "pk"))
372
ttf= pk_to_true_type (root);
375
root= upcase_all (root);
376
if (!done->contains (root)) {
377
prologue << "%%BeginFont: " << root << "\n";
379
prologue << "\n%%EndFont\n";
384
cum << "{}" * as_string (N(a));
385
for (i=0; i<N(a); i++) {
386
string w= tex_width [fn_name * "-" * as_string (a[i])];
387
d= (i==0? a[0]: (a[i]-a[i-1]-1));
388
if (d>0) cum << as_string (d) * "[";
392
if (d>0) cum << as_string (d) * "[";
395
while ((szpos>0) && is_numeric (fn_name[szpos-1])) szpos--;
396
double sz = as_double (fn_name (szpos, pos));
397
double dpi= as_double (fn_name (pos+1, N(fn_name)-2));
398
string mag= as_string (83.022 * (sz/10.0) * (dpi/600.0));
401
for (i=N(cum)-1; i>=0; i--) fdef << cum[i];
402
fdef= "/" * name * " " * fdef * " " * mag * " /" * root * " rf";
403
for (i=0, l=0; i<N(fdef); i++, l++)
404
if ((l<70) || (fdef[i]!=' ')) prologue << fdef[i];
405
else { prologue << '\n'; l=-1; }
409
prologue << "/" << tex_fonts [fn_name]
410
<< " " << as_string (N(a))
411
<< " " << as_string (a[N(a)-1]+1) << " df\n";
412
for (i=0; i<N(a); i++) {
414
string hex_code= tex_chars [fn_name * "-" * as_string (a[i])];
415
for (end=1; end < N(hex_code); end++)
416
if (hex_code[end-1]=='>') break;
417
string after= hex_code (end, N(hex_code));
418
if ((i>0) && (a[i]==(a[i-1]+1))) after << "I";
419
else after << as_string (a[i]) << " D";
420
if (i==(N(a)-1)) after << " E";
421
hex_code= hex_code (0, end);
423
int j, l, n= N(hex_code);
424
for (j=0; j<n; j+=79) {
425
if (n < (j+79)) prologue << hex_code (j, n);
426
else prologue << hex_code (j, j+79) << "\n";
429
if (l<N(after)) prologue << "\n";
430
prologue << after << "\n";
436
/******************************************************************************
438
******************************************************************************/
441
printer_rep::rgb (int r, int g, int b) {
442
return dis->rgb (r, g, b);
446
printer_rep::get_rgb (color col, int& r, int& g, int& b) {
447
dis->get_rgb (col, r, g, b);
451
printer_rep::get_color () {
456
printer_rep::get_background () {
461
printer_rep::set_color (color c) {
468
printer_rep::set_background (color c) {
474
printer_rep::draw (int ch, bitmap_font fn, SI x, SI y) {
475
bitmap_char bmc= fn->get(ch);
476
if (nil (bmc)) return;
477
string name= fn->res_name;
479
if (true_type) ec_to_cm (name, c);
480
make_tex_char (name, c, bmc);
481
select_tex_font (name);
483
print ("(" * prepare_text (string ((char) c)) * ")p");
489
printer_rep::set_line_style (SI w, int type) {
493
select_line_width (w);
497
printer_rep::line (SI x1, SI y1, SI x2, SI y2) {
504
printer_rep::clear (SI x1, SI y1, SI x2, SI y2) {
513
printer_rep::fill (SI x1, SI y1, SI x2, SI y2) {
514
if ((x1<x2) && (y1<y2)) {
522
printer_rep::arc (SI x1, SI y1, SI x2, SI y2, int alpha, int delta) {
523
print ((x1+x2)/2, (y1+y2)/2);
524
print (as_string ((x2-x1)/(2*PIXEL)));
525
print (as_string ((y1-y2)/(2*PIXEL)));
526
print (as_string (((double) alpha)/64));
527
print (as_string (((double) (alpha+delta))/64));
532
printer_rep::polygon (array<SI> x, array<SI> y) {
534
if ((N(y) != n) || (n<1)) return;
536
print (PS_POL_START);
537
for (i=1; i<n; i++) {
545
printer_rep::xpm (url file_name, SI x, SI y) {
546
(void) file_name; (void) x; (void) y;
547
fatal_error ("Not yet implemented", "printer_rep::xpm");
552
incorporate_postscript (string s) {
557
for (; (i<N(s)) && (s[i]!='\n'); i++);
561
for (; (i<N(s)) && (s[i]!='\n'); ) r << s[i++];
562
if (i<N(s)) { r << s[i++]; }
569
printer_rep::postscript (
570
url image, SI w, SI h, SI x, SI y,
571
int x1, int y1, int x2, int y2)
573
double sc_x= (72.0/dpi) * ((double) (w/PIXEL)) / ((double) (x2-x1));
574
double sc_y= (72.0/dpi) * ((double) (h/PIXEL)) / ((double) (y2-y1));
580
print ("currentpoint");
581
print ("currentpoint");
583
print (as_string (sc_x));
584
print (as_string (sc_y));
594
/* Black Black 248 3155 a currentpoint currentpoint translate
595
0.37114 0.37114 scale neg exch neg exch translate 248 3155 a */
597
print ("@beginspecial");
598
print (as_string (x1));
600
print (as_string (y1));
602
print (as_string (x2));
604
print (as_string (y2));
606
print (as_string (10*(x2-x1)));
609
print ("@setspecial");
611
/* @beginspecial 0 @llx 0 @lly 613.291260 @urx 613.291260 @ury 6110 @rwi
614
string ps_image= ps_load (image);
615
string imtext= is_ramdisc (image)? "inline image": as_string (image);
616
body << "%%BeginDocument: " << imtext << "\n";
617
body << ps_image; // incorporate_postscript (ps_image);
618
body << "%%EndDocument";
621
print ("@endspecial");
624
print ("currentpoint");
625
print ("currentpoint");
627
print (as_string (1/sc_x));
628
print (as_string (1/sc_y));
640
/* @endspecial 248 3155 a currentpoint currentpoint translate
641
1 0.37114 div 1 0.37114 div scale neg exch neg exch translate
642
248 3155 a 660 3073 a ... */
648
printer_rep::check_event (int type) {
654
printer_rep::apply_shadow (SI x1, SI y1, SI x2, SI y2) {
655
(void) x1; (void) y1; (void) x2; (void) y2;
658
/******************************************************************************
660
******************************************************************************/
663
printer (display dis, url ps_file_name, int dpi, int nr_pages,
664
string page_type, bool landscape, double paper_w, double paper_h)
666
return new printer_rep (dis, ps_file_name, dpi, nr_pages,
667
page_type, landscape, paper_w, paper_h);