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