File Coverage

blib/lib/Tk/Enscript.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             # -*- perl -*-
2              
3             #
4             # $Id: Enscript.pm,v 1.10 2007/10/29 22:57:00 eserte Exp $
5             # Author: Slaven Rezic
6             #
7             # Copyright (C) 1998,2007 Slaven Rezic. All rights reserved.
8             # This program is free software; you can redistribute it and/or
9             # modify it under the same terms as Perl itself.
10             #
11             # Mail: srezic@cpan.org
12             # WWW: http://www.sourceforge.net/projects/srezic
13             #
14              
15             package Tk::Enscript;
16 1     1   2310 use Tk;
  0            
  0            
17             use Text::Tabs;
18             require Exporter;
19              
20             use strict;
21             use vars qw(%media %postscript_to_x11_font
22             $VERSION @ISA @EXPORT);
23              
24             @ISA = qw(Exporter);
25             @EXPORT = qw(enscript);
26              
27             $VERSION = sprintf "%d.%02d", q$Revision: 1.10 $ =~ /(\d+)\.(\d+)/;
28              
29             parse_cfg();
30              
31             sub enscript {
32             my($top, %args) = @_;
33              
34             my $external = $args{-external};
35              
36             if (!$args{'-columns'}) {
37             $args{'-columns'} = 1;
38             }
39              
40             if (defined $external and $external eq 'best') {
41             if (_is_in_path("enscript")) {
42             $external = "enscript";
43             } elsif (_is_in_path("a2ps")) {
44             $external = "a2ps";
45             } else {
46             undef $external;
47             }
48             }
49             if (defined $external) {
50             if ($external eq 'enscript') {
51             return ext_enscript(%args);
52             } elsif ($external eq 'a2ps') {
53             return ext_a2ps(%args);
54             } else {
55             die "Unknown external program $external";
56             }
57             }
58              
59             my $fontname = $args{-font};
60             my $output = $args{-output} || "/tmp/enscript.%d.ps";
61             my $filename = $args{-file};
62             my $text = $args{-text};
63              
64             my $media = $args{-media} || 'A4';
65             die "Unknown media $media" if !exists $media{$media};
66             my %media_desc = %{$media{$media}};
67              
68             my $width = $args{-width} || $media_desc{Width};
69             my $height = $args{-height} || $media_desc{Height};
70              
71             my $t = $top->Toplevel;
72             my $c = $t->Canvas(-width => $width, -height => $height);
73             $t->withdraw;
74              
75             my($llx, $lly, $urx, $ury) = @{$args{-bbox}} if exists $args{-bbox};
76              
77             $llx = $args{-llx} || $media_desc{LLX};
78             $lly = $args{-lly} || $media_desc{LLY};
79             $urx = $args{-urx} || $media_desc{URX};
80             $ury = $args{-ury} || $media_desc{URY};
81              
82             my $uly = $height - $ury; # XXX unsure
83             my $lry = $height - $lly;
84              
85             my $y = $uly;
86              
87             my $font = x11_font_to_tk_font($t, postscript_to_x11_font($fontname || 'Courier12'));
88              
89             my $page = 0;
90             my $line;
91              
92             my $ps_output_sub = sub {
93             $c->update;
94             $c->postscript(-file => sprintf($output, $page),
95             -pagewidth => $width,
96             -pageheight => $height,
97             -width => $width,
98             -height => $height);
99             $y = $uly;
100             $page++;
101             $c->delete('all');
102             };
103              
104             if (defined $filename) {
105             $text = _read_file($filename);
106             }
107              
108             my $try_again = 0;
109             foreach $line (split(/\n/, $text)) {
110             $line = expand($line);
111             my $i;
112             my @text_args = ($llx, $y,
113             -width => $urx-$llx,
114             -text => $line, -anchor => 'nw',
115             );
116             eval {
117             $i = $c->createText(@text_args,
118             -font => $font,
119             );
120             };
121             warn $@ if $@;
122             if (!defined $i) {
123             warn "Can't get font <$font>, fallback to default font.\n";
124             $i = $c->createText(@text_args);
125             }
126             $y = ($c->bbox($i))[3];
127             if ($y > $lry && !$try_again) {
128             $c->delete($i);
129             $ps_output_sub->();
130             $try_again++;
131             redo;
132             }
133             $try_again = 0;
134             }
135              
136             $ps_output_sub->();
137             $c->destroy;
138              
139             ($output, $page-1); # gibt Output-Dateiname und Anzahl der Seiten zurück
140             }
141              
142             sub _read_file {
143             my $filename = shift;
144             my $text;
145             open(F, $filename) or die "Can't open $filename: $!";
146             local($/) = undef;
147             $text = ;
148             close F;
149             $text;
150             }
151              
152             sub parse_cfg {
153             my $cfg_file = shift;
154             my @cfg_files = (Tk->findINC('enscript.cfg'));
155             if (!defined $cfg_file) {
156             my $home_dir = eval { local $SIG{__DIE__};
157             (getpwuid($<))[7];
158             } || $ENV{'HOME'} || '';
159             my $pers_cfg_file = "$home_dir/.enscriptrc";
160             if (-f $pers_cfg_file && -r $pers_cfg_file) {
161             $cfg_file = $pers_cfg_file;
162             }
163             }
164             if (defined $cfg_file) {
165             push @cfg_files, $cfg_file;
166             }
167             if (!@cfg_files) {
168             die "Can't found any configuration enscript.cfg.";
169             }
170              
171             %media = ();
172             %postscript_to_x11_font = ();
173              
174             for my $cfg_file (@cfg_files) {
175             open(CFG, $cfg_file)
176             or die "Can't open config file <$cfg_file>: $!";
177             while() {
178             s/\s*\#.*//;
179             next if /^\s*$/;
180             if (/^\s*Media:\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/) {
181             $media{$1} = {Width => $2,
182             Height => $3,
183             LLX => $4,
184             LLY => $5,
185             URX => $6,
186             URY => $7};
187             } elsif (/^\s*FontMap:\s*(\S+)\s+(.*)/) {
188             $postscript_to_x11_font{$1} = $2;
189             } else {
190             #warn "Can't parse $_";
191             }
192             }
193             close CFG;
194             }
195             }
196              
197             sub postscript_to_x11_font {
198             my($psfont) = @_;
199             my $x11font;
200             if ($psfont !~ /^(.*?)(\d+)?$/) {
201             die "Can't parse postscript font $psfont";
202             }
203             my($font, $size) = (lc($1), $2);
204             if (!defined $size) { $size = 10 }
205             my $x11font_fmt = $postscript_to_x11_font{$font};
206             if (!defined $x11font_fmt) {
207             die "No X11 font for $font defined";
208             }
209             $x11font = sprintf($x11font_fmt, $size*10);
210             $x11font;
211             }
212              
213             sub x11_font_to_tk_font {
214             my($t, $x11font) = @_;
215              
216             my $Font;
217             if ($Tk::VERSION >= 800.012) {
218             require Tk::X11Font;
219             $Font = 'Tk::X11Font';
220             } else {
221             require Tk::Font;
222             $Font = 'Tk::Font';
223             }
224              
225             my $font = new $Font($t, $x11font);
226              
227             $font;
228             }
229              
230             sub ext_enscript {
231             my(%args) = @_;
232             my @cmd = ("enscript");
233             if ($args{'-columns'}) {
234             push @cmd, "--columns", $args{'-columns'};
235             }
236             if ($args{'-header'}) {
237             push @cmd, "--header", $args{'-header'};
238             }
239             if ($args{'-font'}) {
240             push @cmd, "--font", $args{'-font'};
241             }
242             if ($args{'-output'}) {
243             push @cmd, "--output", $args{'-output'};
244             }
245             print STDERR "Cmd: " . join(" ", @cmd) . "\n" if $args{-verbose};
246             if ($args{'-file'}) {
247             system(@cmd, $args{'-file'});
248             } else {
249             require IO::Pipe;
250             my $pipe = IO::Pipe->new;
251             $pipe->writer(@cmd);
252             $pipe->print($args{'-text'});
253             $pipe->close;
254             }
255             ($args{'-output'}, 1);
256             }
257              
258             sub ext_a2ps {
259             my(%args) = @_;
260              
261             die "Sorry, a2ps is not supported anymore\n";
262              
263             my @cmd = ("a2ps", #"-8",
264             "--output=-");
265             if ($args{'-columns'} =~ /^[12]$/) {
266             push @cmd, "--columns=" . $args{'-columns'};
267             }
268             if ($args{'-font'} and $args{'-font'} =~ /(\d+)$/) {
269             push @cmd, "--font-size=". $1;
270             }
271             if ($args{'-header'}) {
272             push @cmd, "--header=".$args{'-header'};
273             } else {
274             push @cmd, "--no-header";
275             }
276             # "-nP" würde ich auch gerne setzen, existiert aber nicht?!
277             #XXX? push @cmd, "-ns", "-nu", "-nL";
278              
279             my $tmpfile;
280             if (!$args{'-file'}) {
281             $tmpfile = "/tmp/tkenscript-a2ps.$$.txt"; # XXX better solution?
282             open(TMP, ">$tmpfile")
283             or die "Can't write to tempory file $tmpfile: $!";
284             print TMP $args{'-text'};
285             close TMP;
286             $args{'-file'} = $tmpfile;
287             }
288             push @cmd, $args{'-file'};
289             require IO::Pipe;
290             my $pipe = IO::Pipe->new;
291             print STDERR "Cmd: " . join(" ", @cmd) . "\n" if $args{-verbose};
292             $pipe->reader(@cmd);
293             open(OUT, ">$args{-output}") or die "Can't write to $args{-output}: $!";
294             while(<$pipe>) {
295             print OUT $_;
296             }
297             close OUT;
298             $pipe->close;
299              
300             unlink $tmpfile if defined $tmpfile;
301              
302             ($args{'-output'}, 1);
303             }
304              
305             sub _is_in_path {
306             my($prog) = @_;
307             require Config;
308             my $sep = $Config::Config{'path_sep'} || ':';
309             foreach (split(/$sep/o, $ENV{PATH})) {
310             return $_ if -x "$_/$prog";
311             }
312             undef;
313             }
314              
315             1;
316              
317             =head1 NAME
318              
319             Tk::Enscript - a text-to-postscript converter using Tk::Canvas
320              
321             =head1 SYNOPSIS
322              
323             use Tk::Enscript;
324              
325             enscript($top,
326             -text => $text,
327             -media => 'A4',
328             -output => "/tmp/bla.%d.ps",
329             );
330              
331             =head1 DESCRIPTION
332              
333             =head1 AUTHOR
334              
335             Slaven Rezic
336              
337             =head1 COPYRIGHT
338              
339             Copyright (c) 1998 Slaven Rezic. All rights reserved.
340             This module is free software; you can redistribute it and/or modify
341             it under the same terms as Perl itself.
342              
343             =head1 SEE ALSO
344              
345             L, L, L
346              
347             =cut
348