File Coverage

lib/PostScript/Simple.pm
Criterion Covered Total %
statement 406 573 70.8
branch 152 230 66.0
condition 27 56 48.2
subroutine 33 41 80.4
pod 24 25 96.0
total 642 925 69.4


line stmt bran cond sub pod time code
1             #! /usr/bin/perl -w
2              
3             package PostScript::Simple;
4              
5 7     7   78923 use strict;
  7         9  
  7         206  
6 7     7   21 use vars qw($VERSION @ISA @EXPORT);
  7         7  
  7         399  
7 7     7   25 use Carp;
  7         14  
  7         429  
8 7     7   23 use Exporter;
  7         15  
  7         188  
9 7     7   1982 use PostScript::Simple::EPS;
  7         11  
  7         33423  
10              
11             @ISA = qw(Exporter);
12             @EXPORT = qw();
13             $VERSION = '0.09';
14              
15              
16             #-------------------------------------------------------------------------------
17              
18             =head1 NAME
19              
20             PostScript::Simple - Produce PostScript files from Perl
21              
22             =head1 SYNOPSIS
23              
24             use PostScript::Simple;
25            
26             # create a new PostScript object
27             $p = new PostScript::Simple(papersize => "A4",
28             colour => 1,
29             eps => 0,
30             units => "in");
31            
32             # create a new page
33             $p->newpage;
34            
35             # draw some lines and other shapes
36             $p->line(1,1, 1,4);
37             $p->linextend(2,4);
38             $p->box(1.5,1, 2,3.5);
39             $p->circle(2,2, 1);
40             $p->setlinewidth( 0.01 );
41             $p->curve(1,5, 1,7, 3,7, 3,5);
42             $p->curvextend(3,3, 5,3, 5,5);
43            
44             # draw a rotated polygon in a different colour
45             $p->setcolour(0,100,200);
46             $p->polygon({rotate=>45}, 1,1, 1,2, 2,2, 2,1, 1,1);
47            
48             # add some text in red
49             $p->setcolour("red");
50             $p->setfont("Times-Roman", 20);
51             $p->text(1,1, "Hello");
52            
53             # write the output to a file
54             $p->output("file.ps");
55              
56              
57             =head1 DESCRIPTION
58              
59             PostScript::Simple allows you to have a simple method of writing PostScript
60             files from Perl. It has graphics primitives that allow lines, curves, circles,
61             polygons and boxes to be drawn. Text can be added to the page using standard
62             PostScript fonts.
63              
64             The images can be single page EPS files, or multipage PostScript files. The
65             image size can be set by using a recognised paper size ("C", for example) or
66             by giving dimensions. The units used can be specified ("C" or "C", etc)
67             and are the same as those used in TeX. The default unit is a bp, or a PostScript
68             point, unlike TeX.
69              
70             =head1 PREREQUISITES
71              
72             This module requires C and C.
73              
74             =head2 EXPORT
75              
76             None.
77              
78             =cut
79              
80              
81             #-------------------------------------------------------------------------------
82              
83             # Define some colour names
84             my %pscolours = (
85             # Original colours from PostScript::Simple
86             brightred => [255, 0, 0], brightgreen => [0, 255, 0], brightblue => [0, 0, 1],
87             red => [204, 0, 0], green => [0, 204, 0], blue => [0, 0, 204],
88             darkred => [127, 0, 0], darkgreen => [0, 127, 0], darkblue => [0, 0, 127],
89             grey10 => [25, 25, 25], grey20 => [51, 51, 51], grey30 => [76, 76, 76],
90             grey40 => [102, 102, 102], grey50 => [127, 127, 127], grey60 => [153, 153, 153],
91             grey70 => [178, 178, 178], grey80 => [204, 204, 204], grey90 => [229, 229, 229],
92             black => [0, 0, 0], white => [255, 255, 255],
93              
94             # X-Windows colours, unless they clash with the above (only /(dark)?(red|green|blue)/ )
95             aliceblue => [240, 248, 255], antiquewhite => [250, 235, 215], aqua => [0, 255, 255],
96             aquamarine => [127, 255, 212], azure => [240, 255, 255], beige => [245, 245, 220],
97             bisque => [255, 228, 196], blanchedalmond => [255, 255, 205], blueviolet => [138, 43, 226],
98             brown => [165, 42, 42], burlywood => [222, 184, 135], cadetblue => [95, 158, 160],
99             chartreuse => [127, 255, 0], chocolate => [210, 105, 30], coral => [255, 127, 80],
100             cornflowerblue => [100, 149, 237], cornsilk => [255, 248, 220], crimson => [220, 20, 60],
101             cyan => [0, 255, 255], darkcyan => [0, 139, 139], darkgoldenrod => [184, 134, 11],
102             darkgray => [169, 169, 169], darkgrey => [169, 169, 169], darkkhaki => [189, 183, 107],
103             darkmagenta => [139, 0, 139], darkolivegreen => [85, 107, 47], darkorange => [255, 140, 0],
104             darkorchid => [153, 50, 204], darksalmon => [233, 150, 122], darkseagreen => [143, 188, 143],
105             darkslateblue => [72, 61, 139], darkslategray => [47, 79, 79], darkslategrey => [47, 79, 79],
106             darkturquoise => [0, 206, 209], darkviolet => [148, 0, 211], deeppink => [255, 20, 147],
107             deepskyblue => [0, 191, 255], dimgray => [105, 105, 105], dimgrey => [105, 105, 105],
108             dodgerblue => [30, 144, 255], firebrick => [178, 34, 34], floralwhite => [255, 250, 240],
109             forestgreen => [34, 139, 34], fuchsia => [255, 0, 255], gainsboro => [220, 220, 220],
110             ghostwhite => [248, 248, 255], gold => [255, 215, 0], goldenrod => [218, 165, 32],
111             gray => [128, 128, 128], grey => [128, 128, 128], greenyellow => [173, 255, 47],
112             honeydew => [240, 255, 240], hotpink => [255, 105, 180], indianred => [205, 92, 92],
113             indigo => [75, 0, 130], ivory => [255, 240, 240], khaki => [240, 230, 140],
114             lavender => [230, 230, 250], lavenderblush => [255, 240, 245], lawngreen => [124, 252, 0],
115             lemonchiffon => [255, 250, 205], lightblue => [173, 216, 230], lightcoral => [240, 128, 128],
116             lightcyan => [224, 255, 255], lightgoldenrodyellow => [250, 250, 210], lightgray => [211, 211, 211],
117             lightgreen => [144, 238, 144], lightgrey => [211, 211, 211], lightpink => [255, 182, 193],
118             lightsalmon => [255, 160, 122], lightseagreen => [32, 178, 170], lightskyblue => [135, 206, 250],
119             lightslategray => [119, 136, 153], lightslategrey => [119, 136, 153], lightsteelblue => [176, 196, 222],
120             lightyellow => [255, 255, 224], lime => [0, 255, 0], limegreen => [50, 205, 50],
121             linen => [250, 240, 230], magenta => [255, 0, 255], maroon => [128, 0, 0],
122             mediumaquamarine => [102, 205, 170], mediumblue => [0, 0, 205], mediumorchid => [186, 85, 211],
123             mediumpurple => [147, 112, 219], mediumseagreen => [60, 179, 113], mediumslateblue => [123, 104, 238],
124             mediumspringgreen => [0, 250, 154], mediumturquoise => [72, 209, 204], mediumvioletred => [199, 21, 133],
125             midnightblue => [25, 25, 112], mintcream => [245, 255, 250], mistyrose => [255, 228, 225],
126             moccasin => [255, 228, 181], navajowhite => [255, 222, 173], navy => [0, 0, 128],
127             oldlace => [253, 245, 230], olive => [128, 128, 0], olivedrab => [107, 142, 35],
128             orange => [255, 165, 0], orangered => [255, 69, 0], orchid => [218, 112, 214],
129             palegoldenrod => [238, 232, 170], palegreen => [152, 251, 152], paleturquoise => [175, 238, 238],
130             palevioletred => [219, 112, 147], papayawhip => [255, 239, 213], peachpuff => [255, 218, 185],
131             peru => [205, 133, 63], pink => [255, 192, 203], plum => [221, 160, 221],
132             powderblue => [176, 224, 230], purple => [128, 0, 128], rosybrown => [188, 143, 143],
133             royalblue => [65, 105, 225], saddlebrown => [139, 69, 19], salmon => [250, 128, 114],
134             sandybrown => [244, 164, 96], seagreen => [46, 139, 87], seashell => [255, 245, 238],
135             sienna => [160, 82, 45], silver => [192, 192, 192], skyblue => [135, 206, 235],
136             slateblue => [106, 90, 205], slategray => [112, 128, 144], slategrey => [112, 128, 144],
137             snow => [255, 250, 250], springgreen => [0, 255, 127], steelblue => [70, 130, 180],
138             tan => [210, 180, 140], teal => [0, 128, 128], thistle => [216, 191, 216],
139             tomato => [253, 99, 71], turquoise => [64, 224, 208], violet => [238, 130, 238],
140             wheat => [245, 222, 179], whitesmoke => [245, 245, 245], yellow => [255, 255, 0],
141             yellowgreen => [154, 205, 50],
142             );
143              
144              
145             # define page sizes here (a4, letter, etc)
146             # should be Properly Cased
147             my %pspaper = (
148             A0 => [2384, 3370],
149             A1 => [1684, 2384],
150             A2 => [1191, 1684],
151             A3 => [841.88976, 1190.5512],
152             A4 => [595.27559, 841.88976],
153             A5 => [420.94488, 595.27559],
154             A6 => [297, 420],
155             A7 => [210, 297],
156             A8 => [148, 210],
157             A9 => [105, 148],
158              
159             B0 => [2920, 4127],
160             B1 => [2064, 2920],
161             B2 => [1460, 2064],
162             B3 => [1032, 1460],
163             B4 => [729, 1032],
164             B5 => [516, 729],
165             B6 => [363, 516],
166             B7 => [258, 363],
167             B8 => [181, 258],
168             B9 => [127, 181 ],
169             B10 => [91, 127],
170              
171             Executive => [522, 756],
172             Folio => [595, 935],
173             'Half-Letter' => [612, 397],
174             Letter => [612, 792],
175             'US-Letter' => [612, 792],
176             Legal => [612, 1008],
177             'US-Legal' => [612, 1008],
178             Tabloid => [792, 1224],
179             'SuperB' => [843, 1227],
180             Ledger => [1224, 792],
181              
182             'Comm #10 Envelope' => [297, 684],
183             'Envelope-Monarch' => [280, 542],
184             'Envelope-DL' => [312, 624],
185             'Envelope-C5' => [461, 648],
186              
187             'EuroPostcard' => [298, 420],
188             );
189              
190              
191             # The 13 standard fonts that are available on all PS 1 implementations:
192             my @fonts = (
193             'Courier', 'Courier-Bold', 'Courier-BoldOblique', 'Courier-Oblique',
194             'Helvetica', 'Helvetica-Bold', 'Helvetica-BoldOblique', 'Helvetica-Oblique',
195             'Times-Roman', 'Times-Bold', 'Times-BoldItalic', 'Times-Italic',
196             'Symbol');
197              
198             # define the origins for the page a document can have
199             # (default is "LeftBottom")
200             my %psorigin = (
201             'LeftBottom' => [ 0, 0],
202             'LeftTop' => [ 0, -1],
203             'RightBottom' => [-1, 0],
204             'RightTop' => [-1, -1],
205             );
206              
207             # define the co-ordinate direction (default is 'RightUp')
208             my %psdirs = (
209             'RightUp' => [ 1, 1],
210             'RightDown' => [ 1, -1],
211             'LeftUp' => [-1, 1],
212             'LeftDown' => [-1, -1],
213             );
214              
215              
216             # measuring units are two-letter acronyms as used in TeX:
217             # bp: postscript point (72 per inch)
218             # in: inch (72 postscript points)
219             # pt: printer's point (72.27 per inch)
220             # mm: millimetre (25.4 per inch)
221             # cm: centimetre (2.54 per inch)
222             # pi: pica (12 printer's points)
223             # dd: didot point (67.567. per inch)
224             # cc: cicero (12 didot points)
225              
226             # set up the others here (sp) XXXXX
227              
228             my %psunits = (
229             pt => [72, 72.27],
230             pc => [72, 6.0225],
231             in => [72, 1],
232             bp => [1, 1],
233             cm => [72, 2.54],
234             mm => [72, 25.4],
235             dd => [72, 67.567],
236             cc => [72, 810.804],
237             );
238              
239              
240             #-------------------------------------------------------------------------------
241              
242             =head1 CONSTRUCTOR
243              
244             =over 4
245              
246             =item C
247              
248             Create a new PostScript::Simple object. The different options that can be set are:
249              
250             =over 4
251              
252             =item units
253              
254             Units that are to be used in the file. Common units would be C, C,
255             C, C, and C. Others are as used in TeX. (Default: C)
256              
257             =item xsize
258              
259             Specifies the width of the drawing area in units.
260              
261             =item ysize
262              
263             Specifies the height of the drawing area in units.
264              
265             =item papersize
266              
267             The size of paper to use, if C or C are not defined. This allows
268             a document to easily be created using a standard paper size without having to
269             remember the size of paper using PostScript points. Valid choices are currently
270             "C", "C", "C", and "C".
271              
272             =item landscape
273              
274             Use the landscape option to rotate the page by 90 degrees. The paper dimensions
275             are also rotated, so that clipping will still work. (Note that the printer will
276             still think that the paper is portrait.) (Default: 0)
277              
278             =item copies
279              
280             Set the number of copies that should be printed. (Default: 1)
281              
282             =item clip
283              
284             If set to 1, the image will be clipped to the xsize and ysize. This is most
285             useful for an EPS image. (Default: 0)
286              
287             =item colour
288              
289             Specifies whether the image should be rendered in colour or not. If set to 0
290             (default) all requests for a colour are mapped to a greyscale. Otherwise the
291             colour requested with C or C is used. This option is present
292             because most modern laser printers are only black and white. (Default: 0)
293              
294             =item eps
295              
296             Generate an EPS file, rather than a standard PostScript file. If set to 1, no
297             newpage methods will actually create a new page. This option is probably the
298             most useful for generating images to be imported into other applications, such
299             as TeX. (Default: 1)
300              
301             =item page
302              
303             Specifies the initial page number of the (multi page) document. The page number
304             is set with the Adobe DSC comments, and is used nowhere else. It only makes
305             finding your pages easier. See also the C method. (Default: 1)
306              
307             =item coordorigin
308              
309             Defines the co-ordinate origin for each page produced. Valid arguments are
310             C, C, C and C. The default is
311             C.
312              
313             =item direction
314              
315             The direction the co-ordinates go from the origin. Values can be C,
316             C, C and C. The default value is C.
317              
318             =item reencode
319              
320             Requests that a font re-encode function be added and that the 13 standard
321             PostScript fonts get re-encoded in the specified encoding. The most popular
322             choice (other than undef) is 'ISOLatin1Encoding' which selects the iso8859-1
323             encoding and fits most of western Europe, including the Scandinavia. Refer to
324             Adobes Postscript documentation for other encodings.
325              
326             The output file is, by default, re-encoded to ISOLatin1Encoding. To stop this
327             happening, use 'reencode => undef'. To use the re-encoded font, '-iso' must be
328             appended to the names of the fonts used, e.g. 'Helvetica-iso'.
329              
330             =back
331              
332             Example:
333              
334             $ref = new PostScript::Simple(landscape => 1,
335             eps => 0,
336             xsize => 4,
337             ysize => 3,
338             units => "in");
339              
340             Create a document that is 4 by 3 inches and prints landscape on a page. It is
341             not an EPS file, and must therefore use the C method.
342              
343             $ref = new PostScript::Simple(eps => 1,
344             colour => 1,
345             xsize => 12,
346             ysize => 12,
347             units => "cm",
348             reencode => "ISOLatin1Encoding");
349              
350             Create a 12 by 12 cm EPS image that is in colour. Note that "C 1>"
351             did not have to be specified because this is the default. Re-encode the
352             standard fonts into the iso8859-1 encoding, providing all the special characters
353             used in Western Europe. The C method should not be used.
354              
355             =back
356              
357             =cut
358              
359             sub new
360             {
361 9     9 1 467 my ($class, %data) = @_;
362 9         159 my $self = {
363             xsize => undef,
364             ysize => undef,
365             papersize => undef,
366             units => "bp", # measuring units (see below)
367             landscape => 0, # rotate the page 90 degrees
368             copies => 1, # number of copies
369             colour => 0, # use colour
370             clip => 0, # clip to the bounding box
371             eps => 1, # create eps file
372             page => 1, # page number to start at
373             reencode => "ISOLatin1Encoding", # Re-encode the 13 standard
374             # fonts in this encoding
375              
376             bbx1 => 0, # Bounding Box definitions
377             bby1 => 0,
378             bbx2 => 0,
379             bby2 => 0,
380              
381             pscomments => "", # the following entries store data
382             psprolog => "", # for the same DSC areas of the
383             psresources => {}, # postscript file.
384             pssetup => "",
385             pspages => [],
386             pstrailer => "",
387             usedunits => {}, # units that have been used
388              
389             lastfontsize => 0,
390             pspagecount => 0,
391              
392             coordorigin => 'LeftBottom',
393             direction => 'RightUp',
394              
395             lasterror => undef,
396             };
397              
398 9         38 foreach (keys %data) {
399 26         29 $self->{$_} = $data{$_};
400             }
401              
402 9         36 bless $self, $class;
403 9         38 $self->init();
404              
405 9         28 return $self;
406             }
407              
408              
409             #-------------------------------------------------------------------------------
410              
411             sub _u
412             {
413 519     519   1927 my ($self, $u, $rev) = @_;
414              
415 519         282 my $val;
416             my $unit;
417              
418             # $u may be...
419             # a simple number, in which case the current units are used
420             # a listref of [number, "unit"], to force the unit
421             # a string "number unit", e.g. "4 mm" or "2.4in"
422              
423 519 100       529 if (ref($u) eq "ARRAY") {
424 5         7 $val = $$u[0];
425 5         6 $unit = $$u[1];
426 5 100       263 confess "Invalid array" if @$u != 2;
427             } else {
428 514 100       1656 if ($u =~ /^\s*(-?\d+(?:\.\d+)?)\s*([a-z][a-z])?\s*$/) {
429 512         556 $val = $1;
430 512   66     917 $unit = $2 || $self->{units};
431             }
432             }
433              
434 517 100       727 confess "Cannot determine length" unless defined $val;
435 515 50       592 confess "Cannot determine unit (invalid array?)" unless defined $unit;
436              
437 515 100       690 croak "Invalid unit '$unit'" unless defined $psunits{$unit};
438              
439 514 100       590 unless (defined $self->{usedunits}{$unit}) {
440 15         18 my ($m, $d) = @{$psunits{$unit}};
  15         26  
441              
442 15         20 my $c = "{";
443 15 100       38 $c .= "$m mul " unless $m == 1;
444 15 100       75 $c .= "$d div " unless $d == 1;
445 15         34 $c =~ s/ $//;
446 15         18 $c .="}";
447 15         40 $self->{usedunits}{$unit} = "/u$unit $c def";
448             }
449              
450 514 100       823 $val = $rev * $val if defined $rev;
451              
452 514         1231 return "$val u$unit ";
453             }
454              
455             sub _ux
456             {
457 251     251   352 my ($self, $d) = @_;
458              
459 251         340 return $self->_u($d, $psdirs{$self->{direction}}[0]);
460             }
461              
462             sub _uy
463             {
464 250     250   203 my ($self, $d) = @_;
465              
466 250         302 return $self->_u($d, $psdirs{$self->{direction}}[1]);
467             }
468              
469             sub _uxy
470             {
471 249     249   225 my ($self, $x, $y) = @_;
472              
473 249         271 return $self->_ux($x) . $self->_uy($y);
474             }
475              
476              
477             sub init
478             {
479 9     9 0 18 my $self = shift;
480              
481 9         22 my ($m, $d) = (1, 1);
482 9         11 my ($u, $mm);
483              
484             # Create a blank "page" for EPS
485 9 100       53 if ($self->{eps}) {
486 7         12 $self->{currentpage} = [];
487 7         18 $self->{pspages} = [$self->{currentpage}];
488             }
489              
490              
491             # Units
492 9         23 $self->{units} = lc $self->{units};
493              
494 9 50       33 if (defined($psunits{$self->{units}})) {
495 9         64 ($m, $d) = @{$psunits{$self->{units}}};
  9         39  
496             } else {
497 0         0 $self->_error( "unit '$self->{units}' undefined" );
498             }
499              
500              
501             # Paper size
502 9 100       62 if (defined $self->{papersize}) {
503 3         12 $self->{papersize} = ucfirst lc $self->{papersize};
504             }
505              
506 9 100 66     75 if (!defined $self->{xsize} || !defined $self->{ysize}) {
507 6 100 66     31 if (defined $self->{papersize} && defined $pspaper{$self->{papersize}}) {
508 3         6 ($self->{xsize}, $self->{ysize}) = @{$pspaper{$self->{papersize}}};
  3         12  
509 3         11 $self->{bbx2} = int($self->{xsize});
510 3         4 $self->{bby2} = int($self->{ysize});
511 3         48 $self->{pscomments} .= "\%\%DocumentMedia: $self->{papersize} $self->{xsize} ";
512 3         12 $self->{pscomments} .= "$self->{ysize} 0 ( ) ( )\n";
513             } else {
514 3         4 ($self->{xsize}, $self->{ysize}) = (100,100);
515 3         6 $self->_error( "page size undefined" );
516             }
517             } else {
518 3         14 $self->{bbx2} = int(($self->{xsize} * $m) / $d);
519 3         7 $self->{bby2} = int(($self->{ysize} * $m) / $d);
520             }
521              
522 9 100       42 if (!$self->{eps}) {
523 2         17 $self->{pssetup} .= "ll 2 ge { << /PageSize [ $self->{xsize} " .
524             "$self->{ysize} ] /ImagingBBox null >>" .
525             " setpagedevice } if\n";
526             }
527              
528             # Landscape
529 9 50       19 if ($self->{landscape}) {
530 0         0 my $swap;
531              
532 0         0 $self->{psresources}{landscape} = <<"EOP";
533             /landscape {
534             $self->{bbx2} 0 translate 90 rotate
535             } bind def
536             EOP
537              
538             # I now think that Portrait is the correct thing here, as the page is
539             # rotated.
540 0         0 $self->{pscomments} .= "\%\%Orientation: Portrait\n";
541             # $self->{pscomments} .= "\%\%Orientation: Landscape\n";
542 0         0 $swap = $self->{bbx2};
543 0         0 $self->{bbx2} = $self->{bby2};
544 0         0 $self->{bby2} = $swap;
545              
546             # for EPS files, change to landscape here, as there are no pages
547 0 0       0 if ($self->{eps}) { $self->{pssetup} .= "landscape\n" }
  0         0  
548             } else {
549 9         15 $self->{pscomments} .= "\%\%Orientation: Portrait\n";
550             }
551            
552             # Clipping
553 9 50       22 if ($self->{clip}) {
554 0         0 $self->{psresources}{pageclip} = <<"EOP";
555             /pageclip {
556             newpath
557             $self->{bbx1} $self->{bby1} moveto
558             $self->{bbx1} $self->{bby2} lineto
559             $self->{bbx2} $self->{bby2} lineto
560             $self->{bbx2} $self->{bby1} lineto
561             $self->{bbx1} $self->{bby1} lineto
562             closepath clip
563             } bind def
564             EOP
565 0 0       0 if ($self->{eps}) { $self->{pssetup} .= "pageclip\n" }
  0         0  
566             }
567              
568             # Font reencoding
569 9 100       22 if ($self->{reencode}) {
570 8         8 my $encoding; # The name of the encoding
571             my $ext; # The extention to tack onto the std fontnames
572              
573 8 50       18 if (ref $self->{reencode} eq 'ARRAY') {
574 0         0 die "Custom reencoding of fonts not really implemented yet, sorry...";
575 0         0 $encoding = shift @{$self->{reencode}};
  0         0  
576 0         0 $ext = shift @{$self->{reencode}};
  0         0  
577             # TODO: Do something to add the actual encoding to the postscript code.
578             } else {
579 8         11 $encoding = $self->{reencode};
580 8         15 $ext = '-iso';
581             }
582              
583 8         47 $self->{psresources}{REENCODEFONT} = <<'EOP';
584             /STARTDIFFENC { mark } bind def
585             /ENDDIFFENC {
586              
587             % /NewEnc BaseEnc STARTDIFFENC number or glyphname ... ENDDIFFENC -
588             counttomark 2 add -1 roll 256 array copy
589             /TempEncode exch def
590              
591             % pointer for sequential encodings
592             /EncodePointer 0 def
593             {
594             % Get the bottom object
595             counttomark -1 roll
596             % Is it a mark?
597             dup type dup /marktype eq {
598             % End of encoding
599             pop pop exit
600             } {
601             /nametype eq {
602             % Insert the name at EncodePointer
603              
604             % and increment the pointer.
605             TempEncode EncodePointer 3 -1 roll put
606             /EncodePointer EncodePointer 1 add def
607             } {
608             % Set the EncodePointer to the number
609             /EncodePointer exch def
610             } ifelse
611             } ifelse
612             } loop
613              
614             TempEncode def
615             } bind def
616              
617             % Define ISO Latin1 encoding if it doesnt exist
618             /ISOLatin1Encoding where {
619             % (ISOLatin1 exists!) =
620             pop
621             } {
622             (ISOLatin1 does not exist, creating...) =
623             /ISOLatin1Encoding StandardEncoding STARTDIFFENC
624             144 /dotlessi /grave /acute /circumflex /tilde
625             /macron /breve /dotaccent /dieresis /.notdef /ring
626             /cedilla /.notdef /hungarumlaut /ogonek /caron /space
627             /exclamdown /cent /sterling /currency /yen /brokenbar
628             /section /dieresis /copyright /ordfeminine
629             /guillemotleft /logicalnot /hyphen /registered
630             /macron /degree /plusminus /twosuperior
631             /threesuperior /acute /mu /paragraph /periodcentered
632             /cedilla /onesuperior /ordmasculine /guillemotright
633             /onequarter /onehalf /threequarters /questiondown
634             /Agrave /Aacute /Acircumflex /Atilde /Adieresis
635             /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex
636             /Edieresis /Igrave /Iacute /Icircumflex /Idieresis
637             /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde
638             /Odieresis /multiply /Oslash /Ugrave /Uacute
639             /Ucircumflex /Udieresis /Yacute /Thorn /germandbls
640             /agrave /aacute /acircumflex /atilde /adieresis
641             /aring /ae /ccedilla /egrave /eacute /ecircumflex
642             /edieresis /igrave /iacute /icircumflex /idieresis
643             /eth /ntilde /ograve /oacute /ocircumflex /otilde
644             /odieresis /divide /oslash /ugrave /uacute
645             /ucircumflex /udieresis /yacute /thorn /ydieresis
646             ENDDIFFENC
647             } ifelse
648              
649             % Name: Re-encode Font
650             % Description: Creates a new font using the named encoding.
651              
652             /REENCODEFONT { % /Newfont NewEncoding /Oldfont
653             findfont dup length 4 add dict
654             begin
655             { % forall
656             1 index /FID ne
657             2 index /UniqueID ne and
658             2 index /XUID ne and
659             { def } { pop pop } ifelse
660             } forall
661             /Encoding exch def
662             % defs for DPS
663             /BitmapWidths false def
664             /ExactSize 0 def
665             /InBetweenSize 0 def
666             /TransformedChar 0 def
667             currentdict
668             end
669             definefont pop
670             } bind def
671              
672             % Reencode the std fonts:
673             EOP
674              
675 8         19 for my $font (@fonts) {
676 104         180 $self->{psresources}{REENCODEFONT} .= "/${font}$ext $encoding /$font REENCODEFONT\n";
677             }
678             }
679             }
680              
681              
682             #-------------------------------------------------------------------------------
683              
684             =head1 OBJECT METHODS
685              
686             Unless otherwise specified, object methods return 1 for success or 0 in some
687             error condition (e.g. insufficient arguments). Error message text is also
688             drawn on the page.
689              
690             =over 4
691              
692             =item C
693              
694             Generates a new page on a PostScript file. If specified, C gives the
695             number (or name) of the page. This method should not be used for EPS files.
696              
697             The page number is automatically incremented each time this is called without
698             a new page number, or decremented if the current page number is negative.
699              
700             Example:
701              
702             $p->newpage(1);
703             $p->newpage;
704             $p->newpage("hello");
705             $p->newpage(-6);
706             $p->newpage;
707              
708             will generate five pages, numbered: 1, 2, "hello", -6, -7.
709              
710             =cut
711              
712             sub newpage
713             {
714 5     5 1 947 my $self = shift;
715 5         8 my $nextpage = shift;
716            
717 5 100       11 if (defined($nextpage)) { $self->{page} = $nextpage; }
  2         3  
718              
719 5 100       12 if ($self->{eps}) {
720             # Cannot have multiple pages in an EPS file
721 1         5 $self->_error("Do not use newpage for eps files!");
722 1         3 return 0;
723             }
724              
725             # close old page if required
726 4 100       9 if ($self->{pspagecount} != 0) {
727 2         4 $self->_closepage();
728             }
729              
730             # start new page
731 4         9 $self->_openpage();
732              
733 4         8 return 1;
734             }
735              
736              
737             sub _openpage
738             {
739 4     4   4 my $self = shift;
740 4         3 my ($x, $y);
741              
742 4         6 $self->{pspagecount}++;
743              
744 4         6 $self->{currentpage} = [];
745 4         3 push @{$self->{pspages}}, $self->{currentpage};
  4         8  
746              
747 4         17 $self->_addtopage("\%\%Page: $self->{page} $self->{pspagecount}\n");
748              
749 4 100       8 if ($self->{page} >= 0) {
750 2         4 $self->{page} ++;
751             } else {
752 2         3 $self->{page} --;
753             }
754              
755 4         6 $self->_addtopage("\%\%BeginPageSetup\n");
756 4         6 $self->_addtopage("/pagelevel save def\n");
757              
758 4 50       10 if ($self->{landscape}) { $self->_addtopage("landscape\n"); }
  0         0  
759 4 50       8 if ($self->{clip}) { $self->_addtopage("pageclip\n"); }
  0         0  
760              
761 4         9 ($x, $y) = @{$psorigin{$self->{coordorigin}}};
  4         8  
762 4 50       9 $x = $self->{xsize} if ($x < 0);
763 4 50       7 $y = $self->{ysize} if ($y < 0);
764 4 50 33     20 $self->_addtopage("$x $y translate\n") if (($x != 0) || ($y != 0));
765 4         6 $self->_addtopage("\%\%EndPageSetup\n");
766             }
767              
768             sub _closepage
769             {
770 4     4   6 my $self = shift;
771              
772 4         11 $self->_addtopage("\%\%PageTrailer\npagelevel restore\nshowpage\n");
773             }
774              
775              
776              
777             #-------------------------------------------------------------------------------
778              
779             =item C
780              
781             Writes the current PostScript out to the file named C. Will destroy
782             any existing file of the same name.
783              
784             Use this method whenever output is required to disk. The current PostScript
785             document in memory is not cleared, and can still be extended.
786              
787             =cut
788              
789             sub _builddocument
790             {
791 4     4   8 my $self = shift;
792 4         17 my $title = shift;
793            
794 4         5 my $doc;
795 4         649 my $date = scalar localtime;
796 4         8 my $user;
797              
798 4 50       12 $title = 'undefined' unless $title;
799              
800 4         9 $doc = [];
801              
802             # getlogin is unimplemented on some systems
803 4         7 eval { $user = getlogin; };
  4         2206  
804 4 50       27 $user = 'Console' unless $user;
805              
806             # Comments Section
807 4         9 push @$doc, "%!PS-Adobe-3.0";
808 4 100       16 push @$doc, " EPSF-1.2" if ($self->{eps});
809 4         9 push @$doc, "\n";
810 4         12 push @$doc, "\%\%Title: ($title)\n";
811 4         12 push @$doc, "\%\%LanguageLevel: 1\n";
812 4         12 push @$doc, "\%\%Creator: PostScript::Simple perl module version $VERSION\n";
813 4         12 push @$doc, "\%\%CreationDate: $date\n";
814 4         8 push @$doc, "\%\%For: $user\n";
815 4         16 push @$doc, \$self->{pscomments};
816             # push @$doc, "\%\%DocumentFonts: \n";
817 4 100       18 if ($self->{eps}) {
818 2         12 push @$doc, "\%\%BoundingBox: $self->{bbx1} $self->{bby1} $self->{bbx2} $self->{bby2}\n";
819             } else {
820 2         7 push @$doc, "\%\%Pages: $self->{pspagecount}\n";
821             }
822 4         10 push @$doc, "\%\%EndComments\n";
823            
824             # Prolog Section
825 4         8 push @$doc, "\%\%BeginProlog\n";
826 4         5 push @$doc, "/ll 1 def systemdict /languagelevel known {\n";
827 4         7 push @$doc, "/ll languagelevel def } if\n";
828 4         8 push @$doc, \$self->{psprolog};
829 4         5 foreach my $fn (sort keys %{$self->{psresources}}) {
  4         33  
830 13         23 push @$doc, "\%\%BeginResource: PostScript::Simple-$fn\n";
831 13         24 push @$doc, $self->{psresources}{$fn};
832 13         18 push @$doc, "\%\%EndResource\n";
833             }
834 4         12 push @$doc, "\%\%EndProlog\n";
835              
836             # Setup Section
837 4         10 push @$doc, "\%\%BeginSetup\n";
838 4         7 foreach my $un (sort keys %{$self->{usedunits}}) {
  4         12  
839 5         11 push @$doc, $self->{usedunits}{$un} . "\n";
840             }
841 4 50       16 if ($self->{copies} > 1) {
842 0         0 push @$doc, "/#copies " . $self->{copies} . " def\n";
843             }
844 4         8 push @$doc, \$self->{pssetup};
845 4         12 push @$doc, "\%\%EndSetup\n";
846              
847             # Pages
848 4 100 66     23 if ((!$self->{eps}) && ($self->{pspagecount} > 0)) {
849 2         6 $self->_closepage();
850             }
851              
852 4         5 foreach my $page (@{$self->{pspages}}) {
  4         10  
853 6         21 push @$doc, $self->_buildpage($page);
854             }
855              
856             # Trailer Section
857 4 50       12 if (length($self->{pstrailer})) {
858 0         0 push @$doc, "\%\%Trailer\n";
859 0         0 push @$doc, \$self->{pstrailer};
860             }
861 4         10 push @$doc, "\%\%EOF\n";
862            
863 4         7 return $doc;
864             }
865              
866             sub _buildpage
867             {
868 9     9   342 my ($self, $page) = @_;
869              
870 9         12 my $data = "";
871              
872 9         16 foreach my $statement (@$page) {
873 618         511 $data .= $$statement[1];
874             }
875              
876 9         29 return $data;
877             }
878              
879             #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
880              
881             sub output
882             {
883 5     5 1 1578 my $self = shift;
884 5   100     25 my $file = shift || die("Must supply a filename for output");
885 4         7 my $page;
886             my $i;
887            
888 4         19 $page = _builddocument($self, $file);
889              
890 4         14 local *OUT;
891 4 50       409 open(OUT, '>', $file) or die("Cannot write to file $file: $!");
892              
893 4         9 foreach $i (@$page) {
894 128 100       114 if (ref($i) eq "SCALAR") {
895 12         16 print OUT $$i;
896             } else {
897 116         182 print OUT $i;
898             }
899             }
900              
901 4         225 close OUT;
902            
903 4         29 return 1;
904             }
905              
906              
907             #-------------------------------------------------------------------------------
908              
909             =item C
910              
911             Returns the current document.
912              
913             Use this method whenever output is required as a scalar. The current PostScript
914             document in memory is not cleared, and can still be extended.
915              
916             =cut
917              
918             sub get
919             {
920 0     0 1 0 my $self = shift;
921 0         0 my $page;
922             my $i;
923 0         0 my $doc;
924            
925 0         0 $page = _builddocument($self, "PostScript::Simple generated page");
926 0         0 $doc = "";
927 0         0 foreach $i (@$page) {
928 0 0       0 if (ref($i) eq "SCALAR") {
929 0         0 $doc .= $$i;
930             } else {
931 0         0 $doc .= $i;
932             }
933             }
934 0         0 return $doc;
935             }
936              
937              
938             #-------------------------------------------------------------------------------
939              
940             =item C
941              
942             Returns the current document as a PostScript::Simple::EPS object. Only works if
943             the current document is EPS.
944              
945             This method calls new PostScript::Simple::EPS with all the default options. To
946             change these, call it yourself as below, rather than using this method.
947              
948             $eps = new PostScript::Simple::EPS(source => $ps->get);
949              
950             =cut
951              
952             sub geteps
953             {
954 0     0 1 0 my $self = shift;
955 0         0 my $page;
956             my $i;
957 0         0 my $doc;
958 0         0 my $eps;
959            
960 0 0       0 croak "document is not EPS" unless ($$self{eps} == 1);
961              
962 0         0 $eps = new PostScript::Simple::EPS(source => $self->get);
963 0         0 return $eps;
964             }
965              
966              
967             #-------------------------------------------------------------------------------
968              
969             =item C
970              
971             Sets the new drawing colour to the RGB values specified in C, C and
972             C. The values range from 0 to 255.
973              
974             Alternatively, a colour name may be specified. Those currently defined are
975             listed at the top of the PostScript::Simple module in the C<%pscolours> hash
976             and include the standard X-Windows colour names.
977              
978             Example:
979              
980             # set new colour to brown
981             $p->setcolour(200,100,0);
982             # set new colour to black
983             $p->setcolour("black");
984              
985             =cut
986              
987             sub setcolour
988             {
989 53     53 1 317 my $self = shift;
990 53         46 my ($r, $g, $b) = @_;
991              
992 53 100       81 if ( @_ == 1 ) {
993 10         9 $r = lc $r;
994 10 100       23 if (defined $pscolours{$r}) {
995 9         8 ($r, $g, $b) = @{$pscolours{$r}};
  9         16  
996             } else {
997 1         4 $self->_error( "bad colour name '$r'" );
998 1         3 return 0;
999             }
1000             }
1001              
1002 52         43 my $bad = 0;
1003 52 50       75 if (not defined $r) { $r = 'undef'; $bad = 1; }
  0         0  
  0         0  
1004 52 50       78 if (not defined $g) { $g = 'undef'; $bad = 1; }
  0         0  
  0         0  
1005 52 100       68 if (not defined $b) { $b = 'undef'; $bad = 1; }
  2         2  
  2         3  
1006              
1007 52 100       60 if ($bad) {
1008 2         14 $self->_error( "setcolour given invalid arguments: $r, $g, $b" );
1009 2         13 return 0;
1010             }
1011              
1012             # make sure floats aren't too long, and means the tests pass when
1013             # using a system with long doubles enabled by default
1014 50         259 $r = 0 + sprintf("%0.5f", $r / 255);
1015 50         100 $g = 0 + sprintf("%0.5f", $g / 255);
1016 50         90 $b = 0 + sprintf("%0.5f", $b / 255);
1017              
1018 50 50       69 if ($self->{colour}) {
1019 50         188 $self->_addtopage("$r $g $b setrgbcolor\n");
1020             } else {
1021             # Better colour->grey conversion than just 0.33 of each:
1022 0         0 $r = 0.3*$r + 0.59*$g + 0.11*$b;
1023 0         0 $r = 0 + sprintf("%0.5f", $r / 255);
1024 0         0 $self->_addtopage("$r setgray\n");
1025             }
1026            
1027 50         78 return 1;
1028             }
1029              
1030              
1031             #-------------------------------------------------------------------------------
1032              
1033             =item C
1034              
1035             Sets the new drawing colour to the CMYK values specified in C,
1036             C, C. The values range from 0 to 1. Note that
1037             PostScript::Simple does not do any colour management, so the output colour (as
1038             also with C) may vary according to output device.
1039              
1040             Example:
1041              
1042             # set new colour to a shade of blue
1043             $p->setcmykcolour(0.1, 0.5, 0, 0.2);
1044             # set new colour to black
1045             $p->setcmykcolour(0, 0, 0, 1);
1046             # set new colour to a rich black
1047             $p->setcmykcolour(0.5, 0.5, 0.5, 1);
1048              
1049             =cut
1050              
1051             sub setcmykcolour
1052             {
1053 3     3 1 4 my $self = shift;
1054 3         5 my ($c, $m, $y, $k) = @_;
1055              
1056 3 100       7 if ( @_ != 4 ) {
1057 2         5 $self->_error( "setcmykcolour given incorrect number of arguments" );
1058 2         6 return 0;
1059             }
1060              
1061             # Don't currently convert to grey if colour is not set. Patches welcome for
1062             # something that gives a reasonable approximation...
1063              
1064 1         14 $self->_addtopage("$c $m $y $k setcmykcolor\n");
1065            
1066 1         5 return 1;
1067             }
1068              
1069              
1070             #-------------------------------------------------------------------------------
1071              
1072             =item C
1073              
1074             Sets the new line width to C units.
1075              
1076             Example:
1077              
1078             # draw a line 10mm long and 4mm wide
1079             $p = new PostScript::Simple(units => "mm");
1080             $p->setlinewidth(4);
1081             $p->line(10,10, 20,10);
1082              
1083             =cut
1084              
1085             sub setlinewidth
1086             {
1087 5     5 1 10 my $self = shift;
1088 5   66     13 my $width = shift || do {
1089             $self->_error( "setlinewidth not given a width" ); return 0;
1090             };
1091              
1092 4 100       9 $width = "0.4 bp" if $width eq "thin";
1093              
1094 4         9 $self->_addtopage($self->_u($width) . "setlinewidth\n");
1095            
1096 4         8 return 1;
1097             }
1098              
1099              
1100             #-------------------------------------------------------------------------------
1101              
1102             =item C
1103              
1104             Draws a line from the co-ordinates (x1,x2) to (x2,y2). If values are specified
1105             for C, C and C, then the colour is set before the line is drawn.
1106              
1107             Example:
1108              
1109             # set the colour to black
1110             $p->setcolour("black");
1111              
1112             # draw a line in the current colour (black)
1113             $p->line(10,10, 10,20);
1114            
1115             # draw a line in red
1116             $p->line(20,10, 20,20, 255,0,0);
1117              
1118             # draw another line in red
1119             $p->line(30,10, 30,20);
1120              
1121             =cut
1122              
1123             sub line
1124             {
1125 13     13 1 33 my $self = shift;
1126 13         16 my ($x1, $y1, $x2, $y2, $r, $g, $b) = @_;
1127              
1128 13 50 66     32 if ((!$self->{pspagecount}) and (!$self->{eps})) {
1129             # Cannot draw on to non-page when not an eps file
1130 0         0 return 0;
1131             }
1132              
1133 13 100       36 if ( @_ == 7 ) {
    100          
1134 4         8 $self->setcolour($r, $g, $b);
1135             } elsif ( @_ != 4 ) {
1136 2         3 $self->_error( "wrong number of args for line" );
1137 2         28 return 0;
1138             }
1139            
1140 11         22 $self->newpath;
1141 11         22 $self->moveto($x1, $y1);
1142 11         16 $self->_addtopage($self->_uxy($x2, $y2) . "lineto stroke\n");
1143            
1144 11         23 return 1;
1145             }
1146              
1147              
1148             #-------------------------------------------------------------------------------
1149              
1150             =item C
1151              
1152             Assuming the previous command was C, C, C or
1153             C, extend that line to include another segment to the co-ordinates
1154             (x,y). Behaviour after any other method is unspecified.
1155              
1156             Example:
1157              
1158             $p->line(10,10, 10,20);
1159             $p->linextend(20,20);
1160             $p->linextend(20,10);
1161             $p->linextend(10,10);
1162              
1163             Notes
1164              
1165             The C method may be more appropriate.
1166              
1167             =cut
1168              
1169             sub linextend
1170             {
1171 6     6 1 14 my $self = shift;
1172 6         7 my ($x, $y) = @_;
1173              
1174 6 100       15 unless ( @_ == 2 ) {
1175 1         3 $self->_error( "wrong number of args for linextend" );
1176 1         3 return 0;
1177             }
1178              
1179 5         8 my $out = $self->_uxy($x, $y) . "lineto stroke\n";
1180              
1181 5         8 my $p = $self->{currentpage};
1182 5         6 my $last = pop @$p;
1183 5         7 $last = $$last[1];
1184 5         29 $last =~ s/eto stroke\n$/eto\n$out/;
1185 5         9 $self->_addtopage($last);
1186              
1187             # FIXMEFIXMEFIXME
1188             # perhaps we need something like $self->{_lastcommand} to know if operations
1189             # are valid, rather than using a regexp?
1190              
1191 5         10 return 1;
1192             }
1193              
1194              
1195             #-------------------------------------------------------------------------------
1196              
1197             =item C
1198              
1199             Draws an arc on the circle of radius C with centre (C,C). The arc
1200             starts at angle C and finishes at C. Angles are specified
1201             in degrees, where 0 is at 3 o'clock, and the direction of travel is anti-clockwise.
1202              
1203             Any options are passed in a hash reference as the first parameter. The available
1204             option is:
1205              
1206             =over 4
1207              
1208             =item filled => 1
1209              
1210             If C is 1 then the arc will be filled in.
1211              
1212             =back
1213              
1214             Example:
1215              
1216             # semi-circle
1217             $p->arc(10, 10, 5, 0, 180);
1218              
1219             # complete filled circle
1220             $p->arc({filled=>1}, 30, 30, 10, 0, 360);
1221              
1222             =cut
1223              
1224             sub arc
1225             {
1226 0     0 1 0 my $self = shift;
1227 0         0 my %opt = ();
1228              
1229 0 0       0 if (ref($_[0])) {
1230 0         0 %opt = %{; shift};
  0         0  
1231             }
1232              
1233 0 0 0     0 if ((!$self->{pspagecount}) and (!$self->{eps})) {
1234             # Cannot draw on to non-page when not an eps file
1235 0         0 return 0;
1236             }
1237              
1238 0         0 my ($x, $y, $r, $sa, $ea) = @_;
1239              
1240 0 0       0 unless (@_ == 5) {
1241 0         0 $self->_error("arc: wrong number of arguments");
1242 0         0 return 0;
1243             }
1244              
1245 0         0 $self->newpath;
1246 0         0 $self->_addtopage($self->_uxy($x, $y) . $self->_u($r) . "$sa $ea arc ");
1247 0 0       0 if ($opt{'filled'}) {
1248 0         0 $self->_addtopage("fill\n");
1249             } else {
1250 0         0 $self->_addtopage("stroke\n");
1251             }
1252            
1253 0         0 return 1;
1254             }
1255              
1256              
1257             #-------------------------------------------------------------------------------
1258              
1259             =item C
1260              
1261             The C method is multi-function, allowing many shapes to be created and
1262             manipulated. Polygon draws lines from (x1,y1) to (x2,y2) and then from (x2,y2) to
1263             (x3,y3) up to (xn-1,yn-1) to (xn,yn).
1264              
1265             Any options are passed in a hash reference as the first parameter. The available
1266             options are as follows:
1267              
1268             =over 4
1269              
1270             =item rotate => angle
1271             =item rotate => [angle,x,y]
1272              
1273             Rotate the polygon by C degrees anti-clockwise. If x and y are specified
1274             then use the co-ordinate (x,y) as the centre of rotation, otherwise use the
1275             co-ordinate (x1,y1) from the main polygon.
1276              
1277             =item filled => 1
1278              
1279             If C is 1 then the PostScript output is set to fill the object rather
1280             than just draw the lines.
1281              
1282             =item offset => [x,y]
1283              
1284             Displace the object by the vector (x,y).
1285              
1286             =back
1287              
1288             Example:
1289              
1290             # draw a square with lower left point at (10,10)
1291             $p->polygon(10,10, 10,20, 20,20, 20,10, 10,10);
1292              
1293             # draw a filled square with lower left point at (20,20)
1294             $p->polygon( {offset => [10,10], filled => 1},
1295             10,10, 10,20, 20,20, 20,10, 10,10);
1296              
1297             # draw a filled square with lower left point at (10,10)
1298             # rotated 45 degrees (about the point (10,10))
1299             $p->polygon( {rotate => 45, filled => 1},
1300             10,10, 10,20, 20,20, 20,10, 10,10);
1301              
1302             =cut
1303              
1304             sub polygon
1305             {
1306 27     27 1 94 my $self = shift;
1307              
1308 27         26 my %opt = ();
1309 27         23 my ($xoffset, $yoffset) = (0,0);
1310 27         20 my ($rotate, $rotatex, $rotatey) = (0,0,0);
1311              
1312 27 100       46 if ($#_ < 3) {
1313             # cannot have polygon with just one point...
1314 1         2 $self->_error( "bad polygon - not enough points" );
1315 1         4 return 0;
1316             }
1317              
1318 26 100       43 if (ref($_[0])) {
1319 24         16 %opt = %{; shift};
  24         53  
1320             }
1321              
1322 26         22 my $x = shift;
1323 26         18 my $y = shift;
1324              
1325 26 100       45 if (defined $opt{'rotate'}) {
1326 22 100       29 if (ref($opt{'rotate'})) {
1327 20         15 ($rotate, $rotatex, $rotatey) = @{$opt{'rotate'}};
  20         26  
1328             } else {
1329 2         4 ($rotate, $rotatex, $rotatey) = ($opt{'rotate'}, $x, $y);
1330             }
1331             }
1332              
1333 26 100       44 if (defined $opt{'offset'}) {
1334 21 50       21 if (ref($opt{'offset'})) {
1335 21         14 ($xoffset, $yoffset) = @{$opt{'offset'}};
  21         19  
1336             } else {
1337 0         0 $self->_error("polygon: bad offset option" );
1338 0         0 return 0;
1339             }
1340             }
1341              
1342 26 100       47 if (!defined $opt{'filled'}) {
1343 6         8 $opt{'filled'} = 0;
1344             }
1345            
1346 26 50 33     81 unless (defined($x) && defined($y)) {
1347 0         0 $self->_error("polygon: no start point");
1348 0         0 return 0;
1349             }
1350              
1351 26 100 100     103 my $savestate = ($xoffset || $yoffset || $rotate) ? 1 : 0 ;
1352            
1353 26 100       33 if ( $savestate ) {
1354 23         27 $self->_addtopage("gsave ");
1355             }
1356              
1357 26 100 66     76 if ($xoffset || $yoffset) {
1358 3         5 $self->_addtopage($self->_uxy($xoffset, $yoffset) . "translate\n");
1359             }
1360              
1361 26 100       34 if ($rotate) {
1362 21 100       35 unless (defined $self->{psresources}{rotabout}) {
1363 3         6 $self->{psresources}{rotabout} = <<'EOP';
1364             /rotabout {
1365             3 copy pop translate rotate exch
1366             0 exch sub exch 0 exch sub translate
1367             } def
1368             EOP
1369             }
1370              
1371 21         27 $self->_addtopage($self->_uxy($rotatex, $rotatey) . "$rotate rotabout\n");
1372             }
1373            
1374 26         37 $self->newpath;
1375 26         29 $self->moveto($x, $y);
1376            
1377 26         45 while ($#_ > 0) {
1378 63         43 my $x = shift;
1379 63         81 my $y = shift;
1380            
1381 63         69 $self->_addtopage($self->_uxy($x, $y) . "lineto ");
1382             }
1383              
1384 26 100       45 if ($opt{'filled'}) {
1385 2         4 $self->_addtopage("fill\n");
1386             } else {
1387 24         27 $self->_addtopage("stroke\n");
1388             }
1389              
1390 26 100       44 if ( $savestate ) {
1391 23         33 $self->_addtopage("grestore\n");
1392             }
1393            
1394 26         71 return 1;
1395             }
1396              
1397              
1398             #-------------------------------------------------------------------------------
1399              
1400             =item C
1401              
1402             Plot a circle with centre at (x,y) and radius of r.
1403              
1404             There is only one option.
1405              
1406             =over 4
1407              
1408             =item filled => 1
1409              
1410             If C is 1 then the PostScript output is set to fill the object rather
1411             than just draw the lines.
1412              
1413             =back
1414              
1415             Example:
1416              
1417             $p->circle(40,40, 20);
1418             $p->circle( {filled => 1}, 62,31, 15);
1419              
1420             =cut
1421              
1422             sub circle
1423             {
1424 6     6 1 17 my $self = shift;
1425 6         9 my %opt = ();
1426              
1427 6 100       15 if (ref($_[0])) {
1428 2         2 %opt = %{; shift};
  2         6  
1429             }
1430              
1431 6         11 my ($x, $y, $r) = @_;
1432              
1433 6 100       15 unless (@_ == 3) {
1434 2         5 $self->_error("circle: wrong number of arguments");
1435 2         7 return 0;
1436             }
1437              
1438 4 100       11 unless (defined $self->{psresources}{circle}) {
1439 3         10 $self->{psresources}{circle} = "/circle {newpath 0 360 arc closepath} bind def\n";
1440             }
1441              
1442 4         11 $self->_addtopage($self->_uxy($x, $y) . $self->_u($r) . "circle ");
1443 4 100       11 if ($opt{'filled'}) {
1444 2         3 $self->_addtopage("fill\n");
1445             } else {
1446 2         4 $self->_addtopage("stroke\n");
1447             }
1448            
1449 4         10 return 1;
1450             }
1451              
1452              
1453             #-------------------------------------------------------------------------------
1454              
1455             =item C
1456              
1457             Draw text in an arc centered about angle C with circle midpoint (C,C)
1458             and radius C.
1459              
1460             There is only one option.
1461              
1462             =over 4
1463              
1464             =item align => "alignment"
1465              
1466             C can be 'inside' or 'outside'. The default is 'inside'.
1467              
1468             =back
1469              
1470             Example:
1471              
1472             # outside the radius, centered at 90 degrees from the origin
1473             $p->circletext(40, 40, 20, 90, "Hello, Outside World!");
1474             # inside the radius centered at 270 degrees from the origin
1475             $p->circletext( {align => "inside"}, 40, 40, 20, 270, "Hello, Inside World!");
1476              
1477             =cut
1478              
1479             sub circletext
1480             {
1481 0     0 1 0 my $self = shift;
1482 0         0 my %opt = ();
1483              
1484 0 0       0 if (ref($_[0])) {
1485 0         0 %opt = %{; shift};
  0         0  
1486             }
1487              
1488 0         0 my ($x, $y, $r, $a, $text) = @_;
1489              
1490 0 0       0 unless (@_ == 5) {
1491 0         0 $self->_error("circletext: wrong number of arguments");
1492 0         0 return 0;
1493             }
1494              
1495 0 0       0 unless (defined $self->{lastfontsize}) {
1496 0         0 $self->_error("circletext: must set font first");
1497 0         0 return 0;
1498             }
1499              
1500 0 0       0 unless (defined $self->{psresources}{circletext}) {
1501 0         0 $self->{psresources}{circletext} = <<'EOP';
1502             /outsidecircletext
1503             { $circtextdict begin
1504             /radius exch def
1505             /centerangle exch def
1506             /ptsize exch def
1507             /str exch def
1508             /xradius radius ptsize 4 div add def
1509             gsave
1510             centerangle str findhalfangle add rotate
1511             str { /charcode exch def ( ) dup 0 charcode put outsideshowcharandrotate } forall
1512             grestore
1513             end
1514             } def
1515            
1516             /insidecircletext
1517             { $circtextdict begin
1518             /radius exch def
1519             /centerangle exch def
1520             /ptsize exch def
1521             /str exch def
1522             /xradius radius ptsize 3 div sub def
1523             gsave
1524             centerangle str findhalfangle sub rotate
1525             str { /charcode exch def ( ) dup 0 charcode put insideshowcharandrotate } forall
1526             grestore
1527             end
1528             } def
1529             /$circtextdict 16 dict def
1530             $circtextdict begin
1531             /findhalfangle
1532             { stringwidth pop 2 div 2 xradius mul pi mul div 360 mul
1533             } def
1534             /outsideshowcharandrotate
1535             { /char exch def
1536             /halfangle char findhalfangle def
1537             gsave
1538             halfangle neg rotate radius 0 translate -90 rotate
1539             char stringwidth pop 2 div neg 0 moveto char show
1540             grestore
1541             halfangle 2 mul neg rotate
1542             } def
1543             /insideshowcharandrotate
1544             { /char exch def
1545             /halfangle char findhalfangle def
1546             gsave
1547             halfangle rotate radius 0 translate 90 rotate
1548             char stringwidth pop 2 div neg 0 moveto char show
1549             grestore
1550             halfangle 2 mul rotate
1551             } def
1552             /pi 3.1415926 def
1553             end
1554             EOP
1555             }
1556              
1557 0         0 $self->_addtopage("gsave\n");
1558 0         0 $self->_addtopage(" " . $self->_uxy($x, $y) . "translate\n");
1559 0         0 $self->_addtopage(" ($text) $self->{lastfontsize} $a " . $self->_u($r));
1560 0 0 0     0 if ($opt{'align'} && ($opt{'align'} eq "outside")) {
1561 0         0 $self->_addtopage("outsidecircletext\n");
1562             } else {
1563 0         0 $self->_addtopage("insidecircletext\n");
1564             }
1565 0         0 $self->_addtopage("grestore\n");
1566            
1567 0         0 return 1;
1568             }
1569              
1570              
1571             #-------------------------------------------------------------------------------
1572              
1573             =item C
1574              
1575             Draw a rectangle from lower left co-ordinates (x1,y1) to upper right
1576             co-ordinates (y1,y2).
1577              
1578             Options are:
1579              
1580             =over 4
1581              
1582             =item filled => 1
1583              
1584             If C is 1 then fill the rectangle.
1585              
1586             =back
1587              
1588             Example:
1589              
1590             $p->box(10,10, 20,30);
1591             $p->box( {filled => 1}, 10,10, 20,30);
1592              
1593             Notes
1594              
1595             The C method is far more flexible, but this method is quicker!
1596              
1597             =cut
1598              
1599             sub box
1600             {
1601 41     41 1 113 my $self = shift;
1602              
1603 41         39 my %opt = ();
1604              
1605 41 100       64 if (ref($_[0])) {
1606 36         20 %opt = %{; shift};
  36         59  
1607             }
1608              
1609 41         41 my ($x1, $y1, $x2, $y2) = @_;
1610              
1611 41 100       61 unless (@_ == 4) {
1612 1         3 $self->_error("box: wrong number of arguments");
1613 1         5 return 0;
1614             }
1615              
1616 40 100       61 if (!defined($opt{'filled'})) {
1617 4         8 $opt{'filled'} = 0;
1618             }
1619            
1620 40 100       56 unless (defined $self->{psresources}{box}) {
1621 4         9 $self->{psresources}{box} = <<'EOP';
1622             /box {
1623             newpath 3 copy pop exch 4 copy pop pop
1624             8 copy pop pop pop pop exch pop exch
1625             3 copy pop pop exch moveto lineto
1626             lineto lineto pop pop pop pop closepath
1627             } bind def
1628             EOP
1629             }
1630              
1631 40         48 $self->_addtopage($self->_uxy($x1, $y1));
1632 40         57 $self->_addtopage($self->_uxy($x2, $y2) . "box ");
1633 40 100       62 if ($opt{'filled'}) {
1634 36         40 $self->_addtopage("fill\n");
1635             } else {
1636 4         21 $self->_addtopage("stroke\n");
1637             }
1638              
1639 40         84 return 1;
1640             }
1641              
1642              
1643             #-------------------------------------------------------------------------------
1644              
1645             =item C
1646              
1647             Set the current font to the PostScript font C. Set the size in PostScript
1648             points to C.
1649              
1650             Notes
1651              
1652             This method must be called on every page before the C method is used.
1653              
1654             =cut
1655              
1656             sub setfont
1657             {
1658 4     4 1 14 my $self = shift;
1659 4         7 my ($name, $size, $ysize) = @_;
1660              
1661 4 100       15 unless (@_ == 2) {
1662 1         3 $self->_error( "wrong number of arguments for setfont" );
1663 1         5 return 0;
1664             }
1665              
1666             # set font y size XXXXX
1667 3         17 $self->_addtopage("/$name findfont $size scalefont setfont\n");
1668              
1669 3         7 $self->{lastfontsize} = $size;
1670              
1671 3         7 return 1;
1672             }
1673              
1674              
1675             #-------------------------------------------------------------------------------
1676              
1677             =item C
1678              
1679             Plot text on the current page with the lower left co-ordinates at (x,y) and
1680             using the current font. The text is specified in C.
1681              
1682             Options are:
1683              
1684             =over 4
1685              
1686             =item align => "alignment"
1687              
1688             alignment can be 'left', 'centre' or 'right'. The default is 'left'.
1689              
1690             =item rotate => angle
1691              
1692             "rotate" degrees of rotation, defaults to 0 (i.e. no rotation).
1693             The angle to rotate the text, in degrees. Centres about (x,y) and rotates
1694             clockwise. (?). Default 0 degrees.
1695              
1696             =back
1697              
1698             Example:
1699              
1700             $p->setfont("Times-Roman", 12);
1701             $p->text(40,40, "The frog sat on the leaf in the pond.");
1702             $p->text( {align => 'centre'}, 140,40, "This is centered.");
1703             $p->text( {rotate => 90}, 140,40, "This is rotated.");
1704             $p->text( {rotate => 90, align => 'centre'}, 140,40, "This is both.");
1705              
1706             =cut
1707              
1708             sub text
1709             {
1710 19     19 1 124 my $self = shift;
1711              
1712 19         19 my $rot = "";
1713 19         16 my $rot_m = "";
1714 19         19 my $align = "";
1715 19         28 my %opt = ();
1716              
1717 19 100       34 if (ref($_[0])) {
1718 5         6 %opt = %{; shift};
  5         20  
1719             }
1720            
1721 19 100       37 unless ( @_ == 3 )
1722             { # check required params first
1723 2         3 $self->_error("text: wrong number of arguments");
1724 2         7 return 0;
1725             }
1726            
1727 17         17 my ($x, $y, $text) = @_;
1728              
1729 17 100 33     97 unless (defined($x) && defined($y) && defined($text)) {
      66        
1730 1         4 $self->_error("text: wrong number of arguments");
1731 1         2 return 0;
1732             }
1733            
1734             # Escape text to allow parentheses
1735 16         38 $text =~ s|([\\\(\)])|\\$1|g;
1736 16         24 $text =~ s/([\x00-\x1f\x7f-\xff])/sprintf('\\%03o',ord($1))/ge;
  66         95  
1737              
1738 16         27 $self->newpath;
1739 16         21 $self->moveto($x, $y);
1740              
1741             # rotation
1742              
1743 16 100       32 if (defined $opt{'rotate'}) {
1744 3         6 my $rot_a = $opt{ 'rotate' };
1745 3 50       13 if( $rot_a != 0 ) {
1746 3         10 $rot = " $rot_a rotate ";
1747 3         4 $rot_a = -$rot_a;
1748 3         9 $rot_m = " $rot_a rotate ";
1749             };
1750             }
1751              
1752             # alignment
1753              
1754 16         14 $align = " show stroke";
1755 16 100       28 if (defined $opt{'align'}) {
1756             $align = " dup stringwidth pop neg 0 rmoveto show"
1757 3 100       6 if $opt{ 'align' } eq 'right';
1758             $align = " dup stringwidth pop 2 div neg 0 rmoveto show"
1759 3 100 66     19 if $opt{ 'align' } eq 'center' or $opt{ 'align' } eq 'centre';
1760             }
1761            
1762 16         48 $self->_addtopage("($text) $rot $align $rot_m\n");
1763              
1764 16         34 return 1;
1765             }
1766              
1767              
1768             #-------------------------------------------------------------------------------
1769              
1770             =item curve( x1, y1, x2, y2, x3, y3, x4, y4 )
1771              
1772             Create a curve from (x1, y1) to (x4, y4). (x2, y2) and (x3, y3) are the
1773             control points for the start- and end-points respectively.
1774              
1775             =cut
1776              
1777             sub curve
1778             {
1779 2     2 1 3 my $self = shift;
1780 2         4 my ($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4) = @_;
1781              
1782 2 100       9 unless ( @_ == 8 ) {
1783 1         8 $self->_error( "bad curve definition, wrong number of args" );
1784 1         3 return 0;
1785             }
1786            
1787 1 50 33     9 if ((!$self->{pspagecount}) and (!$self->{eps})) {
1788             # Cannot draw on to non-page when not an eps file
1789 0         0 return 0;
1790             }
1791              
1792 1         4 $self->newpath;
1793 1         3 $self->moveto($x1, $y1);
1794 1         3 $self->_addtopage($self->_uxy($x2, $y2));
1795 1         3 $self->_addtopage($self->_uxy($x3, $y3));
1796 1         1 $self->_addtopage($self->_uxy($x4, $y4) . "curveto stroke\n");
1797              
1798 1         4 return 1;
1799             }
1800              
1801              
1802             #-------------------------------------------------------------------------------
1803              
1804             =item curvextend( x1, y1, x2, y2, x3, y3 )
1805              
1806             Assuming the previous command was C, C, C or
1807             C, extend that path with another curve segment to the co-ordinates
1808             (x3, y3). (x1, y1) and (x2, y2) are the control points. Behaviour after any
1809             other method is unspecified.
1810              
1811             =cut
1812              
1813             sub curvextend
1814             {
1815 2     2 1 3 my $self = shift;
1816 2         5 my ($x1, $y1, $x2, $y2, $x3, $y3) = @_;
1817              
1818 2 100       8 unless ( @_ == 6 ) {
1819 1         4 $self->_error( "bad curvextend definition, wrong number of args" );
1820 1         5 return 0;
1821             }
1822            
1823 1         3 my $out = $self->_uxy($x1, $y1);
1824 1         4 $out .= $self->_uxy($x2, $y2);
1825 1         4 $out .= $self->_uxy($x3, $y3) . "curveto stroke\n";
1826              
1827             # FIXMEFIXMEFIXME
1828             # curveto may follow a lineto etc...
1829 1         3 my $p = $self->{currentpage};
1830 1         2 my $last = pop @$p;
1831 1         4 $last = $$last[1];
1832 1         16 $last =~ s/eto stroke\n$/eto\n$out/;
1833 1         5 $self->_addtopage($last);
1834            
1835 1         5 return 1;
1836             }
1837              
1838              
1839             #-------------------------------------------------------------------------------
1840              
1841             =item newpath
1842              
1843             This method is used internally to begin a new drawing path - you should
1844             generally NEVER use it.
1845              
1846             =cut
1847              
1848             sub newpath
1849             {
1850 54     54 1 50 my $self = shift;
1851              
1852 54         69 $self->_addtopage("newpath\n");
1853              
1854 54         49 return 1;
1855             }
1856              
1857              
1858             #-------------------------------------------------------------------------------
1859              
1860             =item moveto( x, y )
1861              
1862             This method is used internally to move the cursor to a new point at (x, y) -
1863             you will generally NEVER use this method.
1864              
1865             =cut
1866              
1867             sub moveto
1868             {
1869 54     54 1 38 my $self = shift;
1870 54         55 my ($x, $y) = @_;
1871              
1872 54         70 $self->_addtopage($self->_uxy($x, $y) . "moveto\n");
1873              
1874 54         57 return 1;
1875             }
1876              
1877              
1878             #-------------------------------------------------------------------------------
1879              
1880             =item C
1881              
1882             Imports an EPS file and scales/translates its bounding box to fill
1883             the area defined by lower left co-ordinates (x1,y1) and upper right
1884             co-ordinates (x2,y2). By default, if the co-ordinates have a different
1885             aspect ratio from the bounding box, the scaling is constrained on the
1886             greater dimension to keep the EPS fully inside the area.
1887              
1888             Options are:
1889              
1890             =over 4
1891              
1892             =item overlap => 1
1893              
1894             If C is 1 then the scaling is calculated on the lesser dimension
1895             and the EPS can overlap the area.
1896              
1897             =item stretch => 1
1898              
1899             If C is 1 then fill the entire area, ignoring the aspect ratio.
1900             This option overrides C if both are given.
1901              
1902             =back
1903              
1904             Example:
1905              
1906             # Assume smiley.eps is a round smiley face in a square bounding box
1907              
1908             # Scale it to a (10,10)(20,20) box
1909             $p->importepsfile("smiley.eps", 10,10, 20,20);
1910              
1911             # Keeps aspect ratio, constrained to smallest fit
1912             $p->importepsfile("smiley.eps", 10,10, 30,20);
1913              
1914             # Keeps aspect ratio, allowed to overlap for largest fit
1915             $p->importepsfile( {overlap => 1}, "smiley.eps", 10,10, 30,20);
1916              
1917             # Aspect ratio is changed to give exact fit
1918             $p->importepsfile( {stretch => 1}, "smiley.eps", 10,10, 30,20);
1919              
1920             =cut
1921              
1922             sub importepsfile
1923             {
1924 0     0 1 0 my $self = shift;
1925              
1926 0         0 my $bbllx;
1927             my $bblly;
1928 0         0 my $bburx;
1929 0         0 my $bbury;
1930 0         0 my $bbw;
1931 0         0 my $bbh;
1932 0         0 my $pagew;
1933 0         0 my $pageh;
1934 0         0 my $scalex;
1935 0         0 my $scaley;
1936 0         0 my $line;
1937 0         0 my $eps;
1938              
1939 0         0 my %opt = ();
1940              
1941 0 0       0 if (ref($_[0])) {
1942 0         0 %opt = %{; shift};
  0         0  
1943             }
1944              
1945 0         0 my ($file, $x1, $y1, $x2, $y2) = @_;
1946              
1947 0 0       0 unless (@_ == 5) {
1948 0         0 $self->_error("importepsfile: wrong number of arguments");
1949 0         0 return 0;
1950             }
1951              
1952 0 0       0 $opt{'overlap'} = 0 if (!defined($opt{'overlap'}));
1953 0 0       0 $opt{'stretch'} = 0 if (!defined($opt{'stretch'}));
1954            
1955 0         0 $eps = new PostScript::Simple::EPS(file => $file);
1956 0         0 ($bbllx, $bblly, $bburx, $bbury) = $eps->get_bbox();
1957              
1958 0         0 $pagew = $x2 - $x1;
1959 0         0 $pageh = $y2 - $y1;
1960              
1961 0         0 $bbw = $bburx - $bbllx;
1962 0         0 $bbh = $bbury - $bblly;
1963              
1964 0 0 0     0 if (($bbw == 0) || ($bbh == 0)) {
1965 0         0 $self->_error("importeps: Bounding Box has zero dimension");
1966 0         0 return 0;
1967             }
1968              
1969 0         0 $scalex = $pagew / $bbw;
1970 0         0 $scaley = $pageh / $bbh;
1971              
1972 0 0       0 if ($opt{'stretch'} == 0) {
1973 0 0       0 if ($opt{'overlap'} == 0) {
1974 0 0       0 if ($scalex > $scaley) {
1975 0         0 $scalex = $scaley;
1976             } else {
1977 0         0 $scaley = $scalex;
1978             }
1979             } else {
1980 0 0       0 if ($scalex > $scaley) {
1981 0         0 $scaley = $scalex;
1982             } else {
1983 0         0 $scalex = $scaley;
1984             }
1985             }
1986             }
1987              
1988 0         0 $eps->scale($scalex, $scaley);
1989 0         0 $eps->translate(-$bbllx, -$bblly);
1990 0         0 $self->_add_eps($eps, $x1, $y1);
1991              
1992 0         0 return 1;
1993             }
1994              
1995              
1996             #-------------------------------------------------------------------------------
1997              
1998             =item C
1999              
2000             Imports a PostScript::Simple::EPS object into the current document at position
2001             C<(x,y)>.
2002              
2003             Example:
2004              
2005             use PostScript::Simple;
2006            
2007             # create a new PostScript object
2008             $p = new PostScript::Simple(papersize => "A4",
2009             colour => 1,
2010             units => "in");
2011            
2012             # create a new page
2013             $p->newpage;
2014            
2015             # create an eps object
2016             $e = new PostScript::Simple::EPS(file => "test.eps");
2017             $e->rotate(90);
2018             $e->scale(0.5);
2019              
2020             # add eps to the current page
2021             $p->importeps($e, 10,50);
2022              
2023             =cut
2024              
2025             sub importeps
2026             {
2027 0     0 1 0 my $self = shift;
2028 0         0 my ($epsobj, $xpos, $ypos) = @_;
2029              
2030 0 0       0 unless (@_ == 3) {
2031 0         0 $self->_error("importeps: wrong number of arguments");
2032 0         0 return 0;
2033             }
2034              
2035 0         0 $self->_add_eps($epsobj, $xpos, $ypos);
2036              
2037 0         0 return 1;
2038             }
2039              
2040              
2041             #-------------------------------------------------------------------------------
2042              
2043             =item C
2044              
2045             Returns the last error generated.
2046              
2047             Example:
2048              
2049             unless ($ps->setcolour("purplewithyellowspots")) {
2050             print $ps->err();
2051             }
2052              
2053             # prints "bad colour name 'purplewithyellowspots'";
2054              
2055             =cut
2056              
2057             sub err {
2058 0     0 1 0 my $self = shift;
2059              
2060 0         0 return $self->{lasterror};
2061             }
2062              
2063              
2064             ################################################################################
2065             # PRIVATE methods
2066              
2067             sub _addtopage
2068             {
2069 532     532   414 my ($self, $data) = @_;
2070              
2071 532 50       567 if (defined $self->{currentpage}) {
2072 532         332 push @{$self->{currentpage}}, ["ps", $data];
  532         1124  
2073             } else {
2074 0         0 confess "internal page error";
2075             }
2076             }
2077              
2078              
2079             #-------------------------------------------------------------------------------
2080              
2081             sub _add_eps
2082             {
2083 0     0   0 my $self = shift;
2084 0         0 my $epsobj;
2085             my $xpos;
2086 0         0 my $ypos;
2087              
2088 0 0       0 if (ref($_[0]) ne "PostScript::Simple::EPS") {
2089 0         0 croak "internal error: _add_eps[0] must be eps object";
2090             }
2091              
2092 0 0 0     0 if ((!$self->{pspagecount}) and (!$self->{eps})) {
2093             # Cannot draw on to non-page when not an eps file
2094 0         0 $self->_error("importeps: no current page");
2095 0         0 return 0;
2096             }
2097              
2098 0 0       0 if ( @_ != 3 ) {
2099 0         0 croak "internal error: wrong number of arguments for _add_eps";
2100 0         0 return 0;
2101             }
2102              
2103 0 0       0 unless (defined $self->{psresources}{importeps}) {
2104 0         0 $self->{psresources}{importeps} = <<'EOP';
2105             /BeginEPSF { /b4_Inc_state save def /dict_count countdictstack def
2106             /op_count count 1 sub def userdict begin /showpage { } def 0 setgray
2107             0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit [ ]
2108             0 setdash newpath /languagelevel where { pop languagelevel 1 ne {
2109             false setstrokeadjust false setoverprint } if } if } bind def
2110             /EndEPSF { count op_count sub {pop} repeat countdictstack dict_count
2111             sub {end} repeat b4_Inc_state restore } bind def
2112             EOP
2113             }
2114              
2115 0         0 ($epsobj, $xpos, $ypos) = @_;
2116              
2117 0         0 my $eps = "BeginEPSF\n";
2118 0         0 $eps .= $self->_uxy($xpos, $ypos) . "translate\n";
2119 0         0 $eps .= $self->_uxy(1, 1) . "scale\n";
2120 0         0 $eps .= $epsobj->_get_include_data($xpos, $ypos);
2121 0         0 $eps .= "EndEPSF\n";
2122              
2123 0         0 $self->_addtopage($eps);
2124            
2125 0         0 return 1;
2126             }
2127              
2128              
2129             #-------------------------------------------------------------------------------
2130              
2131             sub _error {
2132 23     23   20 my $self = shift;
2133 23         21 my $msg = shift;
2134              
2135 23         28 $self->{lasterror} = $msg;
2136 23         64 $self->_addtopage("(error: $msg\n) print flush\n");
2137             }
2138              
2139              
2140             #-------------------------------------------------------------------------------
2141              
2142             # Display method for debugging internal variables
2143             #
2144             #sub display {
2145             # my $self = shift;
2146             # my $i;
2147             #
2148             # foreach $i (keys(%{$self}))
2149             # {
2150             # print "$i = $self->{$i}\n";
2151             # }
2152             #}
2153              
2154             =back
2155              
2156             =head1 BUGS
2157              
2158             Some current functionality may not be as expected, and/or may not work correctly.
2159             That's the fun with using code in development!
2160              
2161             =head1 AUTHOR
2162              
2163             The PostScript::Simple module was created by Matthew Newton, with ideas
2164             and suggestions from Mark Withall and many other people from around the world.
2165             Thanks!
2166              
2167             Please see the README file in the distribution for more information about
2168             contributors.
2169              
2170             Copyright (C) 2002-2014 Matthew C. Newton
2171              
2172             This program is free software; you can redistribute it and/or modify it under
2173             the terms of the GNU General Public License as published by the Free Software
2174             Foundation, version 2.
2175              
2176             This program is distributed in the hope that it will be useful, but WITHOUT ANY
2177             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
2178             PARTICULAR PURPOSE. See the GNU General Public License for more details,
2179             available at http://www.gnu.org/licenses/gpl.html.
2180              
2181             =head1 SEE ALSO
2182              
2183             L
2184              
2185             =cut
2186              
2187             1;
2188              
2189             # vim:foldmethod=marker: