(vc-update-change-log): Use system-tmp-directory.
[bpt/emacs.git] / lisp / ps-print.el
CommitLineData
535efc38 1;;; ps-print.el --- Print text from the buffer as PostScript
12d89a2e 2
12b88fff 3;; Copyright (C) 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
ef2cbb24 4
090be653 5;; Author: Jim Thompson (was <thompson@wg2.waii.com>)
87a16a06 6;; Author: Jacques Duthen <duthen@cegelec-red.fr>
857686a6 7;; Author: Vinicius Jose Latorre <vinicius@cpqd.com.br>
8bd22fcf 8;; Maintainer: Vinicius Jose Latorre <vinicius@cpqd.com.br>
090be653 9;; Keywords: print, PostScript
6bdb808e
RS
10;; Time-stamp: <98/05/05 12:36:30 vinicius>
11;; Version: 3.06.1
090be653 12
6bdb808e
RS
13(defconst ps-print-version "3.06.1"
14 "ps-print.el, v 3.06.1 <98/05/05 vinicius>
090be653 15
535efc38 16Vinicius's last change version -- this file may have been edited as part of
090be653
RS
17Emacs without changes to the version number. When reporting bugs,
18please also report the version of Emacs, if any, that ps-print was
19distributed with.
20
21Please send all bug fixes and enhancements to
8bd22fcf 22 Vinicius Jose Latorre <vinicius@cpqd.com.br>.
090be653 23")
ef2cbb24 24
86c10ecb 25;; This file is part of GNU Emacs.
ef2cbb24
RS
26
27;; GNU Emacs is free software; you can redistribute it and/or modify
28;; it under the terms of the GNU General Public License as published by
29;; the Free Software Foundation; either version 2, or (at your option)
30;; any later version.
31
32;; GNU Emacs is distributed in the hope that it will be useful,
33;; but WITHOUT ANY WARRANTY; without even the implied warranty of
34;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35;; GNU General Public License for more details.
36
37;; You should have received a copy of the GNU General Public License
b578f267
EN
38;; along with GNU Emacs; see the file COPYING. If not, write to the
39;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
40;; Boston, MA 02111-1307, USA.
ef2cbb24 41
12d89a2e 42;;; Commentary:
ef2cbb24
RS
43
44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
45;;
12d89a2e 46;; About ps-print
ef2cbb24 47;; --------------
bcc0d457 48;;
ef2cbb24
RS
49;; This package provides printing of Emacs buffers on PostScript
50;; printers; the buffer's bold and italic text attributes are
51;; preserved in the printer output. Ps-print is intended for use with
00aa16af
RS
52;; Emacs 19 or Lucid Emacs, together with a fontifying package such as
53;; font-lock or hilit.
12d89a2e 54;;
87a16a06
RS
55;; ps-print uses the same face attributes defined through font-lock or hilit
56;; to print a PostScript file, but some faces are better seeing on the screen
57;; than on paper, specially when you have a black/white PostScript printer.
58;;
59;; ps-print allows a remap of face to another one that it is better to print,
60;; for example, the face font-lock-comment-face (if you are using font-lock)
61;; could have bold or italic attribute when printing, besides foreground color.
62;; This remap improves printing look (see How Ps-Print Maps Faces).
63;;
bcc0d457 64;;
12d89a2e 65;; Using ps-print
ef2cbb24 66;; --------------
ef2cbb24 67;;
12d89a2e
RS
68;; The Commands
69;;
70;; Ps-print provides eight commands for generating PostScript images
71;; of Emacs buffers:
72;;
73;; ps-print-buffer
74;; ps-print-buffer-with-faces
75;; ps-print-region
76;; ps-print-region-with-faces
77;; ps-spool-buffer
78;; ps-spool-buffer-with-faces
79;; ps-spool-region
80;; ps-spool-region-with-faces
81;;
82;; These commands all perform essentially the same function: they
83;; generate PostScript images suitable for printing on a PostScript
84;; printer or displaying with GhostScript. These commands are
85;; collectively referred to as "ps-print- commands".
86;;
87;; The word "print" or "spool" in the command name determines when the
88;; PostScript image is sent to the printer:
ef2cbb24 89;;
12d89a2e
RS
90;; print - The PostScript image is immediately sent to the
91;; printer;
ef2cbb24 92;;
12d89a2e
RS
93;; spool - The PostScript image is saved temporarily in an
94;; Emacs buffer. Many images may be spooled locally
95;; before printing them. To send the spooled images
bcc0d457 96;; to the printer, use the command `ps-despool'.
ef2cbb24 97;;
12d89a2e
RS
98;; The spooling mechanism was designed for printing lots of small
99;; files (mail messages or netnews articles) to save paper that would
100;; otherwise be wasted on banner pages, and to make it easier to find
101;; your output at the printer (it's easier to pick up one 50-page
102;; printout than to find 50 single-page printouts).
06fb6aab 103;;
1061ff16 104;; Ps-print has a hook in the `kill-emacs-hook' so that you won't
a7acbbe4 105;; accidentally quit from Emacs while you have unprinted PostScript
12d89a2e
RS
106;; waiting in the spool buffer. If you do attempt to exit with
107;; spooled PostScript, you'll be asked if you want to print it, and if
108;; you decline, you'll be asked to confirm the exit; this is modeled
109;; on the confirmation that Emacs uses for modified buffers.
110;;
111;; The word "buffer" or "region" in the command name determines how
112;; much of the buffer is printed:
113;;
114;; buffer - Print the entire buffer.
115;;
116;; region - Print just the current region.
117;;
118;; The -with-faces suffix on the command name means that the command
119;; will include font, color, and underline information in the
120;; PostScript image, so the printed image can look as pretty as the
121;; buffer. The ps-print- commands without the -with-faces suffix
122;; don't include font, color, or underline information; images printed
123;; with these commands aren't as pretty, but are faster to generate.
124;;
125;; Two ps-print- command examples:
126;;
127;; ps-print-buffer - print the entire buffer,
128;; without font, color, or
129;; underline information, and
130;; send it immediately to the
131;; printer.
132;;
133;; ps-spool-region-with-faces - print just the current region;
134;; include font, color, and
135;; underline information, and
136;; spool the image in Emacs to
137;; send to the printer later.
138;;
139;;
140;; Invoking Ps-Print
bcc0d457 141;; -----------------
ef2cbb24 142;;
12d89a2e 143;; To print your buffer, type
ef2cbb24 144;;
12d89a2e 145;; M-x ps-print-buffer
ef2cbb24 146;;
12d89a2e
RS
147;; or substitute one of the other seven ps-print- commands. The
148;; command will generate the PostScript image and print or spool it as
149;; specified. By giving the command a prefix argument
150;;
151;; C-u M-x ps-print-buffer
152;;
153;; it will save the PostScript image to a file instead of sending it
154;; to the printer; you will be prompted for the name of the file to
155;; save the image to. The prefix argument is ignored by the commands
156;; that spool their images, but you may save the spooled images to a
bcc0d457 157;; file by giving a prefix argument to `ps-despool':
12d89a2e
RS
158;;
159;; C-u M-x ps-despool
160;;
bcc0d457 161;; When invoked this way, `ps-despool' will prompt you for the name of
12d89a2e
RS
162;; the file to save to.
163;;
bcc0d457
RS
164;; Any of the `ps-print-' commands can be bound to keys; I recommend
165;; binding `ps-spool-buffer-with-faces', `ps-spool-region-with-faces',
166;; and `ps-despool'. Here are the bindings I use on my Sun 4 keyboard:
12d89a2e
RS
167;;
168;; (global-set-key 'f22 'ps-spool-buffer-with-faces) ;f22 is prsc
ef2cbb24
RS
169;; (global-set-key '(shift f22) 'ps-spool-region-with-faces)
170;; (global-set-key '(control f22) 'ps-despool)
171;;
12d89a2e
RS
172;;
173;; The Printer Interface
bcc0d457 174;; ---------------------
12d89a2e 175;;
bcc0d457 176;; The variables `ps-lpr-command' and `ps-lpr-switches' determine what
12d89a2e 177;; command is used to send the PostScript images to the printer, and
bcc0d457
RS
178;; what arguments to give the command. These are analogous to
179;; `lpr-command' and `lpr-switches'.
87a16a06 180;;
bcc0d457
RS
181;; Make sure that they contain appropriate values for your system;
182;; see the usage notes below and the documentation of these variables.
183;;
184;; NOTE: `ps-lpr-command' and `ps-lpr-switches' take their initial values
185;; from the variables `lpr-command' and `lpr-switches'. If you have
186;; `lpr-command' set to invoke a pretty-printer such as `enscript',
187;; then ps-print won't work properly. `ps-lpr-command' must name
12d89a2e
RS
188;; a program that does not format the files it prints.
189;;
190;;
bcc0d457
RS
191;; The Page Layout
192;; ---------------
12d89a2e 193;;
bcc0d457
RS
194;; All dimensions are floats in PostScript points.
195;; 1 inch == 2.54 cm == 72 points
196;; 1 cm == (/ 1 2.54) inch == (/ 72 2.54) points
12d89a2e 197;;
bcc0d457
RS
198;; The variable `ps-paper-type' determines the size of paper ps-print
199;; formats for; it should contain one of the symbols:
200;; `a4' `a3' `letter' `legal' `letter-small' `tabloid'
201;; `ledger' `statement' `executive' `a4small' `b4' `b5'
12d89a2e 202;;
bcc0d457
RS
203;; The variable `ps-landscape-mode' determines the orientation
204;; of the printing on the page:
205;; nil means `portrait' mode, non-nil means `landscape' mode.
206;; There is no oblique mode yet, though this is easy to do in ps.
87a16a06 207;;
bcc0d457
RS
208;; In landscape mode, the text is NOT scaled: you may print 70 lines
209;; in portrait mode and only 50 lignes in landscape mode.
210;; The margins represent margins in the printed paper:
211;; the top margin is the margin between the top of the page
212;; and the printed header, whatever the orientation is.
043620f4 213;;
bcc0d457
RS
214;; The variable `ps-number-of-columns' determines the number of columns
215;; both in landscape and portrait mode.
216;; You can use:
217;; - (the standard) one column portrait mode
218;; - (my favorite) two columns landscape mode (which spares trees)
219;; but also
220;; - one column landscape mode for files with very long lines.
221;; - multi-column portrait or landscape mode
12d89a2e 222;;
12d89a2e 223;;
bcc0d457
RS
224;; Horizontal layout
225;; -----------------
12d89a2e 226;;
bcc0d457
RS
227;; The horizontal layout is determined by the variables
228;; `ps-left-margin' `ps-inter-column' `ps-right-margin'
229;; as follows:
12d89a2e 230;;
bcc0d457
RS
231;; ------------------------------------------
232;; | | | | | | | |
233;; | lm | text | ic | text | ic | text | rm |
234;; | | | | | | | |
235;; ------------------------------------------
12d89a2e 236;;
bcc0d457
RS
237;; If `ps-number-of-columns' is 1, `ps-inter-column' is not relevant.
238;; Usually, lm = rm > 0 and ic = lm
239;; If (ic < 0), the text of adjacent columns can overlap.
12d89a2e 240;;
12d89a2e 241;;
bcc0d457
RS
242;; Vertical layout
243;; ---------------
244;;
245;; The vertical layout is determined by the variables
246;; `ps-bottom-margin' `ps-top-margin' `ps-header-offset'
247;; as follows:
248;;
249;; |--------| |--------|
250;; | tm | | tm |
251;; |--------| |--------|
252;; | header | | |
253;; |--------| | |
254;; | ho | | |
255;; |--------| or | text |
256;; | | | |
257;; | text | | |
258;; | | | |
259;; |--------| |--------|
260;; | bm | | bm |
261;; |--------| |--------|
262;;
263;; If `ps-print-header' is nil, `ps-header-offset' is not relevant.
264;; The margins represent margins in the printed paper:
265;; the top margin is the margin between the top of the page
266;; and the printed header, whatever the orientation is.
12d89a2e
RS
267;;
268;;
269;; Headers
bcc0d457 270;; -------
12d89a2e 271;;
12b88fff
RS
272;; Ps-print can print headers at the top of each column or at the top
273;; of each page; the default headers contain the following four items:
274;; on the left, the name of the buffer and, if the buffer is visiting
275;; a file, the file's directory; on the right, the page number and
276;; date of printing. The default headers look something like this:
12d89a2e
RS
277;;
278;; ps-print.el 1/21
279;; /home/jct/emacs-lisp/ps/new 94/12/31
06fb6aab 280;;
12d89a2e 281;; When printing on duplex printers, left and right are reversed so
bcc0d457 282;; that the page numbers are toward the outside (cf. `ps-spool-duplex').
12d89a2e 283;;
bcc0d457
RS
284;; Headers are configurable:
285;; To turn them off completely, set `ps-print-header' to nil.
286;; To turn off the header's gaudy framing box,
287;; set `ps-print-header-frame' to nil.
288;;
12b88fff
RS
289;; To print only one header at the top of each page,
290;; set `ps-print-only-one-header' to t.
291;;
bcc0d457 292;; The font family and size of text in the header are determined
06fb6aab 293;; by the variables `ps-header-font-family', `ps-header-font-size' and
bcc0d457
RS
294;; `ps-header-title-font-size' (see below).
295;;
296;; The variable `ps-header-line-pad' determines the portion of a header
297;; title line height to insert between the header frame and the text
298;; it contains, both in the vertical and horizontal directions:
299;; .5 means half a line.
300
301;; Page numbers are printed in `n/m' format, indicating page n of m pages;
302;; to omit the total page count and just print the page number,
303;; set `ps-show-n-of-n' to nil.
12d89a2e
RS
304;;
305;; The amount of information in the header can be changed by changing
bcc0d457 306;; the number of lines. To show less, set `ps-header-lines' to 1, and
12d89a2e 307;; the header will show only the buffer name and page number. To show
bcc0d457 308;; more, set `ps-header-lines' to 3, and the header will show the time of
12d89a2e
RS
309;; printing below the date.
310;;
311;; To change the content of the headers, change the variables
bcc0d457
RS
312;; `ps-left-header' and `ps-right-header'.
313;; These variables are lists, specifying top-to-bottom the text
314;; to display on the left or right side of the header.
315;; Each element of the list should be a string or a symbol.
316;; Strings are inserted directly into the PostScript arrays,
317;; and should contain the PostScript string delimiters '(' and ')'.
12d89a2e
RS
318;;
319;; Symbols in the header format lists can either represent functions
320;; or variables. Functions are called, and should return a string to
321;; show in the header. Variables should contain strings to display in
322;; the header. In either case, function or variable, the PostScript
a7acbbe4 323;; string delimiters are added by ps-print, and should not be part of
12d89a2e
RS
324;; the returned value.
325;;
326;; Here's an example: say we want the left header to display the text
327;;
328;; Moe
329;; Larry
330;; Curly
331;;
332;; where we have a function to return "Moe"
333;;
334;; (defun moe-func ()
335;; "Moe")
336;;
337;; a variable specifying "Larry"
338;;
339;; (setq larry-var "Larry")
340;;
bcc0d457 341;; and a literal for "Curly". Here's how `ps-left-header' should be
12d89a2e
RS
342;; set:
343;;
344;; (setq ps-left-header (list 'moe-func 'larry-var "(Curly)"))
345;;
346;; Note that Curly has the PostScript string delimiters inside his
bcc0d457 347;; quotes -- those aren't misplaced lisp delimiters!
87a16a06 348;;
bcc0d457
RS
349;; Without them, PostScript would attempt to call the undefined
350;; function Curly, which would result in a PostScript error.
87a16a06 351;;
bcc0d457
RS
352;; Since most printers don't report PostScript errors except by
353;; aborting the print job, this kind of error can be hard to track down.
87a16a06 354;;
bcc0d457 355;; Consider yourself warned!
12d89a2e
RS
356;;
357;;
358;; Duplex Printers
bcc0d457 359;; ---------------
12d89a2e
RS
360;;
361;; If you have a duplex-capable printer (one that prints both sides of
bcc0d457
RS
362;; the paper), set `ps-spool-duplex' to t.
363;; Ps-print will insert blank pages to make sure each buffer starts
364;; on the correct side of the paper.
365;; Don't forget to set `ps-lpr-switches' to select duplex printing
366;; for your printer.
367;;
06fb6aab 368;;
857686a6
RS
369;; Control And 8-bit Characters
370;; ----------------------------
371;;
372;; The variable `ps-print-control-characters' specifies whether you want to see
373;; a printable form for control and 8-bit characters, that is, instead of
6bdb808e 374;; sending, for example, a ^D (\004) to printer, it is sent the string "^D".
857686a6
RS
375;;
376;; Valid values for `ps-print-control-characters' are:
377;;
496725ad 378;; 8-bit This is the value to use when you want an ascii encoding of
6bdb808e
RS
379;; any control or non-ascii character. Control characters are
380;; encoded as "^D", and non-ascii characters have an
381;; octal encoding.
382;;
496725ad 383;; control-8-bit This is the value to use when you want an ascii encoding of
6bdb808e
RS
384;; any control character, whether it is 7 or 8-bit.
385;; European 8-bits accented characters are printed according
386;; the current font.
387;;
496725ad 388;; control Only ascii control characters have an ascii encoding.
6bdb808e
RS
389;; European 8-bits accented characters are printed according
390;; the current font.
391;;
392;; nil No ascii encoding. Any character is printed according the
393;; current font.
857686a6
RS
394;;
395;; Any other value is treated as nil.
396;;
496725ad 397;; The default is `control-8-bit'.
857686a6
RS
398;;
399;; Characters TAB, NEWLINE and FORMFEED are always treated by ps-print engine.
400;;
401;;
87a16a06
RS
402;; Line Number
403;; -----------
404;;
a18ed129
RS
405;; The variable `ps-line-number' specifies whether to number each line;
406;; non-nil means do so. The default is nil (don't number each line).
87a16a06
RS
407;;
408;;
409;; Zebra Stripes
410;; -------------
411;;
a18ed129
RS
412;; Zebra stripes are a kind of background that appear "underneath" the text
413;; and can make the text easier to read. They look like this:
87a16a06
RS
414;;
415;; XXXXXXXXXXXXXXXXXXXXXXXX
416;; XXXXXXXXXXXXXXXXXXXXXXXX
535efc38
RS
417;; XXXXXXXXXXXXXXXXXXXXXXXX
418;;
87a16a06
RS
419;;
420;;
421;; XXXXXXXXXXXXXXXXXXXXXXXX
422;; XXXXXXXXXXXXXXXXXXXXXXXX
535efc38 423;; XXXXXXXXXXXXXXXXXXXXXXXX
87a16a06 424;;
06fb6aab 425;; The blocks of X's represent rectangles filled with a light gray color.
a18ed129
RS
426;; Each rectangle extends all the way across the page.
427;;
428;; The height, in lines, of each rectangle is controlled by
535efc38
RS
429;; the variable `ps-zebra-stripe-height', which is 3 by default.
430;; The distance between stripes equals the height of a stripe.
8bd22fcf 431;;
01961237 432;; The variable `ps-zebra-stripes' controls whether to print zebra stripes.
a18ed129
RS
433;; Non-nil means yes, nil means no. The default is nil.
434;;
435;; See also section How Ps-Print Has A Text And/Or Image On Background.
87a16a06 436;;
87a16a06 437;;
12b88fff
RS
438;; Hooks
439;; -----
440;;
441;; Ps-print has the following hook variables:
442;;
443;; `ps-print-hook'
444;; It is evaluated once before any printing process. This is the right
445;; place to initialize ps-print global data.
446;; For an example, see section Adding a New Font Family.
447;;
448;; `ps-print-begin-page-hook'
449;; It is evaluated on each real beginning of page, that is, ps-print
450;; considers each beginning of column as a beginning of page, and a real
451;; beginning of page is when the beginning of column coincides with a
452;; paper change on your printer.
453;;
454;; `ps-print-begin-column-hook'
455;; It is evaluated on each beginning of column, except in the beginning
456;; of column that `ps-print-begin-page-hook' is evaluated.
457;;
458;;
459;; Font Managing
bcc0d457
RS
460;; -------------
461;;
462;; Ps-print now knows rather precisely some fonts:
463;; the variable `ps-font-info-database' contains information
464;; for a list of font families (currently mainly `Courier' `Helvetica'
465;; `Times' `Palatino' `Helvetica-Narrow' `NewCenturySchlbk').
466;; Each font family contains the font names for standard, bold, italic
467;; and bold-italic characters, a reference size (usually 10) and the
468;; corresponding line height, width of a space and average character width.
06fb6aab 469;;
bcc0d457
RS
470;; The variable `ps-font-family' determines which font family
471;; is to be used for ordinary text.
472;; If its value does not correspond to a known font family,
473;; an error message is printed into the `*Messages*' buffer,
474;; which lists the currently available font families.
475;;
476;; The variable `ps-font-size' determines the size (in points)
477;; of the font for ordinary text, when generating Postscript.
478;; Its value is a float.
479;;
480;; Similarly, the variable `ps-header-font-family' determines
481;; which font family is to be used for text in the header.
482;; The variable `ps-header-font-size' determines the font size,
483;; in points, for text in the header.
484;; The variable `ps-header-title-font-size' determines the font size,
485;; in points, for the top line of text in the header.
486;;
487;;
12b88fff 488;; Adding a New Font Family
bcc0d457
RS
489;; ------------------------
490;;
491;; To use a new font family, you MUST first teach ps-print
87a16a06 492;; this font, i.e., add its information to `ps-font-info-database',
bcc0d457
RS
493;; otherwise ps-print cannot correctly place line and page breaks.
494;;
87a16a06 495;; For example, assuming `Helvetica' is unknown,
bcc0d457
RS
496;; you first need to do the following ONLY ONCE:
497;;
498;; - create a new buffer
499;; - generate the PostScript image to a file (C-u M-x ps-print-buffer)
500;; - open this file and find the line:
501;; `% 3 cm 20 cm moveto 10 /Courier ReportFontInfo showpage'
a18ed129 502;; - delete the leading `%' (which is the PostScript comment character)
bcc0d457
RS
503;; - replace in this line `Courier' by the new font (say `Helvetica')
504;; to get the line:
505;; `3 cm 20 cm moveto 10 /Helvetica ReportFontInfo showpage'
506;; - send this file to the printer (or to ghostscript).
507;; You should read the following on the output page:
508;;
509;; For Helvetica 10 point, the line height is 11.56, the space width is 2.78
510;; and a crude estimate of average character width is 5.09243
511;;
512;; - Add these values to the `ps-font-info-database':
513;; (setq ps-font-info-database
12b88fff
RS
514;; (append
515;; '((Helvetica ; the family key
516;; (fonts (normal . "Helvetica")
517;; (bold . "Helvetica-Bold")
518;; (italic . "Helvetica-Oblique")
519;; (bold-italic . "Helvetica-BoldOblique"))
520;; (size . 10.0)
521;; (line-height . 11.56)
522;; (space-width . 2.78)
523;; (avg-char-width . 5.09243)))
524;; ps-font-info-database))
bcc0d457
RS
525;; - Now you can use this font family with any size:
526;; (setq ps-font-family 'Helvetica)
527;; - if you want to use this family in another emacs session, you must
528;; put into your `~/.emacs':
529;; (require 'ps-print)
530;; (setq ps-font-info-database (append ...)))
531;; if you don't want to load ps-print, you have to copy the whole value:
532;; (setq ps-font-info-database '(<your stuff> <the standard stuff>))
12b88fff
RS
533;; or, use `ps-print-hook' (see section Hooks):
534;; (add-hook 'ps-print-hook
535;; '(lambda () (setq ps-font-info-database (append ...))))
bcc0d457
RS
536;;
537;; You can create new `mixed' font families like:
12b88fff
RS
538;; (my-mixed-family
539;; (fonts (normal . "Courier-Bold")
540;; (bold . "Helvetica")
541;; (italic . "Zapf-Chancery-MediumItalic")
542;; (bold-italic . "NewCenturySchlbk-BoldItalic")
543;; (w3-table-hack-x-face . "LineDrawNormal"))
544;; (size . 10.0)
545;; (line-height . 10.55)
546;; (space-width . 6.0)
547;; (avg-char-width . 6.0))
bcc0d457
RS
548;; Now you can use your new font family with any size:
549;; (setq ps-font-family 'my-mixed-family)
550;;
12b88fff
RS
551;; Note that on above example the `w3-table-hack-x-face' entry refers to
552;; a face symbol, so when printing this face it'll be used the font
553;; `LineDrawNormal'. If the face `w3-table-hack-x-face' is remapped to
554;; use bold and/or italic attribute, the corresponding entry (bold, italic
555;; or bold-italic) will be used instead of `w3-table-hack-x-face' entry.
556;;
557;; Note also that the font family entry order is irrelevant, so the above
558;; example could also be written:
559;; (my-mixed-family
560;; (size . 10.0)
561;; (fonts (w3-table-hack-x-face . "LineDrawNormal")
562;; (bold . "Helvetica")
563;; (bold-italic . "NewCenturySchlbk-BoldItalic")
564;; (italic . "Zapf-Chancery-MediumItalic")
565;; (normal . "Courier-Bold"))
566;; (avg-char-width . 6.0)
567;; (space-width . 6.0)
568;; (line-height . 10.55))
569;;
570;; Despite the note above, it is recommended that some convention about
571;; entry order be used.
572;;
bcc0d457
RS
573;; You can get information on all the fonts resident in YOUR printer
574;; by uncommenting the line:
575;; % 3 cm 20 cm moveto ReportAllFontInfo showpage
576;;
a18ed129
RS
577;; The PostScript file should be sent to YOUR PostScript printer.
578;; If you send it to ghostscript or to another PostScript printer,
bcc0d457
RS
579;; you may get slightly different results.
580;; Anyway, as ghostscript fonts are autoload, you won't get
581;; much font info.
582;;
583;;
584;; How Ps-Print Deals With Faces
585;; -----------------------------
12d89a2e 586;;
bcc0d457
RS
587;; The ps-print-*-with-faces commands attempt to determine which faces
588;; should be printed in bold or italic, but their guesses aren't
589;; always right. For example, you might want to map colors into faces
590;; so that blue faces print in bold, and red faces in italic.
12d89a2e 591;;
857686a6
RS
592;; It is possible to force ps-print to consider specific faces bold,
593;; italic or underline, no matter what font they are displayed in, by setting
594;; the variables `ps-bold-faces', `ps-italic-faces' and `ps-underlined-faces'.
595;; These variables contain lists of faces that ps-print should consider bold,
596;; italic or underline; to set them, put code like the following into your
597;; .emacs file:
12d89a2e 598;;
12b88fff 599;; (setq ps-bold-faces '(my-blue-face))
bcc0d457 600;; (setq ps-italic-faces '(my-red-face))
857686a6 601;; (setq ps-underlined-faces '(my-green-face))
bcc0d457
RS
602;;
603;; Faces like bold-italic that are both bold and italic should go in
604;; *both* lists.
605;;
606;; Ps-print keeps internal lists of which fonts are bold and which are
607;; italic; these lists are built the first time you invoke ps-print.
608;; For the sake of efficiency, the lists are built only once; the same
609;; lists are referred in later invocations of ps-print.
610;;
611;; Because these lists are built only once, it's possible for them to
612;; get out of sync, if a face changes, or if new faces are added. To
613;; get the lists back in sync, you can set the variable
614;; `ps-build-face-reference' to t, and the lists will be rebuilt the
857686a6
RS
615;; next time ps-print is invoked. If you need that the lists always be
616;; rebuilt when ps-print is invoked, set the variable
617;; `ps-always-build-face-reference' to t.
bcc0d457
RS
618;;
619;;
620;; How Ps-Print Deals With Color
621;; -----------------------------
622;;
623;; Ps-print detects faces with foreground and background colors
624;; defined and embeds color information in the PostScript image.
625;; The default foreground and background colors are defined by the
626;; variables `ps-default-fg' and `ps-default-bg'.
627;; On black-and-white printers, colors are displayed in grayscale.
628;; To turn off color output, set `ps-print-color-p' to nil.
629;;
630;;
87a16a06
RS
631;; How Ps-Print Maps Faces
632;; -----------------------
633;;
634;; As ps-print uses PostScript to print buffers, it is possible to have
635;; other attributes associated with faces. So the new attributes used
636;; by ps-print are:
637;;
638;; strikeout - like underline, but the line is in middle of text.
639;; overline - like underline, but the line is over the text.
640;; shadow - text will have a shadow.
641;; box - text will be surrounded by a box.
a18ed129 642;; outline - print characters as hollow outlines.
87a16a06 643;;
06fb6aab 644;; See the documentation for `ps-extend-face'.
87a16a06
RS
645;;
646;; Let's, for example, remap font-lock-keyword-face to another foreground color
647;; and bold attribute:
648;;
a18ed129 649;; (ps-extend-face '(font-lock-keyword-face "RoyalBlue" nil bold) 'MERGE)
87a16a06 650;;
6c8f2753
RS
651;; If you want to use a new face, define it first with `defface',
652;; and then call `ps-extend-face' to specify how to print it.
653;;
87a16a06
RS
654;;
655;; How Ps-Print Has A Text And/Or Image On Background
656;; --------------------------------------------------
657;;
658;; Ps-print can print texts and/or EPS PostScript images on background; it is
659;; possible to define the following text attributes: font name, font size,
660;; initial position, angle, gray scale and pages to print.
661;;
662;; It has the following EPS PostScript images attributes: file name containing
663;; the image, initial position, X and Y scales, angle and pages to print.
664;;
665;; See documentation for `ps-print-background-text' and
666;; `ps-print-background-image'.
667;;
668;; For example, if we wish to print text "preliminary" on all pages and text
669;; "special" on page 5 and from page 11 to page 17, we could specify:
670;;
671;; (setq ps-print-background-text
672;; '(("preliminary")
673;; ("special"
674;; "LeftMargin" "BottomMargin PrintHeight add" ; X and Y position
675;; ; (upper left corner)
676;; nil nil nil
12b88fff 677;; "PrintHeight neg PrintPageWidth atan" ; angle
87a16a06
RS
678;; 5 (11 . 17)) ; page list
679;; ))
680;;
681;; Similarly, we could print image "~/images/EPS-image1.ps" on all pages and
682;; image "~/images/EPS-image2.ps" on page 5 and from page 11 to page 17, we
683;; specify:
684;;
685;; (setq ps-print-background-image
686;; '(("~/images/EPS-image1.ps"
687;; "LeftMargin" "BottomMargin") ; X and Y position (lower left corner)
688;; ("~/images/EPS-image2.ps"
689;; "LeftMargin" "BottomMargin PrintHeight 2 div add" ; X and Y position
690;; ; (upper left corner)
691;; nil nil nil
692;; 5 (11 . 17)) ; page list
693;; ))
694;;
695;; If it is not possible to read (or does not exist) an image file, that file
696;; is ignored.
697;;
698;; The printing order is:
699;;
700;; 1. Print zebra stripes
701;; 2. Print background texts that it should be on all pages
702;; 3. Print background images that it should be on all pages
703;; 4. Print background texts only for current page (if any)
704;; 5. Print background images only for current page (if any)
705;; 6. Print header
a18ed129 706;; 7. Print buffer text (with faces, if specified) and line number
87a16a06
RS
707;;
708;;
bcc0d457
RS
709;; Utilities
710;; ---------
711;;
712;; Some tools are provided to help you customize your font setup.
713;;
714;; `ps-setup' returns (some part of) the current setup.
715;;
716;; To avoid wrapping too many lines, you may want to adjust the
717;; left and right margins and the font size. On UN*X systems, do:
718;; pr -t file | awk '{printf "%3d %s\n", length($0), $0}' | sort -r | head
719;; to determine the longest lines of your file.
87a16a06 720;; Then, the command `ps-line-lengths' will give you the correspondence
bcc0d457
RS
721;; between a line length (number of characters) and the maximum font
722;; size which doesn't wrap such a line with the current ps-print setup.
723;;
724;; The commands `ps-nb-pages-buffer' and `ps-nb-pages-region' display
87a16a06 725;; the correspondence between a number of pages and the maximum font
bcc0d457
RS
726;; size which allow the number of lines of the current buffer or of
727;; its current region to fit in this number of pages.
a18ed129
RS
728;;
729;; NOTE: line folding is not taken into account in this process and could
730;; change the results.
b87c5d3d 731;;
b87c5d3d 732;;
b87c5d3d
RS
733;; New since version 1.5
734;; ---------------------
b87c5d3d 735;;
bcc0d457 736;; Color output capability.
b87c5d3d 737;; Automatic detection of font attributes (bold, italic).
b87c5d3d 738;; Configurable headers with page numbers.
b87c5d3d 739;; Slightly faster.
b87c5d3d 740;; Support for different paper sizes.
b87c5d3d
RS
741;; Better conformance to PostScript Document Structure Conventions.
742;;
ef2cbb24 743;;
bcc0d457
RS
744;; New since version 2.8
745;; ---------------------
746;;
12b88fff
RS
747;; [vinicius] 980306 Vinicius Jose Latorre <vinicius@cpqd.com.br>
748;;
749;; Skip invisible text
750;;
751;; [vinicius] 971130 Vinicius Jose Latorre <vinicius@cpqd.com.br>
752;;
753;; Hooks: `ps-print-hook', `ps-print-begin-page-hook' and
754;; `ps-print-begin-column-hook'.
755;; Put one header per page over the columns.
756;; Better database font management.
757;; Better control characters handling.
758;;
857686a6 759;; [vinicius] 971121 Vinicius Jose Latorre <vinicius@cpqd.com.br>
87a16a06 760;;
12b88fff 761;; Dynamic evaluation at print time of `ps-lpr-switches'.
87a16a06
RS
762;; Handle control characters.
763;; Face remapping.
764;; New face attributes.
765;; Line number.
766;; Zebra stripes.
767;; Text and/or image on background.
768;;
bcc0d457
RS
769;; [jack] 960517 Jacques Duthen <duthen@cegelec-red.fr>
770;;
a18ed129 771;; Font family and float size for text and header.
bcc0d457
RS
772;; Landscape mode.
773;; Multiple columns.
774;; Tools for page setup.
775;;
776;;
ef2cbb24
RS
777;; Known bugs and limitations of ps-print:
778;; --------------------------------------
bcc0d457 779;;
043620f4
KH
780;; Although color printing will work in XEmacs 19.12, it doesn't work
781;; well; in particular, bold or italic fonts don't print in the right
782;; background color.
783;;
784;; Invisible properties aren't correctly ignored in XEmacs 19.12.
785;;
b87c5d3d 786;; Automatic font-attribute detection doesn't work well, especially
00aa16af 787;; with hilit19 and older versions of get-create-face. Users having
bcc0d457 788;; problems with auto-font detection should use the lists
857686a6
RS
789;; `ps-italic-faces', `ps-bold-faces' and `ps-underlined-faces' and/or
790;; turn off automatic detection by setting `ps-auto-font-detect' to nil.
00aa16af 791;;
043620f4 792;; Automatic font-attribute detection doesn't work with XEmacs 19.12
857686a6
RS
793;; in tty mode; use the lists `ps-italic-faces', `ps-bold-faces' and
794;; `ps-underlined-faces' instead.
12d89a2e 795;;
00aa16af 796;; Still too slow; could use some hand-optimization.
ef2cbb24 797;;
12d89a2e 798;; Default background color isn't working.
ef2cbb24
RS
799;;
800;; Faces are always treated as opaque.
801;;
12d89a2e 802;; Epoch and Emacs 18 not supported. At all.
ef2cbb24 803;;
06fb6aab 804;; Fixed-pitch fonts work better for line folding, but are not required.
bcc0d457
RS
805;;
806;; `ps-nb-pages-buffer' and `ps-nb-pages-region' don't take care
807;; of folding lines.
ef2cbb24 808;;
12d89a2e 809;;
bcc0d457
RS
810;; Things to change:
811;; ----------------
ef2cbb24 812;;
12b88fff 813;; Avoid page break inside a paragraph.
bcc0d457 814;; Add `ps-non-bold-faces' and `ps-non-italic-faces' (should be easy).
bcc0d457
RS
815;; Improve the memory management for big files (hard?).
816;; `ps-nb-pages-buffer' and `ps-nb-pages-region' should take care
817;; of folding lines.
ef2cbb24 818;;
ef2cbb24 819;;
12d89a2e
RS
820;; Acknowledgements
821;; ----------------
12b88fff 822;;
6bdb808e
RS
823;; Thanks to Roland Ducournau <ducour@lirmm.fr> for
824;; `ps-print-control-characters' variable documentation.
825;;
12b88fff
RS
826;; Thanks to Marcus G Daniels <marcus@cathcart.sysc.pdx.edu> for a better
827;; database font management.
828;;
829;; Thanks to Martin Boyer <gamin@videotron.ca> for some ideas on putting one
6bdb808e
RS
830;; header per page over the columns and correct line numbers when printing a
831;; region.
12b88fff
RS
832;;
833;; Thanks to Steven L Baur <steve@miranova.com> for dynamic evaluation at
834;; print time of `ps-lpr-switches'.
835;;
6bdb808e
RS
836;; Thanks to Kevin Rodgers <kevinr@ihs.com> for handling control characters
837;; (his code was severely modified, but the main idea was kept).
838;;
12b88fff
RS
839;; Thanks to some suggestions on:
840;; * Face color map: Marco Melgazzi <marco@techie.com>
841;; * XEmacs compatibility: William J. Henney <will@astrosmo.unam.mx>
842;; * Check ps-paper-type: Sudhakar Frederick <sfrederi@asc.corp.mot.com>
843;;
857686a6
RS
844;; Thanks to Jacques Duthen <duthen@cegelec-red.fr> (Jack) for the 3.4 version
845;; I started from. [vinicius]
846;;
bcc0d457
RS
847;; Thanks to Jim Thompson <?@?> for the 2.8 version I started from.
848;; [jack]
849;;
12d89a2e
RS
850;; Thanks to Kevin Rodgers <kevinr@ihs.com> for adding support for
851;; color and the invisible property.
ef2cbb24 852;;
12d89a2e
RS
853;; Thanks to Avishai Yacobi, avishaiy@mcil.comm.mot.com, for writing
854;; the initial port to Emacs 19. His code is no longer part of
855;; ps-print, but his work is still appreciated.
ef2cbb24 856;;
12d89a2e
RS
857;; Thanks to Remi Houdaille and Michel Train, michel@metasoft.fdn.org,
858;; for adding underline support. Their code also is no longer part of
859;; ps-print, but their efforts are not forgotten.
860;;
861;; Thanks also to all of you who mailed code to add features to
862;; ps-print; although I didn't use your code, I still appreciate your
863;; sharing it with me.
864;;
865;; Thanks to all who mailed comments, encouragement, and criticism.
866;; Thanks also to all who responded to my survey; I had too many
867;; responses to reply to them all, but I greatly appreciate your
868;; interest.
869;;
870;; Jim
871;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ef2cbb24
RS
872
873;;; Code:
874
090be653
RS
875(unless (featurep 'lisp-float-type)
876 (error "`ps-print' requires floating point support"))
ef2cbb24
RS
877
878;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12d89a2e
RS
879;; User Variables:
880
bcc0d457
RS
881;;; Interface to the command system
882
e0af0d3e 883(defgroup ps-print nil
8bd22fcf 884 "PostScript generator for Emacs 19"
e0af0d3e
RS
885 :prefix "ps-"
886 :group 'wp)
887
888(defgroup ps-print-horizontal nil
889 "Horizontal page layout"
890 :prefix "ps-"
891 :tag "Horizontal"
892 :group 'ps-print)
893
894(defgroup ps-print-vertical nil
895 "Vertical page layout"
896 :prefix "ps-"
897 :tag "Vertical"
898 :group 'ps-print)
899
900(defgroup ps-print-header nil
901 "Headers layout"
902 :prefix "ps-"
903 :tag "Header"
904 :group 'ps-print)
905
906(defgroup ps-print-font nil
907 "Fonts customization"
908 :prefix "ps-"
909 :tag "Font"
910 :group 'ps-print)
911
912(defgroup ps-print-color nil
913 "Color customization"
914 :prefix "ps-"
915 :tag "Color"
916 :group 'ps-print)
917
918(defgroup ps-print-face nil
919 "Faces customization"
920 :prefix "ps-"
921 :tag "PS Faces"
922 :group 'ps-print
923 :group 'faces)
924
925
926(defcustom ps-lpr-command lpr-command
927 "*The shell command for printing a PostScript file."
928 :type 'string
929 :group 'ps-print)
930
931(defcustom ps-lpr-switches lpr-switches
932 "*A list of extra switches to pass to `ps-lpr-command'."
933 :type '(repeat string)
934 :group 'ps-print)
12d89a2e 935
bcc0d457 936;;; Page layout
12d89a2e 937
bcc0d457
RS
938;; All page dimensions are in PostScript points.
939;; 1 inch == 2.54 cm == 72 points
940;; 1 cm == (/ 1 2.54) inch == (/ 72 2.54) points
941
942;; Letter 8.5 inch x 11.0 inch
943;; Legal 8.5 inch x 14.0 inch
944;; A4 8.26 inch x 11.69 inch = 21.0 cm x 29.7 cm
945
946;; LetterSmall 7.68 inch x 10.16 inch
947;; Tabloid 11.0 inch x 17.0 inch
948;; Ledger 17.0 inch x 11.0 inch
949;; Statement 5.5 inch x 8.5 inch
950;; Executive 7.5 inch x 10.0 inch
951;; A3 11.69 inch x 16.5 inch = 29.7 cm x 42.0 cm
952;; A4Small 7.47 inch x 10.85 inch
953;; B4 10.125 inch x 14.33 inch
954;; B5 7.16 inch x 10.125 inch
955
e0af0d3e 956(defcustom ps-page-dimensions-database
bcc0d457
RS
957 (list (list 'a4 (/ (* 72 21.0) 2.54) (/ (* 72 29.7) 2.54))
958 (list 'a3 (/ (* 72 29.7) 2.54) (/ (* 72 42.0) 2.54))
959 (list 'letter (* 72 8.5) (* 72 11.0))
960 (list 'legal (* 72 8.5) (* 72 14.0))
961 (list 'letter-small (* 72 7.68) (* 72 10.16))
962 (list 'tabloid (* 72 11.0) (* 72 17.0))
963 (list 'ledger (* 72 17.0) (* 72 11.0))
964 (list 'statement (* 72 5.5) (* 72 8.5))
965 (list 'executive (* 72 7.5) (* 72 10.0))
966 (list 'a4small (* 72 7.47) (* 72 10.85))
967 (list 'b4 (* 72 10.125) (* 72 14.33))
968 (list 'b5 (* 72 7.16) (* 72 10.125)))
969 "*List associating a symbolic paper type to its width and height.
e0af0d3e
RS
970see `ps-paper-type'."
971 :type '(repeat (list :tag "Paper Type"
972 (symbol :tag "Name")
973 (number :tag "Width")
974 (number :tag "Height")))
975 :group 'ps-print)
976
857686a6 977;;;###autoload
e0af0d3e 978(defcustom ps-paper-type 'letter
bcc0d457 979 "*Specifies the size of paper to format for.
090be653 980Should be one of the paper types defined in `ps-page-dimensions-database', for
e0af0d3e
RS
981example `letter', `legal' or `a4'."
982 :type '(symbol :validate (lambda (wid)
87a16a06
RS
983 (if (assq (widget-value wid)
984 ps-page-dimensions-database)
e0af0d3e
RS
985 nil
986 (widget-put wid :error "Unknown paper size")
987 wid)))
988 :group 'ps-print)
989
87a16a06 990(defcustom ps-landscape-mode nil
e0af0d3e
RS
991 "*Non-nil means print in landscape mode."
992 :type 'boolean
993 :group 'ps-print)
994
857686a6
RS
995(defcustom ps-print-control-characters 'control-8-bit
996 "*Specifies the printable form for control and 8-bit characters.
6bdb808e
RS
997That is, instead of sending, for example, a ^D (\004) to printer,
998it is sent the string \"^D\".
999
857686a6 1000Valid values are:
6bdb808e 1001
496725ad 1002 `8-bit' This is the value to use when you want an ascii encoding of
6bdb808e
RS
1003 any control or non-ascii character. Control characters are
1004 encoded as \"^D\", and non-ascii characters have an
1005 octal encoding.
1006
496725ad 1007 `control-8-bit' This is the value to use when you want an ascii encoding of
6bdb808e
RS
1008 any control character, whether it is 7 or 8-bit.
1009 European 8-bits accented characters are printed according
1010 the current font.
1011
496725ad 1012 `control' Only ascii control characters have an ascii encoding.
6bdb808e
RS
1013 European 8-bits accented characters are printed according
1014 the current font.
1015
1016 nil No ascii encoding. Any character is printed according the
1017 current font.
1018
857686a6 1019Any other value is treated as nil."
12b88fff
RS
1020 :type '(choice (const 8-bit) (const control-8-bit)
1021 (const control) (const nil))
857686a6
RS
1022 :group 'ps-print)
1023
e0af0d3e
RS
1024(defcustom ps-number-of-columns (if ps-landscape-mode 2 1)
1025 "*Specifies the number of columns"
87a16a06
RS
1026 :type 'number
1027 :group 'ps-print)
1028
535efc38 1029(defcustom ps-zebra-stripes nil
87a16a06 1030 "*Non-nil means print zebra stripes.
06fb6aab 1031See also documentation for `ps-zebra-stripe-height'."
87a16a06
RS
1032 :type 'boolean
1033 :group 'ps-print)
1034
535efc38 1035(defcustom ps-zebra-stripe-height 3
87a16a06 1036 "*Number of zebra stripe lines.
06fb6aab 1037See also documentation for `ps-zebra-stripes'."
87a16a06
RS
1038 :type 'number
1039 :group 'ps-print)
1040
1041(defcustom ps-line-number nil
1042 "*Non-nil means print line number."
1043 :type 'boolean
1044 :group 'ps-print)
1045
1046(defcustom ps-print-background-image nil
1047 "*EPS image list to be printed on background.
1048
1049The elements are:
1050
1051 (FILENAME X Y XSCALE YSCALE ROTATION PAGES...)
1052
1053FILENAME is a file name which contains an EPS image or some PostScript
1054programming like EPS.
1055FILENAME is ignored, if it doesn't exist or is read protected.
1056
1057X and Y are relative positions on paper to put the image.
1058If X and Y are nil, the image is centralized on paper.
1059
1060XSCALE and YSCALE are scale factor to be applied to image before printing.
1061If XSCALE and YSCALE are nil, the original size is used.
1062
1063ROTATION is the image rotation angle; if nil, the default is 0.
1064
1065PAGES designates the page to print background image.
1066PAGES may be a number or a cons cell (FROM . TO) designating FROM page
1067to TO page.
1068If PAGES is nil, print background image on all pages.
1069
1070X, Y, XSCALE, YSCALE and ROTATION may be a floating point number,
1071an integer number or a string. If it is a string, the string should contain
1072PostScript programming that returns a float or integer value.
1073
1074For example, if you wish to print an EPS image on all pages do:
1075
1076 '((\"~/images/EPS-image.ps\"))"
35378a09
KH
1077 :type '(repeat (list file
1078 (choice :tag "X" number string (const nil))
1079 (choice :tag "Y" number string (const nil))
1080 (choice :tag "X Scale" number string (const nil))
1081 (choice :tag "Y Scale" number string (const nil))
1082 (choice :tag "Rotation" number string (const nil))
1083 (repeat :tag "Pages" :inline t
1084 (radio integer
1085 (cons :tag "Range"
1086 (integer :tag "From")
1087 (integer :tag "To"))))))
87a16a06
RS
1088 :group 'ps-print)
1089
1090(defcustom ps-print-background-text nil
1091 "*Text list to be printed on background.
1092
1093The elements are:
1094
1095 (STRING X Y FONT FONTSIZE GRAY ROTATION PAGES...)
1096
1097STRING is the text to be printed on background.
1098
1099X and Y are positions on paper to put the text.
1100If X and Y are nil, the text is positioned at lower left corner.
1101
1102FONT is a font name to be used on printing the text.
1103If nil, \"Times-Roman\" is used.
1104
1105FONTSIZE is font size to be used, if nil, 200 is used.
1106
1107GRAY is the text gray factor (should be very light like 0.8).
1108If nil, the default is 0.85.
1109
1110ROTATION is the text rotation angle; if nil, the angle is given by
1111the diagonal from lower left corner to upper right corner.
1112
1113PAGES designates the page to print background text.
1114PAGES may be a number or a cons cell (FROM . TO) designating FROM page
1115to TO page.
1116If PAGES is nil, print background text on all pages.
1117
1118X, Y, FONTSIZE, GRAY and ROTATION may be a floating point number,
1119an integer number or a string. If it is a string, the string should contain
1120PostScript programming that returns a float or integer value.
1121
1122For example, if you wish to print text \"Preliminary\" on all pages do:
1123
1124 '((\"Preliminary\"))"
35378a09
KH
1125 :type '(repeat (list string
1126 (choice :tag "X" number string (const nil))
1127 (choice :tag "Y" number string (const nil))
1128 (choice :tag "Font" string (const nil))
1129 (choice :tag "Fontsize" number string (const nil))
1130 (choice :tag "Gray" number string (const nil))
1131 (choice :tag "Rotation" number string (const nil))
1132 (repeat :tag "Pages" :inline t
1133 (radio integer
1134 (cons :tag "Range"
1135 (integer :tag "From")
1136 (integer :tag "To"))))))
e0af0d3e 1137 :group 'ps-print)
bcc0d457
RS
1138
1139;;; Horizontal layout
1140
1141;; ------------------------------------------
1142;; | | | | | | | |
1143;; | lm | text | ic | text | ic | text | rm |
1144;; | | | | | | | |
1145;; ------------------------------------------
1146
e0af0d3e
RS
1147(defcustom ps-left-margin (/ (* 72 2.0) 2.54) ; 2 cm
1148 "*Left margin in points (1/72 inch)."
1149 :type 'number
1150 :group 'ps-print-horizontal)
bcc0d457 1151
e0af0d3e
RS
1152(defcustom ps-right-margin (/ (* 72 2.0) 2.54) ; 2 cm
1153 "*Right margin in points (1/72 inch)."
1154 :type 'number
1155 :group 'ps-print-horizontal)
bcc0d457 1156
e0af0d3e
RS
1157(defcustom ps-inter-column (/ (* 72 2.0) 2.54) ; 2 cm
1158 "*Horizontal space between columns in points (1/72 inch)."
1159 :type 'number
1160 :group 'ps-print-horizontal)
bcc0d457
RS
1161
1162;;; Vertical layout
1163
1164;; |--------|
1165;; | tm |
1166;; |--------|
1167;; | header |
1168;; |--------|
1169;; | ho |
1170;; |--------|
1171;; | text |
1172;; |--------|
1173;; | bm |
1174;; |--------|
1175
e0af0d3e
RS
1176(defcustom ps-bottom-margin (/ (* 72 1.5) 2.54) ; 1.5 cm
1177 "*Bottom margin in points (1/72 inch)."
1178 :type 'number
1179 :group 'ps-print-vertical)
bcc0d457 1180
e0af0d3e
RS
1181(defcustom ps-top-margin (/ (* 72 1.5) 2.54) ; 1.5 cm
1182 "*Top margin in points (1/72 inch)."
1183 :type 'number
1184 :group 'ps-print-vertical)
bcc0d457 1185
e0af0d3e
RS
1186(defcustom ps-header-offset (/ (* 72 1.0) 2.54) ; 1.0 cm
1187 "*Vertical space in points (1/72 inch) between the main text and the header."
1188 :type 'number
1189 :group 'ps-print-vertical)
bcc0d457 1190
e0af0d3e 1191(defcustom ps-header-line-pad 0.15
bcc0d457 1192 "*Portion of a header title line height to insert between the header frame
e0af0d3e
RS
1193and the text it contains, both in the vertical and horizontal directions."
1194 :type 'number
1195 :group 'ps-print-vertical)
bcc0d457
RS
1196
1197;;; Header setup
12d89a2e 1198
e0af0d3e 1199(defcustom ps-print-header t
86c10ecb
RS
1200 "*Non-nil means print a header at the top of each page.
1201By default, the header displays the buffer name, page number, and, if
1202the buffer is visiting a file, the file's directory. Headers are
ae7f6761 1203customizable by changing variables `ps-left-header' and
e0af0d3e
RS
1204`ps-right-header'."
1205 :type 'boolean
1206 :group 'ps-print-header)
1207
12b88fff
RS
1208(defcustom ps-print-only-one-header nil
1209 "*Non-nil means print only one header at the top of each page.
1210This is useful when printing more than one column, so it is possible
1211to have only one header over all columns or one header per column.
1212See also `ps-print-header'."
1213 :type 'boolean
1214 :group 'ps-print-header)
1215
e0af0d3e
RS
1216(defcustom ps-print-header-frame t
1217 "*Non-nil means draw a gaudy frame around the header."
1218 :type 'boolean
1219 :group 'ps-print-header)
1220
1221(defcustom ps-header-lines 2
8bd22fcf 1222 "*Number of lines to display in page header, when generating PostScript."
e0af0d3e
RS
1223 :type 'integer
1224 :group 'ps-print-header)
bcc0d457
RS
1225(make-variable-buffer-local 'ps-header-lines)
1226
e0af0d3e 1227(defcustom ps-show-n-of-n t
00aa16af 1228 "*Non-nil means show page numbers as N/M, meaning page N of M.
8bd22fcf
KH
1229NOTE: page numbers are displayed as part of headers,
1230 see variable `ps-print-headers'."
e0af0d3e
RS
1231 :type 'boolean
1232 :group 'ps-print-header)
12d89a2e 1233
e0af0d3e 1234(defcustom ps-spool-duplex nil ; Not many people have duplex
bcc0d457
RS
1235 ; printers, so default to nil.
1236 "*Non-nil indicates spooling is for a two-sided printer.
1237For a duplex printer, the `ps-spool-*' commands will insert blank pages
1238as needed between print jobs so that the next buffer printed will
1239start on the right page. Also, if headers are turned on, the headers
1240will be reversed on duplex printers so that the page numbers fall to
e0af0d3e
RS
1241the left on even-numbered pages."
1242 :type 'boolean
1243 :group 'ps-print-header)
bcc0d457
RS
1244
1245;;; Fonts
1246
e0af0d3e 1247(defcustom ps-font-info-database
bcc0d457 1248 '((Courier ; the family key
12b88fff
RS
1249 (fonts (normal . "Courier")
1250 (bold . "Courier-Bold")
1251 (italic . "Courier-Oblique")
1252 (bold-italic . "Courier-BoldOblique"))
1253 (size . 10.0)
1254 (line-height . 10.55)
1255 (space-width . 6.0)
1256 (avg-char-width . 6.0))
bcc0d457 1257 (Helvetica ; the family key
12b88fff
RS
1258 (fonts (normal . "Helvetica")
1259 (bold . "Helvetica-Bold")
1260 (italic . "Helvetica-Oblique")
1261 (bold-italic . "Helvetica-BoldOblique"))
1262 (size . 10.0)
1263 (line-height . 11.56)
1264 (space-width . 2.78)
1265 (avg-char-width . 5.09243))
bcc0d457 1266 (Times
12b88fff
RS
1267 (fonts (normal . "Times-Roman")
1268 (bold . "Times-Bold")
1269 (italic . "Times-Italic")
1270 (bold-italic . "Times-BoldItalic"))
1271 (size . 10.0)
1272 (line-height . 11.0)
1273 (space-width . 2.5)
1274 (avg-char-width 4.71432))
bcc0d457 1275 (Palatino
12b88fff
RS
1276 (fonts (normal . "Palatino-Roman")
1277 (bold . "Palatino-Bold")
1278 (italic . "Palatino-Italic")
1279 (bold-italic . "Palatino-BoldItalic"))
1280 (size . 10.0)
1281 (line-height . 12.1)
1282 (space-width . 2.5)
1283 (avg-char-width . 5.08676))
bcc0d457 1284 (Helvetica-Narrow
12b88fff
RS
1285 (fonts (normal . "Helvetica-Narrow")
1286 (bold . "Helvetica-Narrow-Bold")
1287 (italic . "Helvetica-Narrow-Oblique")
1288 (bold-italic . "Helvetica-Narrow-BoldOblique"))
1289 (size . 10.0)
1290 (line-height . 11.56)
1291 (space-width . 2.2796)
1292 (avg-char-width . 4.17579))
bcc0d457 1293 (NewCenturySchlbk
12b88fff
RS
1294 (fonts (normal . "NewCenturySchlbk-Roman")
1295 (bold . "NewCenturySchlbk-Bold")
1296 (italic . "NewCenturySchlbk-Italic")
1297 (bold-italic . "NewCenturySchlbk-BoldItalic"))
1298 (size . 10.0)
1299 (line-height 12.15)
1300 (space-width . 2.78)
1301 (avg-char-width . 5.31162))
bcc0d457
RS
1302 ;; got no bold for the next ones
1303 (AvantGarde-Book
12b88fff
RS
1304 (fonts (normal . "AvantGarde-Book")
1305 (italic . "AvantGarde-BookOblique"))
1306 (size . 10.0)
1307 (line-height . 11.77)
1308 (space-width . 2.77)
1309 (avg-char-width . 5.45189))
bcc0d457 1310 (AvantGarde-Demi
12b88fff
RS
1311 (fonts (normal . "AvantGarde-Demi")
1312 (italic . "AvantGarde-DemiOblique"))
1313 (size . 10.0)
1314 (line-height . 12.72)
1315 (space-width . 2.8)
1316 (avg-char-width . 5.51351))
bcc0d457 1317 (Bookman-Demi
12b88fff
RS
1318 (fonts (normal . "Bookman-Demi")
1319 (italic . "Bookman-DemiItalic"))
1320 (size . 10.0)
1321 (line-height . 11.77)
1322 (space-width . 3.4)
1323 (avg-char-width . 6.05946))
bcc0d457 1324 (Bookman-Light
12b88fff
RS
1325 (fonts (normal . "Bookman-Light")
1326 (italic . "Bookman-LightItalic"))
1327 (size . 10.0)
1328 (line-height . 11.79)
1329 (space-width . 3.2)
1330 (avg-char-width . 5.67027))
bcc0d457
RS
1331 ;; got no bold and no italic for the next ones
1332 (Symbol
12b88fff
RS
1333 (fonts (normal . "Symbol"))
1334 (size . 10.0)
1335 (line-height . 13.03)
1336 (space-width . 2.5)
1337 (avg-char-width . 3.24324))
bcc0d457 1338 (Zapf-Dingbats
12b88fff
RS
1339 (fonts (normal . "Zapf-Dingbats"))
1340 (size . 10.0)
1341 (line-height . 9.63)
1342 (space-width . 2.78)
1343 (avg-char-width . 2.78))
bcc0d457 1344 (Zapf-Chancery-MediumItalic
12b88fff
RS
1345 (fonts (normal . "Zapf-Chancery-MediumItalic"))
1346 (size . 10.0)
1347 (line-height . 11.45)
1348 (space-width . 2.2)
1349 (avg-char-width . 4.10811))
87a16a06 1350 )
bcc0d457
RS
1351 "*Font info database: font family (the key), name, bold, italic, bold-italic,
1352reference size, line height, space width, average character width.
1353To get the info for another specific font (say Helvetica), do the following:
1354- create a new buffer
1355- generate the PostScript image to a file (C-u M-x ps-print-buffer)
8bd22fcf 1356- open this file and delete the leading `%' (which is the PostScript
bcc0d457 1357 comment character) from the line
87a16a06 1358 `% 3 cm 20 cm moveto 10 /Courier ReportFontInfo showpage'
bcc0d457 1359 to get the line
87a16a06 1360 `3 cm 20 cm moveto 10 /Helvetica ReportFontInfo showpage'
bcc0d457 1361- add the values to `ps-font-info-database'.
e0af0d3e
RS
1362You can get all the fonts of YOUR printer using `ReportAllFontInfo'."
1363 :type '(repeat (list :tag "Font Definition"
12b88fff
RS
1364 (symbol :tag "Font Family")
1365 (cons (const fonts)
1366 (repeat (cons (choice (const normal)
1367 (const bold)
1368 (const italic)
1369 (const bold-italic)
1370 (symbol :tag "Face"))
1371 (string :tag "Font Name"))))
1372 (cons (const size)
1373 (number :tag "Reference Size"))
1374 (cons (const line-height)
1375 (number :tag "Line Height"))
1376 (cons (const space-width)
1377 (number :tag "Space Width"))
1378 (cons (const avg-char-width)
1379 (number :tag "Average Character Width"))))
e0af0d3e
RS
1380 :group 'ps-print-font)
1381
1382(defcustom ps-font-family 'Courier
8bd22fcf 1383 "Font family name for ordinary text, when generating PostScript."
e0af0d3e
RS
1384 :type 'symbol
1385 :group 'ps-print-font)
1386
1387(defcustom ps-font-size (if ps-landscape-mode 7 8.5)
8bd22fcf 1388 "Font size, in points, for ordinary text, when generating PostScript."
e0af0d3e
RS
1389 :type 'number
1390 :group 'ps-print-font)
1391
1392(defcustom ps-header-font-family 'Helvetica
8bd22fcf 1393 "Font family name for text in the header, when generating PostScript."
e0af0d3e
RS
1394 :type 'symbol
1395 :group 'ps-print-font)
1396
1397(defcustom ps-header-font-size (if ps-landscape-mode 10 12)
8bd22fcf 1398 "Font size, in points, for text in the header, when generating PostScript."
e0af0d3e
RS
1399 :type 'number
1400 :group 'ps-print-font)
1401
1402(defcustom ps-header-title-font-size (if ps-landscape-mode 12 14)
496725ad 1403 "Font size, in points, for the top line of text in header, in PostScript."
e0af0d3e
RS
1404 :type 'number
1405 :group 'ps-print-font)
bcc0d457
RS
1406
1407;;; Colors
1408
87a16a06
RS
1409;; Printing color requires x-color-values.
1410(defcustom ps-print-color-p (or (fboundp 'x-color-values) ; Emacs
857686a6
RS
1411 (fboundp 'color-instance-rgb-components))
1412 ; XEmacs
e0af0d3e
RS
1413 "*If non-nil, print the buffer's text in color."
1414 :type 'boolean
1415 :group 'ps-print-color)
12d89a2e 1416
e0af0d3e
RS
1417(defcustom ps-default-fg '(0.0 0.0 0.0)
1418 "*RGB values of the default foreground color. Defaults to black."
1419 :type '(list (number :tag "Red") (number :tag "Green") (number :tag "Blue"))
1420 :group 'ps-print-color)
12d89a2e 1421
e0af0d3e
RS
1422(defcustom ps-default-bg '(1.0 1.0 1.0)
1423 "*RGB values of the default background color. Defaults to white."
1424 :type '(list (number :tag "Red") (number :tag "Green") (number :tag "Blue"))
1425 :group 'ps-print-color)
12d89a2e 1426
e0af0d3e 1427(defcustom ps-auto-font-detect t
12d89a2e 1428 "*Non-nil means automatically detect bold/italic face attributes.
7f72c06f 1429If nil, we rely solely on the lists `ps-bold-faces', `ps-italic-faces',
e0af0d3e
RS
1430and `ps-underlined-faces'."
1431 :type 'boolean
1432 :group 'ps-print-font)
12d89a2e 1433
e0af0d3e 1434(defcustom ps-bold-faces
090be653
RS
1435 (unless ps-print-color-p
1436 '(font-lock-function-name-face
1437 font-lock-builtin-face
1438 font-lock-variable-name-face
1439 font-lock-keyword-face
1440 font-lock-warning-face))
86c10ecb 1441 "*A list of the \(non-bold\) faces that should be printed in bold font.
8bd22fcf 1442This applies to generating PostScript."
e0af0d3e
RS
1443 :type '(repeat face)
1444 :group 'ps-print-face)
12d89a2e 1445
e0af0d3e 1446(defcustom ps-italic-faces
090be653
RS
1447 (unless ps-print-color-p
1448 '(font-lock-variable-name-face
8bd22fcf 1449 font-lock-type-face
090be653
RS
1450 font-lock-string-face
1451 font-lock-comment-face
1452 font-lock-warning-face))
86c10ecb 1453 "*A list of the \(non-italic\) faces that should be printed in italic font.
8bd22fcf 1454This applies to generating PostScript."
e0af0d3e
RS
1455 :type '(repeat face)
1456 :group 'ps-print-face)
12d89a2e 1457
e0af0d3e 1458(defcustom ps-underlined-faces
090be653
RS
1459 (unless ps-print-color-p
1460 '(font-lock-function-name-face
883212ce 1461 font-lock-constant-face
090be653 1462 font-lock-warning-face))
86c10ecb 1463 "*A list of the \(non-underlined\) faces that should be printed underlined.
8bd22fcf 1464This applies to generating PostScript."
e0af0d3e
RS
1465 :type '(repeat face)
1466 :group 'ps-print-face)
12d89a2e 1467
e0af0d3e 1468(defcustom ps-left-header
12d89a2e 1469 (list 'ps-get-buffer-name 'ps-header-dirpart)
bcc0d457 1470 "*The items to display (each on a line) on the left part of the page header.
8bd22fcf 1471This applies to generating PostScript.
12d89a2e 1472
86c10ecb 1473The value should be a list of strings and symbols, each representing an
12d89a2e
RS
1474entry in the PostScript array HeaderLinesLeft.
1475
1476Strings are inserted unchanged into the array; those representing
1477PostScript string literals should be delimited with PostScript string
1478delimiters '(' and ')'.
1479
1480For symbols with bound functions, the function is called and should
1481return a string to be inserted into the array. For symbols with bound
1482values, the value should be a string to be inserted into the array.
1483In either case, function or variable, the string value has PostScript
e0af0d3e
RS
1484string delimiters added to it."
1485 :type '(repeat (choice string symbol))
a6c6e755 1486 :group 'ps-print-header)
12d89a2e
RS
1487(make-variable-buffer-local 'ps-left-header)
1488
e0af0d3e 1489(defcustom ps-right-header
090be653 1490 (list "/pagenumberstring load" 'time-stamp-mon-dd-yyyy 'time-stamp-hh:mm:ss)
bcc0d457 1491 "*The items to display (each on a line) on the right part of the page header.
8bd22fcf 1492This applies to generating PostScript.
12d89a2e 1493
86c10ecb 1494See the variable `ps-left-header' for a description of the format of
e0af0d3e
RS
1495this variable."
1496 :type '(repeat (choice string symbol))
a6c6e755 1497 :group 'ps-print-header)
12d89a2e 1498(make-variable-buffer-local 'ps-right-header)
ef2cbb24 1499
e0af0d3e
RS
1500(defcustom ps-razzle-dazzle t
1501 "*Non-nil means report progress while formatting buffer."
1502 :type 'boolean
1503 :group 'ps-print)
12d89a2e 1504
a18ed129 1505(defcustom ps-adobe-tag "%!PS-Adobe-3.0\n"
12d89a2e
RS
1506 "*Contains the header line identifying the output as PostScript.
1507By default, `ps-adobe-tag' contains the standard identifier. Some
a18ed129
RS
1508printers require slightly different versions of this line."
1509 :type 'string
1510 :group 'ps-print)
12d89a2e 1511
e0af0d3e 1512(defcustom ps-build-face-reference t
12d89a2e
RS
1513 "*Non-nil means build the reference face lists.
1514
1515Ps-print sets this value to nil after it builds its internal reference
1516lists of bold and italic faces. By settings its value back to t, you
1517can force ps-print to rebuild the lists the next time you invoke one
86c10ecb 1518of the ...-with-faces commands.
12d89a2e
RS
1519
1520You should set this value back to t after you change the attributes of
1521any face, or create new faces. Most users shouldn't have to worry
e0af0d3e
RS
1522about its setting, though."
1523 :type 'boolean
1524 :group 'ps-print-face)
12d89a2e 1525
e0af0d3e 1526(defcustom ps-always-build-face-reference nil
12d89a2e
RS
1527 "*Non-nil means always rebuild the reference face lists.
1528
1529If this variable is non-nil, ps-print will rebuild its internal
1530reference lists of bold and italic faces *every* time one of the
496725ad 1531...-with-faces commands is called. Most users shouldn't need to set this
e0af0d3e
RS
1532variable."
1533 :type 'boolean
1534 :group 'ps-print-face)
ef2cbb24
RS
1535
1536;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12d89a2e 1537;; User commands
ef2cbb24 1538
00aa16af 1539;;;###autoload
ef2cbb24 1540(defun ps-print-buffer (&optional filename)
12d89a2e 1541 "Generate and print a PostScript image of the buffer.
ef2cbb24 1542
86c10ecb 1543When called with a numeric prefix argument (C-u), prompts the user for
ef2cbb24
RS
1544the name of a file to save the PostScript image in, instead of sending
1545it to the printer.
1546
1547More specifically, the FILENAME argument is treated as follows: if it
1548is nil, send the image to the printer. If FILENAME is a string, save
1549the PostScript image in a file with that name. If FILENAME is a
12d89a2e 1550number, prompt the user for the name of the file to save in."
00aa16af 1551 (interactive (list (ps-print-preprint current-prefix-arg)))
87a16a06 1552 (ps-print-without-faces (point-min) (point-max) filename))
ef2cbb24
RS
1553
1554
00aa16af 1555;;;###autoload
ef2cbb24 1556(defun ps-print-buffer-with-faces (&optional filename)
12d89a2e 1557 "Generate and print a PostScript image of the buffer.
12d89a2e 1558Like `ps-print-buffer', but includes font, color, and underline
107e7c70
KH
1559information in the generated image. This command works only if you
1560are using a window system, so it has a way to determine color values."
00aa16af 1561 (interactive (list (ps-print-preprint current-prefix-arg)))
87a16a06 1562 (ps-print-with-faces (point-min) (point-max) filename))
ef2cbb24 1563
ef2cbb24 1564
00aa16af 1565;;;###autoload
ef2cbb24 1566(defun ps-print-region (from to &optional filename)
12d89a2e 1567 "Generate and print a PostScript image of the region.
12d89a2e 1568Like `ps-print-buffer', but prints just the current region."
00aa16af 1569 (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
a18ed129 1570 (ps-print-without-faces from to filename t))
ef2cbb24 1571
ef2cbb24 1572
00aa16af 1573;;;###autoload
ef2cbb24 1574(defun ps-print-region-with-faces (from to &optional filename)
12d89a2e 1575 "Generate and print a PostScript image of the region.
12d89a2e 1576Like `ps-print-region', but includes font, color, and underline
107e7c70
KH
1577information in the generated image. This command works only if you
1578are using a window system, so it has a way to determine color values."
00aa16af 1579 (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
a18ed129 1580 (ps-print-with-faces from to filename t))
ef2cbb24 1581
ef2cbb24 1582
00aa16af 1583;;;###autoload
ef2cbb24 1584(defun ps-spool-buffer ()
12d89a2e 1585 "Generate and spool a PostScript image of the buffer.
12d89a2e
RS
1586Like `ps-print-buffer' except that the PostScript image is saved in a
1587local buffer to be sent to the printer later.
ef2cbb24 1588
12d89a2e 1589Use the command `ps-despool' to send the spooled images to the printer."
ef2cbb24 1590 (interactive)
87a16a06 1591 (ps-spool-without-faces (point-min) (point-max)))
ef2cbb24 1592
ef2cbb24 1593
00aa16af 1594;;;###autoload
ef2cbb24 1595(defun ps-spool-buffer-with-faces ()
12d89a2e 1596 "Generate and spool a PostScript image of the buffer.
12d89a2e 1597Like `ps-spool-buffer', but includes font, color, and underline
107e7c70 1598information in the generated image. This command works only if you
1cd7962f 1599are using a window system, so it has a way to determine color values.
ef2cbb24 1600
12d89a2e 1601Use the command `ps-despool' to send the spooled images to the printer."
ef2cbb24 1602 (interactive)
87a16a06 1603 (ps-spool-with-faces (point-min) (point-max)))
ef2cbb24 1604
ef2cbb24 1605
00aa16af 1606;;;###autoload
ef2cbb24 1607(defun ps-spool-region (from to)
12d89a2e 1608 "Generate a PostScript image of the region and spool locally.
12d89a2e 1609Like `ps-spool-buffer', but spools just the current region.
ef2cbb24 1610
12d89a2e 1611Use the command `ps-despool' to send the spooled images to the printer."
ef2cbb24 1612 (interactive "r")
a18ed129 1613 (ps-spool-without-faces from to t))
ef2cbb24 1614
ef2cbb24 1615
00aa16af 1616;;;###autoload
ef2cbb24 1617(defun ps-spool-region-with-faces (from to)
12d89a2e 1618 "Generate a PostScript image of the region and spool locally.
12d89a2e 1619Like `ps-spool-region', but includes font, color, and underline
107e7c70 1620information in the generated image. This command works only if you
1cd7962f 1621are using a window system, so it has a way to determine color values.
ef2cbb24 1622
12d89a2e 1623Use the command `ps-despool' to send the spooled images to the printer."
ef2cbb24 1624 (interactive "r")
a18ed129 1625 (ps-spool-with-faces from to t))
ef2cbb24 1626
00aa16af 1627;;;###autoload
ef2cbb24
RS
1628(defun ps-despool (&optional filename)
1629 "Send the spooled PostScript to the printer.
1630
1631When called with a numeric prefix argument (C-u), prompt the user for
1632the name of a file to save the spooled PostScript in, instead of sending
1633it to the printer.
1634
1635More specifically, the FILENAME argument is treated as follows: if it
1636is nil, send the image to the printer. If FILENAME is a string, save
1637the PostScript image in a file with that name. If FILENAME is a
1638number, prompt the user for the name of the file to save in."
00aa16af
RS
1639 (interactive (list (ps-print-preprint current-prefix-arg)))
1640 (ps-do-despool filename))
12d89a2e 1641
bcc0d457
RS
1642;;;###autoload
1643(defun ps-line-lengths ()
06fb6aab 1644 "Display the correspondence between a line length and a font size,
bcc0d457
RS
1645using the current ps-print setup.
1646Try: pr -t file | awk '{printf \"%3d %s\n\", length($0), $0}' | sort -r | head"
1647 (interactive)
1648 (ps-line-lengths-internal))
1649
1650;;;###autoload
1651(defun ps-nb-pages-buffer (nb-lines)
06fb6aab
RS
1652 "Display number of pages to print this buffer, for various font heights.
1653The table depends on the current ps-print setup."
bcc0d457
RS
1654 (interactive (list (count-lines (point-min) (point-max))))
1655 (ps-nb-pages nb-lines))
1656
1657;;;###autoload
1658(defun ps-nb-pages-region (nb-lines)
06fb6aab
RS
1659 "Display number of pages to print the region, for various font heights.
1660The table depends on the current ps-print setup."
bcc0d457
RS
1661 (interactive (list (count-lines (mark) (point))))
1662 (ps-nb-pages nb-lines))
1663
1664;;;###autoload
1665(defun ps-setup ()
496725ad 1666 "Return the current PostScript-generation setup."
a18ed129
RS
1667 (format
1668 "
1669\(setq ps-print-color-p %s
bcc0d457
RS
1670 ps-lpr-command \"%s\"
1671 ps-lpr-switches %s
1672
8bd22fcf
KH
1673 ps-paper-type '%s
1674 ps-landscape-mode %s
1675 ps-number-of-columns %s
bcc0d457 1676
8bd22fcf 1677 ps-zebra-stripes %s
01961237 1678 ps-zebra-stripe-height %s
8bd22fcf 1679 ps-line-number %s
a18ed129 1680
857686a6
RS
1681 ps-print-control-characters %s
1682
a18ed129
RS
1683 ps-print-background-image %s
1684
1685 ps-print-background-text %s
1686
1687 ps-left-margin %s
1688 ps-right-margin %s
1689 ps-inter-column %s
1690 ps-bottom-margin %s
1691 ps-top-margin %s
1692 ps-header-offset %s
bcc0d457
RS
1693 ps-header-line-pad %s
1694 ps-print-header %s
1695 ps-print-header-frame %s
1696 ps-header-lines %s
1697 ps-show-n-of-n %s
1698 ps-spool-duplex %s
1699
a18ed129
RS
1700 ps-font-family '%s
1701 ps-font-size %s
1702 ps-header-font-family '%s
1703 ps-header-font-size %s
1704 ps-header-title-font-size %s)
bcc0d457 1705"
a18ed129
RS
1706 ps-print-color-p
1707 ps-lpr-command
1708 ps-lpr-switches
1709 ps-paper-type
1710 ps-landscape-mode
1711 ps-number-of-columns
01961237
RS
1712 ps-zebra-stripes
1713 ps-zebra-stripe-height
a18ed129 1714 ps-line-number
857686a6 1715 ps-print-control-characters
a18ed129
RS
1716 ps-print-background-image
1717 ps-print-background-text
1718 ps-left-margin
1719 ps-right-margin
1720 ps-inter-column
1721 ps-bottom-margin
1722 ps-top-margin
1723 ps-header-offset
1724 ps-header-line-pad
1725 ps-print-header
1726 ps-print-header-frame
1727 ps-header-lines
1728 ps-show-n-of-n
1729 ps-spool-duplex
1730 ps-font-family
1731 ps-font-size
1732 ps-header-font-family
1733 ps-header-font-size
1734 ps-header-title-font-size))
bcc0d457 1735
12d89a2e
RS
1736;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1737;; Utility functions and variables:
1738
6770a60f
RS
1739(defvar ps-print-emacs-type
1740 (cond ((string-match "XEmacs" emacs-version) 'xemacs)
1741 ((string-match "Lucid" emacs-version) 'lucid)
1742 ((string-match "Epoch" emacs-version) 'epoch)
1743 (t 'emacs)))
1744
1745(if (or (eq ps-print-emacs-type 'lucid)
1746 (eq ps-print-emacs-type 'xemacs))
043620f4
KH
1747 (if (< emacs-minor-version 12)
1748 (setq ps-print-color-p nil))
12d89a2e
RS
1749 (require 'faces)) ; face-font, face-underline-p,
1750 ; x-font-regexp
1751
857686a6
RS
1752;; Return t if the device (which can be changed during an emacs session)
1753;; can handle colors.
1754;; This is function is not yet implemented for GNU emacs.
1755(defun ps-color-device ()
1756 (if (and (eq ps-print-emacs-type 'xemacs)
1757 (>= emacs-minor-version 12))
1758 (eq (device-class) 'color)
1759 t))
1760
12d89a2e
RS
1761(require 'time-stamp)
1762
bcc0d457
RS
1763(defvar ps-print-prologue-1
1764 "% ISOLatin1Encoding stolen from ps_init.ps in GhostScript 2.6.1.4:
12d89a2e 1765/ISOLatin1Encoding where { pop } {
bcc0d457
RS
1766% -- The ISO Latin-1 encoding vector isn't known, so define it.
1767% -- The first half is the same as the standard encoding,
1768% -- except for minus instead of hyphen at code 055.
12d89a2e
RS
1769/ISOLatin1Encoding
1770StandardEncoding 0 45 getinterval aload pop
1771 /minus
1772StandardEncoding 46 82 getinterval aload pop
1773%*** NOTE: the following are missing in the Adobe documentation,
1774%*** but appear in the displayed table:
1775%*** macron at 0225, dieresis at 0230, cedilla at 0233, space at 0240.
bcc0d457 1776% 0200 (128)
12d89a2e
RS
1777 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
1778 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
1779 /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent
1780 /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron
bcc0d457 1781% 0240 (160)
12d89a2e
RS
1782 /space /exclamdown /cent /sterling
1783 /currency /yen /brokenbar /section
1784 /dieresis /copyright /ordfeminine /guillemotleft
1785 /logicalnot /hyphen /registered /macron
1786 /degree /plusminus /twosuperior /threesuperior
1787 /acute /mu /paragraph /periodcentered
1788 /cedilla /onesuperior /ordmasculine /guillemotright
1789 /onequarter /onehalf /threequarters /questiondown
bcc0d457 1790% 0300 (192)
12d89a2e
RS
1791 /Agrave /Aacute /Acircumflex /Atilde
1792 /Adieresis /Aring /AE /Ccedilla
1793 /Egrave /Eacute /Ecircumflex /Edieresis
1794 /Igrave /Iacute /Icircumflex /Idieresis
1795 /Eth /Ntilde /Ograve /Oacute
1796 /Ocircumflex /Otilde /Odieresis /multiply
1797 /Oslash /Ugrave /Uacute /Ucircumflex
1798 /Udieresis /Yacute /Thorn /germandbls
bcc0d457 1799% 0340 (224)
12d89a2e
RS
1800 /agrave /aacute /acircumflex /atilde
1801 /adieresis /aring /ae /ccedilla
1802 /egrave /eacute /ecircumflex /edieresis
1803 /igrave /iacute /icircumflex /idieresis
1804 /eth /ntilde /ograve /oacute
1805 /ocircumflex /otilde /odieresis /divide
1806 /oslash /ugrave /uacute /ucircumflex
1807 /udieresis /yacute /thorn /ydieresis
1808256 packedarray def
1809} ifelse
1810
1811/reencodeFontISO { %def
1812 dup
87a16a06 1813 length 12 add dict % Make a new font (a new dict the same size
bcc0d457 1814 % as the old one) with room for our new symbols.
12d89a2e 1815
bcc0d457 1816 begin % Make the new font the current dictionary.
12d89a2e
RS
1817
1818
1819 { 1 index /FID ne
1820 { def } { pop pop } ifelse
bcc0d457
RS
1821 } forall % Copy each of the symbols from the old dictionary
1822 % to the new one except for the font ID.
12d89a2e 1823
12b88fff
RS
1824 currentdict /FontType get 0 ne {
1825 /Encoding ISOLatin1Encoding def % Override the encoding with
12d89a2e 1826 % the ISOLatin1 encoding.
12b88fff 1827 } if
12d89a2e
RS
1828
1829 % Use the font's bounding box to determine the ascent, descent,
1830 % and overall height; don't forget that these values have to be
1831 % transformed using the font's matrix.
bcc0d457
RS
1832
1833% ^ (x2 y2)
1834% | |
1835% | v
1836% | +----+ - -
1837% | | | ^
1838% | | | | Ascent (usually > 0)
1839% | | | |
1840% (0 0) -> +--+----+-------->
1841% | | |
1842% | | v Descent (usually < 0)
1843% (x1 y1) --> +----+ - -
1844
12b88fff
RS
1845 currentdict /FontType get 0 ne {
1846 FontBBox % -- x1 y1 x2 y2
1847 FontMatrix transform /Ascent exch def pop
1848 FontMatrix transform /Descent exch def pop
1849 } {
1850 /PrimaryFont FDepVector 0 get def
1851 PrimaryFont /FontBBox get aload pop
1852 PrimaryFont /FontMatrix get transform /Ascent exch def pop
1853 PrimaryFont /FontMatrix get transform /Descent exch def pop
1854 } ifelse
1855
bcc0d457 1856 /FontHeight Ascent Descent sub def % use `sub' because descent < 0
12d89a2e 1857
bcc0d457 1858 % Define these in case they're not in the FontInfo
87a16a06
RS
1859 % (also, here they're easier to get to).
1860 /UnderlinePosition Descent 0.70 mul def
1861 /OverlinePosition Descent UnderlinePosition sub Ascent add def
1862 /StrikeoutPosition Ascent 0.30 mul def
1863 /LineThickness 0 50 FontMatrix transform exch pop def
1864 /Xshadow 0 80 FontMatrix transform exch pop def
1865 /Yshadow 0 -90 FontMatrix transform exch pop def
1866 /SpaceBackground Descent neg UnderlinePosition add def
1867 /XBox Descent neg def
1868 /YBox LineThickness 0.7 mul def
12d89a2e 1869
bcc0d457
RS
1870 currentdict % Leave the new font on the stack
1871 end % Stop using the font as the current dictionary.
1872 definefont % Put the font into the font dictionary
1873 pop % Discard the returned font.
12d89a2e 1874} bind def
ef2cbb24 1875
bcc0d457 1876/DefFont { % Font definition
12d89a2e
RS
1877 findfont exch scalefont reencodeFontISO
1878} def
1879
bcc0d457 1880/F { % Font selection
12d89a2e 1881 findfont
87a16a06
RS
1882 dup /Ascent get /Ascent exch def
1883 dup /Descent get /Descent exch def
1884 dup /FontHeight get /FontHeight exch def
1885 dup /UnderlinePosition get /UnderlinePosition exch def
1886 dup /OverlinePosition get /OverlinePosition exch def
1887 dup /StrikeoutPosition get /StrikeoutPosition exch def
1888 dup /LineThickness get /LineThickness exch def
1889 dup /Xshadow get /Xshadow exch def
1890 dup /Yshadow get /Yshadow exch def
1891 dup /SpaceBackground get /SpaceBackground exch def
1892 dup /XBox get /XBox exch def
1893 dup /YBox get /YBox exch def
12d89a2e
RS
1894 setfont
1895} def
1896
1897/FG /setrgbcolor load def
1898
1899/bg false def
1900/BG {
1901 dup /bg exch def
87a16a06
RS
1902 {mark 4 1 roll ]}
1903 {[ 1.0 1.0 1.0 ]}
1904 ifelse
1905 /bgcolor exch def
12d89a2e
RS
1906} def
1907
bcc0d457
RS
1908% B width C
1909% +-----------+
1910% | Ascent (usually > 0)
1911% A + +
1912% | Descent (usually < 0)
1913% +-----------+
1914% E width D
1915
12d89a2e 1916/dobackground { % width --
bcc0d457 1917 currentpoint % -- width x y
12d89a2e
RS
1918 gsave
1919 newpath
bcc0d457
RS
1920 moveto % A (x y)
1921 0 Ascent rmoveto % B
1922 dup 0 rlineto % C
1923 0 Descent Ascent sub rlineto % D
1924 neg 0 rlineto % E
12d89a2e
RS
1925 closepath
1926 bgcolor aload pop setrgbcolor
1927 fill
1928 grestore
1929} def
1930
bcc0d457
RS
1931/eolbg { % dobackground until right margin
1932 PrintWidth % -- x-eol
1933 currentpoint pop % -- cur-x
1934 sub % -- width until eol
1935 dobackground
12d89a2e
RS
1936} def
1937
87a16a06 1938/PLN {PrintLineNumber {doLineNumber}if} def
12d89a2e
RS
1939
1940/SL { % Soft Linefeed
1941 bg { eolbg } if
bcc0d457 1942 0 currentpoint exch pop LineHeight sub moveto
12d89a2e
RS
1943} def
1944
87a16a06 1945/HL {SL PLN} def % Hard Linefeed
12d89a2e
RS
1946
1947% Some debug
1948/dcp { currentpoint exch 40 string cvs print (, ) print = } def
87a16a06 1949/dp { print 2 copy exch 40 string cvs print (, ) print = } def
12d89a2e
RS
1950
1951/W {
bcc0d457
RS
1952 ( ) stringwidth % Get the width of a space in the current font.
1953 pop % Discard the Y component.
1954 mul % Multiply the width of a space
1955 % by the number of spaces to plot
12d89a2e
RS
1956 bg { dup dobackground } if
1957 0 rmoveto
87a16a06
RS
1958} def
1959
1960/Effect 0 def
1961/EF {/Effect exch def} def
1962
1963% stack: string |- --
1964% effect: 1 - underline 2 - strikeout 4 - overline
1965% 8 - shadow 16 - box 32 - outline
1966/S {
1967 /xx currentpoint dup Descent add /yy exch def
1968 Ascent add /YY exch def def
1969 dup stringwidth pop xx add /XX exch def
1970 Effect 8 and 0 ne {
1971 /yy yy Yshadow add def
1972 /XX XX Xshadow add def
1973 } if
1974 bg {
1975 true
1976 Effect 16 and 0 ne
1977 {SpaceBackground doBox}
1978 {xx yy XX YY doRect}
1979 ifelse
1980 } if % background
1981 Effect 16 and 0 ne {false 0 doBox}if % box
1982 Effect 8 and 0 ne {dup doShadow}if % shadow
1983 Effect 32 and 0 ne
1984 {true doOutline} % outline
1985 {show} % normal text
1986 ifelse
1987 Effect 1 and 0 ne {UnderlinePosition Hline}if % underline
1988 Effect 2 and 0 ne {StrikeoutPosition Hline}if % strikeout
1989 Effect 4 and 0 ne {OverlinePosition Hline}if % overline
1990} bind def
1991
1992% stack: position |- --
1993/Hline {
1994 currentpoint exch pop add dup
1995 gsave
1996 newpath
1997 xx exch moveto
1998 XX exch lineto
1999 closepath
2000 LineThickness setlinewidth stroke
2001 grestore
2002} bind def
2003
2004% stack: fill-or-not delta |- --
2005/doBox {
2006 /dd exch def
2007 xx XBox sub dd sub yy YBox sub dd sub
2008 XX XBox add dd add YY YBox add dd add
2009 doRect
2010} bind def
2011
2012% stack: fill-or-not lower-x lower-y upper-x upper-y |- --
2013/doRect {
2014 /rYY exch def
2015 /rXX exch def
2016 /ryy exch def
2017 /rxx exch def
2018 gsave
2019 newpath
2020 rXX rYY moveto
2021 rxx rYY lineto
2022 rxx ryy lineto
2023 rXX ryy lineto
2024 closepath
2025 % top of stack: fill-or-not
2026 {FillBgColor}
2027 {LineThickness setlinewidth stroke}
2028 ifelse
2029 grestore
2030} bind def
2031
2032% stack: string |- --
2033/doShadow {
2034 gsave
2035 Xshadow Yshadow rmoveto
2036 false doOutline
2037 grestore
2038} bind def
2039
2040/st 1 string def
2041
2042% stack: string fill-or-not |- --
2043/doOutline {
2044 /-fillp- exch def
2045 /-ox- currentpoint /-oy- exch def def
2046 gsave
2047 LineThickness setlinewidth
2048 {
2049 st 0 3 -1 roll put
2050 st dup true charpath
2051 -fillp- {gsave FillBgColor grestore}if
2052 stroke stringwidth
2053 -oy- add /-oy- exch def
2054 -ox- add /-ox- exch def
2055 -ox- -oy- moveto
2056 } forall
2057 grestore
2058 -ox- -oy- moveto
2059} bind def
2060
2061% stack: --
2062/FillBgColor {bgcolor aload pop setrgbcolor fill} bind def
2063
2064/L0 6 /Times-Italic DefFont
2065
2066% stack: --
2067/doLineNumber {
2068 currentfont
2069 gsave
2070 0.0 0.0 0.0 setrgbcolor
2071 /L0 findfont setfont
2072 LineNumber Lines ge
2073 {(end )}
2074 {LineNumber 6 string cvs ( ) strcat}
2075 ifelse
2076 dup stringwidth pop neg 0 rmoveto
2077 show
2078 grestore
2079 setfont
2080 /LineNumber LineNumber 1 add def
2081} def
2082
2083% stack: --
2084/printZebra {
2085 gsave
2086 0.985 setgray
857686a6 2087 /double-zebra ZebraHeight ZebraHeight add def
87a16a06
RS
2088 /yiter double-zebra LineHeight mul neg def
2089 /xiter PrintWidth InterColumn add def
2090 NumberOfColumns {LinesPerColumn doColumnZebra xiter 0 rmoveto}repeat
2091 grestore
2092} def
2093
2094% stack: lines-per-column |- --
2095/doColumnZebra {
2096 gsave
857686a6 2097 dup double-zebra idiv {ZebraHeight doZebra 0 yiter rmoveto}repeat
87a16a06 2098 double-zebra mod
857686a6 2099 dup 0 le {pop}{dup ZebraHeight gt {pop ZebraHeight}if doZebra}ifelse
87a16a06
RS
2100 grestore
2101} def
2102
2103% stack: zebra-height (in lines) |- --
2104/doZebra {
2105 /zh exch 0.05 sub LineHeight mul def
2106 gsave
2107 0 LineHeight 0.65 mul rmoveto
2108 PrintWidth 0 rlineto
2109 0 zh neg rlineto
2110 PrintWidth neg 0 rlineto
2111 0 zh rlineto
2112 fill
2113 grestore
2114} def
2115
2116% tx ty rotation xscale yscale xpos ypos BeginBackImage
2117/BeginBackImage {
2118 /-save-image- save def
2119 /showpage {}def
2120 translate
2121 scale
2122 rotate
2123 translate
2124} def
2125
2126/EndBackImage {
2127 -save-image- restore
2128} def
2129
2130% string fontsize fontname rotation gray xpos ypos ShowBackText
2131/ShowBackText {
2132 gsave
2133 translate
2134 setgray
2135 rotate
2136 findfont exch dup /-offset- exch -0.25 mul def scalefont setfont
2137 0 -offset- moveto
2138 /-saveLineThickness- LineThickness def
2139 /LineThickness 1 def
2140 false doOutline
2141 /LineThickness -saveLineThickness- def
2142 grestore
12d89a2e
RS
2143} def
2144
bcc0d457
RS
2145/BeginDoc {
2146 % ---- save the state of the document (useful for ghostscript!)
2147 /docState save def
2148 % ---- [jack] Kludge: my ghostscript window is 21x27.7 instead of 21x29.7
2149 /JackGhostscript where {
2150 pop 1 27.7 29.7 div scale
2151 } if
2152 LandscapeMode {
2153 % ---- translate to bottom-right corner of Portrait page
2154 LandscapePageHeight 0 translate
2155 90 rotate
2156 } if
2157 /ColumnWidth PrintWidth InterColumn add def
2158 % ---- translate to lower left corner of TEXT
2159 LeftMargin BottomMargin translate
2160 % ---- define where printing will start
2161 /f0 F % this installs Ascent
2162 /PrintStartY PrintHeight Ascent sub def
2163 /ColumnIndex 1 def
2164} def
2165
2166/EndDoc {
2167 % ---- on last page but not last column, spit out the page
2168 ColumnIndex 1 eq not { showpage } if
2169 % ---- restore the state of the document (useful for ghostscript!)
2170 docState restore
2171} def
2172
12d89a2e 2173/BeginDSCPage {
bcc0d457 2174 % ---- when 1st column, save the state of the page
a18ed129 2175 ColumnIndex 1 eq { /pageState save def } if
bcc0d457
RS
2176 % ---- save the state of the column
2177 /columnState save def
12d89a2e
RS
2178} def
2179
12b88fff
RS
2180/PrintHeaderWidth PrintOnlyOneHeader{PrintPageWidth}{PrintWidth}ifelse def
2181
12d89a2e 2182/BeginPage {
a18ed129
RS
2183 % ---- when 1st column, print all background effects
2184 ColumnIndex 1 eq {
2185 0 PrintStartY moveto % move to where printing will start
2186 Zebra {printZebra}if
2187 printGlobalBackground
2188 printLocalBackground
2189 } if
12d89a2e 2190 PrintHeader {
12b88fff
RS
2191 PrintOnlyOneHeader{ColumnIndex 1 eq}{true}ifelse {
2192 PrintHeaderFrame {HeaderFrame}if
2193 HeaderText
2194 } if
12d89a2e 2195 } if
bcc0d457 2196 0 PrintStartY moveto % move to where printing will start
87a16a06 2197 PLN
12d89a2e
RS
2198} def
2199
2200/EndPage {
2201 bg { eolbg } if
12d89a2e
RS
2202} def
2203
2204/EndDSCPage {
bcc0d457
RS
2205 ColumnIndex NumberOfColumns eq {
2206 % ---- on last column, spit out the page
2207 showpage
2208 % ---- restore the state of the page
2209 pageState restore
2210 /ColumnIndex 1 def
2211 } { % else
2212 % ---- restore the state of the current column
2213 columnState restore
2214 % ---- and translate to the next column
2215 ColumnWidth 0 translate
2216 /ColumnIndex ColumnIndex 1 add def
2217 } ifelse
12d89a2e
RS
2218} def
2219
bcc0d457 2220/SetHeaderLines { % nb-lines --
12d89a2e 2221 /HeaderLines exch def
bcc0d457
RS
2222 % ---- bottom up
2223 HeaderPad
2224 HeaderLines 1 sub HeaderLineHeight mul add
2225 HeaderTitleLineHeight add
2226 HeaderPad add
2227 /HeaderHeight exch def
12d89a2e
RS
2228} def
2229
bcc0d457
RS
2230% |---------|
2231% | tm |
2232% |---------|
2233% | header |
2234% |-+-------| <-- (x y)
2235% | ho |
2236% |---------|
2237% | text |
2238% |-+-------| <-- (0 0)
2239% | bm |
2240% |---------|
2241
2242/HeaderFrameStart { % -- x y
2243 0 PrintHeight HeaderOffset add
12d89a2e
RS
2244} def
2245
2246/HeaderFramePath {
12b88fff
RS
2247 PrintHeaderWidth 0 rlineto
2248 0 HeaderHeight rlineto
2249 PrintHeaderWidth neg 0 rlineto
2250 0 HeaderHeight neg rlineto
12d89a2e
RS
2251} def
2252
2253/HeaderFrame {
2254 gsave
2255 0.4 setlinewidth
bcc0d457 2256 % ---- fill a black rectangle (the shadow of the next one)
12d89a2e
RS
2257 HeaderFrameStart moveto
2258 1 -1 rmoveto
2259 HeaderFramePath
2260 0 setgray fill
bcc0d457 2261 % ---- do the next rectangle ...
12d89a2e
RS
2262 HeaderFrameStart moveto
2263 HeaderFramePath
bcc0d457
RS
2264 gsave 0.9 setgray fill grestore % filled with grey
2265 gsave 0 setgray stroke grestore % drawn with black
12d89a2e
RS
2266 grestore
2267} def
2268
2269/HeaderStart {
2270 HeaderFrameStart
bcc0d457
RS
2271 exch HeaderPad add exch % horizontal pad
2272 % ---- bottom up
2273 HeaderPad add % vertical pad
2274 HeaderDescent sub
2275 HeaderLineHeight HeaderLines 1 sub mul add
12d89a2e
RS
2276} def
2277
2278/strcat {
2279 dup length 3 -1 roll dup length dup 4 -1 roll add string dup
2280 0 5 -1 roll putinterval
2281 dup 4 2 roll exch putinterval
2282} def
2283
2284/pagenumberstring {
2285 PageNumber 32 string cvs
2286 ShowNofN {
2287 (/) strcat
2288 PageCount 32 string cvs strcat
2289 } if
2290} def
2291
2292/HeaderText {
2293 HeaderStart moveto
2294
bcc0d457
RS
2295 HeaderLinesRight HeaderLinesLeft % -- rightLines leftLines
2296
2297 % ---- hack: `PN 1 and' == `PN 2 modulo'
2298
2299 % ---- if duplex and even page number, then exchange left and right
12d89a2e
RS
2300 Duplex PageNumber 1 and 0 eq and { exch } if
2301
bcc0d457 2302 { % ---- process the left lines
12d89a2e
RS
2303 aload pop
2304 exch F
2305 gsave
2306 dup xcheck { exec } if
2307 show
2308 grestore
2309 0 HeaderLineHeight neg rmoveto
2310 } forall
2311
2312 HeaderStart moveto
2313
bcc0d457 2314 { % ---- process the right lines
12d89a2e
RS
2315 aload pop
2316 exch F
2317 gsave
2318 dup xcheck { exec } if
2319 dup stringwidth pop
12b88fff 2320 PrintHeaderWidth exch sub HeaderPad 2 mul sub 0 rmoveto
12d89a2e
RS
2321 show
2322 grestore
2323 0 HeaderLineHeight neg rmoveto
2324 } forall
2325} def
2326
2327/ReportFontInfo {
2328 2 copy
bcc0d457 2329 /t0 3 1 roll DefFont
12d89a2e 2330 /t0 F
00aa16af 2331 /lh FontHeight def
12d89a2e
RS
2332 /sw ( ) stringwidth pop def
2333 /aw (01234567890abcdefghijklmnopqrstuvwxyz) dup length exch
2334 stringwidth pop exch div def
bcc0d457 2335 /t1 12 /Helvetica-Oblique DefFont
12d89a2e 2336 /t1 F
12d89a2e
RS
2337 gsave
2338 (For ) show
2339 128 string cvs show
2340 ( ) show
2341 32 string cvs show
2342 ( point, the line height is ) show
2343 lh 32 string cvs show
2344 (, the space width is ) show
2345 sw 32 string cvs show
2346 (,) show
2347 grestore
00aa16af 2348 0 FontHeight neg rmoveto
bcc0d457
RS
2349 gsave
2350 (and a crude estimate of average character width is ) show
2351 aw 32 string cvs show
2352 (.) show
2353 grestore
2354 0 FontHeight neg rmoveto
2355} def
2356
2357/cm { % cm to point
2358 72 mul 2.54 div
2359} def
2360
2361/ReportAllFontInfo {
2362 FontDirectory
2363 { % key = font name value = font dictionary
2364 pop 10 exch ReportFontInfo
2365 } forall
12d89a2e
RS
2366} def
2367
bcc0d457
RS
2368% 3 cm 20 cm moveto 10 /Courier ReportFontInfo showpage
2369% 3 cm 20 cm moveto ReportAllFontInfo showpage
2370
2371")
2372
2373(defvar ps-print-prologue-2
2374 "
2375% ---- These lines must be kept together because...
2376
2377/h0 F
2378/HeaderTitleLineHeight FontHeight def
2379
2380/h1 F
2381/HeaderLineHeight FontHeight def
2382/HeaderDescent Descent def
2383
2384% ---- ...because `F' has a side-effect on `FontHeight' and `Descent'
2385
12d89a2e
RS
2386")
2387
2388;; Start Editing Here:
ef2cbb24 2389
12d89a2e
RS
2390(defvar ps-source-buffer nil)
2391(defvar ps-spool-buffer-name "*PostScript*")
2392(defvar ps-spool-buffer nil)
ef2cbb24 2393
12d89a2e
RS
2394(defvar ps-output-head nil)
2395(defvar ps-output-tail nil)
ef2cbb24 2396
12d89a2e 2397(defvar ps-page-count 0)
87a16a06
RS
2398(defvar ps-showline-count 1)
2399
857686a6
RS
2400(defvar ps-control-or-escape-regexp nil)
2401
87a16a06
RS
2402(defvar ps-background-pages nil)
2403(defvar ps-background-all-pages nil)
2404(defvar ps-background-text-count 0)
2405(defvar ps-background-image-count 0)
ef2cbb24 2406
12d89a2e 2407(defvar ps-current-font 0)
12d89a2e
RS
2408(defvar ps-default-color (if ps-print-color-p ps-default-fg)) ; black
2409(defvar ps-current-color ps-default-color)
2410(defvar ps-current-bg nil)
2411
2412(defvar ps-razchunk 0)
2413
bcc0d457
RS
2414(defvar ps-color-format
2415 (if (eq ps-print-emacs-type 'emacs)
12d89a2e 2416
12b88fff
RS
2417 ;; Emacs understands the %f format; we'll use it to limit color RGB
2418 ;; values to three decimals to cut down some on the size of the
2419 ;; PostScript output.
2420 "%0.3f %0.3f %0.3f"
12d89a2e 2421
12b88fff 2422 ;; Lucid emacsen will have to make do with %s (princ) for floats.
bcc0d457 2423 "%s %s %s"))
12d89a2e
RS
2424
2425;; These values determine how much print-height to deduct when headers
2426;; are turned on. This is a pretty clumsy way of handling it, but
2427;; it'll do for now.
12d89a2e 2428
bcc0d457 2429(defvar ps-header-pad 0
496725ad
RS
2430 "Vertical and horizontal space between the header frame and the text.
2431This is in units of points (1/72 inch).")
12d89a2e 2432
bcc0d457 2433;; Define accessors to the dimensions list.
12d89a2e 2434
bcc0d457
RS
2435(defmacro ps-page-dimensions-get-width (dims) `(nth 0 ,dims))
2436(defmacro ps-page-dimensions-get-height (dims) `(nth 1 ,dims))
12d89a2e 2437
87a16a06 2438(defvar ps-landscape-page-height nil)
12d89a2e 2439
12d89a2e
RS
2440(defvar ps-print-width nil)
2441(defvar ps-print-height nil)
2442
8bd22fcf
KH
2443(defvar ps-height-remaining nil)
2444(defvar ps-width-remaining nil)
12d89a2e 2445
bcc0d457
RS
2446(defvar ps-print-color-scale nil)
2447
87a16a06
RS
2448\f
2449;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2450;; Internal Variables
2451
2452
2453(defvar ps-print-face-extension-alist nil
a18ed129 2454 "Alist of symbolic faces *WITH* extension features (box, outline, etc).
87a16a06
RS
2455An element of this list has the following form:
2456
2457 (FACE . [BITS FG BG])
2458
2459 FACE is a symbol denoting a face name
2460 BITS is a bit vector, where each bit correspond
2461 to a feature (bold, underline, etc)
2462 (see documentation for `ps-print-face-map-alist')
2463 FG foreground color (string or nil)
2464 BG background color (string or nil)
2465
a18ed129
RS
2466Don't change this list directly; instead,
2467use `ps-extend-face' and `ps-extend-face-list'.
2468See documentation for `ps-extend-face' for valid extension symbol.")
2469
2470
2471(defvar ps-print-face-alist nil
2472 "Alist of symbolic faces *WITHOUT* extension features (box, outline, etc).
2473
2474An element of this list has the same form as an element of
2475`ps-print-face-extension-alist'.
2476
2477Don't change this list directly; this list is used by `ps-face-attributes',
2478`ps-map-face' and `ps-build-reference-face-lists'.")
87a16a06
RS
2479
2480
2481(defconst ps-print-face-map-alist
2482 '((bold . 1)
2483 (italic . 2)
2484 (underline . 4)
2485 (strikeout . 8)
2486 (overline . 16)
2487 (shadow . 32)
2488 (box . 64)
2489 (outline . 128))
2490 "Alist of all features and the corresponding bit mask.
2491Each symbol correspond to one bit in a bit vector.")
2492
2493\f
2494;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
a18ed129 2495;; Remapping Faces
87a16a06
RS
2496
2497
2498;;;###autoload
2499(defun ps-extend-face-list (face-extension-list &optional merge-p)
2500 "Extend face in `ps-print-face-extension-alist'.
2501
a18ed129
RS
2502If optional MERGE-P is non-nil, extensions in FACE-EXTENSION-LIST are merged
2503with face extension in `ps-print-face-extension-alist'; otherwise, overrides.
87a16a06
RS
2504
2505The elements in FACE-EXTENSION-LIST is like those for `ps-extend-face'.
2506
2507See `ps-extend-face' for documentation."
2508 (while face-extension-list
2509 (ps-extend-face (car face-extension-list) merge-p)
2510 (setq face-extension-list (cdr face-extension-list))))
2511
2512
2513;;;###autoload
2514(defun ps-extend-face (face-extension &optional merge-p)
2515 "Extend face in `ps-print-face-extension-alist'.
2516
6bdb808e 2517If optional MERGE-P is non-nil, extensions in FACE-EXTENSION list are merged
a18ed129 2518with face extensions in `ps-print-face-extension-alist'; otherwise, overrides.
87a16a06
RS
2519
2520The elements of FACE-EXTENSION list have the form:
2521
2522 (FACE-NAME FOREGROUND BACKGROUND EXTENSION...)
2523
2524FACE-NAME is a face name symbol.
2525
2526FOREGROUND and BACKGROUND may be nil or a string that denotes the
2527foreground and background colors respectively.
2528
2529EXTENSION is one of the following symbols:
2530 bold - use bold font.
2531 italic - use italic font.
2532 underline - put a line under text.
2533 strikeout - like underline, but the line is in middle of text.
2534 overline - like underline, but the line is over the text.
2535 shadow - text will have a shadow.
2536 box - text will be surrounded by a box.
a18ed129 2537 outline - print characters as hollow outlines.
87a16a06
RS
2538
2539If EXTENSION is any other symbol, it is ignored."
2540 (let* ((face-name (nth 0 face-extension))
2541 (foreground (nth 1 face-extension))
2542 (background (nth 2 face-extension))
2543 (ps-face (cdr (assq face-name ps-print-face-extension-alist)))
2544 (face-vector (or ps-face (vector 0 nil nil)))
2545 (face-bit (ps-extension-bit face-extension)))
2546 ;; extend face
2547 (aset face-vector 0 (if merge-p
2548 (logior (aref face-vector 0) face-bit)
2549 face-bit))
2550 (and foreground (stringp foreground) (aset face-vector 1 foreground))
2551 (and background (stringp background) (aset face-vector 2 background))
2552 ;; if face does not exist, insert it
2553 (or ps-face
2554 (setq ps-print-face-extension-alist
2555 (cons (cons face-name face-vector)
2556 ps-print-face-extension-alist)))))
2557
2558
2559(defun ps-extension-bit (face-extension)
2560 (let ((face-bit 0))
2561 ;; map valid symbol extension to bit vector
2562 (setq face-extension (cdr (cdr face-extension)))
2563 (while (setq face-extension (cdr face-extension))
2564 (setq face-bit (logior face-bit
2565 (or (cdr (assq (car face-extension)
2566 ps-print-face-map-alist))
2567 0))))
2568 face-bit))
2569
2570\f
857686a6
RS
2571;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2572;; Adapted from font-lock:
2573;; Originally face attributes were specified via `font-lock-face-attributes'.
2574;; Users then changed the default face attributes by setting that variable.
2575;; However, we try and be back-compatible and respect its value if set except
2576;; for faces where M-x customize has been used to save changes for the face.
2577
2578(defun ps-font-lock-face-attributes ()
2579 (and (boundp 'font-lock-mode) (symbol-value 'font-lock-mode)
2580 (boundp 'font-lock-face-attributes)
2581 (let ((face-attributes font-lock-face-attributes))
2582 (while face-attributes
6bdb808e
RS
2583 (let* ((face-attribute
2584 (car (prog1 face-attributes
2585 (setq face-attributes (cdr face-attributes)))))
857686a6
RS
2586 (face (car face-attribute)))
2587 ;; Rustle up a `defface' SPEC from a
2588 ;; `font-lock-face-attributes' entry.
2589 (unless (get face 'saved-face)
2590 (let ((foreground (nth 1 face-attribute))
2591 (background (nth 2 face-attribute))
2592 (bold-p (nth 3 face-attribute))
2593 (italic-p (nth 4 face-attribute))
2594 (underline-p (nth 5 face-attribute))
2595 face-spec)
2596 (when foreground
2597 (setq face-spec (cons ':foreground
2598 (cons foreground face-spec))))
2599 (when background
2600 (setq face-spec (cons ':background
2601 (cons background face-spec))))
2602 (when bold-p
2603 (setq face-spec (append '(:bold t) face-spec)))
2604 (when italic-p
2605 (setq face-spec (append '(:italic t) face-spec)))
2606 (when underline-p
2607 (setq face-spec (append '(:underline t) face-spec)))
2608 (custom-declare-face face (list (list t face-spec)) nil)
2609 )))))))
2610
2611\f
87a16a06
RS
2612;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2613;; Internal functions and variables
2614
2615
12b88fff
RS
2616(make-local-hook 'ps-print-hook)
2617(make-local-hook 'ps-print-begin-page-hook)
2618(make-local-hook 'ps-print-begin-column-hook)
2619
2620
a18ed129 2621(defun ps-print-without-faces (from to &optional filename region-p)
857686a6 2622 (ps-spool-without-faces from to region-p)
87a16a06
RS
2623 (ps-do-despool filename))
2624
2625
a18ed129 2626(defun ps-spool-without-faces (from to &optional region-p)
12b88fff 2627 (run-hooks 'ps-print-hook)
a18ed129 2628 (ps-printing-region region-p)
87a16a06
RS
2629 (ps-generate (current-buffer) from to 'ps-generate-postscript))
2630
2631
a18ed129 2632(defun ps-print-with-faces (from to &optional filename region-p)
857686a6 2633 (ps-spool-with-faces from to region-p)
87a16a06
RS
2634 (ps-do-despool filename))
2635
2636
a18ed129 2637(defun ps-spool-with-faces (from to &optional region-p)
12b88fff 2638 (run-hooks 'ps-print-hook)
a18ed129 2639 (ps-printing-region region-p)
87a16a06
RS
2640 (ps-generate (current-buffer) from to 'ps-generate-postscript-with-faces))
2641
2642
a18ed129
RS
2643(defsubst ps-count-lines (from to)
2644 (+ (count-lines from to)
857686a6
RS
2645 (save-excursion
2646 (goto-char to)
2647 (if (= (current-column) 0) 1 0))))
87a16a06
RS
2648
2649
a18ed129 2650(defvar ps-printing-region nil
496725ad 2651 "Variable used to indicate if ps-print is printing a region.
a18ed129
RS
2652If non-nil, it is a cons, the car of which is the line number
2653where the region begins, and its cdr is the total number of lines
2654in the buffer. Formatting functions can use this information
2655to print the original line number (and not the number of lines printed),
2656and to indicate in the header that the printout is of a partial file.")
87a16a06
RS
2657
2658
a18ed129
RS
2659(defun ps-printing-region (region-p)
2660 (setq ps-printing-region
2661 (and region-p
2662 (cons (ps-count-lines (point-min) (region-beginning))
2663 (ps-count-lines (point-min) (point-max))))))
87a16a06
RS
2664
2665\f
12d89a2e
RS
2666;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2667;; Internal functions
2668
7ae35a2f 2669(defsubst ps-font-alist (font-sym)
12b88fff
RS
2670 (get font-sym 'fonts))
2671
2672(defun ps-font (font-sym font-type)
2673 "Font family name for text of `font-type', when generating PostScript."
7ae35a2f 2674 (let* ((font-list (ps-font-alist font-sym))
12b88fff 2675 (normal-font (cdr (assq 'normal font-list))))
6bdb808e
RS
2676 (while (and font-list (not (eq font-type (car (car font-list)))))
2677 (setq font-list (cdr font-list)))
2678 (or (cdr (car font-list)) normal-font)))
12b88fff
RS
2679
2680(defun ps-fonts (font-sym)
7ae35a2f 2681 (mapcar 'cdr (ps-font-alist font-sym)))
12b88fff
RS
2682
2683(defun ps-font-number (font-sym font-type)
7ae35a2f 2684 (or (ps-alist-position font-type (ps-font-alist font-sym))
12b88fff
RS
2685 0))
2686
2687(defsubst ps-line-height (font-sym)
2688 "The height of a line, for generating PostScript.
2689This is the value that ps-print uses to determine the height,
2690y-dimension, of the lines of text it has printed, and thus affects the
2691point at which page-breaks are placed.
2692The line-height is *not* the same as the point size of the font."
2693 (get font-sym 'line-height))
2694
2695(defsubst ps-title-line-height (font-sym)
2696 "The height of a `title' line, for generating PostScript.
2697This is the value that ps-print uses to determine the height,
2698y-dimension, of the lines of text it has printed, and thus affects the
2699point at which page-breaks are placed.
2700The title-line-height is *not* the same as the point size of the font."
2701 (get font-sym 'title-line-height))
2702
2703(defsubst ps-space-width (font-sym)
2704 "The width of a space character, for generating PostScript.
2705This value is used in expanding tab characters."
2706 (get font-sym 'space-width))
2707
2708(defsubst ps-avg-char-width (font-sym)
2709 "The average width, in points, of a character, for generating PostScript.
2710This is the value that ps-print uses to determine the length,
2711x-dimension, of the text it has printed, and thus affects the point at
2712which long lines wrap around."
2713 (get font-sym 'avg-char-width))
2714
bcc0d457 2715(defun ps-line-lengths-internal ()
87a16a06 2716 "Display the correspondence between a line length and a font size,
bcc0d457
RS
2717using the current ps-print setup.
2718Try: pr -t file | awk '{printf \"%3d %s\n\", length($0), $0}' | sort -r | head"
2719 (let ((buf (get-buffer-create "*Line-lengths*"))
2720 (ifs ps-font-size) ; initial font size
12b88fff 2721 (icw (ps-avg-char-width 'ps-font-for-text)) ; initial character width
bcc0d457
RS
2722 (print-width (progn (ps-get-page-dimensions)
2723 ps-print-width))
2724 (ps-setup (ps-setup)) ; setup for the current buffer
2725 (fs-min 5) ; minimum font size
2726 cw-min ; minimum character width
2727 nb-cpl-max ; maximum nb of characters per line
2728 (fs-max 14) ; maximum font size
2729 cw-max ; maximum character width
2730 nb-cpl-min ; minimum nb of characters per line
2731 fs ; current font size
2732 cw ; current character width
2733 nb-cpl ; current nb of characters per line
2734 )
2735 (setq cw-min (/ (* icw fs-min) ifs)
2736 nb-cpl-max (floor (/ print-width cw-min))
2737 cw-max (/ (* icw fs-max) ifs)
8bd22fcf
KH
2738 nb-cpl-min (floor (/ print-width cw-max))
2739 nb-cpl nb-cpl-min)
bcc0d457
RS
2740 (set-buffer buf)
2741 (goto-char (point-max))
8bd22fcf
KH
2742 (or (bolp) (insert "\n"))
2743 (insert ps-setup
2744 "nb char per line / font size\n")
bcc0d457 2745 (while (<= nb-cpl nb-cpl-max)
8bd22fcf
KH
2746 (setq cw (/ print-width (float nb-cpl))
2747 fs (/ (* ifs cw) icw))
bcc0d457
RS
2748 (insert (format "%3s %s\n" nb-cpl fs))
2749 (setq nb-cpl (1+ nb-cpl)))
2750 (insert "\n")
2751 (display-buffer buf 'not-this-window)))
2752
2753(defun ps-nb-pages (nb-lines)
496725ad
RS
2754 "Display correspondence between font size and the number of pages.
2755The correspondence is based on having NB-LINES lines of text,
2756and on the current ps-print setup."
bcc0d457
RS
2757 (let ((buf (get-buffer-create "*Nb-Pages*"))
2758 (ifs ps-font-size) ; initial font size
12b88fff 2759 (ilh (ps-line-height 'ps-font-for-text)) ; initial line height
bcc0d457
RS
2760 (page-height (progn (ps-get-page-dimensions)
2761 ps-print-height))
2762 (ps-setup (ps-setup)) ; setup for the current buffer
2763 (fs-min 4) ; minimum font size
2764 lh-min ; minimum line height
2765 nb-lpp-max ; maximum nb of lines per page
2766 nb-page-min ; minimum nb of pages
2767 (fs-max 14) ; maximum font size
2768 lh-max ; maximum line height
2769 nb-lpp-min ; minimum nb of lines per page
2770 nb-page-max ; maximum nb of pages
2771 fs ; current font size
2772 lh ; current line height
2773 nb-lpp ; current nb of lines per page
2774 nb-page ; current nb of pages
2775 )
2776 (setq lh-min (/ (* ilh fs-min) ifs)
2777 nb-lpp-max (floor (/ page-height lh-min))
2778 nb-page-min (ceiling (/ (float nb-lines) nb-lpp-max))
2779 lh-max (/ (* ilh fs-max) ifs)
2780 nb-lpp-min (floor (/ page-height lh-max))
8bd22fcf
KH
2781 nb-page-max (ceiling (/ (float nb-lines) nb-lpp-min))
2782 nb-page nb-page-min)
bcc0d457
RS
2783 (set-buffer buf)
2784 (goto-char (point-max))
8bd22fcf
KH
2785 (or (bolp) (insert "\n"))
2786 (insert ps-setup
2787 (format "%d lines\n" nb-lines)
2788 "nb page / font size\n")
bcc0d457
RS
2789 (while (<= nb-page nb-page-max)
2790 (setq nb-lpp (ceiling (/ nb-lines (float nb-page)))
2791 lh (/ page-height nb-lpp)
2792 fs (/ (* ifs lh) ilh))
2793 (insert (format "%s %s\n" nb-page fs))
2794 (setq nb-page (1+ nb-page)))
2795 (insert "\n")
2796 (display-buffer buf 'not-this-window)))
2797
6bdb808e
RS
2798;; macros used in `ps-select-font'
2799(defmacro ps-lookup (key) `(cdr (assq ,key font-entry)))
2800(defmacro ps-size-scale (key) `(/ (* (ps-lookup ,key) font-size) size))
2801
12b88fff
RS
2802(defun ps-select-font (font-family sym font-size title-font-size)
2803 (let ((font-entry (cdr (assq font-family ps-font-info-database))))
2804 (or font-entry
2805 (error "Don't have data to scale font %s. Known fonts families are %s"
2806 font-family
2807 (mapcar 'car ps-font-info-database)))
6bdb808e
RS
2808 (let ((size (ps-lookup 'size)))
2809 (put sym 'fonts (ps-lookup 'fonts))
2810 (put sym 'space-width (ps-size-scale 'space-width))
2811 (put sym 'avg-char-width (ps-size-scale 'avg-char-width))
2812 (put sym 'line-height (ps-size-scale 'line-height))
2813 (put sym 'title-line-height
2814 (/ (* (ps-lookup 'line-height) title-font-size) size)))))
bcc0d457 2815
12d89a2e 2816(defun ps-get-page-dimensions ()
bcc0d457
RS
2817 (let ((page-dimensions (cdr (assq ps-paper-type ps-page-dimensions-database)))
2818 page-width page-height)
2819 (cond
2820 ((null page-dimensions)
2821 (error "`ps-paper-type' must be one of:\n%s"
2822 (mapcar 'car ps-page-dimensions-database)))
2823 ((< ps-number-of-columns 1)
12b88fff 2824 (error "The number of columns %d should be positive"
8bd22fcf 2825 ps-number-of-columns)))
bcc0d457 2826
12b88fff
RS
2827 (ps-select-font ps-font-family 'ps-font-for-text
2828 ps-font-size ps-font-size)
2829 (ps-select-font ps-header-font-family 'ps-font-for-header
2830 ps-header-font-size ps-header-title-font-size)
bcc0d457
RS
2831
2832 (setq page-width (ps-page-dimensions-get-width page-dimensions)
2833 page-height (ps-page-dimensions-get-height page-dimensions))
2834
2835 ;; Landscape mode
2836 (if ps-landscape-mode
2837 ;; exchange width and height
2838 (setq page-width (prog1 page-height (setq page-height page-width))))
2839
2840 ;; It is used to get the lower right corner (only in landscape mode)
2841 (setq ps-landscape-page-height page-height)
2842
2843 ;; | lm | text | ic | text | ic | text | rm |
2844 ;; page-width == lm + n * pw + (n - 1) * ic + rm
2845 ;; => pw == (page-width - lm -rm - (n - 1) * ic) / n
8bd22fcf
KH
2846 (setq ps-print-width (/ (- page-width
2847 ps-left-margin ps-right-margin
2848 (* (1- ps-number-of-columns) ps-inter-column))
2849 ps-number-of-columns))
bcc0d457
RS
2850 (if (<= ps-print-width 0)
2851 (error "Bad horizontal layout:
2852page-width == %s
2853ps-left-margin == %s
2854ps-right-margin == %s
2855ps-inter-column == %s
2856ps-number-of-columns == %s
2857| lm | text | ic | text | ic | text | rm |
2858page-width == lm + n * print-width + (n - 1) * ic + rm
2859=> print-width == %d !"
2860 page-width
2861 ps-left-margin
2862 ps-right-margin
2863 ps-inter-column
2864 ps-number-of-columns
2865 ps-print-width))
2866
2867 (setq ps-print-height
2868 (- page-height ps-bottom-margin ps-top-margin))
2869 (if (<= ps-print-height 0)
2870 (error "Bad vertical layout:
2871ps-top-margin == %s
2872ps-bottom-margin == %s
2873page-height == bm + print-height + tm
2874=> print-height == %d !"
2875 ps-top-margin
2876 ps-bottom-margin
2877 ps-print-height))
2878 ;; If headers are turned on, deduct the height of the header from
2879 ;; the print height.
8bd22fcf 2880 (if ps-print-header
12b88fff
RS
2881 (setq ps-header-pad (* ps-header-line-pad
2882 (ps-title-line-height 'ps-font-for-header))
8bd22fcf
KH
2883 ps-print-height (- ps-print-height
2884 ps-header-offset
2885 ps-header-pad
12b88fff
RS
2886 (ps-title-line-height 'ps-font-for-header)
2887 (* (ps-line-height 'ps-font-for-header)
2888 (1- ps-header-lines))
8bd22fcf 2889 ps-header-pad)))
bcc0d457
RS
2890 (if (<= ps-print-height 0)
2891 (error "Bad vertical layout:
2892ps-top-margin == %s
2893ps-bottom-margin == %s
2894ps-header-offset == %s
2895ps-header-pad == %s
2896header-height == %s
2897page-height == bm + print-height + tm - ho - hh
2898=> print-height == %d !"
2899 ps-top-margin
2900 ps-bottom-margin
2901 ps-header-offset
2902 ps-header-pad
2903 (+ ps-header-pad
12b88fff
RS
2904 (ps-title-line-height 'ps-font-for-header)
2905 (* (ps-line-height 'ps-font-for-header)
2906 (1- ps-header-lines))
bcc0d457
RS
2907 ps-header-pad)
2908 ps-print-height))))
ef2cbb24 2909
12d89a2e 2910(defun ps-print-preprint (&optional filename)
8bd22fcf
KH
2911 (and filename
2912 (or (numberp filename)
2913 (listp filename))
2914 (let* ((name (concat (buffer-name) ".ps"))
2915 (prompt (format "Save PostScript to file: (default %s) " name))
2916 (res (read-file-name prompt default-directory name nil)))
2917 (if (file-directory-p res)
2918 (expand-file-name name (file-name-as-directory res))
2919 res))))
12d89a2e
RS
2920
2921;; The following functions implement a simple list-buffering scheme so
2922;; that ps-print doesn't have to repeatedly switch between buffers
857686a6
RS
2923;; while spooling. The functions `ps-output' and `ps-output-string' build
2924;; up the lists; the function `ps-flush-output' takes the lists and
12d89a2e
RS
2925;; insert its contents into the spool buffer (*PostScript*).
2926
857686a6
RS
2927(defvar ps-string-escape-codes
2928 (let ((table (make-vector 256 nil))
2929 (char ?\000))
2930 ;; control characters
2931 (while (<= char ?\037)
2932 (aset table char (format "\\%03o" char))
2933 (setq char (1+ char)))
2934 ;; printable characters
2935 (while (< char ?\177)
2936 (aset table char (format "%c" char))
2937 (setq char (1+ char)))
2938 ;; DEL and 8-bit characters
2939 (while (<= char ?\377)
2940 (aset table char (format "\\%o" char))
2941 (setq char (1+ char)))
2942 ;; Override ASCII formatting characters with named escape code:
2943 (aset table ?\n "\\n") ; [NL] linefeed
2944 (aset table ?\r "\\r") ; [CR] carriage return
2945 (aset table ?\t "\\t") ; [HT] horizontal tab
2946 (aset table ?\b "\\b") ; [BS] backspace
2947 (aset table ?\f "\\f") ; [NP] form feed
2948 ;; Escape PostScript escape and string delimiter characters:
2949 (aset table ?\\ "\\\\")
2950 (aset table ?\( "\\(")
2951 (aset table ?\) "\\)")
2952 table)
2953 "Vector used to map characters to PostScript string escape codes.")
2954
12d89a2e
RS
2955(defun ps-output-string-prim (string)
2956 (insert "(") ;insert start-string delimiter
2957 (save-excursion ;insert string
2958 (insert string))
12d89a2e 2959 ;; Find and quote special characters as necessary for PS
b61e2c11
RS
2960 ;; This skips everything except control chars, nonascii chars,
2961 ;; (, ) and \.
2962 (while (progn (skip-chars-forward " -'*-[]-~") (not (eobp)))
2963 (let ((special (following-char)))
bb58920c
EZ
2964 (if (> (char-bytes special) 1)
2965 (forward-char)
2966 (delete-char 1)
2967 (insert (aref ps-string-escape-codes special)))))
12d89a2e
RS
2968 (goto-char (point-max))
2969 (insert ")")) ;insert end-string delimiter
ef2cbb24 2970
12d89a2e 2971(defun ps-init-output-queue ()
8bd22fcf
KH
2972 (setq ps-output-head '("")
2973 ps-output-tail ps-output-head))
ef2cbb24 2974
12d89a2e
RS
2975(defun ps-output (&rest args)
2976 (setcdr ps-output-tail args)
2977 (while (cdr ps-output-tail)
2978 (setq ps-output-tail (cdr ps-output-tail))))
ef2cbb24 2979
12d89a2e
RS
2980(defun ps-output-string (string)
2981 (ps-output t string))
ef2cbb24 2982
87a16a06
RS
2983(defun ps-output-list (the-list)
2984 (mapcar 'ps-output the-list))
2985
12d89a2e
RS
2986(defun ps-flush-output ()
2987 (save-excursion
2988 (set-buffer ps-spool-buffer)
2989 (goto-char (point-max))
2990 (while ps-output-head
2991 (let ((it (car ps-output-head)))
2992 (if (not (eq t it))
2993 (insert it)
2994 (setq ps-output-head (cdr ps-output-head))
2995 (ps-output-string-prim (car ps-output-head))))
2996 (setq ps-output-head (cdr ps-output-head))))
2997 (ps-init-output-queue))
2998
2999(defun ps-insert-file (fname)
3000 (ps-flush-output)
12d89a2e 3001 ;; Check to see that the file exists and is readable; if not, throw
87a16a06
RS
3002 ;; an error.
3003 (or (file-readable-p fname)
12d89a2e 3004 (error "Could not read file `%s'" fname))
12d89a2e
RS
3005 (save-excursion
3006 (set-buffer ps-spool-buffer)
3007 (goto-char (point-max))
3008 (insert-file fname)))
06fb6aab 3009
12d89a2e
RS
3010;; These functions insert the arrays that define the contents of the
3011;; headers.
ef2cbb24 3012
12d89a2e
RS
3013(defun ps-generate-header-line (fonttag &optional content)
3014 (ps-output " [ " fonttag " ")
3015 (cond
3016 ;; Literal strings should be output as is -- the string must
3017 ;; contain its own PS string delimiters, '(' and ')', if necessary.
3018 ((stringp content)
3019 (ps-output content))
3020
3021 ;; Functions are called -- they should return strings; they will be
3022 ;; inserted as strings and the PS string delimiters added.
3023 ((and (symbolp content) (fboundp content))
3024 (ps-output-string (funcall content)))
3025
3026 ;; Variables will have their contents inserted. They should
3027 ;; contain strings, and will be inserted as strings.
3028 ((and (symbolp content) (boundp content))
3029 (ps-output-string (symbol-value content)))
3030
3031 ;; Anything else will get turned into an empty string.
3032 (t
3033 (ps-output-string "")))
3034 (ps-output " ]\n"))
3035
3036(defun ps-generate-header (name contents)
3037 (ps-output "/" name " [\n")
3038 (if (> ps-header-lines 0)
3039 (let ((count 1))
3040 (ps-generate-header-line "/h0" (car contents))
3041 (while (and (< count ps-header-lines)
3042 (setq contents (cdr contents)))
3043 (ps-generate-header-line "/h1" (car contents))
8bd22fcf 3044 (setq count (1+ count)))
12d89a2e
RS
3045 (ps-output "] def\n"))))
3046
3047(defun ps-output-boolean (name bool)
3048 (ps-output (format "/%s %s def\n" name (if bool "true" "false"))))
ef2cbb24 3049
06fb6aab 3050
87a16a06
RS
3051(defun ps-background-pages (page-list func)
3052 (if page-list
3053 (mapcar
3054 '(lambda (pages)
3055 (let ((start (if (consp pages) (car pages) pages))
3056 (end (if (consp pages) (cdr pages) pages)))
3057 (and (integerp start) (integerp end) (<= start end)
3058 (add-to-list 'ps-background-pages (vector start end func)))))
3059 page-list)
3060 (setq ps-background-all-pages (cons func ps-background-all-pages))))
3061
3062
3063(defun ps-get-boundingbox ()
3064 (save-excursion
3065 (set-buffer ps-spool-buffer)
3066 (save-excursion
3067 (if (re-search-forward
3068 "^%%BoundingBox:\\s-+\\([0-9.]+\\)\\s-+\\([0-9.]+\\)\\s-+\\([0-9.]+\\)\\s-+\\([0-9.]+\\)"
3069 nil t)
3070 (vector (string-to-number ; lower x
3071 (buffer-substring (match-beginning 1) (match-end 1)))
3072 (string-to-number ; lower y
3073 (buffer-substring (match-beginning 2) (match-end 2)))
3074 (string-to-number ; upper x
3075 (buffer-substring (match-beginning 3) (match-end 3)))
3076 (string-to-number ; upper y
3077 (buffer-substring (match-beginning 4) (match-end 4))))
3078 (vector 0 0 0 0)))))
3079
3080
3081;; Emacs understands the %f format; we'll use it to limit color RGB values
3082;; to three decimals to cut down some on the size of the PostScript output.
3083;; Lucid emacsen will have to make do with %s (princ) for floats.
3084
3085(defvar ps-float-format (if (eq ps-print-emacs-type 'emacs)
3086 "%0.3f " ; emacs
3087 "%s ")) ; Lucid emacsen
3088
3089
3090(defun ps-float-format (value &optional default)
3091 (let ((literal (or value default)))
3092 (if literal
3093 (format (if (numberp literal)
3094 ps-float-format
3095 "%s ")
3096 literal)
3097 " ")))
3098
3099
3100(defun ps-background-text ()
3101 (mapcar
3102 '(lambda (text)
3103 (setq ps-background-text-count (1+ ps-background-text-count))
3104 (ps-output (format "/ShowBackText-%d {\n" ps-background-text-count))
3105 (ps-output-string (nth 0 text)) ; text
3106 (ps-output
3107 "\n"
3108 (ps-float-format (nth 4 text) 200.0) ; font size
3109 (format "/%s " (or (nth 3 text) "Times-Roman")) ; font name
3110 (ps-float-format (nth 6 text)
3111 "PrintHeight PrintPageWidth atan") ; rotation
3112 (ps-float-format (nth 5 text) 0.85) ; gray
3113 (ps-float-format (nth 1 text) "0") ; x position
3114 (ps-float-format (nth 2 text) "BottomMargin") ; y position
3115 "\nShowBackText} def\n")
3116 (ps-background-pages (nthcdr 7 text) ; page list
3117 (format "ShowBackText-%d\n"
3118 ps-background-text-count)))
3119 ps-print-background-text))
3120
3121
3122(defun ps-background-image ()
3123 (mapcar
3124 '(lambda (image)
3125 (let ((image-file (expand-file-name (nth 0 image))))
3126 (if (file-readable-p image-file)
3127 (progn
3128 (setq ps-background-image-count (1+ ps-background-image-count))
3129 (ps-output
3130 (format "/ShowBackImage-%d {\n--back-- " ps-background-image-count)
3131 (ps-float-format (nth 5 image) 0.0) ; rotation
3132 (ps-float-format (nth 3 image) 1.0) ; x scale
3133 (ps-float-format (nth 4 image) 1.0) ; y scale
3134 (ps-float-format (nth 1 image) ; x position
3135 "PrintPageWidth 2 div")
3136 (ps-float-format (nth 2 image) ; y position
3137 "PrintHeight 2 div BottomMargin add")
3138 "\nBeginBackImage\n")
3139 (ps-insert-file image-file)
3140 ;; coordinate adjustment to centralize image
3141 ;; around x and y position
3142 (let ((box (ps-get-boundingbox)))
3143 (save-excursion
3144 (set-buffer ps-spool-buffer)
3145 (save-excursion
3146 (if (re-search-backward "^--back--" nil t)
3147 (replace-match
3148 (format "%s %s"
3149 (ps-float-format
3150 (- (+ (/ (- (aref box 2) (aref box 0)) 2.0)
3151 (aref box 0))))
3152 (ps-float-format
3153 (- (+ (/ (- (aref box 3) (aref box 1)) 2.0)
3154 (aref box 1)))))
3155 t)))))
3156 (ps-output "\nEndBackImage} def\n")
3157 (ps-background-pages (nthcdr 6 image) ; page list
3158 (format "ShowBackImage-%d\n"
3159 ps-background-image-count))))))
3160 ps-print-background-image))
3161
3162
a18ed129 3163(defun ps-background (page-number)
87a16a06
RS
3164 (let (has-local-background)
3165 (mapcar '(lambda (range)
a18ed129
RS
3166 (and (<= (aref range 0) page-number)
3167 (<= page-number (aref range 1))
87a16a06
RS
3168 (if has-local-background
3169 (ps-output (aref range 2))
3170 (setq has-local-background t)
3171 (ps-output "/printLocalBackground {\n"
3172 (aref range 2)))))
3173 ps-background-pages)
3174 (and has-local-background (ps-output "} def\n"))))
3175
3176
0140c600
EZ
3177;; Return a list of the distinct elements of LIST.
3178;; Elements are compared with `equal'.
3179(defun ps-remove-duplicates (list)
3180 (let (new (tail list))
3181 (while tail
3182 (or (member (car tail) new)
3183 (setq new (cons (car tail) new)))
3184 (setq tail (cdr tail)))
3185 (nreverse new)))
3186
6bdb808e
RS
3187;; Find the first occurrence of ITEM in LIST.
3188;; Return the index of the matching item, or nil if not found.
3189;; Elements are compared with `eq'.
7ae35a2f 3190(defun ps-alist-position (item list)
6bdb808e
RS
3191 (let ((tail list) (index 0) found)
3192 (while tail
7ae35a2f 3193 (if (setq found (eq (car (car tail)) item))
6bdb808e
RS
3194 (setq tail nil)
3195 (setq index (1+ index)
3196 tail (cdr tail))))
3197 (and found index)))
3198
3199
ef2cbb24 3200(defun ps-begin-file ()
bcc0d457 3201 (ps-get-page-dimensions)
a18ed129 3202 (setq ps-showline-count (if ps-printing-region (car ps-printing-region) 1)
87a16a06
RS
3203 ps-background-text-count 0
3204 ps-background-image-count 0
3205 ps-background-pages nil
3206 ps-background-all-pages nil)
12d89a2e 3207
8bd22fcf
KH
3208 (ps-output ps-adobe-tag
3209 "%%Title: " (buffer-name) ; Take job name from name of
3210 ; first buffer printed
3211 "\n%%Creator: " (user-full-name)
857686a6
RS
3212 " (using ps-print v" ps-print-version
3213 ")\n%%CreationDate: "
87a16a06
RS
3214 (time-stamp-hh:mm:ss) " " (time-stamp-mon-dd-yyyy)
3215 "\n%%Orientation: "
8bd22fcf
KH
3216 (if ps-landscape-mode "Landscape" "Portrait")
3217 "\n%% DocumentFonts: Times-Roman Times-Italic "
12b88fff 3218 (mapconcat 'identity
0140c600 3219 (ps-remove-duplicates
12b88fff
RS
3220 (append (ps-fonts 'ps-font-for-text)
3221 (list (ps-font 'ps-font-for-header 'normal)
0140c600 3222 (ps-font 'ps-font-for-header 'bold))))
12b88fff 3223 " ")
8bd22fcf
KH
3224 "\n%%Pages: (atend)\n"
3225 "%%EndComments\n\n")
12d89a2e 3226
bcc0d457 3227 (ps-output-boolean "LandscapeMode" ps-landscape-mode)
8bd22fcf 3228 (ps-output (format "/NumberOfColumns %d def\n" ps-number-of-columns)
12d89a2e 3229
8bd22fcf
KH
3230 (format "/LandscapePageHeight %s def\n" ps-landscape-page-height)
3231 (format "/PrintPageWidth %s def\n"
87a16a06
RS
3232 (- (* (+ ps-print-width ps-inter-column)
3233 ps-number-of-columns)
8bd22fcf
KH
3234 ps-inter-column))
3235 (format "/PrintWidth %s def\n" ps-print-width)
3236 (format "/PrintHeight %s def\n" ps-print-height)
12d89a2e 3237
8bd22fcf
KH
3238 (format "/LeftMargin %s def\n" ps-left-margin)
3239 (format "/RightMargin %s def\n" ps-right-margin) ; not used
3240 (format "/InterColumn %s def\n" ps-inter-column)
bcc0d457 3241
8bd22fcf
KH
3242 (format "/BottomMargin %s def\n" ps-bottom-margin)
3243 (format "/TopMargin %s def\n" ps-top-margin) ; not used
3244 (format "/HeaderOffset %s def\n" ps-header-offset)
3245 (format "/HeaderPad %s def\n" ps-header-pad))
06fb6aab 3246
12b88fff
RS
3247 (ps-output-boolean "PrintHeader" ps-print-header)
3248 (ps-output-boolean "PrintOnlyOneHeader" ps-print-only-one-header)
3249 (ps-output-boolean "PrintHeaderFrame" ps-print-header-frame)
3250 (ps-output-boolean "ShowNofN" ps-show-n-of-n)
3251 (ps-output-boolean "Duplex" ps-spool-duplex)
bcc0d457 3252
12b88fff
RS
3253 (let ((line-height (ps-line-height 'ps-font-for-text)))
3254 (ps-output (format "/LineHeight %s def\n" line-height)
3255 (format "/LinesPerColumn %d def\n"
3256 (round (/ (+ ps-print-height
3257 (* line-height 0.45))
3258 line-height)))))
87a16a06 3259
535efc38 3260 (ps-output-boolean "Zebra" ps-zebra-stripes)
87a16a06 3261 (ps-output-boolean "PrintLineNumber" ps-line-number)
857686a6 3262 (ps-output (format "/ZebraHeight %d def\n" ps-zebra-stripe-height)
8bd22fcf 3263 (format "/Lines %d def\n"
a18ed129
RS
3264 (if ps-printing-region
3265 (cdr ps-printing-region)
8bd22fcf
KH
3266 (ps-count-lines (point-min) (point-max))))
3267 "/PageCount 0 def\n") ; set total page number
3268 ; when printing has finished
3269 ; (see `ps-generate')
87a16a06
RS
3270
3271 (ps-background-text)
3272 (ps-background-image)
3273 (setq ps-background-all-pages (nreverse ps-background-all-pages)
3274 ps-background-pages (nreverse ps-background-pages))
12d89a2e 3275
bcc0d457 3276 (ps-output ps-print-prologue-1)
12d89a2e 3277
87a16a06
RS
3278 (ps-output "/printGlobalBackground {\n")
3279 (ps-output-list ps-background-all-pages)
3280 (ps-output "} def\n/printLocalBackground {\n} def\n")
3281
bcc0d457 3282 ;; Header fonts
8bd22fcf 3283 (ps-output (format "/h0 %s /%s DefFont\n" ; /h0 14 /Helvetica-Bold DefFont
12b88fff
RS
3284 ps-header-title-font-size (ps-font 'ps-font-for-header
3285 'bold))
8bd22fcf 3286 (format "/h1 %s /%s DefFont\n" ; /h1 12 /Helvetica DefFont
12b88fff
RS
3287 ps-header-font-size (ps-font 'ps-font-for-header
3288 'normal)))
bcc0d457
RS
3289
3290 (ps-output ps-print-prologue-2)
3291
3292 ;; Text fonts
7ae35a2f 3293 (let ((font (ps-font-alist 'ps-font-for-text))
6bdb808e
RS
3294 (i 0))
3295 (while font
3296 (ps-output (format "/f%d %s /%s DefFont\n"
3297 i
3298 ps-font-size
3299 (ps-font 'ps-font-for-text (car (car font)))))
3300 (setq font (cdr font)
3301 i (1+ i))))
bcc0d457 3302
8bd22fcf
KH
3303 (ps-output "\nBeginDoc\n\n"
3304 "%%EndPrologue\n"))
ef2cbb24 3305
12d89a2e
RS
3306(defun ps-header-dirpart ()
3307 (let ((fname (buffer-file-name)))
3308 (if fname
3309 (if (string-equal (buffer-name) (file-name-nondirectory fname))
3310 (file-name-directory fname)
3311 fname)
3312 "")))
ef2cbb24 3313
12d89a2e 3314(defun ps-get-buffer-name ()
bcc0d457
RS
3315 (cond
3316 ;; Indulge Jim this little easter egg:
3317 ((string= (buffer-name) "ps-print.el")
3318 "Hey, Cool! It's ps-print.el!!!")
3319 ;; Indulge Jack this other little easter egg:
3320 ((string= (buffer-name) "sokoban.el")
3321 "Super! C'est sokoban.el!")
87a16a06 3322 (t (concat
a18ed129 3323 (and ps-printing-region "Subset of: ")
87a16a06
RS
3324 (buffer-name)
3325 (and (buffer-modified-p) " (unsaved)")))))
ef2cbb24 3326
12d89a2e 3327(defun ps-begin-job ()
857686a6
RS
3328 (setq ps-page-count 0
3329 ps-control-or-escape-regexp
12b88fff
RS
3330 (cond ((eq ps-print-control-characters '8-bit)
3331 "[\000-\037\177-\377]")
3332 ((eq ps-print-control-characters 'control-8-bit)
3333 "[\000-\037\177-\237]")
3334 ((eq ps-print-control-characters 'control)
3335 "[\000-\037\177]")
857686a6 3336 (t "[\t\n\f]"))))
ef2cbb24 3337
12b88fff
RS
3338(defmacro ps-page-number ()
3339 `(1+ (/ (1- ps-page-count) ps-number-of-columns)))
3340
ef2cbb24 3341(defun ps-end-file ()
8bd22fcf 3342 (ps-output "\nEndDoc\n\n%%Trailer\n%%Pages: "
12b88fff 3343 (format "%d" (ps-page-number))
8bd22fcf 3344 "\n%%EOF\n"))
87a16a06
RS
3345
3346
ef2cbb24
RS
3347(defun ps-next-page ()
3348 (ps-end-page)
12d89a2e
RS
3349 (ps-flush-output)
3350 (ps-begin-page))
3351
12b88fff
RS
3352(defun ps-header-page ()
3353 (if (prog1
3354 (zerop (mod ps-page-count ps-number-of-columns))
6bdb808e 3355 (setq ps-page-count (1+ ps-page-count)))
a18ed129 3356 ;; Print only when a new real page begins.
12b88fff 3357 (let ((page-number (ps-page-number)))
a18ed129
RS
3358 (ps-output (format "\n%%%%Page: %d %d\n" page-number page-number))
3359 (ps-output "BeginDSCPage\n")
3360 (ps-background page-number)
12b88fff 3361 (run-hooks 'ps-print-begin-page-hook))
a18ed129 3362 ;; Print when any other page begins.
12b88fff
RS
3363 (ps-output "BeginDSCPage\n")
3364 (run-hooks 'ps-print-begin-column-hook)))
a18ed129 3365
8bd22fcf 3366(defun ps-begin-page ()
12d89a2e 3367 (ps-get-page-dimensions)
8bd22fcf
KH
3368 (setq ps-width-remaining ps-print-width
3369 ps-height-remaining ps-print-height)
12d89a2e 3370
a18ed129 3371 (ps-header-page)
12d89a2e 3372
87a16a06 3373 (ps-output (format "/LineNumber %d def\n" ps-showline-count)
12b88fff
RS
3374 (format "/PageNumber %d def\n" (if ps-print-only-one-header
3375 (ps-page-number)
3376 ps-page-count)))
12d89a2e 3377
090be653
RS
3378 (when ps-print-header
3379 (ps-generate-header "HeaderLinesLeft" ps-left-header)
3380 (ps-generate-header "HeaderLinesRight" ps-right-header)
3381 (ps-output (format "%d SetHeaderLines\n" ps-header-lines)))
12d89a2e
RS
3382
3383 (ps-output "BeginPage\n")
87a16a06
RS
3384 (ps-set-font ps-current-font)
3385 (ps-set-bg ps-current-bg)
3386 (ps-set-color ps-current-color))
ef2cbb24
RS
3387
3388(defun ps-end-page ()
a18ed129 3389 (ps-output "EndPage\nEndDSCPage\n"))
12d89a2e
RS
3390
3391(defun ps-dummy-page ()
12b88fff 3392 (ps-header-page)
a18ed129 3393 (ps-output "/PrintHeader false def
12d89a2e
RS
3394BeginPage
3395EndPage
3396EndDSCPage\n"))
06fb6aab 3397
ef2cbb24 3398(defun ps-next-line ()
87a16a06 3399 (setq ps-showline-count (1+ ps-showline-count))
12b88fff
RS
3400 (let ((lh (ps-line-height 'ps-font-for-text)))
3401 (if (< ps-height-remaining lh)
3402 (ps-next-page)
3403 (setq ps-width-remaining ps-print-width
3404 ps-height-remaining (- ps-height-remaining lh))
3405 (ps-output "HL\n"))))
ef2cbb24
RS
3406
3407(defun ps-continue-line ()
12b88fff
RS
3408 (let ((lh (ps-line-height 'ps-font-for-text)))
3409 (if (< ps-height-remaining lh)
3410 (ps-next-page)
3411 (setq ps-width-remaining ps-print-width
3412 ps-height-remaining (- ps-height-remaining lh))
3413 (ps-output "SL\n"))))
12d89a2e
RS
3414
3415(defun ps-find-wrappoint (from to char-width)
3416 (let ((avail (truncate (/ ps-width-remaining char-width)))
3417 (todo (- to from)))
3418 (if (< todo avail)
3419 (cons to (* todo char-width))
3420 (cons (+ from avail) ps-width-remaining))))
3421
3422(defun ps-basic-plot-string (from to &optional bg-color)
12b88fff
RS
3423 (let* ((wrappoint (ps-find-wrappoint from to
3424 (ps-avg-char-width 'ps-font-for-text)))
12d89a2e 3425 (to (car wrappoint))
055e7bf2 3426 (string (buffer-substring-no-properties from to)))
12d89a2e 3427 (ps-output-string string)
bcc0d457 3428 (ps-output " S\n")
12d89a2e
RS
3429 wrappoint))
3430
3431(defun ps-basic-plot-whitespace (from to &optional bg-color)
12b88fff
RS
3432 (let* ((wrappoint (ps-find-wrappoint from to
3433 (ps-space-width 'ps-font-for-text)))
12d89a2e 3434 (to (car wrappoint)))
12d89a2e
RS
3435 (ps-output (format "%d W\n" (- to from)))
3436 wrappoint))
3437
3438(defun ps-plot (plotfunc from to &optional bg-color)
ef2cbb24 3439 (while (< from to)
12d89a2e
RS
3440 (let* ((wrappoint (funcall plotfunc from to bg-color))
3441 (plotted-to (car wrappoint))
3442 (plotted-width (cdr wrappoint)))
8bd22fcf
KH
3443 (setq from plotted-to
3444 ps-width-remaining (- ps-width-remaining plotted-width))
12d89a2e
RS
3445 (if (< from to)
3446 (ps-continue-line))))
ef2cbb24
RS
3447 (if ps-razzle-dazzle
3448 (let* ((q-todo (- (point-max) (point-min)))
12d89a2e 3449 (q-done (- (point) (point-min)))
ef2cbb24 3450 (chunkfrac (/ q-todo 8))
857686a6 3451 (chunksize (min chunkfrac 1000)))
ef2cbb24 3452 (if (> (- q-done ps-razchunk) chunksize)
8bd22fcf 3453 (progn
ef2cbb24 3454 (setq ps-razchunk q-done)
8bd22fcf
KH
3455 (message "Formatting...%3d%%"
3456 (if (< q-todo 100)
3457 (/ (* 100 q-done) q-todo)
3458 (/ q-done (/ q-todo 100)))
3459 ))))))
12d89a2e
RS
3460
3461(defun ps-set-font (font)
8bd22fcf 3462 (ps-output (format "/f%d F\n" (setq ps-current-font font))))
12d89a2e 3463
12d89a2e
RS
3464(defun ps-set-bg (color)
3465 (if (setq ps-current-bg color)
8bd22fcf
KH
3466 (ps-output (format ps-color-format
3467 (nth 0 color) (nth 1 color) (nth 2 color))
12d89a2e
RS
3468 " true BG\n")
3469 (ps-output "false BG\n")))
3470
3471(defun ps-set-color (color)
a18ed129 3472 (setq ps-current-color (or color ps-default-fg))
8bd22fcf
KH
3473 (ps-output (format ps-color-format
3474 (nth 0 ps-current-color)
043620f4
KH
3475 (nth 1 ps-current-color) (nth 2 ps-current-color))
3476 " FG\n"))
12d89a2e 3477
12d89a2e 3478
87a16a06 3479(defvar ps-current-effect 0)
12d89a2e 3480
87a16a06
RS
3481
3482(defun ps-plot-region (from to font &optional fg-color bg-color effects)
12d89a2e
RS
3483 (if (not (equal font ps-current-font))
3484 (ps-set-font font))
06fb6aab 3485
12d89a2e
RS
3486 ;; Specify a foreground color only if one's specified and it's
3487 ;; different than the current.
3488 (if (not (equal fg-color ps-current-color))
3489 (ps-set-color fg-color))
06fb6aab 3490
12d89a2e
RS
3491 (if (not (equal bg-color ps-current-bg))
3492 (ps-set-bg bg-color))
06fb6aab 3493
87a16a06
RS
3494 ;; Specify effects (underline, overline, box, etc)
3495 (cond
3496 ((not (integerp effects))
3497 (ps-output "0 EF\n")
3498 (setq ps-current-effect 0))
3499 ((/= effects ps-current-effect)
3500 (ps-output (number-to-string effects) " EF\n")
3501 (setq ps-current-effect effects)))
ef2cbb24 3502
12d89a2e 3503 ;; Starting at the beginning of the specified region...
ef2cbb24
RS
3504 (save-excursion
3505 (goto-char from)
12d89a2e
RS
3506
3507 ;; ...break the region up into chunks separated by tabs, linefeeds,
87a16a06 3508 ;; pagefeeds, control characters, and plot each chunk.
ef2cbb24 3509 (while (< from to)
857686a6 3510 (if (re-search-forward ps-control-or-escape-regexp to t)
a18ed129 3511 ;; region with some control characters
12b88fff
RS
3512 (let* ((match-point (match-beginning 0))
3513 (match (char-after match-point)))
857686a6
RS
3514 (ps-plot 'ps-basic-plot-string from (1- (point)) bg-color)
3515 (cond
3516 ((= match ?\t) ; tab
3517 (let ((linestart (save-excursion (beginning-of-line) (point))))
3518 (forward-char -1)
3519 (setq from (+ linestart (current-column)))
3520 (if (re-search-forward "[ \t]+" to t)
3521 (ps-plot 'ps-basic-plot-whitespace
3522 from (+ linestart (current-column))
3523 bg-color))))
3524
3525 ((= match ?\n) ; newline
3526 (ps-next-line))
3527
3528 ((= match ?\f) ; form feed
12b88fff
RS
3529 ;; do not skip page if previous character is NEWLINE and
3530 ;; it is a beginning of page.
3531 (or (and (= (char-after (1- match-point)) ?\n)
3532 (= ps-height-remaining ps-print-height))
3533 (ps-next-page)))
857686a6
RS
3534 ; characters from ^@ to ^_ and
3535 (t ; characters from 127 to 255
3536 (ps-control-character match)))
87a16a06
RS
3537 (setq from (point)))
3538 ;; region without control characters
3539 (ps-plot 'ps-basic-plot-string from to bg-color)
3540 (setq from to)))))
3541
857686a6
RS
3542(defvar ps-string-control-codes
3543 (let ((table (make-vector 256 nil))
3544 (char ?\000))
3545 ;; control character
3546 (while (<= char ?\037)
3547 (aset table char (format "^%c" (+ char ?@)))
3548 (setq char (1+ char)))
3549 ;; printable character
3550 (while (< char ?\177)
3551 (aset table char (format "%c" char))
3552 (setq char (1+ char)))
3553 ;; DEL
3554 (aset table char "^?")
3555 ;; 8-bit character
3556 (while (<= (setq char (1+ char)) ?\377)
3557 (aset table char (format "\\%o" char)))
3558 table)
3559 "Vector used to map characters to a printable string.")
3560
3561(defun ps-control-character (char)
3562 (let* ((str (aref ps-string-control-codes char))
3563 (from (1- (point)))
87a16a06
RS
3564 (len (length str))
3565 (to (+ from len))
12b88fff
RS
3566 (char-width (ps-avg-char-width 'ps-font-for-text))
3567 (wrappoint (ps-find-wrappoint from to char-width)))
87a16a06
RS
3568 (if (< (car wrappoint) to)
3569 (ps-continue-line))
12b88fff 3570 (setq ps-width-remaining (- ps-width-remaining (* len char-width)))
87a16a06
RS
3571 (ps-output-string str)
3572 (ps-output " S\n")))
ef2cbb24 3573
12d89a2e
RS
3574(defun ps-color-value (x-color-value)
3575 ;; Scale 16-bit X-COLOR-VALUE to PostScript color value in [0, 1] interval.
3576 (/ x-color-value ps-print-color-scale))
ef2cbb24 3577
043620f4
KH
3578(defun ps-color-values (x-color)
3579 (cond ((fboundp 'x-color-values)
3580 (x-color-values x-color))
12b88fff
RS
3581 ((and (fboundp 'color-instance-rgb-components)
3582 (ps-color-device))
3583 (color-instance-rgb-components
3584 (if (color-instance-p x-color)
3585 x-color
3586 (make-color-instance
3587 (if (color-specifier-p x-color)
3588 (color-name x-color)
3589 x-color)))))
043620f4
KH
3590 (t (error "No available function to determine X color values."))))
3591
87a16a06 3592
a18ed129
RS
3593(defun ps-face-attributes (face)
3594 "Return face attribute vector.
87a16a06 3595
a18ed129
RS
3596If FACE is not in `ps-print-face-extension-alist' or in
3597`ps-print-face-alist', insert it on `ps-print-face-alist' and
3598return the attribute vector.
87a16a06
RS
3599
3600If FACE is not a valid face name, it is used default face."
a18ed129
RS
3601 (cdr (or (assq face ps-print-face-extension-alist)
3602 (assq face ps-print-face-alist)
3603 (let* ((the-face (if (facep face) face 'default))
3604 (new-face (ps-screen-to-bit-face the-face)))
3605 (or (and (eq the-face 'default)
3606 (assq the-face ps-print-face-alist))
3607 (setq ps-print-face-alist (cons new-face ps-print-face-alist)))
3608 new-face))))
87a16a06 3609
043620f4
KH
3610
3611(defun ps-face-attribute-list (face-or-list)
3612 (if (listp face-or-list)
87a16a06 3613 ;; list of faces
857686a6
RS
3614 (let ((effects 0)
3615 foreground background face-attr)
043620f4 3616 (while face-or-list
857686a6 3617 (setq face-attr (ps-face-attributes (car face-or-list))
87a16a06
RS
3618 effects (logior effects (aref face-attr 0)))
3619 (or foreground (setq foreground (aref face-attr 1)))
3620 (or background (setq background (aref face-attr 2)))
043620f4 3621 (setq face-or-list (cdr face-or-list)))
87a16a06
RS
3622 (vector effects foreground background))
3623 ;; simple face
043620f4
KH
3624 (ps-face-attributes face-or-list)))
3625
87a16a06 3626
12b88fff
RS
3627(defconst ps-font-type (vector nil 'bold 'italic 'bold-italic))
3628
3629
12d89a2e 3630(defun ps-plot-with-face (from to face)
12b88fff
RS
3631 (cond
3632 ((null face) ; print text with null face
87a16a06 3633 (ps-plot-region from to 0))
12b88fff
RS
3634 ((eq face 'emacs--invisible--face)) ; skip invisible text!!!
3635 (t ; otherwise, text has a valid face
3636 (let* ((face-bit (ps-face-attribute-list face))
3637 (effect (aref face-bit 0))
3638 (foreground (aref face-bit 1))
3639 (background (aref face-bit 2))
3640 (fg-color (if (and ps-print-color-p foreground (ps-color-device))
3641 (mapcar 'ps-color-value
3642 (ps-color-values foreground))
3643 ps-default-color))
3644 (bg-color (and ps-print-color-p background (ps-color-device)
3645 (mapcar 'ps-color-value
3646 (ps-color-values background)))))
3647 (ps-plot-region
3648 from to
3649 (ps-font-number 'ps-font-for-text
3650 (or (aref ps-font-type (logand effect 3))
3651 face))
3652 fg-color bg-color (lsh effect -2)))))
87a16a06 3653 (goto-char to))
12d89a2e
RS
3654
3655
12d89a2e 3656(defun ps-xemacs-face-kind-p (face kind kind-regex kind-list)
857686a6
RS
3657 (let* ((frame-font (or (face-font-instance face)
3658 (face-font-instance 'default)))
3659 (kind-cons (and frame-font
3660 (assq kind (font-instance-properties frame-font))))
12d89a2e
RS
3661 (kind-spec (cdr-safe kind-cons))
3662 (case-fold-search t))
12d89a2e
RS
3663 (or (and kind-spec (string-match kind-regex kind-spec))
3664 ;; Kludge-compatible:
3665 (memq face kind-list))))
3666
3667(defun ps-face-bold-p (face)
6770a60f 3668 (if (eq ps-print-emacs-type 'emacs)
06fb6aab
RS
3669 (or (face-bold-p face)
3670 (memq face ps-bold-faces))
8bd22fcf 3671 (ps-xemacs-face-kind-p face 'WEIGHT_NAME "bold\\|demibold" ps-bold-faces)))
12d89a2e
RS
3672
3673(defun ps-face-italic-p (face)
6770a60f 3674 (if (eq ps-print-emacs-type 'emacs)
06fb6aab
RS
3675 (or (face-italic-p face)
3676 (memq face ps-italic-faces))
8bd22fcf
KH
3677 (or (ps-xemacs-face-kind-p face 'ANGLE_NAME "i\\|o" ps-italic-faces)
3678 (ps-xemacs-face-kind-p face 'SLANT "i\\|o" ps-italic-faces))))
12d89a2e
RS
3679
3680(defun ps-face-underlined-p (face)
3681 (or (face-underline-p face)
3682 (memq face ps-underlined-faces)))
3683
a18ed129 3684
043620f4
KH
3685;; Ensure that face-list is fbound.
3686(or (fboundp 'face-list) (defalias 'face-list 'list-faces))
12d89a2e 3687
a18ed129 3688
12d89a2e 3689(defun ps-build-reference-face-lists ()
857686a6
RS
3690 ;; Ensure that face database is updated with faces on
3691 ;; `font-lock-face-attributes' (obsolete stuff)
3692 (ps-font-lock-face-attributes)
3693 ;; Now, rebuild reference face lists
a18ed129 3694 (setq ps-print-face-alist nil)
12d89a2e 3695 (if ps-auto-font-detect
a18ed129
RS
3696 (mapcar 'ps-map-face (face-list))
3697 (mapcar 'ps-set-face-bold ps-bold-faces)
3698 (mapcar 'ps-set-face-italic ps-italic-faces)
3699 (mapcar 'ps-set-face-underline ps-underlined-faces))
12d89a2e 3700 (setq ps-build-face-reference nil))
ef2cbb24 3701
a18ed129
RS
3702
3703(defun ps-set-face-bold (face)
3704 (ps-set-face-attribute face 1))
3705
3706(defun ps-set-face-italic (face)
3707 (ps-set-face-attribute face 2))
3708
3709(defun ps-set-face-underline (face)
3710 (ps-set-face-attribute face 4))
3711
3712
3713(defun ps-set-face-attribute (face effect)
3714 (let ((face-bit (cdr (ps-map-face face))))
3715 (aset face-bit 0 (logior (aref face-bit 0) effect))))
3716
3717
3718(defun ps-map-face (face)
3719 (let* ((face-map (ps-screen-to-bit-face face))
3720 (ps-face-bit (cdr (assq (car face-map) ps-print-face-alist))))
3721 (if ps-face-bit
3722 ;; if face exists, merge both
3723 (let ((face-bit (cdr face-map)))
3724 (aset ps-face-bit 0 (logior (aref ps-face-bit 0) (aref face-bit 0)))
3725 (or (aref ps-face-bit 1) (aset ps-face-bit 1 (aref face-bit 1)))
3726 (or (aref ps-face-bit 2) (aset ps-face-bit 2 (aref face-bit 2))))
3727 ;; if face does not exist, insert it
3728 (setq ps-print-face-alist (cons face-map ps-print-face-alist)))
3729 face-map))
3730
3731
3732(defun ps-screen-to-bit-face (face)
3733 (cons face
3734 (vector (logior (if (ps-face-bold-p face) 1 0) ; bold
3735 (if (ps-face-italic-p face) 2 0) ; italic
3736 (if (ps-face-underlined-p face) 4 0)) ; underline
3737 (face-foreground face)
3738 (face-background face))))
3739
3740
ef2cbb24
RS
3741(defun ps-mapper (extent list)
3742 (nconc list (list (list (extent-start-position extent) 'push extent)
06fb6aab 3743 (list (extent-end-position extent) 'pull extent)))
ef2cbb24
RS
3744 nil)
3745
00aa16af
RS
3746(defun ps-extent-sorter (a b)
3747 (< (extent-priority a) (extent-priority b)))
043620f4
KH
3748
3749(defun ps-print-ensure-fontified (start end)
857686a6 3750 (and (boundp 'lazy-lock-mode) (symbol-value 'lazy-lock-mode)
8bd22fcf
KH
3751 (if (fboundp 'lazy-lock-fontify-region)
3752 (lazy-lock-fontify-region start end) ; the new
3753 (lazy-lock-fontify-buffer)))) ; the old
043620f4 3754
ef2cbb24 3755(defun ps-generate-postscript-with-faces (from to)
87a16a06 3756 ;; Some initialization...
857686a6 3757 (setq ps-current-effect 0)
87a16a06 3758
00aa16af 3759 ;; Build the reference lists of faces if necessary.
12d89a2e
RS
3760 (if (or ps-always-build-face-reference
3761 ps-build-face-reference)
3762 (progn
3763 (message "Collecting face information...")
3764 (ps-build-reference-face-lists)))
00aa16af
RS
3765 ;; Set the color scale. We do it here instead of in the defvar so
3766 ;; that ps-print can be dumped into emacs. This expression can't be
3767 ;; evaluated at dump-time because X isn't initialized.
3768 (setq ps-print-color-scale
857686a6 3769 (if (and ps-print-color-p (ps-color-device))
043620f4 3770 (float (car (ps-color-values "white")))
00aa16af
RS
3771 1.0))
3772 ;; Generate some PostScript.
ef2cbb24
RS
3773 (save-restriction
3774 (narrow-to-region from to)
12d89a2e
RS
3775 (let ((face 'default)
3776 (position to))
043620f4 3777 (ps-print-ensure-fontified from to)
87a16a06
RS
3778 (cond
3779 ((or (eq ps-print-emacs-type 'lucid)
3780 (eq ps-print-emacs-type 'xemacs))
3781 ;; Build the list of extents...
3782 (let ((a (cons 'dummy nil))
3783 record type extent extent-list)
3784 (map-extents 'ps-mapper nil from to a)
8bd22fcf
KH
3785 (setq a (sort (cdr a) 'car-less-than-car)
3786 extent-list nil)
87a16a06
RS
3787
3788 ;; Loop through the extents...
3789 (while a
8bd22fcf 3790 (setq record (car a)
87a16a06 3791
8bd22fcf
KH
3792 position (car record)
3793 record (cdr record)
87a16a06 3794
8bd22fcf
KH
3795 type (car record)
3796 record (cdr record)
87a16a06 3797
8bd22fcf 3798 extent (car record))
87a16a06
RS
3799
3800 ;; Plot up to this record.
3801 ;; XEmacs 19.12: for some reason, we're getting into a
3802 ;; situation in which some of the records have
3803 ;; positions less than 'from'. Since we've narrowed
3804 ;; the buffer, this'll generate errors. This is a
3805 ;; hack, but don't call ps-plot-with-face unless from >
3806 ;; point-min.
8bd22fcf
KH
3807 (and (>= from (point-min)) (<= position (point-max))
3808 (ps-plot-with-face from position face))
87a16a06
RS
3809
3810 (cond
3811 ((eq type 'push)
3812 (if (extent-face extent)
3813 (setq extent-list (sort (cons extent extent-list)
3814 'ps-extent-sorter))))
3815
3816 ((eq type 'pull)
3817 (setq extent-list (sort (delq extent extent-list)
3818 'ps-extent-sorter))))
3819
3820 (setq face
3821 (if extent-list
3822 (extent-face (car extent-list))
8bd22fcf 3823 'default)
87a16a06 3824
8bd22fcf
KH
3825 from position
3826 a (cdr a)))))
87a16a06
RS
3827
3828 ((eq ps-print-emacs-type 'emacs)
3829 (let ((property-change from)
3830 (overlay-change from))
3831 (while (< from to)
3832 (if (< property-change to) ; Don't search for property change
12d89a2e 3833 ; unless previous search succeeded.
87a16a06
RS
3834 (setq property-change
3835 (next-property-change from nil to)))
3836 (if (< overlay-change to) ; Don't search for overlay change
12d89a2e 3837 ; unless previous search succeeded.
87a16a06
RS
3838 (setq overlay-change
3839 (min (next-overlay-change from) to)))
3840 (setq position
3841 (min property-change overlay-change))
3842 ;; The code below is not quite correct,
3843 ;; because a non-nil overlay invisible property
3844 ;; which is inactive according to the current value
3845 ;; of buffer-invisibility-spec nonetheless overrides
3846 ;; a face text property.
3847 (setq face
3848 (cond ((let ((prop (get-text-property from 'invisible)))
3849 ;; Decide whether this invisible property
3850 ;; really makes the text invisible.
3851 (if (eq buffer-invisibility-spec t)
3852 (not (null prop))
3853 (or (memq prop buffer-invisibility-spec)
3854 (assq prop buffer-invisibility-spec))))
12b88fff 3855 'emacs--invisible--face)
87a16a06
RS
3856 ((get-text-property from 'face))
3857 (t 'default)))
3858 (let ((overlays (overlays-at from))
3859 (face-priority -1)) ; text-property
3860 (while overlays
3861 (let* ((overlay (car overlays))
3862 (overlay-face (overlay-get overlay 'face))
3863 (overlay-invisible (overlay-get overlay 'invisible))
3864 (overlay-priority (or (overlay-get overlay
3865 'priority)
3866 0)))
8bd22fcf
KH
3867 (and (or overlay-invisible overlay-face)
3868 (> overlay-priority face-priority)
3869 (setq face (cond ((if (eq buffer-invisibility-spec t)
3870 (not (null overlay-invisible))
3871 (or (memq overlay-invisible
3872 buffer-invisibility-spec)
3873 (assq overlay-invisible
3874 buffer-invisibility-spec)))
3875 nil)
3876 ((and face overlay-face)))
3877 face-priority overlay-priority)))
87a16a06
RS
3878 (setq overlays (cdr overlays))))
3879 ;; Plot up to this record.
3880 (ps-plot-with-face from position face)
3881 (setq from position)))))
3882 (ps-plot-with-face from to face))))
ef2cbb24
RS
3883
3884(defun ps-generate-postscript (from to)
12d89a2e 3885 (ps-plot-region from to 0 nil))
ef2cbb24
RS
3886
3887(defun ps-generate (buffer from to genfunc)
87a16a06
RS
3888 (save-excursion
3889 (let ((from (min to from))
3890 (to (max to from))
3891 ;; This avoids trouble if chars with read-only properties
3892 ;; are copied into ps-spool-buffer.
3893 (inhibit-read-only t))
3894 (save-restriction
3895 (narrow-to-region from to)
857686a6
RS
3896 (and ps-razzle-dazzle
3897 (message "Formatting...%3d%%" (setq ps-razchunk 0)))
87a16a06 3898 (set-buffer buffer)
8bd22fcf
KH
3899 (setq ps-source-buffer buffer
3900 ps-spool-buffer (get-buffer-create ps-spool-buffer-name))
87a16a06
RS
3901 (ps-init-output-queue)
3902 (let (safe-marker completed-safely needs-begin-file)
3903 (unwind-protect
00aa16af
RS
3904 (progn
3905 (set-buffer ps-spool-buffer)
ef2cbb24 3906
87a16a06
RS
3907 ;; Get a marker and make it point to the current end of the
3908 ;; buffer, If an error occurs, we'll delete everything from
3909 ;; the end of this marker onwards.
3910 (setq safe-marker (make-marker))
3911 (set-marker safe-marker (point-max))
3912
3913 (goto-char (point-min))
8bd22fcf
KH
3914 (or (looking-at (regexp-quote ps-adobe-tag))
3915 (setq needs-begin-file t))
87a16a06
RS
3916 (save-excursion
3917 (set-buffer ps-source-buffer)
3918 (if needs-begin-file (ps-begin-file))
3919 (ps-begin-job)
3920 (ps-begin-page))
3921 (set-buffer ps-source-buffer)
3922 (funcall genfunc from to)
3923 (ps-end-page)
3924
8bd22fcf
KH
3925 (and ps-spool-duplex (= (mod ps-page-count 2) 1)
3926 (ps-dummy-page))
87a16a06
RS
3927 (ps-flush-output)
3928
3929 ;; Back to the PS output buffer to set the page count
3930 (set-buffer ps-spool-buffer)
8bd22fcf
KH
3931 (goto-char (point-min))
3932 (and (re-search-forward "^/PageCount 0 def$" nil t)
12b88fff
RS
3933 (replace-match (format "/PageCount %d def"
3934 (if ps-print-only-one-header
3935 (ps-page-number)
3936 ps-page-count))
8bd22fcf 3937 t))
87a16a06
RS
3938
3939 ;; Setting this variable tells the unwind form that the
8bd22fcf 3940 ;; the PostScript was generated without error.
87a16a06
RS
3941 (setq completed-safely t))
3942
3943 ;; Unwind form: If some bad mojo occurred while generating
8bd22fcf 3944 ;; PostScript, delete all the PostScript that was generated.
87a16a06
RS
3945 ;; This protects the previously spooled files from getting
3946 ;; corrupted.
8bd22fcf
KH
3947 (and (markerp safe-marker) (not completed-safely)
3948 (progn
3949 (set-buffer ps-spool-buffer)
3950 (delete-region (marker-position safe-marker) (point-max))))))
87a16a06 3951
857686a6 3952 (and ps-razzle-dazzle (message "Formatting...done"))))))
ef2cbb24 3953
857686a6 3954;; Permit dynamic evaluation at print time of `ps-lpr-switches'.
ef2cbb24 3955(defun ps-do-despool (filename)
12d89a2e 3956 (if (or (not (boundp 'ps-spool-buffer))
bcc0d457 3957 (not (symbol-value 'ps-spool-buffer)))
12d89a2e 3958 (message "No spooled PostScript to print")
ef2cbb24 3959 (ps-end-file)
12d89a2e 3960 (ps-flush-output)
ef2cbb24
RS
3961 (if filename
3962 (save-excursion
857686a6 3963 (and ps-razzle-dazzle (message "Saving..."))
12d89a2e 3964 (set-buffer ps-spool-buffer)
ef2cbb24 3965 (setq filename (expand-file-name filename))
7ffaf659
EZ
3966 (let ((coding-system-for-write 'raw-text-unix))
3967 (write-region (point-min) (point-max) filename))
857686a6 3968 (and ps-razzle-dazzle (message "Wrote %s" filename)))
ef2cbb24 3969 ;; Else, spool to the printer
857686a6 3970 (and ps-razzle-dazzle (message "Printing..."))
ef2cbb24 3971 (save-excursion
12d89a2e 3972 (set-buffer ps-spool-buffer)
7ffaf659
EZ
3973 (let ((coding-system-for-write 'raw-text-unix))
3974 (if (and (eq system-type 'ms-dos)
3975 (stringp (symbol-value 'dos-ps-printer)))
3976 (write-region (point-min) (point-max)
3977 (symbol-value 'dos-ps-printer) t 0)
62901aee
RS
3978 (apply 'call-process-region
3979 (point-min) (point-max) ps-lpr-command nil
857686a6 3980 (and (fboundp 'start-process) 0)
62901aee 3981 nil
857686a6
RS
3982 (ps-flatten-list ; dynamic evaluation
3983 (mapcar 'ps-eval-switch ps-lpr-switches))))))
3984 (and ps-razzle-dazzle (message "Printing...done")))
12d89a2e
RS
3985 (kill-buffer ps-spool-buffer)))
3986
857686a6
RS
3987;; Dynamic evaluation
3988(defun ps-eval-switch (arg)
3989 (cond ((stringp arg) arg)
3990 ((functionp arg) (apply arg nil))
3991 ((symbolp arg) (symbol-value arg))
3992 ((consp arg) (apply (car arg) (cdr arg)))
3993 (t nil)))
3994
3995;; `ps-flatten-list' is defined here (copied from "message.el" and
3996;; enhanced to handle dotted pairs as well) until we can get some
3997;; sensible autoloads, or `flatten-list' gets put somewhere decent.
3998
3999;; (ps-flatten-list '((a . b) c (d . e) (f g h) i . j))
4000;; => (a b c d e f g h i j)
4001
4002(defun ps-flatten-list (&rest list)
4003 (ps-flatten-list-1 list))
4004
4005(defun ps-flatten-list-1 (list)
4006 (cond ((null list) nil)
4007 ((consp list) (append (ps-flatten-list-1 (car list))
4008 (ps-flatten-list-1 (cdr list))))
4009 (t (list list))))
4010
12d89a2e
RS
4011(defun ps-kill-emacs-check ()
4012 (let (ps-buffer)
8bd22fcf
KH
4013 (and (setq ps-buffer (get-buffer ps-spool-buffer-name))
4014 (buffer-modified-p ps-buffer)
4015 (y-or-n-p "Unprinted PostScript waiting; print now? ")
4016 (ps-despool))
4017 (and (setq ps-buffer (get-buffer ps-spool-buffer-name))
4018 (buffer-modified-p ps-buffer)
4019 (not (yes-or-no-p "Unprinted PostScript waiting; exit anyway? "))
4020 (error "Unprinted PostScript"))))
12d89a2e
RS
4021
4022(if (fboundp 'add-hook)
bcc0d457 4023 (funcall 'add-hook 'kill-emacs-hook 'ps-kill-emacs-check)
12d89a2e
RS
4024 (if kill-emacs-hook
4025 (message "Won't override existing kill-emacs-hook")
4026 (setq kill-emacs-hook 'ps-kill-emacs-check)))
ef2cbb24 4027
12d89a2e 4028;;; Sample Setup Code:
ef2cbb24 4029
12d89a2e 4030;; This stuff is for anybody that's brave enough to look this far,
87a16a06
RS
4031;; and able to figure out how to use it. It isn't really part of
4032;; ps-print, but I'll leave it here in hopes it might be useful:
ef2cbb24 4033
043620f4
KH
4034;; WARNING!!! The following code is *sample* code only. Don't use it
4035;; unless you understand what it does!
4036
87a16a06
RS
4037(defmacro ps-prsc ()
4038 `(if (eq ps-print-emacs-type 'emacs) [f22] 'f22))
4039(defmacro ps-c-prsc ()
4040 `(if (eq ps-print-emacs-type 'emacs) [C-f22] '(control f22)))
4041(defmacro ps-s-prsc ()
4042 `(if (eq ps-print-emacs-type 'emacs) [S-f22] '(shift f22)))
00aa16af 4043
a18ed129
RS
4044;; A hook to bind to `rmail-mode-hook' to locally bind prsc and set the
4045;; `ps-left-headers' specially for mail messages.
4046(defun ps-rmail-mode-hook ()
4047 (local-set-key (ps-prsc) 'ps-rmail-print-message-from-summary)
4048 (setq ps-header-lines 3
4049 ps-left-header
4050 ;; The left headers will display the message's subject, its
4051 ;; author, and the name of the folder it was in.
4052 '(ps-article-subject ps-article-author buffer-name)))
4053
4054;; See `ps-gnus-print-article-from-summary'. This function does the
4055;; same thing for rmail.
4056(defun ps-rmail-print-message-from-summary ()
4057 (interactive)
4058 (ps-print-message-from-summary 'rmail-summary-buffer "RMAIL"))
4059
4060;; Used in `ps-rmail-print-article-from-summary',
4061;; `ps-gnus-print-article-from-summary' and `ps-vm-print-message-from-summary'.
4062(defun ps-print-message-from-summary (summary-buffer summary-default)
4063 (let ((ps-buf (or (and (boundp summary-buffer)
4064 (symbol-value summary-buffer))
4065 summary-default)))
4066 (and (get-buffer ps-buf)
4067 (save-excursion
4068 (set-buffer ps-buf)
4069 (ps-spool-buffer-with-faces)))))
4070
12d89a2e 4071;; Look in an article or mail message for the Subject: line. To be
87a16a06 4072;; placed in `ps-left-headers'.
12d89a2e 4073(defun ps-article-subject ()
ef2cbb24 4074 (save-excursion
12d89a2e 4075 (goto-char (point-min))
45a870d9 4076 (if (re-search-forward "^Subject:[ \t]+\\(.*\\)$" nil t)
055e7bf2 4077 (buffer-substring-no-properties (match-beginning 1) (match-end 1))
12d89a2e
RS
4078 "Subject ???")))
4079
4080;; Look in an article or mail message for the From: line. Sorta-kinda
4081;; understands RFC-822 addresses and can pull the real name out where
87a16a06 4082;; it's provided. To be placed in `ps-left-headers'.
12d89a2e
RS
4083(defun ps-article-author ()
4084 (save-excursion
4085 (goto-char (point-min))
a97592dd 4086 (if (re-search-forward "^From:[ \t]+\\(.*\\)$" nil t)
87a16a06
RS
4087 (let ((fromstring (buffer-substring-no-properties (match-beginning 1)
4088 (match-end 1))))
12d89a2e
RS
4089 (cond
4090
4091 ;; Try first to match addresses that look like
4092 ;; thompson@wg2.waii.com (Jim Thompson)
4093 ((string-match ".*[ \t]+(\\(.*\\))" fromstring)
4094 (substring fromstring (match-beginning 1) (match-end 1)))
4095
4096 ;; Next try to match addresses that look like
4097 ;; Jim Thompson <thompson@wg2.waii.com>
4098 ((string-match "\\(.*\\)[ \t]+<.*>" fromstring)
4099 (substring fromstring (match-beginning 1) (match-end 1)))
4100
4101 ;; Couldn't find a real name -- show the address instead.
4102 (t fromstring)))
4103 "From ???")))
4104
a18ed129 4105;; A hook to bind to `gnus-article-prepare-hook'. This will set the
87a16a06
RS
4106;; `ps-left-headers' specially for gnus articles. Unfortunately,
4107;; `gnus-article-mode-hook' is called only once, the first time the *Article*
12d89a2e
RS
4108;; buffer enters that mode, so it would only work for the first time
4109;; we ran gnus. The second time, this hook wouldn't get set up. The
87a16a06 4110;; only alternative is `gnus-article-prepare-hook'.
12d89a2e 4111(defun ps-gnus-article-prepare-hook ()
8bd22fcf
KH
4112 (setq ps-header-lines 3
4113 ps-left-header
12d89a2e
RS
4114 ;; The left headers will display the article's subject, its
4115 ;; author, and the newsgroup it was in.
8bd22fcf 4116 '(ps-article-subject ps-article-author gnus-newsgroup-name)))
12d89a2e 4117
a18ed129
RS
4118;; A hook to bind to `vm-mode-hook' to locally bind prsc and set the
4119;; `ps-left-headers' specially for mail messages.
12d89a2e 4120(defun ps-vm-mode-hook ()
00aa16af 4121 (local-set-key (ps-prsc) 'ps-vm-print-message-from-summary)
8bd22fcf
KH
4122 (setq ps-header-lines 3
4123 ps-left-header
12d89a2e
RS
4124 ;; The left headers will display the message's subject, its
4125 ;; author, and the name of the folder it was in.
8bd22fcf 4126 '(ps-article-subject ps-article-author buffer-name)))
12d89a2e
RS
4127
4128;; Every now and then I forget to switch from the *Summary* buffer to
4129;; the *Article* before hitting prsc, and a nicely formatted list of
4130;; article subjects shows up at the printer. This function, bound to
4131;; prsc for the gnus *Summary* buffer means I don't have to switch
4132;; buffers first.
87a16a06 4133;; sb: Updated for Gnus 5.
12d89a2e
RS
4134(defun ps-gnus-print-article-from-summary ()
4135 (interactive)
a18ed129 4136 (ps-print-message-from-summary 'gnus-article-buffer "*Article*"))
ef2cbb24 4137
87a16a06 4138;; See `ps-gnus-print-article-from-summary'. This function does the
12d89a2e
RS
4139;; same thing for vm.
4140(defun ps-vm-print-message-from-summary ()
4141 (interactive)
a18ed129 4142 (ps-print-message-from-summary 'vm-mail-buffer ""))
ef2cbb24 4143
87a16a06 4144;; A hook to bind to bind to `gnus-summary-setup-buffer' to locally bind
12d89a2e
RS
4145;; prsc.
4146(defun ps-gnus-summary-setup ()
00aa16af 4147 (local-set-key (ps-prsc) 'ps-gnus-print-article-from-summary))
12d89a2e
RS
4148
4149;; Look in an article or mail message for the Subject: line. To be
87a16a06 4150;; placed in `ps-left-headers'.
12d89a2e
RS
4151(defun ps-info-file ()
4152 (save-excursion
4153 (goto-char (point-min))
a97592dd 4154 (if (re-search-forward "File:[ \t]+\\([^, \t\n]*\\)" nil t)
055e7bf2 4155 (buffer-substring-no-properties (match-beginning 1) (match-end 1))
12d89a2e
RS
4156 "File ???")))
4157
4158;; Look in an article or mail message for the Subject: line. To be
87a16a06 4159;; placed in `ps-left-headers'.
12d89a2e
RS
4160(defun ps-info-node ()
4161 (save-excursion
4162 (goto-char (point-min))
a97592dd 4163 (if (re-search-forward "Node:[ \t]+\\([^,\t\n]*\\)" nil t)
055e7bf2 4164 (buffer-substring-no-properties (match-beginning 1) (match-end 1))
12d89a2e
RS
4165 "Node ???")))
4166
4167(defun ps-info-mode-hook ()
4168 (setq ps-left-header
4169 ;; The left headers will display the node name and file name.
8bd22fcf 4170 '(ps-info-node ps-info-file)))
12d89a2e 4171
043620f4
KH
4172;; WARNING! The following function is a *sample* only, and is *not*
4173;; meant to be used as a whole unless you understand what the effects
87a16a06
RS
4174;; will be! (In fact, this is a copy of Jim's setup for ps-print --
4175;; I'd be very surprised if it was useful to *anybody*, without
043620f4
KH
4176;; modification.)
4177
12d89a2e 4178(defun ps-jts-ps-setup ()
00aa16af
RS
4179 (global-set-key (ps-prsc) 'ps-spool-buffer-with-faces) ;f22 is prsc
4180 (global-set-key (ps-s-prsc) 'ps-spool-region-with-faces)
4181 (global-set-key (ps-c-prsc) 'ps-despool)
12d89a2e
RS
4182 (add-hook 'gnus-article-prepare-hook 'ps-gnus-article-prepare-hook)
4183 (add-hook 'gnus-summary-mode-hook 'ps-gnus-summary-setup)
4184 (add-hook 'vm-mode-hook 'ps-vm-mode-hook)
00aa16af 4185 (add-hook 'vm-mode-hooks 'ps-vm-mode-hook)
12d89a2e 4186 (add-hook 'Info-mode-hook 'ps-info-mode-hook)
8bd22fcf
KH
4187 (setq ps-spool-duplex t
4188 ps-print-color-p nil
4189 ps-lpr-command "lpr"
4190 ps-lpr-switches '("-Jjct,duplex_long"))
bcc0d457
RS
4191 'ps-jts-ps-setup)
4192
4193;; WARNING! The following function is a *sample* only, and is *not*
4194;; meant to be used as a whole unless it corresponds to your needs.
4195;; (In fact, this is a copy of Jack's setup for ps-print --
4196;; I would not be that surprised if it was useful to *anybody*,
4197;; without modification.)
4198
4199(defun ps-jack-setup ()
87a16a06 4200 (setq ps-print-color-p nil
bcc0d457 4201 ps-lpr-command "lpr"
8bd22fcf 4202 ps-lpr-switches nil
bcc0d457 4203
87a16a06
RS
4204 ps-paper-type 'a4
4205 ps-landscape-mode t
bcc0d457
RS
4206 ps-number-of-columns 2
4207
4208 ps-left-margin (/ (* 72 1.0) 2.54) ; 1.0 cm
4209 ps-right-margin (/ (* 72 1.0) 2.54) ; 1.0 cm
4210 ps-inter-column (/ (* 72 1.0) 2.54) ; 1.0 cm
4211 ps-bottom-margin (/ (* 72 1.5) 2.54) ; 1.5 cm
4212 ps-top-margin (/ (* 72 1.5) 2.54) ; 1.5 cm
4213 ps-header-offset (/ (* 72 1.0) 2.54) ; 1.0 cm
4214 ps-header-line-pad .15
4215 ps-print-header t
4216 ps-print-header-frame t
4217 ps-header-lines 2
4218 ps-show-n-of-n t
4219 ps-spool-duplex nil
4220
4221 ps-font-family 'Courier
4222 ps-font-size 5.5
4223 ps-header-font-family 'Helvetica
4224 ps-header-font-size 6
4225 ps-header-title-font-size 8)
4226 'ps-jack-setup)
12d89a2e
RS
4227
4228(provide 'ps-print)
b87c5d3d 4229
12d89a2e 4230;;; ps-print.el ends here