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