]> code.delx.au - gnu-emacs/blob - lisp/ps-print.el
Add DSSSL mode and share code with newly required
[gnu-emacs] / lisp / ps-print.el
1 ;;; ps-print.el --- Jim's Pretty-Good PostScript Generator for Emacs 19.
2
3 ;; Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
4
5 ;; Author: Jim Thompson (was <thompson@wg2.waii.com>)
6 ;; Maintainer: Jacques Duthen <duthen@cegelec-red.fr>
7 ;; Keywords: print, PostScript
8 ;; Time-stamp: <97/01/09 13:52:08 duthen>
9 ;; Version: 3.04
10
11 (defconst ps-print-version "3.04"
12 "ps-print.el, v 3.04 <97/01/09 duthen>
13
14 Jack's last change version -- this file may have been edited as part of
15 Emacs without changes to the version number. When reporting bugs,
16 please also report the version of Emacs, if any, that ps-print was
17 distributed with.
18
19 Please send all bug fixes and enhancements to
20 Jacques Duthen <duthen@cegelec-red.fr>.
21 ")
22
23 ;; This file is part of GNU Emacs.
24
25 ;; GNU Emacs is free software; you can redistribute it and/or modify
26 ;; it under the terms of the GNU General Public License as published by
27 ;; the Free Software Foundation; either version 2, or (at your option)
28 ;; any later version.
29
30 ;; GNU Emacs is distributed in the hope that it will be useful,
31 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
32 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 ;; GNU General Public License for more details.
34
35 ;; You should have received a copy of the GNU General Public License
36 ;; along with GNU Emacs; see the file COPYING. If not, write to the
37 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
38 ;; Boston, MA 02111-1307, USA.
39
40 ;;; Commentary:
41
42 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
43 ;;
44 ;; About ps-print
45 ;; --------------
46 ;;
47 ;; This package provides printing of Emacs buffers on PostScript
48 ;; printers; the buffer's bold and italic text attributes are
49 ;; preserved in the printer output. Ps-print is intended for use with
50 ;; Emacs 19 or Lucid Emacs, together with a fontifying package such as
51 ;; font-lock or hilit.
52 ;;
53 ;;
54 ;; Using ps-print
55 ;; --------------
56 ;;
57 ;; The Commands
58 ;;
59 ;; Ps-print provides eight commands for generating PostScript images
60 ;; of Emacs buffers:
61 ;;
62 ;; ps-print-buffer
63 ;; ps-print-buffer-with-faces
64 ;; ps-print-region
65 ;; ps-print-region-with-faces
66 ;; ps-spool-buffer
67 ;; ps-spool-buffer-with-faces
68 ;; ps-spool-region
69 ;; ps-spool-region-with-faces
70 ;;
71 ;; These commands all perform essentially the same function: they
72 ;; generate PostScript images suitable for printing on a PostScript
73 ;; printer or displaying with GhostScript. These commands are
74 ;; collectively referred to as "ps-print- commands".
75 ;;
76 ;; The word "print" or "spool" in the command name determines when the
77 ;; PostScript image is sent to the printer:
78 ;;
79 ;; print - The PostScript image is immediately sent to the
80 ;; printer;
81 ;;
82 ;; spool - The PostScript image is saved temporarily in an
83 ;; Emacs buffer. Many images may be spooled locally
84 ;; before printing them. To send the spooled images
85 ;; to the printer, use the command `ps-despool'.
86 ;;
87 ;; The spooling mechanism was designed for printing lots of small
88 ;; files (mail messages or netnews articles) to save paper that would
89 ;; otherwise be wasted on banner pages, and to make it easier to find
90 ;; your output at the printer (it's easier to pick up one 50-page
91 ;; printout than to find 50 single-page printouts).
92 ;;
93 ;; Ps-print has a hook in the `kill-emacs-hooks' so that you won't
94 ;; accidentally quit from Emacs while you have unprinted PostScript
95 ;; waiting in the spool buffer. If you do attempt to exit with
96 ;; spooled PostScript, you'll be asked if you want to print it, and if
97 ;; you decline, you'll be asked to confirm the exit; this is modeled
98 ;; on the confirmation that Emacs uses for modified buffers.
99 ;;
100 ;; The word "buffer" or "region" in the command name determines how
101 ;; much of the buffer is printed:
102 ;;
103 ;; buffer - Print the entire buffer.
104 ;;
105 ;; region - Print just the current region.
106 ;;
107 ;; The -with-faces suffix on the command name means that the command
108 ;; will include font, color, and underline information in the
109 ;; PostScript image, so the printed image can look as pretty as the
110 ;; buffer. The ps-print- commands without the -with-faces suffix
111 ;; don't include font, color, or underline information; images printed
112 ;; with these commands aren't as pretty, but are faster to generate.
113 ;;
114 ;; Two ps-print- command examples:
115 ;;
116 ;; ps-print-buffer - print the entire buffer,
117 ;; without font, color, or
118 ;; underline information, and
119 ;; send it immediately to the
120 ;; printer.
121 ;;
122 ;; ps-spool-region-with-faces - print just the current region;
123 ;; include font, color, and
124 ;; underline information, and
125 ;; spool the image in Emacs to
126 ;; send to the printer later.
127 ;;
128 ;;
129 ;; Invoking Ps-Print
130 ;; -----------------
131 ;;
132 ;; To print your buffer, type
133 ;;
134 ;; M-x ps-print-buffer
135 ;;
136 ;; or substitute one of the other seven ps-print- commands. The
137 ;; command will generate the PostScript image and print or spool it as
138 ;; specified. By giving the command a prefix argument
139 ;;
140 ;; C-u M-x ps-print-buffer
141 ;;
142 ;; it will save the PostScript image to a file instead of sending it
143 ;; to the printer; you will be prompted for the name of the file to
144 ;; save the image to. The prefix argument is ignored by the commands
145 ;; that spool their images, but you may save the spooled images to a
146 ;; file by giving a prefix argument to `ps-despool':
147 ;;
148 ;; C-u M-x ps-despool
149 ;;
150 ;; When invoked this way, `ps-despool' will prompt you for the name of
151 ;; the file to save to.
152 ;;
153 ;; Any of the `ps-print-' commands can be bound to keys; I recommend
154 ;; binding `ps-spool-buffer-with-faces', `ps-spool-region-with-faces',
155 ;; and `ps-despool'. Here are the bindings I use on my Sun 4 keyboard:
156 ;;
157 ;; (global-set-key 'f22 'ps-spool-buffer-with-faces) ;f22 is prsc
158 ;; (global-set-key '(shift f22) 'ps-spool-region-with-faces)
159 ;; (global-set-key '(control f22) 'ps-despool)
160 ;;
161 ;;
162 ;; The Printer Interface
163 ;; ---------------------
164 ;;
165 ;; The variables `ps-lpr-command' and `ps-lpr-switches' determine what
166 ;; command is used to send the PostScript images to the printer, and
167 ;; what arguments to give the command. These are analogous to
168 ;; `lpr-command' and `lpr-switches'.
169 ;; Make sure that they contain appropriate values for your system;
170 ;; see the usage notes below and the documentation of these variables.
171 ;;
172 ;; NOTE: `ps-lpr-command' and `ps-lpr-switches' take their initial values
173 ;; from the variables `lpr-command' and `lpr-switches'. If you have
174 ;; `lpr-command' set to invoke a pretty-printer such as `enscript',
175 ;; then ps-print won't work properly. `ps-lpr-command' must name
176 ;; a program that does not format the files it prints.
177 ;;
178 ;;
179 ;; The Page Layout
180 ;; ---------------
181 ;;
182 ;; All dimensions are floats in PostScript points.
183 ;; 1 inch == 2.54 cm == 72 points
184 ;; 1 cm == (/ 1 2.54) inch == (/ 72 2.54) points
185 ;;
186 ;; The variable `ps-paper-type' determines the size of paper ps-print
187 ;; formats for; it should contain one of the symbols:
188 ;; `a4' `a3' `letter' `legal' `letter-small' `tabloid'
189 ;; `ledger' `statement' `executive' `a4small' `b4' `b5'
190 ;;
191 ;; The variable `ps-landscape-mode' determines the orientation
192 ;; of the printing on the page:
193 ;; nil means `portrait' mode, non-nil means `landscape' mode.
194 ;; There is no oblique mode yet, though this is easy to do in ps.
195
196 ;; In landscape mode, the text is NOT scaled: you may print 70 lines
197 ;; in portrait mode and only 50 lignes in landscape mode.
198 ;; The margins represent margins in the printed paper:
199 ;; the top margin is the margin between the top of the page
200 ;; and the printed header, whatever the orientation is.
201 ;;
202 ;; The variable `ps-number-of-columns' determines the number of columns
203 ;; both in landscape and portrait mode.
204 ;; You can use:
205 ;; - (the standard) one column portrait mode
206 ;; - (my favorite) two columns landscape mode (which spares trees)
207 ;; but also
208 ;; - one column landscape mode for files with very long lines.
209 ;; - multi-column portrait or landscape mode
210 ;;
211 ;;
212 ;; Horizontal layout
213 ;; -----------------
214 ;;
215 ;; The horizontal layout is determined by the variables
216 ;; `ps-left-margin' `ps-inter-column' `ps-right-margin'
217 ;; as follows:
218 ;;
219 ;; ------------------------------------------
220 ;; | | | | | | | |
221 ;; | lm | text | ic | text | ic | text | rm |
222 ;; | | | | | | | |
223 ;; ------------------------------------------
224 ;;
225 ;; If `ps-number-of-columns' is 1, `ps-inter-column' is not relevant.
226 ;; Usually, lm = rm > 0 and ic = lm
227 ;; If (ic < 0), the text of adjacent columns can overlap.
228 ;;
229 ;;
230 ;; Vertical layout
231 ;; ---------------
232 ;;
233 ;; The vertical layout is determined by the variables
234 ;; `ps-bottom-margin' `ps-top-margin' `ps-header-offset'
235 ;; as follows:
236 ;;
237 ;; |--------| |--------|
238 ;; | tm | | tm |
239 ;; |--------| |--------|
240 ;; | header | | |
241 ;; |--------| | |
242 ;; | ho | | |
243 ;; |--------| or | text |
244 ;; | | | |
245 ;; | text | | |
246 ;; | | | |
247 ;; |--------| |--------|
248 ;; | bm | | bm |
249 ;; |--------| |--------|
250 ;;
251 ;; If `ps-print-header' is nil, `ps-header-offset' is not relevant.
252 ;; The margins represent margins in the printed paper:
253 ;; the top margin is the margin between the top of the page
254 ;; and the printed header, whatever the orientation is.
255 ;;
256 ;;
257 ;; Headers
258 ;; -------
259 ;;
260 ;; Ps-print can print headers at the top of each column; the default
261 ;; headers contain the following four items: on the left, the name of
262 ;; the buffer and, if the buffer is visiting a file, the file's
263 ;; directory; on the right, the page number and date of printing.
264 ;; The default headers look something like this:
265 ;;
266 ;; ps-print.el 1/21
267 ;; /home/jct/emacs-lisp/ps/new 94/12/31
268 ;;
269 ;; When printing on duplex printers, left and right are reversed so
270 ;; that the page numbers are toward the outside (cf. `ps-spool-duplex').
271 ;;
272 ;; Headers are configurable:
273 ;; To turn them off completely, set `ps-print-header' to nil.
274 ;; To turn off the header's gaudy framing box,
275 ;; set `ps-print-header-frame' to nil.
276 ;;
277 ;; The font family and size of text in the header are determined
278 ;; by the variables `ps-header-font-family', `ps-header-font-size' and
279 ;; `ps-header-title-font-size' (see below).
280 ;;
281 ;; The variable `ps-header-line-pad' determines the portion of a header
282 ;; title line height to insert between the header frame and the text
283 ;; it contains, both in the vertical and horizontal directions:
284 ;; .5 means half a line.
285
286 ;; Page numbers are printed in `n/m' format, indicating page n of m pages;
287 ;; to omit the total page count and just print the page number,
288 ;; set `ps-show-n-of-n' to nil.
289 ;;
290 ;; The amount of information in the header can be changed by changing
291 ;; the number of lines. To show less, set `ps-header-lines' to 1, and
292 ;; the header will show only the buffer name and page number. To show
293 ;; more, set `ps-header-lines' to 3, and the header will show the time of
294 ;; printing below the date.
295 ;;
296 ;; To change the content of the headers, change the variables
297 ;; `ps-left-header' and `ps-right-header'.
298 ;; These variables are lists, specifying top-to-bottom the text
299 ;; to display on the left or right side of the header.
300 ;; Each element of the list should be a string or a symbol.
301 ;; Strings are inserted directly into the PostScript arrays,
302 ;; and should contain the PostScript string delimiters '(' and ')'.
303 ;;
304 ;; Symbols in the header format lists can either represent functions
305 ;; or variables. Functions are called, and should return a string to
306 ;; show in the header. Variables should contain strings to display in
307 ;; the header. In either case, function or variable, the PostScript
308 ;; string delimiters are added by ps-print, and should not be part of
309 ;; the returned value.
310 ;;
311 ;; Here's an example: say we want the left header to display the text
312 ;;
313 ;; Moe
314 ;; Larry
315 ;; Curly
316 ;;
317 ;; where we have a function to return "Moe"
318 ;;
319 ;; (defun moe-func ()
320 ;; "Moe")
321 ;;
322 ;; a variable specifying "Larry"
323 ;;
324 ;; (setq larry-var "Larry")
325 ;;
326 ;; and a literal for "Curly". Here's how `ps-left-header' should be
327 ;; set:
328 ;;
329 ;; (setq ps-left-header (list 'moe-func 'larry-var "(Curly)"))
330 ;;
331 ;; Note that Curly has the PostScript string delimiters inside his
332 ;; quotes -- those aren't misplaced lisp delimiters!
333 ;; Without them, PostScript would attempt to call the undefined
334 ;; function Curly, which would result in a PostScript error.
335 ;; Since most printers don't report PostScript errors except by
336 ;; aborting the print job, this kind of error can be hard to track down.
337 ;; Consider yourself warned!
338 ;;
339 ;;
340 ;; Duplex Printers
341 ;; ---------------
342 ;;
343 ;; If you have a duplex-capable printer (one that prints both sides of
344 ;; the paper), set `ps-spool-duplex' to t.
345 ;; Ps-print will insert blank pages to make sure each buffer starts
346 ;; on the correct side of the paper.
347 ;; Don't forget to set `ps-lpr-switches' to select duplex printing
348 ;; for your printer.
349 ;;
350 ;;
351 ;; Font managing
352 ;; -------------
353 ;;
354 ;; Ps-print now knows rather precisely some fonts:
355 ;; the variable `ps-font-info-database' contains information
356 ;; for a list of font families (currently mainly `Courier' `Helvetica'
357 ;; `Times' `Palatino' `Helvetica-Narrow' `NewCenturySchlbk').
358 ;; Each font family contains the font names for standard, bold, italic
359 ;; and bold-italic characters, a reference size (usually 10) and the
360 ;; corresponding line height, width of a space and average character width.
361 ;;
362 ;; The variable `ps-font-family' determines which font family
363 ;; is to be used for ordinary text.
364 ;; If its value does not correspond to a known font family,
365 ;; an error message is printed into the `*Messages*' buffer,
366 ;; which lists the currently available font families.
367 ;;
368 ;; The variable `ps-font-size' determines the size (in points)
369 ;; of the font for ordinary text, when generating Postscript.
370 ;; Its value is a float.
371 ;;
372 ;; Similarly, the variable `ps-header-font-family' determines
373 ;; which font family is to be used for text in the header.
374 ;; The variable `ps-header-font-size' determines the font size,
375 ;; in points, for text in the header.
376 ;; The variable `ps-header-title-font-size' determines the font size,
377 ;; in points, for the top line of text in the header.
378 ;;
379 ;;
380 ;; Adding a new font family
381 ;; ------------------------
382 ;;
383 ;; To use a new font family, you MUST first teach ps-print
384 ;; this font, ie add its information to `ps-font-info-database',
385 ;; otherwise ps-print cannot correctly place line and page breaks.
386 ;;
387 ;; For example, assuming `Helvetica' is unkown,
388 ;; you first need to do the following ONLY ONCE:
389 ;;
390 ;; - create a new buffer
391 ;; - generate the PostScript image to a file (C-u M-x ps-print-buffer)
392 ;; - open this file and find the line:
393 ;; `% 3 cm 20 cm moveto 10 /Courier ReportFontInfo showpage'
394 ;; - delete the leading `%' (which is the Postscript comment character)
395 ;; - replace in this line `Courier' by the new font (say `Helvetica')
396 ;; to get the line:
397 ;; `3 cm 20 cm moveto 10 /Helvetica ReportFontInfo showpage'
398 ;; - send this file to the printer (or to ghostscript).
399 ;; You should read the following on the output page:
400 ;;
401 ;; For Helvetica 10 point, the line height is 11.56, the space width is 2.78
402 ;; and a crude estimate of average character width is 5.09243
403 ;;
404 ;; - Add these values to the `ps-font-info-database':
405 ;; (setq ps-font-info-database
406 ;; (append
407 ;; '((Helvetica ; the family name
408 ;; "Helvetica" "Helvetica-Bold" "Helvetica-Oblique" "Helvetica-BoldOblique"
409 ;; 10.0 11.56 2.78 5.09243))
410 ;; ps-font-info-database))
411 ;; - Now you can use this font family with any size:
412 ;; (setq ps-font-family 'Helvetica)
413 ;; - if you want to use this family in another emacs session, you must
414 ;; put into your `~/.emacs':
415 ;; (require 'ps-print)
416 ;; (setq ps-font-info-database (append ...)))
417 ;; if you don't want to load ps-print, you have to copy the whole value:
418 ;; (setq ps-font-info-database '(<your stuff> <the standard stuff>))
419 ;; or, if you can wait until the `ps-print-hook' is implemented, do:
420 ;; (add-hook 'ps-print-hook '(setq ps-font-info-database (append ...)))
421 ;; This does not work yet, since there is no `ps-print-hook' yet.
422 ;;
423 ;; You can create new `mixed' font families like:
424 ;; (my-mixed-family
425 ;; "Courier-Bold" "Helvetica"
426 ;; "Zapf-Chancery-MediumItalic" "NewCenturySchlbk-BoldItalic"
427 ;; 10.0 10.55 6.0 6.0)
428 ;; Now you can use your new font family with any size:
429 ;; (setq ps-font-family 'my-mixed-family)
430 ;;
431 ;; You can get information on all the fonts resident in YOUR printer
432 ;; by uncommenting the line:
433 ;; % 3 cm 20 cm moveto ReportAllFontInfo showpage
434 ;;
435 ;; The postscript file should be sent to YOUR postscript printer.
436 ;; If you send it to ghostscript or to another postscript printer,
437 ;; you may get slightly different results.
438 ;; Anyway, as ghostscript fonts are autoload, you won't get
439 ;; much font info.
440 ;;
441 ;;
442 ;; How Ps-Print Deals With Faces
443 ;; -----------------------------
444 ;;
445 ;; The ps-print-*-with-faces commands attempt to determine which faces
446 ;; should be printed in bold or italic, but their guesses aren't
447 ;; always right. For example, you might want to map colors into faces
448 ;; so that blue faces print in bold, and red faces in italic.
449 ;;
450 ;; It is possible to force ps-print to consider specific faces bold or
451 ;; italic, no matter what font they are displayed in, by setting the
452 ;; variables `ps-bold-faces' and `ps-italic-faces'. These variables
453 ;; contain lists of faces that ps-print should consider bold or
454 ;; italic; to set them, put code like the following into your .emacs
455 ;; file:
456 ;;
457 ;; (setq ps-bold-faces '(my-blue-face))
458 ;; (setq ps-italic-faces '(my-red-face))
459 ;;
460 ;; Faces like bold-italic that are both bold and italic should go in
461 ;; *both* lists.
462 ;;
463 ;; Ps-print keeps internal lists of which fonts are bold and which are
464 ;; italic; these lists are built the first time you invoke ps-print.
465 ;; For the sake of efficiency, the lists are built only once; the same
466 ;; lists are referred in later invocations of ps-print.
467 ;;
468 ;; Because these lists are built only once, it's possible for them to
469 ;; get out of sync, if a face changes, or if new faces are added. To
470 ;; get the lists back in sync, you can set the variable
471 ;; `ps-build-face-reference' to t, and the lists will be rebuilt the
472 ;; next time ps-print is invoked.
473 ;;
474 ;;
475 ;; How Ps-Print Deals With Color
476 ;; -----------------------------
477 ;;
478 ;; Ps-print detects faces with foreground and background colors
479 ;; defined and embeds color information in the PostScript image.
480 ;; The default foreground and background colors are defined by the
481 ;; variables `ps-default-fg' and `ps-default-bg'.
482 ;; On black-and-white printers, colors are displayed in grayscale.
483 ;; To turn off color output, set `ps-print-color-p' to nil.
484 ;;
485 ;;
486 ;; Utilities
487 ;; ---------
488 ;;
489 ;; Some tools are provided to help you customize your font setup.
490 ;;
491 ;; `ps-setup' returns (some part of) the current setup.
492 ;;
493 ;; To avoid wrapping too many lines, you may want to adjust the
494 ;; left and right margins and the font size. On UN*X systems, do:
495 ;; pr -t file | awk '{printf "%3d %s\n", length($0), $0}' | sort -r | head
496 ;; to determine the longest lines of your file.
497 ;; Then, the command `ps-line-lengths' will give you the correspondance
498 ;; between a line length (number of characters) and the maximum font
499 ;; size which doesn't wrap such a line with the current ps-print setup.
500 ;;
501 ;; The commands `ps-nb-pages-buffer' and `ps-nb-pages-region' display
502 ;; the correspondance between a number of pages and the maximum font
503 ;; size which allow the number of lines of the current buffer or of
504 ;; its current region to fit in this number of pages.
505 ;; Note: line folding is not taken into account in this process
506 ;; and could change the results.
507 ;;
508 ;;
509 ;; New since version 1.5
510 ;; ---------------------
511 ;;
512 ;; Color output capability.
513 ;; Automatic detection of font attributes (bold, italic).
514 ;; Configurable headers with page numbers.
515 ;; Slightly faster.
516 ;; Support for different paper sizes.
517 ;; Better conformance to PostScript Document Structure Conventions.
518 ;;
519 ;;
520 ;; New since version 2.8
521 ;; ---------------------
522 ;;
523 ;; [jack] 960517 Jacques Duthen <duthen@cegelec-red.fr>
524 ;;
525 ;; Font familiy and float size for text and header.
526 ;; Landscape mode.
527 ;; Multiple columns.
528 ;; Tools for page setup.
529 ;;
530 ;;
531 ;; Known bugs and limitations of ps-print:
532 ;; --------------------------------------
533 ;;
534 ;; Although color printing will work in XEmacs 19.12, it doesn't work
535 ;; well; in particular, bold or italic fonts don't print in the right
536 ;; background color.
537 ;;
538 ;; Invisible properties aren't correctly ignored in XEmacs 19.12.
539 ;;
540 ;; Automatic font-attribute detection doesn't work well, especially
541 ;; with hilit19 and older versions of get-create-face. Users having
542 ;; problems with auto-font detection should use the lists
543 ;; `ps-italic-faces' and `ps-bold-faces' and/or turn off automatic
544 ;; detection by setting `ps-auto-font-detect' to nil.
545 ;;
546 ;; Automatic font-attribute detection doesn't work with XEmacs 19.12
547 ;; in tty mode; use the lists `ps-italic-faces' and `ps-bold-faces'
548 ;; instead.
549 ;;
550 ;; Still too slow; could use some hand-optimization.
551 ;;
552 ;; ASCII Control characters other than tab, linefeed and pagefeed are
553 ;; not handled.
554 ;;
555 ;; Default background color isn't working.
556 ;;
557 ;; Faces are always treated as opaque.
558 ;;
559 ;; Epoch and Emacs 18 not supported. At all.
560 ;;
561 ;; Fixed-pitch fonts work better for line folding, but are not required.
562 ;;
563 ;; `ps-nb-pages-buffer' and `ps-nb-pages-region' don't take care
564 ;; of folding lines.
565 ;;
566 ;;
567 ;; Things to change:
568 ;; ----------------
569 ;;
570 ;; Add `ps-print-hook' (I don't know how to do that (yet!)).
571 ;; Add 4-up capability (really needed?).
572 ;; Add line numbers (should not be too hard).
573 ;; Add `ps-non-bold-faces' and `ps-non-italic-faces' (should be easy).
574 ;; Put one header per page over the columns (easy but needed?).
575 ;; Improve the memory management for big files (hard?).
576 ;; `ps-nb-pages-buffer' and `ps-nb-pages-region' should take care
577 ;; of folding lines.
578 ;;
579 ;;
580 ;; Acknowledgements
581 ;; ----------------
582 ;; Thanks to Jim Thompson <?@?> for the 2.8 version I started from.
583 ;; [jack]
584 ;;
585 ;; Thanks to Kevin Rodgers <kevinr@ihs.com> for adding support for
586 ;; color and the invisible property.
587 ;;
588 ;; Thanks to Avishai Yacobi, avishaiy@mcil.comm.mot.com, for writing
589 ;; the initial port to Emacs 19. His code is no longer part of
590 ;; ps-print, but his work is still appreciated.
591 ;;
592 ;; Thanks to Remi Houdaille and Michel Train, michel@metasoft.fdn.org,
593 ;; for adding underline support. Their code also is no longer part of
594 ;; ps-print, but their efforts are not forgotten.
595 ;;
596 ;; Thanks also to all of you who mailed code to add features to
597 ;; ps-print; although I didn't use your code, I still appreciate your
598 ;; sharing it with me.
599 ;;
600 ;; Thanks to all who mailed comments, encouragement, and criticism.
601 ;; Thanks also to all who responded to my survey; I had too many
602 ;; responses to reply to them all, but I greatly appreciate your
603 ;; interest.
604 ;;
605 ;; Jim
606 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
607
608 ;;; Code:
609
610 (eval-when-compile
611 (require 'cl))
612
613 (unless (featurep 'lisp-float-type)
614 (error "`ps-print' requires floating point support"))
615
616 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
617 ;; User Variables:
618
619 ;;; Interface to the command system
620
621 (defvar ps-lpr-command lpr-command
622 "*The shell command for printing a PostScript file.")
623
624 (defvar ps-lpr-switches lpr-switches
625 "*A list of extra switches to pass to `ps-lpr-command'.")
626
627 ;;; Page layout
628
629 ;; All page dimensions are in PostScript points.
630 ;; 1 inch == 2.54 cm == 72 points
631 ;; 1 cm == (/ 1 2.54) inch == (/ 72 2.54) points
632
633 ;; Letter 8.5 inch x 11.0 inch
634 ;; Legal 8.5 inch x 14.0 inch
635 ;; A4 8.26 inch x 11.69 inch = 21.0 cm x 29.7 cm
636
637 ;; LetterSmall 7.68 inch x 10.16 inch
638 ;; Tabloid 11.0 inch x 17.0 inch
639 ;; Ledger 17.0 inch x 11.0 inch
640 ;; Statement 5.5 inch x 8.5 inch
641 ;; Executive 7.5 inch x 10.0 inch
642 ;; A3 11.69 inch x 16.5 inch = 29.7 cm x 42.0 cm
643 ;; A4Small 7.47 inch x 10.85 inch
644 ;; B4 10.125 inch x 14.33 inch
645 ;; B5 7.16 inch x 10.125 inch
646
647 (defvar ps-page-dimensions-database
648 (list (list 'a4 (/ (* 72 21.0) 2.54) (/ (* 72 29.7) 2.54))
649 (list 'a3 (/ (* 72 29.7) 2.54) (/ (* 72 42.0) 2.54))
650 (list 'letter (* 72 8.5) (* 72 11.0))
651 (list 'legal (* 72 8.5) (* 72 14.0))
652 (list 'letter-small (* 72 7.68) (* 72 10.16))
653 (list 'tabloid (* 72 11.0) (* 72 17.0))
654 (list 'ledger (* 72 17.0) (* 72 11.0))
655 (list 'statement (* 72 5.5) (* 72 8.5))
656 (list 'executive (* 72 7.5) (* 72 10.0))
657 (list 'a4small (* 72 7.47) (* 72 10.85))
658 (list 'b4 (* 72 10.125) (* 72 14.33))
659 (list 'b5 (* 72 7.16) (* 72 10.125)))
660 "*List associating a symbolic paper type to its width and height.
661 see `ps-paper-type'.")
662
663 (defvar ps-paper-type 'letter
664 "*Specifies the size of paper to format for.
665 Should be one of the paper types defined in `ps-page-dimensions-database', for
666 example `letter', `legal' or `a4'.")
667
668 (defvar ps-landscape-mode 'nil
669 "*Non-nil means print in landscape mode.")
670
671 (defvar ps-number-of-columns (if ps-landscape-mode 2 1)
672 "*Specifies the number of columns")
673
674 ;;; Horizontal layout
675
676 ;; ------------------------------------------
677 ;; | | | | | | | |
678 ;; | lm | text | ic | text | ic | text | rm |
679 ;; | | | | | | | |
680 ;; ------------------------------------------
681
682 (defvar ps-left-margin (/ (* 72 2.0) 2.54) ; 2 cm
683 "*Left margin in points (1/72 inch).")
684
685 (defvar ps-right-margin (/ (* 72 2.0) 2.54) ; 2 cm
686 "*Right margin in points (1/72 inch).")
687
688 (defvar ps-inter-column (/ (* 72 2.0) 2.54) ; 2 cm
689 "*Horizontal space between columns in points (1/72 inch).")
690
691 ;;; Vertical layout
692
693 ;; |--------|
694 ;; | tm |
695 ;; |--------|
696 ;; | header |
697 ;; |--------|
698 ;; | ho |
699 ;; |--------|
700 ;; | text |
701 ;; |--------|
702 ;; | bm |
703 ;; |--------|
704
705 (defvar ps-bottom-margin (/ (* 72 1.5) 2.54) ; 1.5 cm
706 "*Bottom margin in points (1/72 inch).")
707
708 (defvar ps-top-margin (/ (* 72 1.5) 2.54) ; 1.5 cm
709 "*Top margin in points (1/72 inch).")
710
711 (defvar ps-header-offset (/ (* 72 1.0) 2.54) ; 1.0 cm
712 "*Vertical space in points (1/72 inch) between the main text and the header.")
713
714 (defvar ps-header-line-pad 0.15
715 "*Portion of a header title line height to insert between the header frame
716 and the text it contains, both in the vertical and horizontal directions.")
717
718 ;;; Header setup
719
720 (defvar ps-print-header t
721 "*Non-nil means print a header at the top of each page.
722 By default, the header displays the buffer name, page number, and, if
723 the buffer is visiting a file, the file's directory. Headers are
724 customizable by changing variables `ps-left-header' and
725 `ps-right-header'.")
726
727 (defvar ps-print-header-frame t
728 "*Non-nil means draw a gaudy frame around the header.")
729
730 (defvar ps-header-lines 2
731 "*Number of lines to display in page header, when generating Postscript.")
732 (make-variable-buffer-local 'ps-header-lines)
733
734 (defvar ps-show-n-of-n t
735 "*Non-nil means show page numbers as N/M, meaning page N of M.
736 Note: page numbers are displayed as part of headers, see variable
737 `ps-print-headers'.")
738
739 (defvar ps-spool-duplex nil ; Not many people have duplex
740 ; printers, so default to nil.
741 "*Non-nil indicates spooling is for a two-sided printer.
742 For a duplex printer, the `ps-spool-*' commands will insert blank pages
743 as needed between print jobs so that the next buffer printed will
744 start on the right page. Also, if headers are turned on, the headers
745 will be reversed on duplex printers so that the page numbers fall to
746 the left on even-numbered pages.")
747
748 ;;; Fonts
749
750 (defvar ps-font-info-database
751 '((Courier ; the family key
752 "Courier" "Courier-Bold" "Courier-Oblique" "Courier-BoldOblique"
753 10.0 10.55 6.0 6.0)
754 (Helvetica ; the family key
755 "Helvetica" "Helvetica-Bold" "Helvetica-Oblique" "Helvetica-BoldOblique"
756 10.0 11.56 2.78 5.09243)
757 (Times
758 "Times-Roman" "Times-Bold" "Times-Italic" "Times-BoldItalic"
759 10.0 11.0 2.5 4.71432)
760 (Palatino
761 "Palatino-Roman" "Palatino-Bold" "Palatino-Italic" "Palatino-BoldItalic"
762 10.0 12.1 2.5 5.08676)
763 (Helvetica-Narrow
764 "Helvetica-Narrow" "Helvetica-Narrow-Bold"
765 "Helvetica-Narrow-Oblique" "Helvetica-Narrow-BoldOblique"
766 10.0 11.56 2.2796 4.17579)
767 (NewCenturySchlbk
768 "NewCenturySchlbk-Roman" "NewCenturySchlbk-Bold"
769 "NewCenturySchlbk-Italic" "NewCenturySchlbk-BoldItalic"
770 10.0 12.15 2.78 5.31162)
771 ;; got no bold for the next ones
772 (AvantGarde-Book
773 "AvantGarde-Book" "AvantGarde-Book"
774 "AvantGarde-BookOblique" "AvantGarde-BookOblique"
775 10.0 11.77 2.77 5.45189)
776 (AvantGarde-Demi
777 "AvantGarde-Demi" "AvantGarde-Demi"
778 "AvantGarde-DemiOblique" "AvantGarde-DemiOblique"
779 10.0 12.72 2.8 5.51351)
780 (Bookman-Demi
781 "Bookman-Demi" "Bookman-Demi"
782 "Bookman-DemiItalic" "Bookman-DemiItalic"
783 10.0 11.77 3.4 6.05946)
784 (Bookman-Light
785 "Bookman-Light" "Bookman-Light"
786 "Bookman-LightItalic" "Bookman-LightItalic"
787 10.0 11.79 3.2 5.67027)
788 ;; got no bold and no italic for the next ones
789 (Symbol
790 "Symbol" "Symbol" "Symbol" "Symbol"
791 10.0 13.03 2.5 3.24324)
792 (Zapf-Dingbats
793 "Zapf-Dingbats" "Zapf-Dingbats" "Zapf-Dingbats" "Zapf-Dingbats"
794 10.0 9.63 2.78 2.78)
795 (Zapf-Chancery-MediumItalic
796 "Zapf-Chancery-MediumItalic" "Zapf-Chancery-MediumItalic"
797 "Zapf-Chancery-MediumItalic" "Zapf-Chancery-MediumItalic"
798 10.0 11.45 2.2 4.10811)
799 )
800 "*Font info database: font family (the key), name, bold, italic, bold-italic,
801 reference size, line height, space width, average character width.
802 To get the info for another specific font (say Helvetica), do the following:
803 - create a new buffer
804 - generate the PostScript image to a file (C-u M-x ps-print-buffer)
805 - open this file and delete the leading `%' (which is the Postscript
806 comment character) from the line
807 `% 3 cm 20 cm moveto 10 /Courier ReportFontInfo showpage'
808 to get the line
809 `3 cm 20 cm moveto 10 /Helvetica ReportFontInfo showpage'
810 - add the values to `ps-font-info-database'.
811 You can get all the fonts of YOUR printer using `ReportAllFontInfo'.")
812
813 (defvar ps-font-family 'Courier
814 "Font family name for ordinary text, when generating Postscript.")
815
816 (defvar ps-font-size (if ps-landscape-mode 7 8.5)
817 "Font size, in points, for ordinary text, when generating Postscript.")
818
819 (defvar ps-header-font-family 'Helvetica
820 "Font family name for text in the header, when generating Postscript.")
821
822 (defvar ps-header-font-size (if ps-landscape-mode 10 12)
823 "Font size, in points, for text in the header, when generating Postscript.")
824
825 (defvar ps-header-title-font-size (if ps-landscape-mode 12 14)
826 "Font size, in points, for the top line of text in the header,
827 when generating Postscript.")
828
829 ;;; Colors
830
831 (defvar ps-print-color-p (or (fboundp 'x-color-values) ; Emacs
832 (fboundp 'pixel-components)) ; XEmacs
833 ; Printing color requires x-color-values.
834 "*If non-nil, print the buffer's text in color.")
835
836 (defvar ps-default-fg '(0.0 0.0 0.0)
837 "*RGB values of the default foreground color. Defaults to black.")
838
839 (defvar ps-default-bg '(1.0 1.0 1.0)
840 "*RGB values of the default background color. Defaults to white.")
841
842 (defvar ps-auto-font-detect t
843 "*Non-nil means automatically detect bold/italic face attributes.
844 nil means rely solely on the lists `ps-bold-faces', `ps-italic-faces',
845 and `ps-underlined-faces'.")
846
847 (defvar ps-bold-faces
848 (unless ps-print-color-p
849 '(font-lock-function-name-face
850 font-lock-builtin-face
851 font-lock-variable-name-face
852 font-lock-keyword-face
853 font-lock-warning-face))
854 "*A list of the \(non-bold\) faces that should be printed in bold font.
855 This applies to generating Postscript.")
856
857 (defvar ps-italic-faces
858 (unless ps-print-color-p
859 '(font-lock-variable-name-face
860 font-lock-string-face
861 font-lock-comment-face
862 font-lock-warning-face))
863 "*A list of the \(non-italic\) faces that should be printed in italic font.
864 This applies to generating Postscript.")
865
866 (defvar ps-underlined-faces
867 (unless ps-print-color-p
868 '(font-lock-function-name-face
869 font-lock-type-face
870 font-lock-reference-face
871 font-lock-warning-face))
872 "*A list of the \(non-underlined\) faces that should be printed underlined.
873 This applies to generating Postscript.")
874
875 (defvar ps-left-header
876 (list 'ps-get-buffer-name 'ps-header-dirpart)
877 "*The items to display (each on a line) on the left part of the page header.
878 This applies to generating Postscript.
879
880 The value should be a list of strings and symbols, each representing an
881 entry in the PostScript array HeaderLinesLeft.
882
883 Strings are inserted unchanged into the array; those representing
884 PostScript string literals should be delimited with PostScript string
885 delimiters '(' and ')'.
886
887 For symbols with bound functions, the function is called and should
888 return a string to be inserted into the array. For symbols with bound
889 values, the value should be a string to be inserted into the array.
890 In either case, function or variable, the string value has PostScript
891 string delimiters added to it.")
892 (make-variable-buffer-local 'ps-left-header)
893
894 (defvar ps-right-header
895 (list "/pagenumberstring load" 'time-stamp-mon-dd-yyyy 'time-stamp-hh:mm:ss)
896 "*The items to display (each on a line) on the right part of the page header.
897 This applies to generating Postscript.
898
899 See the variable `ps-left-header' for a description of the format of
900 this variable.")
901 (make-variable-buffer-local 'ps-right-header)
902
903 (defvar ps-razzle-dazzle t
904 "*Non-nil means report progress while formatting buffer.")
905
906 (defvar ps-adobe-tag "%!PS-Adobe-1.0\n"
907 "*Contains the header line identifying the output as PostScript.
908 By default, `ps-adobe-tag' contains the standard identifier. Some
909 printers require slightly different versions of this line.")
910
911 (defvar ps-build-face-reference t
912 "*Non-nil means build the reference face lists.
913
914 Ps-print sets this value to nil after it builds its internal reference
915 lists of bold and italic faces. By settings its value back to t, you
916 can force ps-print to rebuild the lists the next time you invoke one
917 of the ...-with-faces commands.
918
919 You should set this value back to t after you change the attributes of
920 any face, or create new faces. Most users shouldn't have to worry
921 about its setting, though.")
922
923 (defvar ps-always-build-face-reference nil
924 "*Non-nil means always rebuild the reference face lists.
925
926 If this variable is non-nil, ps-print will rebuild its internal
927 reference lists of bold and italic faces *every* time one of the
928 -with-faces commands is called. Most users shouldn't need to set this
929 variable.")
930
931 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
932 ;; User commands
933
934 ;;;###autoload
935 (defun ps-print-buffer (&optional filename)
936 "Generate and print a PostScript image of the buffer.
937
938 When called with a numeric prefix argument (C-u), prompts the user for
939 the name of a file to save the PostScript image in, instead of sending
940 it to the printer.
941
942 More specifically, the FILENAME argument is treated as follows: if it
943 is nil, send the image to the printer. If FILENAME is a string, save
944 the PostScript image in a file with that name. If FILENAME is a
945 number, prompt the user for the name of the file to save in."
946
947 (interactive (list (ps-print-preprint current-prefix-arg)))
948 (ps-generate (current-buffer) (point-min) (point-max)
949 'ps-generate-postscript)
950 (ps-do-despool filename))
951
952
953 ;;;###autoload
954 (defun ps-print-buffer-with-faces (&optional filename)
955 "Generate and print a PostScript image of the buffer.
956 Like `ps-print-buffer', but includes font, color, and underline
957 information in the generated image. This command works only if you
958 are using a window system, so it has a way to determine color values."
959 (interactive (list (ps-print-preprint current-prefix-arg)))
960 (ps-generate (current-buffer) (point-min) (point-max)
961 'ps-generate-postscript-with-faces)
962 (ps-do-despool filename))
963
964
965 ;;;###autoload
966 (defun ps-print-region (from to &optional filename)
967 "Generate and print a PostScript image of the region.
968 Like `ps-print-buffer', but prints just the current region."
969
970 (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
971 (ps-generate (current-buffer) from to
972 'ps-generate-postscript)
973 (ps-do-despool filename))
974
975
976 ;;;###autoload
977 (defun ps-print-region-with-faces (from to &optional filename)
978 "Generate and print a PostScript image of the region.
979 Like `ps-print-region', but includes font, color, and underline
980 information in the generated image. This command works only if you
981 are using a window system, so it has a way to determine color values."
982
983 (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
984 (ps-generate (current-buffer) from to
985 'ps-generate-postscript-with-faces)
986 (ps-do-despool filename))
987
988
989 ;;;###autoload
990 (defun ps-spool-buffer ()
991 "Generate and spool a PostScript image of the buffer.
992 Like `ps-print-buffer' except that the PostScript image is saved in a
993 local buffer to be sent to the printer later.
994
995 Use the command `ps-despool' to send the spooled images to the printer."
996 (interactive)
997 (ps-generate (current-buffer) (point-min) (point-max)
998 'ps-generate-postscript))
999
1000
1001 ;;;###autoload
1002 (defun ps-spool-buffer-with-faces ()
1003 "Generate and spool a PostScript image of the buffer.
1004 Like `ps-spool-buffer', but includes font, color, and underline
1005 information in the generated image. This command works only if you
1006 are using a window system, so it has a way to determine color values.
1007
1008 Use the command `ps-despool' to send the spooled images to the printer."
1009
1010 (interactive)
1011 (ps-generate (current-buffer) (point-min) (point-max)
1012 'ps-generate-postscript-with-faces))
1013
1014
1015 ;;;###autoload
1016 (defun ps-spool-region (from to)
1017 "Generate a PostScript image of the region and spool locally.
1018 Like `ps-spool-buffer', but spools just the current region.
1019
1020 Use the command `ps-despool' to send the spooled images to the printer."
1021 (interactive "r")
1022 (ps-generate (current-buffer) from to
1023 'ps-generate-postscript))
1024
1025
1026 ;;;###autoload
1027 (defun ps-spool-region-with-faces (from to)
1028 "Generate a PostScript image of the region and spool locally.
1029 Like `ps-spool-region', but includes font, color, and underline
1030 information in the generated image. This command works only if you
1031 are using a window system, so it has a way to determine color values.
1032
1033 Use the command `ps-despool' to send the spooled images to the printer."
1034 (interactive "r")
1035 (ps-generate (current-buffer) from to
1036 'ps-generate-postscript-with-faces))
1037
1038 ;;;###autoload
1039 (defun ps-despool (&optional filename)
1040 "Send the spooled PostScript to the printer.
1041
1042 When called with a numeric prefix argument (C-u), prompt the user for
1043 the name of a file to save the spooled PostScript in, instead of sending
1044 it to the printer.
1045
1046 More specifically, the FILENAME argument is treated as follows: if it
1047 is nil, send the image to the printer. If FILENAME is a string, save
1048 the PostScript image in a file with that name. If FILENAME is a
1049 number, prompt the user for the name of the file to save in."
1050 (interactive (list (ps-print-preprint current-prefix-arg)))
1051 (ps-do-despool filename))
1052
1053 ;;;###autoload
1054 (defun ps-line-lengths ()
1055 "*Display the correspondance between a line length and a font size,
1056 using the current ps-print setup.
1057 Try: pr -t file | awk '{printf \"%3d %s\n\", length($0), $0}' | sort -r | head"
1058 (interactive)
1059 (ps-line-lengths-internal))
1060
1061 ;;;###autoload
1062 (defun ps-nb-pages-buffer (nb-lines)
1063 "*Display an approximate correspondance between a font size and the number
1064 of pages the current buffer would require to print
1065 using the current ps-print setup."
1066 (interactive (list (count-lines (point-min) (point-max))))
1067 (ps-nb-pages nb-lines))
1068
1069 ;;;###autoload
1070 (defun ps-nb-pages-region (nb-lines)
1071 "*Display an approximate correspondance between a font size and the number
1072 of pages the current region would require to print
1073 using the current ps-print setup."
1074 (interactive (list (count-lines (mark) (point))))
1075 (ps-nb-pages nb-lines))
1076
1077 ;;;###autoload
1078 (defun ps-setup ()
1079 "*Return the current setup"
1080 (format "
1081 (setq ps-print-color-p %s
1082 ps-lpr-command \"%s\"
1083 ps-lpr-switches %s
1084
1085 ps-paper-type '%s
1086 ps-landscape-mode %s
1087 ps-number-of-columns %s
1088
1089 ps-left-margin %s
1090 ps-right-margin %s
1091 ps-inter-column %s
1092 ps-bottom-margin %s
1093 ps-top-margin %s
1094 ps-header-offset %s
1095 ps-header-line-pad %s
1096 ps-print-header %s
1097 ps-print-header-frame %s
1098 ps-header-lines %s
1099 ps-show-n-of-n %s
1100 ps-spool-duplex %s
1101
1102 ps-font-family '%s
1103 ps-font-size %s
1104 ps-header-font-family '%s
1105 ps-header-font-size %s
1106 ps-header-title-font-size %s)
1107 "
1108 ps-print-color-p
1109 ps-lpr-command
1110 ps-lpr-switches
1111 ps-paper-type
1112 ps-landscape-mode
1113 ps-number-of-columns
1114 ps-left-margin
1115 ps-right-margin
1116 ps-inter-column
1117 ps-bottom-margin
1118 ps-top-margin
1119 ps-header-offset
1120 ps-header-line-pad
1121 ps-print-header
1122 ps-print-header-frame
1123 ps-header-lines
1124 ps-show-n-of-n
1125 ps-spool-duplex
1126 ps-font-family
1127 ps-font-size
1128 ps-header-font-family
1129 ps-header-font-size
1130 ps-header-title-font-size))
1131
1132 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1133 ;; Utility functions and variables:
1134
1135 (defvar ps-print-emacs-type
1136 (cond ((string-match "XEmacs" emacs-version) 'xemacs)
1137 ((string-match "Lucid" emacs-version) 'lucid)
1138 ((string-match "Epoch" emacs-version) 'epoch)
1139 (t 'emacs)))
1140
1141 (if (or (eq ps-print-emacs-type 'lucid)
1142 (eq ps-print-emacs-type 'xemacs))
1143 (if (< emacs-minor-version 12)
1144 (setq ps-print-color-p nil))
1145 (require 'faces)) ; face-font, face-underline-p,
1146 ; x-font-regexp
1147
1148 (require 'time-stamp)
1149
1150 (defvar ps-font nil
1151 "Font family name for ordinary text, when generating Postscript.")
1152
1153 (defvar ps-font-bold nil
1154 "Font family name for bold text, when generating Postscript.")
1155
1156 (defvar ps-font-italic nil
1157 "Font family name for italic text, when generating Postscript.")
1158
1159 (defvar ps-font-bold-italic nil
1160 "Font family name for bold italic text, when generating Postscript.")
1161
1162 (defvar ps-avg-char-width nil
1163 "The average width, in points, of a character, for generating Postscript.
1164 This is the value that ps-print uses to determine the length,
1165 x-dimension, of the text it has printed, and thus affects the point at
1166 which long lines wrap around.")
1167
1168 (defvar ps-space-width nil
1169 "The width of a space character, for generating Postscript.
1170 This value is used in expanding tab characters.")
1171
1172 (defvar ps-line-height nil
1173 "The height of a line, for generating Postscript.
1174 This is the value that ps-print uses to determine the height,
1175 y-dimension, of the lines of text it has printed, and thus affects the
1176 point at which page-breaks are placed.
1177 The line-height is *not* the same as the point size of the font.")
1178
1179 (defvar ps-print-prologue-1
1180 "% ISOLatin1Encoding stolen from ps_init.ps in GhostScript 2.6.1.4:
1181 /ISOLatin1Encoding where { pop } {
1182 % -- The ISO Latin-1 encoding vector isn't known, so define it.
1183 % -- The first half is the same as the standard encoding,
1184 % -- except for minus instead of hyphen at code 055.
1185 /ISOLatin1Encoding
1186 StandardEncoding 0 45 getinterval aload pop
1187 /minus
1188 StandardEncoding 46 82 getinterval aload pop
1189 %*** NOTE: the following are missing in the Adobe documentation,
1190 %*** but appear in the displayed table:
1191 %*** macron at 0225, dieresis at 0230, cedilla at 0233, space at 0240.
1192 % 0200 (128)
1193 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
1194 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
1195 /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent
1196 /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron
1197 % 0240 (160)
1198 /space /exclamdown /cent /sterling
1199 /currency /yen /brokenbar /section
1200 /dieresis /copyright /ordfeminine /guillemotleft
1201 /logicalnot /hyphen /registered /macron
1202 /degree /plusminus /twosuperior /threesuperior
1203 /acute /mu /paragraph /periodcentered
1204 /cedilla /onesuperior /ordmasculine /guillemotright
1205 /onequarter /onehalf /threequarters /questiondown
1206 % 0300 (192)
1207 /Agrave /Aacute /Acircumflex /Atilde
1208 /Adieresis /Aring /AE /Ccedilla
1209 /Egrave /Eacute /Ecircumflex /Edieresis
1210 /Igrave /Iacute /Icircumflex /Idieresis
1211 /Eth /Ntilde /Ograve /Oacute
1212 /Ocircumflex /Otilde /Odieresis /multiply
1213 /Oslash /Ugrave /Uacute /Ucircumflex
1214 /Udieresis /Yacute /Thorn /germandbls
1215 % 0340 (224)
1216 /agrave /aacute /acircumflex /atilde
1217 /adieresis /aring /ae /ccedilla
1218 /egrave /eacute /ecircumflex /edieresis
1219 /igrave /iacute /icircumflex /idieresis
1220 /eth /ntilde /ograve /oacute
1221 /ocircumflex /otilde /odieresis /divide
1222 /oslash /ugrave /uacute /ucircumflex
1223 /udieresis /yacute /thorn /ydieresis
1224 256 packedarray def
1225 } ifelse
1226
1227 /reencodeFontISO { %def
1228 dup
1229 length 5 add dict % Make a new font (a new dict the same size
1230 % as the old one) with room for our new symbols.
1231
1232 begin % Make the new font the current dictionary.
1233
1234
1235 { 1 index /FID ne
1236 { def } { pop pop } ifelse
1237 } forall % Copy each of the symbols from the old dictionary
1238 % to the new one except for the font ID.
1239
1240 /Encoding ISOLatin1Encoding def % Override the encoding with
1241 % the ISOLatin1 encoding.
1242
1243 % Use the font's bounding box to determine the ascent, descent,
1244 % and overall height; don't forget that these values have to be
1245 % transformed using the font's matrix.
1246
1247 % ^ (x2 y2)
1248 % | |
1249 % | v
1250 % | +----+ - -
1251 % | | | ^
1252 % | | | | Ascent (usually > 0)
1253 % | | | |
1254 % (0 0) -> +--+----+-------->
1255 % | | |
1256 % | | v Descent (usually < 0)
1257 % (x1 y1) --> +----+ - -
1258
1259 FontBBox % -- x1 y1 x2 y2
1260 FontMatrix transform /Ascent exch def pop
1261 FontMatrix transform /Descent exch def pop
1262 /FontHeight Ascent Descent sub def % use `sub' because descent < 0
1263
1264 % Define these in case they're not in the FontInfo
1265 % (also, here they're easier to get to.
1266 /UnderlinePosition 1 def
1267 /UnderlineThickness 1 def
1268
1269 % Get the underline position and thickness if they're defined.
1270 currentdict /FontInfo known {
1271 FontInfo
1272
1273 dup /UnderlinePosition known {
1274 dup /UnderlinePosition get
1275 0 exch FontMatrix transform exch pop
1276 /UnderlinePosition exch def
1277 } if
1278
1279 dup /UnderlineThickness known {
1280 /UnderlineThickness get
1281 0 exch FontMatrix transform exch pop
1282 /UnderlineThickness exch def
1283 } if
1284
1285 } if
1286
1287 currentdict % Leave the new font on the stack
1288 end % Stop using the font as the current dictionary.
1289 definefont % Put the font into the font dictionary
1290 pop % Discard the returned font.
1291 } bind def
1292
1293 /DefFont { % Font definition
1294 findfont exch scalefont reencodeFontISO
1295 } def
1296
1297 /F { % Font selection
1298 findfont
1299 dup /Ascent get /Ascent exch def
1300 dup /Descent get /Descent exch def
1301 dup /FontHeight get /FontHeight exch def
1302 dup /UnderlinePosition get /UnderlinePosition exch def
1303 dup /UnderlineThickness get /UnderlineThickness exch def
1304 setfont
1305 } def
1306
1307 /FG /setrgbcolor load def
1308
1309 /bg false def
1310 /BG {
1311 dup /bg exch def
1312 { mark 4 1 roll ] /bgcolor exch def } if
1313 } def
1314
1315 % B width C
1316 % +-----------+
1317 % | Ascent (usually > 0)
1318 % A + +
1319 % | Descent (usually < 0)
1320 % +-----------+
1321 % E width D
1322
1323 /dobackground { % width --
1324 currentpoint % -- width x y
1325 gsave
1326 newpath
1327 moveto % A (x y)
1328 0 Ascent rmoveto % B
1329 dup 0 rlineto % C
1330 0 Descent Ascent sub rlineto % D
1331 neg 0 rlineto % E
1332 closepath
1333 bgcolor aload pop setrgbcolor
1334 fill
1335 grestore
1336 } def
1337
1338 /dobackgroundstring { % string --
1339 stringwidth pop
1340 dobackground
1341 } def
1342
1343 /dounderline { % fromx fromy --
1344 currentpoint
1345 gsave
1346 UnderlineThickness setlinewidth
1347 4 2 roll
1348 UnderlinePosition add moveto
1349 UnderlinePosition add lineto
1350 stroke
1351 grestore
1352 } def
1353
1354 /eolbg { % dobackground until right margin
1355 PrintWidth % -- x-eol
1356 currentpoint pop % -- cur-x
1357 sub % -- width until eol
1358 dobackground
1359 } def
1360
1361 /eolul { % idem for underline
1362 PrintWidth % -- x-eol
1363 currentpoint exch pop % -- x-eol cur-y
1364 dounderline
1365 } def
1366
1367 /SL { % Soft Linefeed
1368 bg { eolbg } if
1369 ul { eolul } if
1370 0 currentpoint exch pop LineHeight sub moveto
1371 } def
1372
1373 /HL /SL load def % Hard Linefeed
1374
1375 /sp1 { currentpoint 3 -1 roll } def
1376
1377 % Some debug
1378 /dcp { currentpoint exch 40 string cvs print (, ) print = } def
1379 /dp { print 2 copy
1380 exch 40 string cvs print (, ) print = } def
1381
1382 /S {
1383 bg { dup dobackgroundstring } if
1384 ul { sp1 } if
1385 show
1386 ul { dounderline } if
1387 } def
1388
1389 /W {
1390 ul { sp1 } if
1391 ( ) stringwidth % Get the width of a space in the current font.
1392 pop % Discard the Y component.
1393 mul % Multiply the width of a space
1394 % by the number of spaces to plot
1395 bg { dup dobackground } if
1396 0 rmoveto
1397 ul { dounderline } if
1398 } def
1399
1400 /BeginDoc {
1401 % ---- save the state of the document (useful for ghostscript!)
1402 /docState save def
1403 % ---- [jack] Kludge: my ghostscript window is 21x27.7 instead of 21x29.7
1404 /JackGhostscript where {
1405 pop 1 27.7 29.7 div scale
1406 } if
1407 LandscapeMode {
1408 % ---- translate to bottom-right corner of Portrait page
1409 LandscapePageHeight 0 translate
1410 90 rotate
1411 } if
1412 /ColumnWidth PrintWidth InterColumn add def
1413 % ---- translate to lower left corner of TEXT
1414 LeftMargin BottomMargin translate
1415 % ---- define where printing will start
1416 /f0 F % this installs Ascent
1417 /PrintStartY PrintHeight Ascent sub def
1418 /ColumnIndex 1 def
1419 } def
1420
1421 /EndDoc {
1422 % ---- on last page but not last column, spit out the page
1423 ColumnIndex 1 eq not { showpage } if
1424 % ---- restore the state of the document (useful for ghostscript!)
1425 docState restore
1426 } def
1427
1428 /BeginDSCPage {
1429 % ---- when 1st column, save the state of the page
1430 ColumnIndex 1 eq { /pageState save def } if
1431 % ---- save the state of the column
1432 /columnState save def
1433 } def
1434
1435 /BeginPage {
1436 PrintHeader {
1437 PrintHeaderFrame { HeaderFrame } if
1438 HeaderText
1439 } if
1440 0 PrintStartY moveto % move to where printing will start
1441 } def
1442
1443 /EndPage {
1444 bg { eolbg } if
1445 ul { eolul } if
1446 } def
1447
1448 /EndDSCPage {
1449 ColumnIndex NumberOfColumns eq {
1450 % ---- on last column, spit out the page
1451 showpage
1452 % ---- restore the state of the page
1453 pageState restore
1454 /ColumnIndex 1 def
1455 } { % else
1456 % ---- restore the state of the current column
1457 columnState restore
1458 % ---- and translate to the next column
1459 ColumnWidth 0 translate
1460 /ColumnIndex ColumnIndex 1 add def
1461 } ifelse
1462 } def
1463
1464 /ul false def
1465
1466 /UL { /ul exch def } def
1467
1468 /SetHeaderLines { % nb-lines --
1469 /HeaderLines exch def
1470 % ---- bottom up
1471 HeaderPad
1472 HeaderLines 1 sub HeaderLineHeight mul add
1473 HeaderTitleLineHeight add
1474 HeaderPad add
1475 /HeaderHeight exch def
1476 } def
1477
1478 % |---------|
1479 % | tm |
1480 % |---------|
1481 % | header |
1482 % |-+-------| <-- (x y)
1483 % | ho |
1484 % |---------|
1485 % | text |
1486 % |-+-------| <-- (0 0)
1487 % | bm |
1488 % |---------|
1489
1490 /HeaderFrameStart { % -- x y
1491 0 PrintHeight HeaderOffset add
1492 } def
1493
1494 /HeaderFramePath {
1495 PrintWidth 0 rlineto
1496 0 HeaderHeight rlineto
1497 PrintWidth neg 0 rlineto
1498 0 HeaderHeight neg rlineto
1499 } def
1500
1501 /HeaderFrame {
1502 gsave
1503 0.4 setlinewidth
1504 % ---- fill a black rectangle (the shadow of the next one)
1505 HeaderFrameStart moveto
1506 1 -1 rmoveto
1507 HeaderFramePath
1508 0 setgray fill
1509 % ---- do the next rectangle ...
1510 HeaderFrameStart moveto
1511 HeaderFramePath
1512 gsave 0.9 setgray fill grestore % filled with grey
1513 gsave 0 setgray stroke grestore % drawn with black
1514 grestore
1515 } def
1516
1517 /HeaderStart {
1518 HeaderFrameStart
1519 exch HeaderPad add exch % horizontal pad
1520 % ---- bottom up
1521 HeaderPad add % vertical pad
1522 HeaderDescent sub
1523 HeaderLineHeight HeaderLines 1 sub mul add
1524 } def
1525
1526 /strcat {
1527 dup length 3 -1 roll dup length dup 4 -1 roll add string dup
1528 0 5 -1 roll putinterval
1529 dup 4 2 roll exch putinterval
1530 } def
1531
1532 /pagenumberstring {
1533 PageNumber 32 string cvs
1534 ShowNofN {
1535 (/) strcat
1536 PageCount 32 string cvs strcat
1537 } if
1538 } def
1539
1540 /HeaderText {
1541 HeaderStart moveto
1542
1543 HeaderLinesRight HeaderLinesLeft % -- rightLines leftLines
1544
1545 % ---- hack: `PN 1 and' == `PN 2 modulo'
1546
1547 % ---- if duplex and even page number, then exchange left and right
1548 Duplex PageNumber 1 and 0 eq and { exch } if
1549
1550 { % ---- process the left lines
1551 aload pop
1552 exch F
1553 gsave
1554 dup xcheck { exec } if
1555 show
1556 grestore
1557 0 HeaderLineHeight neg rmoveto
1558 } forall
1559
1560 HeaderStart moveto
1561
1562 { % ---- process the right lines
1563 aload pop
1564 exch F
1565 gsave
1566 dup xcheck { exec } if
1567 dup stringwidth pop
1568 PrintWidth exch sub HeaderPad 2 mul sub 0 rmoveto
1569 show
1570 grestore
1571 0 HeaderLineHeight neg rmoveto
1572 } forall
1573 } def
1574
1575 /ReportFontInfo {
1576 2 copy
1577 /t0 3 1 roll DefFont
1578 /t0 F
1579 /lh FontHeight def
1580 /sw ( ) stringwidth pop def
1581 /aw (01234567890abcdefghijklmnopqrstuvwxyz) dup length exch
1582 stringwidth pop exch div def
1583 /t1 12 /Helvetica-Oblique DefFont
1584 /t1 F
1585 gsave
1586 (For ) show
1587 128 string cvs show
1588 ( ) show
1589 32 string cvs show
1590 ( point, the line height is ) show
1591 lh 32 string cvs show
1592 (, the space width is ) show
1593 sw 32 string cvs show
1594 (,) show
1595 grestore
1596 0 FontHeight neg rmoveto
1597 gsave
1598 (and a crude estimate of average character width is ) show
1599 aw 32 string cvs show
1600 (.) show
1601 grestore
1602 0 FontHeight neg rmoveto
1603 } def
1604
1605 /cm { % cm to point
1606 72 mul 2.54 div
1607 } def
1608
1609 /ReportAllFontInfo {
1610 FontDirectory
1611 { % key = font name value = font dictionary
1612 pop 10 exch ReportFontInfo
1613 } forall
1614 } def
1615
1616 % 3 cm 20 cm moveto 10 /Courier ReportFontInfo showpage
1617 % 3 cm 20 cm moveto ReportAllFontInfo showpage
1618
1619 ")
1620
1621 (defvar ps-print-prologue-2
1622 "
1623 % ---- These lines must be kept together because...
1624
1625 /h0 F
1626 /HeaderTitleLineHeight FontHeight def
1627
1628 /h1 F
1629 /HeaderLineHeight FontHeight def
1630 /HeaderDescent Descent def
1631
1632 % ---- ...because `F' has a side-effect on `FontHeight' and `Descent'
1633
1634 ")
1635
1636 ;; Start Editing Here:
1637
1638 (defvar ps-source-buffer nil)
1639 (defvar ps-spool-buffer-name "*PostScript*")
1640 (defvar ps-spool-buffer nil)
1641
1642 (defvar ps-output-head nil)
1643 (defvar ps-output-tail nil)
1644
1645 (defvar ps-page-count 0)
1646 (defvar ps-showpage-count 0)
1647
1648 (defvar ps-current-font 0)
1649 (defvar ps-current-underline-p nil)
1650 (defvar ps-default-color (if ps-print-color-p ps-default-fg)) ; black
1651 (defvar ps-current-color ps-default-color)
1652 (defvar ps-current-bg nil)
1653
1654 (defvar ps-razchunk 0)
1655
1656 (defvar ps-color-format
1657 (if (eq ps-print-emacs-type 'emacs)
1658
1659 ;;Emacs understands the %f format; we'll
1660 ;;use it to limit color RGB values to
1661 ;;three decimals to cut down some on the
1662 ;;size of the PostScript output.
1663 "%0.3f %0.3f %0.3f"
1664
1665 ;; Lucid emacsen will have to make do with
1666 ;; %s (princ) for floats.
1667 "%s %s %s"))
1668
1669 ;; These values determine how much print-height to deduct when headers
1670 ;; are turned on. This is a pretty clumsy way of handling it, but
1671 ;; it'll do for now.
1672
1673 (defvar ps-header-font)
1674 (defvar ps-header-title-font)
1675
1676 (defvar ps-header-line-height)
1677 (defvar ps-header-title-line-height)
1678 (defvar ps-header-pad 0
1679 "Vertical and horizontal space in points (1/72 inch) between the header frame
1680 and the text it contains.")
1681
1682 ;; Define accessors to the dimensions list.
1683
1684 (defmacro ps-page-dimensions-get-width (dims) `(nth 0 ,dims))
1685 (defmacro ps-page-dimensions-get-height (dims) `(nth 1 ,dims))
1686
1687 (defvar ps-landscape-page-height)
1688
1689 (defvar ps-print-width nil)
1690 (defvar ps-print-height nil)
1691
1692 (defvar ps-height-remaining)
1693 (defvar ps-width-remaining)
1694
1695 (defvar ps-ref-bold-faces nil)
1696 (defvar ps-ref-italic-faces nil)
1697 (defvar ps-ref-underlined-faces nil)
1698
1699 (defvar ps-print-color-scale nil)
1700
1701 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1702 ;; Internal functions
1703
1704 (defun ps-line-lengths-internal ()
1705 "Display the correspondance between a line length and a font size,
1706 using the current ps-print setup.
1707 Try: pr -t file | awk '{printf \"%3d %s\n\", length($0), $0}' | sort -r | head"
1708 (let ((buf (get-buffer-create "*Line-lengths*"))
1709 (ifs ps-font-size) ; initial font size
1710 (icw ps-avg-char-width) ; initial character width
1711 (print-width (progn (ps-get-page-dimensions)
1712 ps-print-width))
1713 (ps-setup (ps-setup)) ; setup for the current buffer
1714 (fs-min 5) ; minimum font size
1715 cw-min ; minimum character width
1716 nb-cpl-max ; maximum nb of characters per line
1717 (fs-max 14) ; maximum font size
1718 cw-max ; maximum character width
1719 nb-cpl-min ; minimum nb of characters per line
1720 fs ; current font size
1721 cw ; current character width
1722 nb-cpl ; current nb of characters per line
1723 )
1724 (setq cw-min (/ (* icw fs-min) ifs)
1725 nb-cpl-max (floor (/ print-width cw-min))
1726 cw-max (/ (* icw fs-max) ifs)
1727 nb-cpl-min (floor (/ print-width cw-max)))
1728 (setq nb-cpl nb-cpl-min)
1729 (set-buffer buf)
1730 (goto-char (point-max))
1731 (if (not (bolp)) (insert "\n"))
1732 (insert ps-setup)
1733 (insert "nb char per line / font size\n")
1734 (while (<= nb-cpl nb-cpl-max)
1735 (setq cw (/ print-width (float nb-cpl))
1736 fs (/ (* ifs cw) icw))
1737 (insert (format "%3s %s\n" nb-cpl fs))
1738 (setq nb-cpl (1+ nb-cpl)))
1739 (insert "\n")
1740 (display-buffer buf 'not-this-window)))
1741
1742 (defun ps-nb-pages (nb-lines)
1743 "Display an approximate correspondance between a font size and the number
1744 of pages the number of lines would require to print
1745 using the current ps-print setup."
1746 (let ((buf (get-buffer-create "*Nb-Pages*"))
1747 (ifs ps-font-size) ; initial font size
1748 (ilh ps-line-height) ; initial line height
1749 (page-height (progn (ps-get-page-dimensions)
1750 ps-print-height))
1751 (ps-setup (ps-setup)) ; setup for the current buffer
1752 (fs-min 4) ; minimum font size
1753 lh-min ; minimum line height
1754 nb-lpp-max ; maximum nb of lines per page
1755 nb-page-min ; minimum nb of pages
1756 (fs-max 14) ; maximum font size
1757 lh-max ; maximum line height
1758 nb-lpp-min ; minimum nb of lines per page
1759 nb-page-max ; maximum nb of pages
1760 fs ; current font size
1761 lh ; current line height
1762 nb-lpp ; current nb of lines per page
1763 nb-page ; current nb of pages
1764 )
1765 (setq lh-min (/ (* ilh fs-min) ifs)
1766 nb-lpp-max (floor (/ page-height lh-min))
1767 nb-page-min (ceiling (/ (float nb-lines) nb-lpp-max))
1768 lh-max (/ (* ilh fs-max) ifs)
1769 nb-lpp-min (floor (/ page-height lh-max))
1770 nb-page-max (ceiling (/ (float nb-lines) nb-lpp-min)))
1771 (setq nb-page nb-page-min)
1772 (set-buffer buf)
1773 (goto-char (point-max))
1774 (if (not (bolp)) (insert "\n"))
1775 (insert ps-setup)
1776 (insert (format "%d lines\n" nb-lines))
1777 (insert "nb page / font size\n")
1778 (while (<= nb-page nb-page-max)
1779 (setq nb-lpp (ceiling (/ nb-lines (float nb-page)))
1780 lh (/ page-height nb-lpp)
1781 fs (/ (* ifs lh) ilh))
1782 (insert (format "%s %s\n" nb-page fs))
1783 (setq nb-page (1+ nb-page)))
1784 (insert "\n")
1785 (display-buffer buf 'not-this-window)))
1786
1787 (defun ps-select-font ()
1788 "Choose the font name and size (scaling data)."
1789 (let ((assoc (assq ps-font-family ps-font-info-database))
1790 l fn fb fi bi sz lh sw aw)
1791 (if (null assoc)
1792 (error "Don't have data to scale font %s. Known fonts families are %s"
1793 ps-font-family
1794 (mapcar 'car ps-font-info-database)))
1795 (setq l (cdr assoc)
1796 fn (prog1 (car l) (setq l (cdr l))) ; need `pop'
1797 fb (prog1 (car l) (setq l (cdr l)))
1798 fi (prog1 (car l) (setq l (cdr l)))
1799 bi (prog1 (car l) (setq l (cdr l)))
1800 sz (prog1 (car l) (setq l (cdr l)))
1801 lh (prog1 (car l) (setq l (cdr l)))
1802 sw (prog1 (car l) (setq l (cdr l)))
1803 aw (prog1 (car l) (setq l (cdr l))))
1804
1805 (setq ps-font fn)
1806 (setq ps-font-bold fb)
1807 (setq ps-font-italic fi)
1808 (setq ps-font-bold-italic bi)
1809 ;; These data just need to be rescaled:
1810 (setq ps-line-height (/ (* lh ps-font-size) sz))
1811 (setq ps-space-width (/ (* sw ps-font-size) sz))
1812 (setq ps-avg-char-width (/ (* aw ps-font-size) sz))
1813 ps-font-family))
1814
1815 (defun ps-select-header-font ()
1816 "Choose the font name and size (scaling data) for the header."
1817 (let ((assoc (assq ps-header-font-family ps-font-info-database))
1818 l fn fb fi bi sz lh sw aw)
1819 (if (null assoc)
1820 (error "Don't have data to scale font %s. Known fonts families are %s"
1821 ps-font-family
1822 (mapcar 'car ps-font-info-database)))
1823 (setq l (cdr assoc)
1824 fn (prog1 (car l) (setq l (cdr l))) ; need `pop'
1825 fb (prog1 (car l) (setq l (cdr l)))
1826 fi (prog1 (car l) (setq l (cdr l)))
1827 bi (prog1 (car l) (setq l (cdr l)))
1828 sz (prog1 (car l) (setq l (cdr l)))
1829 lh (prog1 (car l) (setq l (cdr l)))
1830 sw (prog1 (car l) (setq l (cdr l)))
1831 aw (prog1 (car l) (setq l (cdr l))))
1832
1833 ;; Font name
1834 (setq ps-header-font fn)
1835 (setq ps-header-title-font fb)
1836 ;; Line height: These data just need to be rescaled:
1837 (setq ps-header-title-line-height (/ (* lh ps-header-title-font-size) sz))
1838 (setq ps-header-line-height (/ (* lh ps-header-font-size) sz))
1839 ps-header-font-family))
1840
1841 (defun ps-get-page-dimensions ()
1842 (let ((page-dimensions (cdr (assq ps-paper-type ps-page-dimensions-database)))
1843 page-width page-height)
1844 (cond
1845 ((null page-dimensions)
1846 (error "`ps-paper-type' must be one of:\n%s"
1847 (mapcar 'car ps-page-dimensions-database)))
1848 ((< ps-number-of-columns 1)
1849 (error "The number of columns %d should not be negative")))
1850
1851 (ps-select-font)
1852 (ps-select-header-font)
1853
1854 (setq page-width (ps-page-dimensions-get-width page-dimensions)
1855 page-height (ps-page-dimensions-get-height page-dimensions))
1856
1857 ;; Landscape mode
1858 (if ps-landscape-mode
1859 ;; exchange width and height
1860 (setq page-width (prog1 page-height (setq page-height page-width))))
1861
1862 ;; It is used to get the lower right corner (only in landscape mode)
1863 (setq ps-landscape-page-height page-height)
1864
1865 ;; | lm | text | ic | text | ic | text | rm |
1866 ;; page-width == lm + n * pw + (n - 1) * ic + rm
1867 ;; => pw == (page-width - lm -rm - (n - 1) * ic) / n
1868 (setq ps-print-width
1869 (/ (- page-width
1870 ps-left-margin ps-right-margin
1871 (* (1- ps-number-of-columns) ps-inter-column))
1872 ps-number-of-columns))
1873 (if (<= ps-print-width 0)
1874 (error "Bad horizontal layout:
1875 page-width == %s
1876 ps-left-margin == %s
1877 ps-right-margin == %s
1878 ps-inter-column == %s
1879 ps-number-of-columns == %s
1880 | lm | text | ic | text | ic | text | rm |
1881 page-width == lm + n * print-width + (n - 1) * ic + rm
1882 => print-width == %d !"
1883 page-width
1884 ps-left-margin
1885 ps-right-margin
1886 ps-inter-column
1887 ps-number-of-columns
1888 ps-print-width))
1889
1890 (setq ps-print-height
1891 (- page-height ps-bottom-margin ps-top-margin))
1892 (if (<= ps-print-height 0)
1893 (error "Bad vertical layout:
1894 ps-top-margin == %s
1895 ps-bottom-margin == %s
1896 page-height == bm + print-height + tm
1897 => print-height == %d !"
1898 ps-top-margin
1899 ps-bottom-margin
1900 ps-print-height))
1901 ;; If headers are turned on, deduct the height of the header from
1902 ;; the print height.
1903 (cond
1904 (ps-print-header
1905 (setq ps-header-pad
1906 (* ps-header-line-pad ps-header-title-line-height))
1907 (setq ps-print-height
1908 (- ps-print-height
1909 ps-header-offset
1910 ps-header-pad
1911 ps-header-title-line-height
1912 (* ps-header-line-height (- ps-header-lines 1))
1913 ps-header-pad))))
1914 (if (<= ps-print-height 0)
1915 (error "Bad vertical layout:
1916 ps-top-margin == %s
1917 ps-bottom-margin == %s
1918 ps-header-offset == %s
1919 ps-header-pad == %s
1920 header-height == %s
1921 page-height == bm + print-height + tm - ho - hh
1922 => print-height == %d !"
1923 ps-top-margin
1924 ps-bottom-margin
1925 ps-header-offset
1926 ps-header-pad
1927 (+ ps-header-pad
1928 ps-header-title-line-height
1929 (* ps-header-line-height (- ps-header-lines 1))
1930 ps-header-pad)
1931 ps-print-height))))
1932
1933 (defun ps-print-preprint (&optional filename)
1934 (if (and filename
1935 (or (numberp filename)
1936 (listp filename)))
1937 (let* ((name (concat (buffer-name) ".ps"))
1938 (prompt (format "Save PostScript to file: (default %s) "
1939 name))
1940 (res (read-file-name prompt default-directory name nil)))
1941 (if (file-directory-p res)
1942 (expand-file-name name (file-name-as-directory res))
1943 res))))
1944
1945 ;; The following functions implement a simple list-buffering scheme so
1946 ;; that ps-print doesn't have to repeatedly switch between buffers
1947 ;; while spooling. The functions ps-output and ps-output-string build
1948 ;; up the lists; the function ps-flush-output takes the lists and
1949 ;; insert its contents into the spool buffer (*PostScript*).
1950
1951 (defun ps-output-string-prim (string)
1952 (insert "(") ;insert start-string delimiter
1953 (save-excursion ;insert string
1954 (insert string))
1955
1956 ;; Find and quote special characters as necessary for PS
1957 (while (re-search-forward "[()\\]" nil t)
1958 (save-excursion
1959 (forward-char -1)
1960 (insert "\\")))
1961
1962 (goto-char (point-max))
1963 (insert ")")) ;insert end-string delimiter
1964
1965 (defun ps-init-output-queue ()
1966 (setq ps-output-head (list ""))
1967 (setq ps-output-tail ps-output-head))
1968
1969 (defun ps-output (&rest args)
1970 (setcdr ps-output-tail args)
1971 (while (cdr ps-output-tail)
1972 (setq ps-output-tail (cdr ps-output-tail))))
1973
1974 (defun ps-output-string (string)
1975 (ps-output t string))
1976
1977 (defun ps-flush-output ()
1978 (save-excursion
1979 (set-buffer ps-spool-buffer)
1980 (goto-char (point-max))
1981 (while ps-output-head
1982 (let ((it (car ps-output-head)))
1983 (if (not (eq t it))
1984 (insert it)
1985 (setq ps-output-head (cdr ps-output-head))
1986 (ps-output-string-prim (car ps-output-head))))
1987 (setq ps-output-head (cdr ps-output-head))))
1988 (ps-init-output-queue))
1989
1990 (defun ps-insert-file (fname)
1991 (ps-flush-output)
1992
1993 ;; Check to see that the file exists and is readable; if not, throw
1994 ;; and error.
1995 (if (not (file-readable-p fname))
1996 (error "Could not read file `%s'" fname))
1997
1998 (save-excursion
1999 (set-buffer ps-spool-buffer)
2000 (goto-char (point-max))
2001 (insert-file fname)))
2002
2003 ;; These functions insert the arrays that define the contents of the
2004 ;; headers.
2005
2006 (defun ps-generate-header-line (fonttag &optional content)
2007 (ps-output " [ " fonttag " ")
2008 (cond
2009 ;; Literal strings should be output as is -- the string must
2010 ;; contain its own PS string delimiters, '(' and ')', if necessary.
2011 ((stringp content)
2012 (ps-output content))
2013
2014 ;; Functions are called -- they should return strings; they will be
2015 ;; inserted as strings and the PS string delimiters added.
2016 ((and (symbolp content) (fboundp content))
2017 (ps-output-string (funcall content)))
2018
2019 ;; Variables will have their contents inserted. They should
2020 ;; contain strings, and will be inserted as strings.
2021 ((and (symbolp content) (boundp content))
2022 (ps-output-string (symbol-value content)))
2023
2024 ;; Anything else will get turned into an empty string.
2025 (t
2026 (ps-output-string "")))
2027 (ps-output " ]\n"))
2028
2029 (defun ps-generate-header (name contents)
2030 (ps-output "/" name " [\n")
2031 (if (> ps-header-lines 0)
2032 (let ((count 1))
2033 (ps-generate-header-line "/h0" (car contents))
2034 (while (and (< count ps-header-lines)
2035 (setq contents (cdr contents)))
2036 (ps-generate-header-line "/h1" (car contents))
2037 (setq count (+ count 1)))
2038 (ps-output "] def\n"))))
2039
2040 (defun ps-output-boolean (name bool)
2041 (ps-output (format "/%s %s def\n" name (if bool "true" "false"))))
2042
2043 (defun ps-begin-file ()
2044 (ps-get-page-dimensions)
2045 (setq ps-showpage-count 0)
2046
2047 (ps-output ps-adobe-tag)
2048 (ps-output "%%Title: " (buffer-name) "\n") ;Take job name from name of
2049 ;first buffer printed
2050 (ps-output "%%Creator: " (user-full-name) "\n")
2051 (ps-output "%%CreationDate: "
2052 (time-stamp-hh:mm:ss) " " (time-stamp-mon-dd-yyyy) "\n")
2053 (ps-output "%% DocumentFonts: "
2054 ps-font " " ps-font-bold " " ps-font-italic " "
2055 ps-font-bold-italic " "
2056 ps-header-font " " ps-header-title-font "\n")
2057 (ps-output "%%Pages: (atend)\n")
2058 (ps-output "%%EndComments\n\n")
2059
2060 (ps-output-boolean "LandscapeMode" ps-landscape-mode)
2061 (ps-output (format "/NumberOfColumns %d def\n" ps-number-of-columns))
2062
2063 (ps-output (format "/LandscapePageHeight %s def\n" ps-landscape-page-height))
2064 (ps-output (format "/PrintWidth %s def\n" ps-print-width))
2065 (ps-output (format "/PrintHeight %s def\n" ps-print-height))
2066
2067 (ps-output (format "/LeftMargin %s def\n" ps-left-margin))
2068 (ps-output (format "/RightMargin %s def\n" ps-right-margin)) ; not used
2069 (ps-output (format "/InterColumn %s def\n" ps-inter-column))
2070
2071 (ps-output (format "/BottomMargin %s def\n" ps-bottom-margin))
2072 (ps-output (format "/TopMargin %s def\n" ps-top-margin)) ; not used
2073 (ps-output (format "/HeaderOffset %s def\n" ps-header-offset))
2074 (ps-output (format "/HeaderPad %s def\n" ps-header-pad))
2075
2076 (ps-output-boolean "PrintHeader" ps-print-header)
2077 (ps-output-boolean "PrintHeaderFrame" ps-print-header-frame)
2078 (ps-output-boolean "ShowNofN" ps-show-n-of-n)
2079 (ps-output-boolean "Duplex" ps-spool-duplex)
2080
2081 (ps-output (format "/LineHeight %s def\n" ps-line-height))
2082
2083 (ps-output ps-print-prologue-1)
2084
2085 ;; Header fonts
2086 (ps-output ; /h0 14 /Helvetica-Bold Font
2087 (format "/h0 %s /%s DefFont\n" ps-header-title-font-size ps-header-title-font))
2088 (ps-output ; /h1 12 /Helvetica Font
2089 (format "/h1 %s /%s DefFont\n" ps-header-font-size ps-header-font))
2090
2091 (ps-output ps-print-prologue-2)
2092
2093 ;; Text fonts
2094 (ps-output (format "/f0 %s /%s DefFont\n" ps-font-size ps-font))
2095 (ps-output (format "/f1 %s /%s DefFont\n" ps-font-size ps-font-bold))
2096 (ps-output (format "/f2 %s /%s DefFont\n" ps-font-size ps-font-italic))
2097 (ps-output (format "/f3 %s /%s DefFont\n" ps-font-size ps-font-bold-italic))
2098
2099 (ps-output "\nBeginDoc\n\n")
2100 (ps-output "%%EndPrologue\n"))
2101
2102 (defun ps-header-dirpart ()
2103 (let ((fname (buffer-file-name)))
2104 (if fname
2105 (if (string-equal (buffer-name) (file-name-nondirectory fname))
2106 (file-name-directory fname)
2107 fname)
2108 "")))
2109
2110 (defun ps-get-buffer-name ()
2111 (cond
2112 ;; Indulge Jim this little easter egg:
2113 ((string= (buffer-name) "ps-print.el")
2114 "Hey, Cool! It's ps-print.el!!!")
2115 ;; Indulge Jack this other little easter egg:
2116 ((string= (buffer-name) "sokoban.el")
2117 "Super! C'est sokoban.el!")
2118 (t (buffer-name))))
2119
2120 (defun ps-begin-job ()
2121 (setq ps-page-count 0))
2122
2123 (defun ps-end-file ()
2124 (ps-output "\nEndDoc\n\n")
2125 (ps-output "%%Trailer\n")
2126 (ps-output (format "%%%%Pages: %d\n" (1+ (/ (1- ps-page-count)
2127 ps-number-of-columns)))))
2128
2129 (defun ps-next-page ()
2130 (ps-end-page)
2131 (ps-flush-output)
2132 (ps-begin-page))
2133
2134 (defun ps-begin-page (&optional dummypage)
2135 (ps-get-page-dimensions)
2136 (setq ps-width-remaining ps-print-width)
2137 (setq ps-height-remaining ps-print-height)
2138
2139 ;; Print only when a new real page begins.
2140 (when (zerop (mod ps-page-count ps-number-of-columns))
2141 (ps-output (format "\n%%%%Page: %d %d\n"
2142 (1+ (/ ps-page-count ps-number-of-columns))
2143 (1+ (/ ps-page-count ps-number-of-columns)))))
2144
2145 (ps-output "BeginDSCPage\n")
2146 (ps-output (format "/PageNumber %d def\n" (incf ps-page-count)))
2147 (ps-output "/PageCount 0 def\n")
2148
2149 (when ps-print-header
2150 (ps-generate-header "HeaderLinesLeft" ps-left-header)
2151 (ps-generate-header "HeaderLinesRight" ps-right-header)
2152 (ps-output (format "%d SetHeaderLines\n" ps-header-lines)))
2153
2154 (ps-output "BeginPage\n")
2155 (ps-set-font ps-current-font)
2156 (ps-set-bg ps-current-bg)
2157 (ps-set-color ps-current-color)
2158 (ps-set-underline ps-current-underline-p))
2159
2160 (defun ps-end-page ()
2161 (setq ps-showpage-count (+ 1 ps-showpage-count))
2162 (ps-output "EndPage\n")
2163 (ps-output "EndDSCPage\n"))
2164
2165 (defun ps-dummy-page ()
2166 (setq ps-showpage-count (+ 1 ps-showpage-count))
2167 (ps-output "%%Page: " (format "- %d\n" ps-showpage-count)
2168 "BeginDSCPage
2169 /PrintHeader false def
2170 BeginPage
2171 EndPage
2172 EndDSCPage\n"))
2173
2174 (defun ps-next-line ()
2175 (if (< ps-height-remaining ps-line-height)
2176 (ps-next-page)
2177 (setq ps-width-remaining ps-print-width)
2178 (setq ps-height-remaining (- ps-height-remaining ps-line-height))
2179 (ps-hard-lf)))
2180
2181 (defun ps-continue-line ()
2182 (if (< ps-height-remaining ps-line-height)
2183 (ps-next-page)
2184 (setq ps-width-remaining ps-print-width)
2185 (setq ps-height-remaining (- ps-height-remaining ps-line-height))
2186 (ps-soft-lf)))
2187
2188 ;; [jack] Why hard and soft ?
2189
2190 (defun ps-hard-lf ()
2191 (ps-output "HL\n"))
2192
2193 (defun ps-soft-lf ()
2194 (ps-output "SL\n"))
2195
2196 (defun ps-find-wrappoint (from to char-width)
2197 (let ((avail (truncate (/ ps-width-remaining char-width)))
2198 (todo (- to from)))
2199 (if (< todo avail)
2200 (cons to (* todo char-width))
2201 (cons (+ from avail) ps-width-remaining))))
2202
2203 (defun ps-basic-plot-string (from to &optional bg-color)
2204 (let* ((wrappoint (ps-find-wrappoint from to ps-avg-char-width))
2205 (to (car wrappoint))
2206 (string (buffer-substring from to)))
2207 (ps-output-string string)
2208 (ps-output " S\n")
2209 wrappoint))
2210
2211 (defun ps-basic-plot-whitespace (from to &optional bg-color)
2212 (let* ((wrappoint (ps-find-wrappoint from to ps-space-width))
2213 (to (car wrappoint)))
2214
2215 (ps-output (format "%d W\n" (- to from)))
2216 wrappoint))
2217
2218 (defun ps-plot (plotfunc from to &optional bg-color)
2219 (while (< from to)
2220 (let* ((wrappoint (funcall plotfunc from to bg-color))
2221 (plotted-to (car wrappoint))
2222 (plotted-width (cdr wrappoint)))
2223 (setq from plotted-to)
2224 (setq ps-width-remaining (- ps-width-remaining plotted-width))
2225 (if (< from to)
2226 (ps-continue-line))))
2227 (if ps-razzle-dazzle
2228 (let* ((q-todo (- (point-max) (point-min)))
2229 (q-done (- (point) (point-min)))
2230 (chunkfrac (/ q-todo 8))
2231 (chunksize (if (> chunkfrac 1000) 1000 chunkfrac)))
2232 (if (> (- q-done ps-razchunk) chunksize)
2233 (let (foo)
2234 (setq ps-razchunk q-done)
2235 (setq foo
2236 (if (< q-todo 100)
2237 (/ (* 100 q-done) q-todo)
2238 (/ q-done (/ q-todo 100))))
2239 (message "Formatting...%3d%%" foo))))))
2240
2241 (defun ps-set-font (font)
2242 (setq ps-current-font font)
2243 (ps-output (format "/f%d F\n" ps-current-font)))
2244
2245 (defun ps-set-bg (color)
2246 (if (setq ps-current-bg color)
2247 (ps-output (format ps-color-format (nth 0 color) (nth 1 color)
2248 (nth 2 color))
2249 " true BG\n")
2250 (ps-output "false BG\n")))
2251
2252 (defun ps-set-color (color)
2253 (if (setq ps-current-color color)
2254 nil
2255 (setq ps-current-color ps-default-fg))
2256 (ps-output (format ps-color-format (nth 0 ps-current-color)
2257 (nth 1 ps-current-color) (nth 2 ps-current-color))
2258 " FG\n"))
2259
2260 (defun ps-set-underline (underline-p)
2261 (ps-output (if underline-p "true" "false") " UL\n")
2262 (setq ps-current-underline-p underline-p))
2263
2264 (defun ps-plot-region (from to font fg-color &optional bg-color underline-p)
2265
2266 (if (not (equal font ps-current-font))
2267 (ps-set-font font))
2268
2269 ;; Specify a foreground color only if one's specified and it's
2270 ;; different than the current.
2271 (if (not (equal fg-color ps-current-color))
2272 (ps-set-color fg-color))
2273
2274 (if (not (equal bg-color ps-current-bg))
2275 (ps-set-bg bg-color))
2276
2277 ;; Toggle underlining if different.
2278 (if (not (equal underline-p ps-current-underline-p))
2279 (ps-set-underline underline-p))
2280
2281 ;; Starting at the beginning of the specified region...
2282 (save-excursion
2283 (goto-char from)
2284
2285 ;; ...break the region up into chunks separated by tabs, linefeeds,
2286 ;; and pagefeeds, and plot each chunk.
2287 (while (< from to)
2288 (if (re-search-forward "[\t\n\f]" to t)
2289 (let ((match (char-after (match-beginning 0))))
2290 (cond
2291 ((= match ?\t)
2292 (let ((linestart
2293 (save-excursion (beginning-of-line) (point))))
2294 (ps-plot 'ps-basic-plot-string from (- (point) 1)
2295 bg-color)
2296 (forward-char -1)
2297 (setq from (+ linestart (current-column)))
2298 (if (re-search-forward "[ \t]+" to t)
2299 (ps-plot 'ps-basic-plot-whitespace
2300 from (+ linestart (current-column))
2301 bg-color))))
2302
2303 ((= match ?\n)
2304 (ps-plot 'ps-basic-plot-string from (- (point) 1)
2305 bg-color)
2306 (ps-next-line)
2307 )
2308
2309 ((= match ?\f)
2310 (ps-plot 'ps-basic-plot-string from (- (point) 1)
2311 bg-color)
2312 (ps-next-page)))
2313 (setq from (point)))
2314 (ps-plot 'ps-basic-plot-string from to bg-color)
2315 (setq from to)))))
2316
2317 (defun ps-color-value (x-color-value)
2318 ;; Scale 16-bit X-COLOR-VALUE to PostScript color value in [0, 1] interval.
2319 (/ x-color-value ps-print-color-scale))
2320
2321 (defun ps-color-values (x-color)
2322 (cond ((fboundp 'x-color-values)
2323 (x-color-values x-color))
2324 ((fboundp 'pixel-components)
2325 (pixel-components x-color))
2326 (t (error "No available function to determine X color values."))))
2327
2328 (defun ps-face-attributes (face)
2329 (let ((differs (face-differs-from-default-p face)))
2330 (list (memq face ps-ref-bold-faces)
2331 (memq face ps-ref-italic-faces)
2332 (memq face ps-ref-underlined-faces)
2333 (and differs (face-foreground face))
2334 (and differs (face-background face)))))
2335
2336 (defun ps-face-attribute-list (face-or-list)
2337 (if (listp face-or-list)
2338 (let (bold-p italic-p underline-p foreground background face-attr face)
2339 (while face-or-list
2340 (setq face (car face-or-list))
2341 (setq face-attr (ps-face-attributes face))
2342 (setq bold-p (or bold-p (nth 0 face-attr)))
2343 (setq italic-p (or italic-p (nth 1 face-attr)))
2344 (setq underline-p (or underline-p (nth 2 face-attr)))
2345 (if foreground
2346 nil
2347 (setq foreground (nth 3 face-attr)))
2348 (if background
2349 nil
2350 (setq background (nth 4 face-attr)))
2351 (setq face-or-list (cdr face-or-list)))
2352 (list bold-p italic-p underline-p foreground background))
2353
2354 (ps-face-attributes face-or-list)))
2355
2356 (defun ps-plot-with-face (from to face)
2357 (if face
2358 (let* ((face-attr (ps-face-attribute-list face))
2359 (bold-p (nth 0 face-attr))
2360 (italic-p (nth 1 face-attr))
2361 (underline-p (nth 2 face-attr))
2362 (foreground (nth 3 face-attr))
2363 (background (nth 4 face-attr))
2364 (fg-color (if (and ps-print-color-p foreground)
2365 (mapcar 'ps-color-value
2366 (ps-color-values foreground))
2367 ps-default-color))
2368 (bg-color (if (and ps-print-color-p background)
2369 (mapcar 'ps-color-value
2370 (ps-color-values background)))))
2371 (ps-plot-region from to
2372 (cond ((and bold-p italic-p) 3)
2373 (italic-p 2)
2374 (bold-p 1)
2375 (t 0))
2376 ; (or fg-color '(0.0 0.0 0.0))
2377 fg-color
2378 bg-color underline-p))
2379 (goto-char to)))
2380
2381
2382 (defun ps-emacs-face-kind-p (face kind kind-regex kind-list)
2383 (let ((frame-font (face-font face))
2384 (face-defaults (face-font face t)))
2385 (or
2386 ;; Check FACE defaults:
2387 (and (listp face-defaults)
2388 (memq kind face-defaults))
2389
2390 ;; Check the user's preferences
2391 (memq face kind-list))))
2392
2393 (defun ps-xemacs-face-kind-p (face kind kind-regex kind-list)
2394 (let* ((frame-font (or (face-font face) (face-font 'default)))
2395 (kind-cons (assq kind (x-font-properties frame-font)))
2396 (kind-spec (cdr-safe kind-cons))
2397 (case-fold-search t))
2398
2399 (or (and kind-spec (string-match kind-regex kind-spec))
2400 ;; Kludge-compatible:
2401 (memq face kind-list))))
2402
2403 (defun ps-face-bold-p (face)
2404 (if (eq ps-print-emacs-type 'emacs)
2405 (ps-emacs-face-kind-p face 'bold "-\\(bold\\|demibold\\)-"
2406 ps-bold-faces)
2407 (ps-xemacs-face-kind-p face 'WEIGHT_NAME "bold\\|demibold"
2408 ps-bold-faces)))
2409
2410 (defun ps-face-italic-p (face)
2411 (if (eq ps-print-emacs-type 'emacs)
2412 (ps-emacs-face-kind-p face 'italic "-[io]-" ps-italic-faces)
2413 (or
2414 (ps-xemacs-face-kind-p face 'ANGLE_NAME "i\\|o" ps-italic-faces)
2415 (ps-xemacs-face-kind-p face 'SLANT "i\\|o" ps-italic-faces))))
2416
2417 (defun ps-face-underlined-p (face)
2418 (or (face-underline-p face)
2419 (memq face ps-underlined-faces)))
2420
2421 ;; Ensure that face-list is fbound.
2422 (or (fboundp 'face-list) (defalias 'face-list 'list-faces))
2423
2424 (defun ps-build-reference-face-lists ()
2425 (if ps-auto-font-detect
2426 (let ((faces (face-list))
2427 the-face)
2428 (setq ps-ref-bold-faces nil
2429 ps-ref-italic-faces nil
2430 ps-ref-underlined-faces nil)
2431 (while faces
2432 (setq the-face (car faces))
2433 (if (ps-face-italic-p the-face)
2434 (setq ps-ref-italic-faces
2435 (cons the-face ps-ref-italic-faces)))
2436 (if (ps-face-bold-p the-face)
2437 (setq ps-ref-bold-faces
2438 (cons the-face ps-ref-bold-faces)))
2439 (if (ps-face-underlined-p the-face)
2440 (setq ps-ref-underlined-faces
2441 (cons the-face ps-ref-underlined-faces)))
2442 (setq faces (cdr faces))))
2443 (setq ps-ref-bold-faces ps-bold-faces)
2444 (setq ps-ref-italic-faces ps-italic-faces)
2445 (setq ps-ref-underlined-faces ps-underlined-faces))
2446 (setq ps-build-face-reference nil))
2447
2448 (defun ps-mapper (extent list)
2449 (nconc list (list (list (extent-start-position extent) 'push extent)
2450 (list (extent-end-position extent) 'pull extent)))
2451 nil)
2452
2453 (defun ps-extent-sorter (a b)
2454 (< (extent-priority a) (extent-priority b)))
2455
2456 (defun ps-print-ensure-fontified (start end)
2457 (if (and (boundp 'lazy-lock-mode) lazy-lock-mode)
2458 (if (fboundp 'lazy-lock-fontify-region)
2459 (lazy-lock-fontify-region start end) ; the new
2460 (lazy-lock-fontify-buffer)))) ; the old
2461
2462 (defun ps-generate-postscript-with-faces (from to)
2463 ;; Build the reference lists of faces if necessary.
2464 (if (or ps-always-build-face-reference
2465 ps-build-face-reference)
2466 (progn
2467 (message "Collecting face information...")
2468 (ps-build-reference-face-lists)))
2469 ;; Set the color scale. We do it here instead of in the defvar so
2470 ;; that ps-print can be dumped into emacs. This expression can't be
2471 ;; evaluated at dump-time because X isn't initialized.
2472 (setq ps-print-color-scale
2473 (if ps-print-color-p
2474 (float (car (ps-color-values "white")))
2475 1.0))
2476 ;; Generate some PostScript.
2477 (save-restriction
2478 (narrow-to-region from to)
2479 (let ((face 'default)
2480 (position to))
2481 (ps-print-ensure-fontified from to)
2482 (cond ((or (eq ps-print-emacs-type 'lucid)
2483 (eq ps-print-emacs-type 'xemacs))
2484 ;; Build the list of extents...
2485 (let ((a (cons 'dummy nil))
2486 record type extent extent-list)
2487 (map-extents 'ps-mapper nil from to a)
2488 (setq a (sort (cdr a) 'car-less-than-car))
2489
2490 (setq extent-list nil)
2491
2492 ;; Loop through the extents...
2493 (while a
2494 (setq record (car a))
2495
2496 (setq position (car record))
2497 (setq record (cdr record))
2498
2499 (setq type (car record))
2500 (setq record (cdr record))
2501
2502 (setq extent (car record))
2503
2504 ;; Plot up to this record.
2505 ;; XEmacs 19.12: for some reason, we're getting into a
2506 ;; situation in which some of the records have
2507 ;; positions less than 'from'. Since we've narrowed
2508 ;; the buffer, this'll generate errors. This is a
2509 ;; hack, but don't call ps-plot-with-face unless from >
2510 ;; point-min.
2511 (if (and (>= from (point-min))
2512 (<= position (point-max)))
2513 (ps-plot-with-face from position face))
2514
2515 (cond
2516 ((eq type 'push)
2517 (if (extent-face extent)
2518 (setq extent-list (sort (cons extent extent-list)
2519 'ps-extent-sorter))))
2520
2521 ((eq type 'pull)
2522 (setq extent-list (sort (delq extent extent-list)
2523 'ps-extent-sorter))))
2524
2525 (setq face
2526 (if extent-list
2527 (extent-face (car extent-list))
2528 'default))
2529
2530 (setq from position)
2531 (setq a (cdr a)))))
2532
2533 ((eq ps-print-emacs-type 'emacs)
2534 (let ((property-change from)
2535 (overlay-change from))
2536 (while (< from to)
2537 (if (< property-change to) ; Don't search for property change
2538 ; unless previous search succeeded.
2539 (setq property-change
2540 (next-property-change from nil to)))
2541 (if (< overlay-change to) ; Don't search for overlay change
2542 ; unless previous search succeeded.
2543 (setq overlay-change
2544 (min (next-overlay-change from) to)))
2545 (setq position
2546 (min property-change overlay-change))
2547 ;; The code below is not quite correct,
2548 ;; because a non-nil overlay invisible property
2549 ;; which is inactive according to the current value
2550 ;; of buffer-invisibility-spec nonetheless overrides
2551 ;; a face text property.
2552 (setq face
2553 (cond ((let ((prop (get-text-property from 'invisible)))
2554 ;; Decide whether this invisible property
2555 ;; really makes the text invisible.
2556 (if (eq buffer-invisibility-spec t)
2557 (not (null prop))
2558 (or (memq prop buffer-invisibility-spec)
2559 (assq prop buffer-invisibility-spec))))
2560 nil)
2561 ((get-text-property from 'face))
2562 (t 'default)))
2563 (let ((overlays (overlays-at from))
2564 (face-priority -1)) ; text-property
2565 (while overlays
2566 (let* ((overlay (car overlays))
2567 (overlay-face (overlay-get overlay 'face))
2568 (overlay-invisible (overlay-get overlay 'invisible))
2569 (overlay-priority (or (overlay-get overlay
2570 'priority)
2571 0)))
2572 (if (and (or overlay-invisible overlay-face)
2573 (> overlay-priority face-priority))
2574 (setq face (cond ((if (eq buffer-invisibility-spec t)
2575 (not (null overlay-invisible))
2576 (or (memq overlay-invisible buffer-invisibility-spec)
2577 (assq overlay-invisible buffer-invisibility-spec)))
2578 nil)
2579 ((and face overlay-face)))
2580 face-priority overlay-priority)))
2581 (setq overlays (cdr overlays))))
2582 ;; Plot up to this record.
2583 (ps-plot-with-face from position face)
2584 (setq from position)))))
2585 (ps-plot-with-face from to face))))
2586
2587 (defun ps-generate-postscript (from to)
2588 (ps-plot-region from to 0 nil))
2589
2590 (defun ps-generate (buffer from to genfunc)
2591 (let ((from (min to from))
2592 (to (max to from))
2593 ;; This avoids trouble if chars with read-only properties
2594 ;; are copied into ps-spool-buffer.
2595 (inhibit-read-only t))
2596 (save-restriction
2597 (narrow-to-region from to)
2598 (if ps-razzle-dazzle
2599 (message "Formatting...%3d%%" (setq ps-razchunk 0)))
2600 (set-buffer buffer)
2601 (setq ps-source-buffer buffer)
2602 (setq ps-spool-buffer (get-buffer-create ps-spool-buffer-name))
2603 (ps-init-output-queue)
2604 (let (safe-marker completed-safely needs-begin-file)
2605 (unwind-protect
2606 (progn
2607 (set-buffer ps-spool-buffer)
2608
2609 ;; Get a marker and make it point to the current end of the
2610 ;; buffer, If an error occurs, we'll delete everything from
2611 ;; the end of this marker onwards.
2612 (setq safe-marker (make-marker))
2613 (set-marker safe-marker (point-max))
2614
2615 (goto-char (point-min))
2616 (if (looking-at (regexp-quote "%!PS-Adobe-1.0"))
2617 nil
2618 (setq needs-begin-file t))
2619 (save-excursion
2620 (set-buffer ps-source-buffer)
2621 (if needs-begin-file (ps-begin-file))
2622 (ps-begin-job)
2623 (ps-begin-page))
2624 (set-buffer ps-source-buffer)
2625 (funcall genfunc from to)
2626 (ps-end-page)
2627
2628 (if (and ps-spool-duplex
2629 (= (mod ps-page-count 2) 1))
2630 (ps-dummy-page))
2631 (ps-flush-output)
2632
2633 ;; Back to the PS output buffer to set the page count
2634 (set-buffer ps-spool-buffer)
2635 (goto-char (point-max))
2636 (while (re-search-backward "^/PageCount 0 def$" nil t)
2637 (replace-match (format "/PageCount %d def" ps-page-count) t))
2638
2639 ;; Setting this variable tells the unwind form that the
2640 ;; the postscript was generated without error.
2641 (setq completed-safely t))
2642
2643 ;; Unwind form: If some bad mojo occurred while generating
2644 ;; postscript, delete all the postscript that was generated.
2645 ;; This protects the previously spooled files from getting
2646 ;; corrupted.
2647 (if (and (markerp safe-marker) (not completed-safely))
2648 (progn
2649 (set-buffer ps-spool-buffer)
2650 (delete-region (marker-position safe-marker) (point-max))))))
2651
2652 (if ps-razzle-dazzle
2653 (message "Formatting...done")))))
2654
2655 (defun ps-do-despool (filename)
2656 (if (or (not (boundp 'ps-spool-buffer))
2657 (not (symbol-value 'ps-spool-buffer)))
2658 (message "No spooled PostScript to print")
2659 (ps-end-file)
2660 (ps-flush-output)
2661 (if filename
2662 (save-excursion
2663 (if ps-razzle-dazzle
2664 (message "Saving..."))
2665 (set-buffer ps-spool-buffer)
2666 (setq filename (expand-file-name filename))
2667 (write-region (point-min) (point-max) filename)
2668 (if ps-razzle-dazzle
2669 (message "Wrote %s" filename)))
2670 ;; Else, spool to the printer
2671 (if ps-razzle-dazzle
2672 (message "Printing..."))
2673 (save-excursion
2674 (set-buffer ps-spool-buffer)
2675 (if (and (eq system-type 'ms-dos) (stringp dos-ps-printer))
2676 (write-region (point-min) (point-max) dos-ps-printer t 0)
2677 (let ((binary-process-input t)) ; for MS-DOS
2678 (apply 'call-process-region
2679 (point-min) (point-max) ps-lpr-command nil
2680 (if (fboundp 'start-process) 0 nil)
2681 nil
2682 ps-lpr-switches))))
2683 (if ps-razzle-dazzle
2684 (message "Printing...done")))
2685 (kill-buffer ps-spool-buffer)))
2686
2687 (defun ps-kill-emacs-check ()
2688 (let (ps-buffer)
2689 (if (and (setq ps-buffer (get-buffer ps-spool-buffer-name))
2690 (buffer-modified-p ps-buffer))
2691 (if (y-or-n-p "Unprinted PostScript waiting; print now? ")
2692 (ps-despool)))
2693 (if (and (setq ps-buffer (get-buffer ps-spool-buffer-name))
2694 (buffer-modified-p ps-buffer))
2695 (if (yes-or-no-p "Unprinted PostScript waiting; exit anyway? ")
2696 nil
2697 (error "Unprinted PostScript")))))
2698
2699 (if (fboundp 'add-hook)
2700 (funcall 'add-hook 'kill-emacs-hook 'ps-kill-emacs-check)
2701 (if kill-emacs-hook
2702 (message "Won't override existing kill-emacs-hook")
2703 (setq kill-emacs-hook 'ps-kill-emacs-check)))
2704
2705 ;;; Sample Setup Code:
2706
2707 ;; This stuff is for anybody that's brave enough to look this far,
2708 ;; and able to figure out how to use it. It isn't really part of ps-
2709 ;; print, but I'll leave it here in hopes it might be useful:
2710
2711 ;; WARNING!!! The following code is *sample* code only. Don't use it
2712 ;; unless you understand what it does!
2713
2714 (defmacro ps-prsc () (list 'if (list 'eq 'ps-print-emacs-type ''emacs)
2715 [f22] ''f22))
2716 (defmacro ps-c-prsc () (list 'if (list 'eq 'ps-print-emacs-type ''emacs)
2717 [C-f22]
2718 ''(control f22)))
2719 (defmacro ps-s-prsc () (list 'if (list 'eq 'ps-print-emacs-type ''emacs)
2720 [S-f22]
2721 ''(shift f22)))
2722
2723 ;; Look in an article or mail message for the Subject: line. To be
2724 ;; placed in ps-left-headers.
2725 (defun ps-article-subject ()
2726 (save-excursion
2727 (goto-char (point-min))
2728 (if (re-search-forward "^Subject:[ \t]+\\(.*\\)$" nil t)
2729 (buffer-substring (match-beginning 1) (match-end 1))
2730 "Subject ???")))
2731
2732 ;; Look in an article or mail message for the From: line. Sorta-kinda
2733 ;; understands RFC-822 addresses and can pull the real name out where
2734 ;; it's provided. To be placed in ps-left-headers.
2735 (defun ps-article-author ()
2736 (save-excursion
2737 (goto-char (point-min))
2738 (if (re-search-forward "^From:[ \t]+\\(.*\\)$" nil t)
2739 (let ((fromstring (buffer-substring (match-beginning 1) (match-end 1))))
2740 (cond
2741
2742 ;; Try first to match addresses that look like
2743 ;; thompson@wg2.waii.com (Jim Thompson)
2744 ((string-match ".*[ \t]+(\\(.*\\))" fromstring)
2745 (substring fromstring (match-beginning 1) (match-end 1)))
2746
2747 ;; Next try to match addresses that look like
2748 ;; Jim Thompson <thompson@wg2.waii.com>
2749 ((string-match "\\(.*\\)[ \t]+<.*>" fromstring)
2750 (substring fromstring (match-beginning 1) (match-end 1)))
2751
2752 ;; Couldn't find a real name -- show the address instead.
2753 (t fromstring)))
2754 "From ???")))
2755
2756 ;; A hook to bind to gnus-Article-prepare-hook. This will set the ps-
2757 ;; left-headers specially for gnus articles. Unfortunately, gnus-
2758 ;; article-mode-hook is called only once, the first time the *Article*
2759 ;; buffer enters that mode, so it would only work for the first time
2760 ;; we ran gnus. The second time, this hook wouldn't get set up. The
2761 ;; only alternative is gnus-article-prepare-hook.
2762 (defun ps-gnus-article-prepare-hook ()
2763 (setq ps-header-lines 3)
2764 (setq ps-left-header
2765 ;; The left headers will display the article's subject, its
2766 ;; author, and the newsgroup it was in.
2767 (list 'ps-article-subject 'ps-article-author 'gnus-newsgroup-name)))
2768
2769 ;; A hook to bind to vm-mode-hook to locally bind prsc and set the ps-
2770 ;; left-headers specially for mail messages. This header setup would
2771 ;; also work, I think, for RMAIL.
2772 (defun ps-vm-mode-hook ()
2773 (local-set-key (ps-prsc) 'ps-vm-print-message-from-summary)
2774 (setq ps-header-lines 3)
2775 (setq ps-left-header
2776 ;; The left headers will display the message's subject, its
2777 ;; author, and the name of the folder it was in.
2778 (list 'ps-article-subject 'ps-article-author 'buffer-name)))
2779
2780 ;; Every now and then I forget to switch from the *Summary* buffer to
2781 ;; the *Article* before hitting prsc, and a nicely formatted list of
2782 ;; article subjects shows up at the printer. This function, bound to
2783 ;; prsc for the gnus *Summary* buffer means I don't have to switch
2784 ;; buffers first.
2785 (defun ps-gnus-print-article-from-summary ()
2786 (interactive)
2787 (if (get-buffer "*Article*")
2788 (save-excursion
2789 (set-buffer "*Article*")
2790 (ps-spool-buffer-with-faces))))
2791
2792 ;; See ps-gnus-print-article-from-summary. This function does the
2793 ;; same thing for vm.
2794 (defun ps-vm-print-message-from-summary ()
2795 (interactive)
2796 (if (and (boundp 'vm-mail-buffer) (symbol-value 'vm-mail-buffer))
2797 (save-excursion
2798 (set-buffer (symbol-value 'vm-mail-buffer))
2799 (ps-spool-buffer-with-faces))))
2800
2801 ;; A hook to bind to bind to gnus-summary-setup-buffer to locally bind
2802 ;; prsc.
2803 (defun ps-gnus-summary-setup ()
2804 (local-set-key (ps-prsc) 'ps-gnus-print-article-from-summary))
2805
2806 ;; Look in an article or mail message for the Subject: line. To be
2807 ;; placed in ps-left-headers.
2808 (defun ps-info-file ()
2809 (save-excursion
2810 (goto-char (point-min))
2811 (if (re-search-forward "File:[ \t]+\\([^, \t\n]*\\)" nil t)
2812 (buffer-substring (match-beginning 1) (match-end 1))
2813 "File ???")))
2814
2815 ;; Look in an article or mail message for the Subject: line. To be
2816 ;; placed in ps-left-headers.
2817 (defun ps-info-node ()
2818 (save-excursion
2819 (goto-char (point-min))
2820 (if (re-search-forward "Node:[ \t]+\\([^,\t\n]*\\)" nil t)
2821 (buffer-substring (match-beginning 1) (match-end 1))
2822 "Node ???")))
2823
2824 (defun ps-info-mode-hook ()
2825 (setq ps-left-header
2826 ;; The left headers will display the node name and file name.
2827 (list 'ps-info-node 'ps-info-file)))
2828
2829 ;; WARNING! The following function is a *sample* only, and is *not*
2830 ;; meant to be used as a whole unless you understand what the effects
2831 ;; will be! (In fact, this is a copy of Jim's setup for ps-print -- I'd
2832 ;; be very surprised if it was useful to *anybody*, without
2833 ;; modification.)
2834
2835 (defun ps-jts-ps-setup ()
2836 (global-set-key (ps-prsc) 'ps-spool-buffer-with-faces) ;f22 is prsc
2837 (global-set-key (ps-s-prsc) 'ps-spool-region-with-faces)
2838 (global-set-key (ps-c-prsc) 'ps-despool)
2839 (add-hook 'gnus-article-prepare-hook 'ps-gnus-article-prepare-hook)
2840 (add-hook 'gnus-summary-mode-hook 'ps-gnus-summary-setup)
2841 (add-hook 'vm-mode-hook 'ps-vm-mode-hook)
2842 (add-hook 'vm-mode-hooks 'ps-vm-mode-hook)
2843 (add-hook 'Info-mode-hook 'ps-info-mode-hook)
2844 (setq ps-spool-duplex t)
2845 (setq ps-print-color-p nil)
2846 (setq ps-lpr-command "lpr")
2847 (setq ps-lpr-switches '("-Jjct,duplex_long"))
2848 'ps-jts-ps-setup)
2849
2850 ;; WARNING! The following function is a *sample* only, and is *not*
2851 ;; meant to be used as a whole unless it corresponds to your needs.
2852 ;; (In fact, this is a copy of Jack's setup for ps-print --
2853 ;; I would not be that surprised if it was useful to *anybody*,
2854 ;; without modification.)
2855
2856 (defun ps-jack-setup ()
2857 (setq ps-print-color-p 'nil
2858 ps-lpr-command "lpr"
2859 ps-lpr-switches (list)
2860
2861 ps-paper-type 'a4
2862 ps-landscape-mode 't
2863 ps-number-of-columns 2
2864
2865 ps-left-margin (/ (* 72 1.0) 2.54) ; 1.0 cm
2866 ps-right-margin (/ (* 72 1.0) 2.54) ; 1.0 cm
2867 ps-inter-column (/ (* 72 1.0) 2.54) ; 1.0 cm
2868 ps-bottom-margin (/ (* 72 1.5) 2.54) ; 1.5 cm
2869 ps-top-margin (/ (* 72 1.5) 2.54) ; 1.5 cm
2870 ps-header-offset (/ (* 72 1.0) 2.54) ; 1.0 cm
2871 ps-header-line-pad .15
2872 ps-print-header t
2873 ps-print-header-frame t
2874 ps-header-lines 2
2875 ps-show-n-of-n t
2876 ps-spool-duplex nil
2877
2878 ps-font-family 'Courier
2879 ps-font-size 5.5
2880 ps-header-font-family 'Helvetica
2881 ps-header-font-size 6
2882 ps-header-title-font-size 8)
2883 'ps-jack-setup)
2884
2885 (provide 'ps-print)
2886
2887 ;;; ps-print.el ends here