git ssb

0+

cel / freecheck



Tree: feb0e084199fb46a40a769d11a23843969deb0e8

Files: feb0e084199fb46a40a769d11a23843969deb0e8 / freecheck

44500 bytesRaw
1#!/usr/bin/perl
2
3#---------------
4#
5# FreeCheck - a free check printing application released
6# under the GNU General Public Licene.
7#
8# Copyright (C) 2000 Eric Sandeen <sandeen-freecheck@sandeen.net>
9# Copyright (C) 2002 James Klicman <james@klicman.org>
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation; either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; if not, write to the Free Software
23# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24#
25#---------------
26
27$version = "0.30.1";
28$systemConfigFile = "/etc/freecheck/freecheck.cfg";
29$ConfigFile = $ENV{"HOME"} . "/.freecheck.cfg";
30
31use Getopt::Long;
32use File::Copy qw(copy);
33
34
35# This tells us how to format the strings from the cfg file
36# so we can print it as a PostScript definition
37# The key read will replace "value" for each of these
38# Strings are enclosed in parentheses (String) (Foobar)
39# Fonts are preceded by a "/" /FontName /Arial
40# Digits are fine as they are Digit 123
41# Booleans are fine too Bool true
42# But to be safe, do digits and bools as subroutines:
43# Subroutines are in {} {subr} {3 mul}
44
45%Formats = qw(
46 # Globals
47 MICRFontName /value
48 MICRFontSize {value}
49 TransitSymbol (value)
50 OnUsSymbol (value)
51 AmountSymbol (value)
52 DashSymbol (value)
53 MICRVerTweak {value}
54 MICRHorTweak {value}
55 # Account
56 CheckNumber {value}
57 PrintCheckBody {value}
58 PrintMICRLine {value}
59 NumPages {value}
60 Name1 (value)
61 Name2 (value)
62 Address1 (value)
63 Address2 (value)
64 CityStateZip (value)
65 PhoneNumber (value)
66 BankName (value)
67 BankAddr1 (value)
68 BankAddr2 (value)
69 BankCityStateZip (value)
70 AuxOnUs (value)
71 Routing (value)
72 OnUs (value)
73 Fraction (value)
74 PrintVOID {value}
75 # Styles
76 CheckLayout /value
77 StandardFontName /value
78 StandardFontSize {value}
79 BoldFontName /value
80 BoldFontSize {value}
81 CheckNumDigits {value}
82 CheckNumFontName /value
83 CheckNumFontSize {value}
84 FractionFontName /value
85 FractionFontSize {value}
86 Underline {value}
87 LineWidth {value}
88 MemoLineHeight {value}
89 SignatureLineHeight {value}
90 BankInfoHeight {value}
91 AmountLineHeight {value}
92 PayeeLineHeight {value}
93 DateLineHeight {value}
94 LogoFile (value)
95 LogoWidth {value}
96 LogoHeight {value}
97 LogoPadding {value}
98 LogoBorder {value}
99 LogoBBox [value]
100 # Check Blank Types
101 CheckHeight {value}
102 CheckWidth {value}
103 CheckHorOffset {value}
104 CheckVerOffset {value}
105 ChecksPerPage {value}
106 LeftMargin {value}
107 RightMargin {value}
108 TopMargin {value}
109 );
110
111# Parse command line options and deal with them:
112
113GetOptions ("config:s", # Config file
114 "account:s", # Account definition name
115 "checknum:i", # Check number optional (overrides acct file)
116 "pages:i", # Number of pages to print
117 "checkstyle:s", # Check style (defaults to "normal_style.ps"
118 "checktype:s", # Check blank definition
119 "nomicr", # Prevents MICR line from printing (body only)
120 "nobody", # Prevents body from printing (MICR line only)
121 "showaccounts", # Show available accounts
122 "showstyles", # Show available check styles
123 "showblanks", # Show available check blanks
124 "test", # Don't increment check n, and print VOID
125 "preserve", # Don't increment check n
126 "cgi:s", # Accept big string from CGI script (or similar)
127 "help")
128
129or Show_Usage();
130
131if ($opt_help) {
132 Show_Usage();
133}
134
135if ($opt_config) {
136 $ConfigFile = $opt_config;
137} elsif ( ! -e $ConfigFile ) {
138 copy $systemConfigFile, $ConfigFile;
139}
140
141# Some defaults...
142if (!$opt_cgi) {
143 $opt_account = "sample" unless defined $opt_account;
144 $opt_checktype = "MVG3001" unless defined $opt_checktype;
145 $opt_checkstyle = "normal" unless defined $opt_checkstyle;
146}
147
148# Pull the config file into a string...
149$config_file = read_file($ConfigFile);
150
151# See what sections are available
152Get_Sections();
153
154# If we're missing the [Global] section, or if a requested section
155# cannot be found, die.
156if (!$global_found) {
157 die ("No [Global] section found in config file\n");
158}
159
160if ($accounts !~ /${opt_account}/i) {
161 die ("Account $opt_account not found in config file\n");
162}
163
164if ($checkblanks !~ /$opt_checktype/i) {
165 die ("Check type $opt_checktype not found in config file\n");
166}
167
168if ($checkstyles !~ /$opt_checkstyle/i) {
169 die ("Style $opt_checkstyle not found in config file\n");
170}
171
172# Show list of available sections, if requested
173if ($opt_showaccounts || $opt_showstyles || $opt_showblanks) {
174 print "\nFreeCheck v$version\n";
175 if ($opt_showaccounts) {
176 print "Accounts:\n";
177 foreach (split(/\s+/,$accounts)) {
178 print "\t$_\n";
179 }
180 }
181 if ($opt_showstyles) {
182 print "Check Styles:\n";
183 foreach (split(/\s+/,$checkstyles)) {
184 print "\t$_\n";
185 }
186 }
187 if ($opt_showblanks) {
188 print "Check Types:\n";
189 foreach (split(/\s+/,$checkblanks)) {
190 print "\t$_\n";
191 }
192 }
193 die("\n");
194}
195
196# Go through the config and fill up a hash with PostScript defines...
197Parse_Config($config_file);
198
199# Overwrite anything we got from the config file with what was on the
200# Command Line (if anything...)
201
202if ($opt_checknum) {
203 $Definitions{"CheckNumber"} = $opt_checknum;
204}
205
206if ($opt_pages) {
207 $Definitions{"NumPages"} = $opt_pages;
208}
209
210if ($opt_nomicr) {
211 $Definitions{"PrintMICRLine"} = "false";
212}
213
214if ($opt_nobody) {
215 $Definitions{"PrintCheckBody"} = "false";
216}
217
218# This probably isn't in the config file (although it might be...)
219# so cover both possibilites (true/false)
220if ($opt_test) {
221 $Definitions{"PrintVOID"} = "true";
222} else {
223 $Definitions{"PrintVOID"} = "false";
224}
225
226# the --cgi option lets us pass in name value pairs in a string.
227# This will overwrite anything we got from the config file, or
228# from the other command line options (--cgi has the last word)
229# Parse as follows:
230# name is the first word, everything following it is the value
231# each line contains one name/value pair.
232
233while ( $opt_cgi =~ /(^\w+)\s+?(.*$)/mcg ) {
234 $Definitions{$1} = $2;
235}
236
237##################
238# Error Checking #
239##################
240
241$error = "";
242
243# Make sure that MICR line is only numbers and symbols
244
245if ( $Definitions{"Routing"} !~ /^R[0-9]+R$/ ) {
246 $error = $error . "Error - Routing number must be numeric, with an \"R\" on each end\n";
247}
248
249if ( $Definitions{"AuxOnUs"} !~ /^[0-9\-CPS]*$/ ) {
250 $error = $error . "Error - Auxiliary On-Us field may only be numeric, with \"-\", and MICR symbols (C,P,S)\n";
251}
252
253if ( $Definitions{"OnUs"} !~ /^[0-9\-CPS]+$/ ) {
254 $error = $error . "Error - On-Us field may only be numeric, with \"-\", and MICR symbols (C,P,S)\n";
255}
256
257if ( $Definitions{"CheckNumber"} !~ /^[0-9]+$/ ) {
258 $error = $error . "Error - Check number must be numeric \n";
259}
260
261if ( $Definitions{"NumPages"} !~ /^[0-9]+$/ ) {
262 $error = $error . "Error - Number of pages must be numeric\n";
263}
264
265if ( $Definitions{"Fraction"} !~ /^[0-9]{2}\s*\-\s*[0-9]{1,4}\s*\/\s*[0-9]{3,4}$/ ) {
266 $error = $error . "Error - Routing fraction must be numeric, with a \"-\" in the numerator\n";
267}
268
269if ($Definitions{'CheckLayout'} !~ /^(Original|QStandard|QWallet)$/) {
270 $error .= "Error - CheckLayout must be Original, QStandard or QWallet\n";
271}
272
273# Get routing symbol and institution number from routing number
274$RoutingSymbol = substr($Definitions{"Routing"},1,4);
275$Institution = substr($Definitions{"Routing"},5,4);
276
277# Strip any leading zeros...
278# Only should be one on routing...
279$RoutingSymbol =~ s/^0//;
280# One or more on institution
281#$Institution =~ s/^0+//;
282
283# Fraction format:
284#
285# 2 digits, a "-", institution number (no leading zeros)
286# ------------------------------------------------------
287# routing number (no leading zeros)
288
289
290if ( $Definitions{"Fraction"} !~ /^[0-9]{2}\-${Institution}\/${RoutingSymbol}$/ ) {
291 $error = $error . "Error - Routing fraction does not match routing number\n";
292}
293
294
295# Test the MICR line for correctness
296if ( length ($Definitions{"Routing"}) != 11 ) {
297 $error = $error . "Error - Routing number must be exactly 9 digits long, with
298 an \"R\" on each end\n";
299}
300
301# Test the MICR checksum
302# Don't forget the real routing number is sandwiched between "Rs"
303
304unless ( ( $Definitions{"Routing"} !~ /^R[0-9]+R$/) || ( length ($Definitions{"Routing"}) != 11 ) ){
305
306 $CheckSum = 0;
307
308 @CheckSumMults = (3, 7, 1, 3, 7, 1, 3, 7);
309 for ($Digit = 1; $Digit < 9; $Digit++) {
310 $CheckSum = $CheckSum +
311 $CheckSumMults[$Digit-1] * substr($Definitions{"Routing"}, $Digit, 1);
312 }
313
314 $CheckSum = 10 - ($CheckSum % 10);
315
316 # Kludge alert...
317 if ($CheckSum == 10) {
318 $CheckSum = 0;
319 }
320
321 if ( $CheckSum ne substr($Definitions{"Routing"}, 9, 1) ) {
322 $error = $error . "Error - Routing Number Checksum Incorrect\n";
323 }
324}
325
326if (defined $Definitions{'LogoFile'}) {
327 if (open(EPS,"<$Definitions{'LogoFile'}")) {
328 my $foundbbox = 0;
329 while (<EPS>) {
330 break if /^%%EndComments/;
331 next unless s/^%%((?:HiRes)?BoundingBox):\s*//;
332 my $hires = ($1 eq 'HiResBoundingBox');
333 $foundbbox = 1;
334 if (/^(\d+(?:\.\d+)?(?:\s+\d+(?:\.\d+)?){3})\s*(?:%.*)?$/) {
335 $Definitions{'LogoBBox'} = $1;
336 } else {
337 $error .= "Error - Can't parse EPS Logo BoundingBox comment\n";
338 }
339 # keep looking until HiResBoundingBox or EndComments
340 break if $hires;
341 }
342 close(EPS);
343
344 unless ($foundbbox) {
345 $error .= "Error - Required EPS Logo BoundingBox not found\n";
346 }
347 } else {
348 $error .= "Error - Can't open LogoFile $Definitions{'LogoFile'}: $!\n";
349 }
350}
351
352
353# die() if we got errors
354if ( $error && !$opt_test ) {
355 print STDERR $error;
356 die("Errors Encountered\n");
357}
358
359# Print PostScript
360
361# Initial stuff:
362print <<"__END_OF_POSTSCRIPT__";
363%!PS-Adobe-3.0
364%%Title: FreeCheck
365%%LanguageLevel: 2
366%%EndComments
367%%BeginProlog
368/inch {72 mul} def
369__END_OF_POSTSCRIPT__
370
371# Go through $Definitions and print them out PostScript-Like
372Print_Defs();
373
374
375if (defined $Definitions{'LogoFile'}) {
376 my $filesize = (stat($Definitions{'LogoFile'}))[7];
377 print <<"__END_OF_POSTSCRIPT__";
378%%BeginProcSet: logo
379%%Creator: James Klicman <james\@klicman.org>
380%%CreationDate: October 2002
381%%Version: 0.3
382
383% if
384/LogoPadding where
385{
386 pop % discard dict
387}
388% else
389{
390 /LogoPadding 0 def
391}
392ifelse
393
394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395%
396% Calculate LogoMatrix
397%
398% LogoXScale
399LogoWidth LogoPadding 2 mul sub
400% BBWidth
401 LogoBBox 2 get % x2
402 LogoBBox 0 get % x1
403 sub % x2 x1 sub
404div % LogoWidth BBWidth div
405% LogoYScale
406LogoHeight LogoPadding 2 mul sub
407% BBHeight
408 LogoBBox 3 get % y2
409 LogoBBox 1 get % y1
410 sub % y2 y1 sub
411div % LogoHeight BBHeight div
412
413% if
4142 copy lt % LogoXScale LogoYScale lt
415{
416 pop % discard LogoYScale
417}
418% else
419{
420 exch pop % discard LogoXScale
421}
422ifelse
423% ^ (LogoXScale < LogoYScale ? LogoXScale : LogoYScale)
424dup matrix scale /LogoMatrix exch def
425
426/DrawLogo {
427 /LogoForm where {
428 pop % discard dict
429 gsave
430
431 /LogoBorder where {
432 pop % discard dict
433 newpath
434 LeftMargin LogoBorder 2 div add
435 CheckHeight TopMargin sub LogoBorder 2 div sub moveto
436
437 LogoWidth LogoBorder sub 0 rlineto
438 0 LogoHeight LogoBorder sub neg rlineto
439 LogoWidth LogoBorder sub neg 0 rlineto
440 closepath
441 LogoBorder setlinewidth stroke
442 } if
443
444
445 % Logo is placed at the top-left corner of the check
446 LeftMargin CheckHeight TopMargin sub translate
447
448 LogoForm /BBox get aload pop % ^ llx lly urx ury
449
450 % translate top-left corner of LogoBBox to current point
451 % ^ llx lly urx ury
452 3 index neg % llx neg ^ llx lly urx ury -llx
453 1 index neg % ury neg ^ llx lly urx ury -llx -ury
454 LogoForm /Matrix get
455 transform % -llx -ury LogoMatrix transform
456 translate % transformedX transformedY translate
457
458 % calculate real width and height of LogoBBox
459 % ^ llx lly urx ury
460 exch % ^ llx lly ury urx
461 4 -1 roll % ^ lly ury urx llx
462 sub % urx llx sub ^ lly ury urx-llx
463 3 -2 roll % ^ urx-llx lly ury
464 exch % ^ urx-llx ury lly
465 sub % ury lly sub
466 % ^ urx-llx ury-lly
467 LogoForm /Matrix get
468 transform % urx-llx ury-lly LogoMatrix transform
469 % ^ RealLogoWidth RealLogoHeight
470
471 % Calculate difference of RealLogoWidth, RealLogoHeight
472 % and LogoWidth, LogoHeight for centering logo.
473 exch LogoWidth exch sub 2 div
474 exch LogoHeight exch sub 2 div neg
475 translate % LogoHAlign LogoVAlign translate
476
477 LogoForm execform
478
479 grestore
480 } if
481} def
482%%EndProcSet
483
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485
486%
487% The following EPS Form handling code is based on code contained in
488% Adobe Technical Note #5144 Using EPS Files in PostScript Language Forms.
489%
490
491%%BeginResource: procset forms_ops 1.0 0
492%%Title: (Forms Operators)
493%%Version: 1.0
494userdict /forms_ops 10 dict dup begin put
495
496/StartEPSF { % prepare for EPSF inclusion
497 userdict begin
498 /PreEPS_state save def
499 /dict_stack countdictstack def
500 /ops_count count 1 sub def
501 /showpage {} def
502} bind def
503
504/EPSFCleanUp { % clean up after EPSF inclusion
505 count ops_count sub {pop} repeat
506 countdictstack dict_stack sub {end} repeat
507 PreEPS_state restore
508 end % userdict
509} bind def
510
511/STRING_SIZE 16000 def % Best value to not fragment printer's VM
512% recommended ARRAY_SIZE = filesize/16000 + 2
513% +2 resulted in errors
514% +3 worked
515/ARRAY_SIZE $filesize 16000 idiv 3 add def
516
517% for initial counter and final empty string.
518/buffer STRING_SIZE string def
519/inputFile currentfile 0 (% EOD_Marker_$$) /SubFileDecode filter def
520
521/readdata { % array readdata --
522 1 { % put counter on stack
523 % stack: array counter
524 2 copy % stack: array counter array counter
525 inputFile buffer readstring % read contents of currentfile into buffer
526 % stack: array counter array counter string boolean
527 4 1 roll % put boolean indicating EOF lower on stack
528 STRING_SIZE string copy % copy buffer string into new string
529 % stack: array counter boolean array counter newstring
530 put % put string into array
531 not {exit} if % if EOF has been reached, exit loop.
532 1 add % increment counter
533 } loop
534 % increment counter and place empty string in next position
535 1 add 2 copy () put pop
536 currentglobal true setglobal exch
537 0 1 array put % create an array for counter in global VM,
538 % so as not to be affected by save/restore calls in EPS file.
539 % place as first element of string array.
540 setglobal % restore previously set value
541} bind def
542currentdict readonly pop end
543%%EndResource
544%%EndProlog
545%%BeginSetup
546% set MaxFormItem to be equivalent to MaxFormCache
547<< /MaxFormItem currentsystemparams /MaxFormCache get >> setuserparams
548% make forms procset available
549forms_ops begin
550userdict begin
551% download form resource
552%%BeginResource: form LogoForm
553/LogoForm
554 10 dict begin
555 /FormType 1 def
556 /EPSArray ARRAY_SIZE array def
557 /AcquisitionProc {
558 EPSArray dup 0 get dup 0 get % array counter_array counter
559 dup 3 1 roll % array counter counter_array counter
560 1 add 0 exch put % increment counter
561 get % use old counter as index into array, placing
562 % next string on operand stack.
563 } bind def
564 /PaintProc {
565 begin
566 StartEPSF
567 % May want to translate here, prior to executing EPS
568 EPSArray 0 get 0 1 put
569 //AcquisitionProc 0 () /SubFileDecode filter
570 cvx exec
571 EPSFCleanUp
572 end
573 } bind def
574 /Matrix //LogoMatrix def
575 /BBox //LogoBBox def
576 currentdict
577 end
578def % LogoForm
579LogoForm /EPSArray get
580readdata
581%%BeginDocument: ($Definitions{'LogoFile'})
582__END_OF_POSTSCRIPT__
583
584 open(EPS, "<$Definitions{'LogoFile'}") || die "can't open logo file: $!\n";
585 print while (<EPS>);
586 close(EPS);
587
588 print <<"__END_OF_POSTSCRIPT__";
589%%EndDocument
590% EOD_Marker_$$
591%%EndResource
592%%EndSetup
593__END_OF_POSTSCRIPT__
594}
595
596# Then print the main body
597print while (<DATA>);
598
599if (defined $Definitions{'LogoFile'}) {
600 print <<"__END_OF_POSTSCRIPT__";
601end % userdict
602end % forms_ops
603__END_OF_POSTSCRIPT__
604}
605
606print "%%EOF\n";
607
608
609# Update the config file with the new check number, if it's not just a test
610if (!$opt_test && !$opt_cgi && !$opt_preserve) {
611 $next_check_number = $Definitions{"CheckNumber"}
612 + ($Definitions{"NumPages"} * $Definitions{"ChecksPerPage"});
613
614 $config_file = Replace_Val($config_file, "Account", $opt_account,
615 "CheckNumber", $next_check_number);
616 write_file ($ConfigFile, $config_file);
617}
618
619###############
620# Subroutines #
621###############
622
623# read_file and write_file shamelessly stolen from the File::Slurp module
624# Short enough, and I didn't want to require a non-standard module
625
626sub read_file
627{
628 my ($file) = @_;
629
630 local(*F);
631 my $r;
632 my (@r);
633
634 open(F, "<$file") || die "open $file: $!";
635 @r = <F>;
636 close(F);
637
638 return @r if wantarray;
639 return join("",@r);
640}
641
642sub write_file
643{
644 my ($f, @data) = @_;
645
646 local(*F);
647
648 open(F, ">$f") || die "open >$f: $!";
649 (print F @data) || die "write $f: $!";
650 close(F) || die "close $f: $!";
651 return 1;
652}
653
654# Wow, this is ugly! Anybody have a better suggestion?
655sub Parse_Config {
656 local ($config_file) = ($_[0]);
657 # Find each section we're looking for...
658 while ($config_file =~ /^\[\s*(
659 Global |
660 Account\s+${opt_account} |
661 Style\s+${opt_checkstyle} |
662 CheckBlank\s+${opt_checktype}
663 )\s*\]/xmgci) {
664 # and get the lines under it one by one
665 while ($config_file =~ /(^.+$)/mgc) {
666 $line = $+;
667 # If this line is a comment, skip it
668 if ($line =~ /^#/) {
669 next;
670 }
671 # If the line we just found is a new section..."[...]"
672 if ($line =~ /^\[.+\]/) {
673 # and it is another section we're looking for
674 # Grab the next line, and keep going
675 if ($line =~ /\[\s*(
676 Global |
677 Account\s+${opt_account} |
678 Style\s+${opt_checkstyle} |
679 CheckBlank\s+${opt_checktype}
680 )\s*]/xi) {
681 # Grab the next line, and keep going
682 next;
683 } else {
684 # Not a section we need, so break out
685 # of the loop
686 last;
687 }
688 }
689
690 ($key, $val) = split (/\s*=\s*/,$line);
691 # Need to strip trailing whitespace...
692 $val =~ s/\s*$//;
693 $Definitions{$key} = $val;
694 } # line-by-line while
695 } # section match conditional
696}
697
698sub Replace_Val {
699 local ($string, $section, $name, $key, $value) =
700 ($_[0], $_[1], $_[2], $_[3], $_[4]);
701 # We want to get "[section name] ... key = value" and replace it
702 # with the new value.
703
704 # s - "." matches ANYTHING including newline
705 # m - ^ and $ match after and before any newline
706 # in this case, ".+?" means the minimum number of <anything> i.e. end
707 # when we find the first instance of $key after [section name]
708 $string =~
709 s/(^\[\s*$section\s+$name\s*\].+?^${key}\s*=\s*).*?$/$+$value/smi;
710 $string;
711}
712# Given a section type, list all the section names of that type
713sub Get_Sections {
714 local $section;
715 while ($config_file =~ /^\[\s*(
716 Global |
717 Account.+ |
718 Style.+ |
719 CheckBlank.+
720 )\s*\]/xmgci) {
721 $section = $+;
722 if ( $section =~/CheckBlank\s+(.+)/i ) {
723 $checkblanks = "$+ $checkblanks";
724 } elsif ( $section =~/Style\s+(.+)/i ) {
725 $checkstyles = "$+ $checkstyles";
726 } elsif ( $section =~/Account\s+(.+)/i ) {
727 $accounts = "$+ $accounts";
728 } elsif ( $section =~/Global/i ) {
729 $global_found = "true";
730 }
731 }
732}
733
734sub Show_Usage {
735 print "\nFreeCheck v.$version - a Free Check printing Utility\n\n";
736 print "Usage: freecheck <options>:\n";
737 print "\n";
738 print "options:\n";
739 print " --config <filename> config file (default \"~/.freecheck.cfg\")\n";
740 print " --account <name> account to use (default \"$opt_account\")\n";
741 print " --checknum <integer> starting check number (overrides cfg)\n";
742 print " --pages <integer> number of pages to print (overrides cfg)\n";
743 print " --checkstyle <filename> check style to use (default \"$opt_checkstyle\")\n";
744 print " --checktype <filename> blank check type to use (default \"$opt_checktype\")\n";
745 print " --nomicr do not print MICR line\n";
746 print " --nobody do not print check body\n";
747 print " --showaccounts show all configured accounts\n";
748 print " --showstyles show all configured check styles\n";
749 print " --showblanks show all configured check blanks\n";
750 print " --help print this message\n";
751 print " --preserve print but don't increment check number\n";
752 print " --test print but don't increment check number\n";
753 print " and print VOID on the check\n";
754 print " --cgi accept string from CGI script (see docs)\n";
755 die "\n";
756}
757
758sub Print_Defs {
759 # Go through each def in the hash table, and print according to the
760 # formatting hash
761 while ( ($key, $val) = each (%Definitions) ) {
762 print "/$key\t";
763 $_ = $Formats{$key};
764 s/value/$val/;
765 print;
766 print " def\n";
767 }
768}
769# End of Perl
770__END__
771
772% This is the main body of the postscript file, that acts on all of the
773% definitions we got from the config file.
774
775% Available Check Layouts
776/CheckLayoutDict <<
777 /Original { DrawOriginalCheckBody }
778 /QStandard { DrawQStandardCheckBody }
779 /QWallet { DrawQWalletCheckBody }
780>> def
781
782% Other Constants:
783
784% Size of the rectangular box for the amount (digits)
785/AmountBoxWidth {1 inch} def
786/AmountBoxHeight {0.25 inch} def
787
788% Max number of digits in check number, and allocate string
789/CheckNumDigits 4 def
790/CheckNumberString CheckNumber log floor 1 add cvi string def
791
792%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
793% Helpful Printing Routines %
794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
795
796% Shows a line, then does a "carriage return / line feed"
797% But only if the string exists (more than 0 chars)
798% (How do we get the current font size (height)?)
799
800/ShowAndCR {
801 % if
802 dup length 0 gt % First copy
803 {
804 dup show % Second copy
805 stringwidth pop neg 0 rmoveto % Original copy & move back
806 neg 0 exch rmoveto % line down
807 }
808 % else
809 {
810 pop % discard (string)
811 pop % discard height
812 }
813 ifelse
814} def
815
816%%BeginProcSet: substitute
817%%Creator: James Klicman <james@klicman.org>
818%%CreationDate: October 2002
819%%Version: 0.3
820%
821% (string) (O) (N) substitute -
822%
823% example: (A?C) (?) (B) substitute -> (ABC)
824%
825/substitute {
826 0 get exch 0 get exch % convert (O) and (N) to char codes
827 0 % counter
828 3 index % (string) {} forall
829 {
830 % ^ (string) O N counter C
831 3 index % (O)[0]
832 eq % (string)[i] == (O)[0]
833 {
834 % ^ (string) O N counter
835 3 index % (string)
836 % ^ (string) O N counter (string)
837 1 index % counter
838 % ^ (string) O N counter (string) counter
839 3 index % N
840 % ^ (string) O N counter (string) counter N
841 put % (string) counter N put
842 } if
843 1 add % increment counter
844 } forall
845 pop % counter
846 pop % N
847 pop % O
848 pop % (string)
849} def
850%%EndProcSet
851
852% Fix up the MICR line components (replace placeholders with MICR
853% characters)
854% Argh... surely there's a better way - anyone? use "forall?"
855
856/FixMICR {
857
858 /CheckNumStart -1 def
859 /CheckNumEnd -1 def
860 /CheckNumInOnUs false def
861 /CheckNumInAuxOnUs false def
862
863 % Get starting and ending positions for check number in
864 % (Aux)OnUs field
865 % (This will break if check number is entered in both fields)
866
867 OnUs length 1 sub -1 0 {
868 dup % dups the index
869 OnUs exch get (C) 0 get eq {
870 /CheckNumInOnUs true def
871 % If end number not yet defined, define it
872 CheckNumEnd 0 lt {
873 /CheckNumEnd exch def
874 } {
875 /CheckNumStart exch def
876 } ifelse
877
878 } {
879 pop
880 } ifelse
881 } for
882
883 AuxOnUs length 1 sub -1 0 {
884 dup % dups the index
885 AuxOnUs exch get (C) 0 get eq {
886 /CheckNumInAuxOnUs true def
887 % If end number not yet defined, define it
888 CheckNumEnd 0 lt {
889 /CheckNumEnd exch def
890 } {
891 /CheckNumStart exch def
892 } ifelse
893
894 } {
895 pop
896 } ifelse
897 } for
898
899
900 % Replace "R" in routing number with actual transit number symbol
901 % That's it - should be no spaces, dashes, or anything but digits
902 Routing (R) TransitSymbol substitute
903
904 % Replace "S" with space character in AuxOnUs
905 AuxOnUs (S) ( ) substitute
906
907 % Replace "-" with dash character in AuxOnUs
908 AuxOnUs (-) DashSymbol substitute
909
910 % Replace "P" with OnUs character in AuxOnUs
911 AuxOnUs (P) OnUsSymbol substitute
912
913 % Replace "S" with space character in OnUs
914 OnUs (S) ( ) substitute
915
916 % Replace "-" with dash character in OnUs
917 OnUs (-) DashSymbol substitute
918
919 % Replace "P" with OnUs character in OnUs
920 OnUs (P) OnUsSymbol substitute
921
922} def
923
924%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
925% Original Feature Printing Routines %
926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
927
928/DrawMemoLine {
929 LeftMargin MemoLineHeight CheckHeight mul moveto
930 2.5 inch 0 inch rlineto
931 -2.5 inch 0 inch rmoveto
932 0 2 rmoveto
933 (for) show
934} def
935
936/DrawSignatureLine { % Expects height of signature line
937 % and right edge of check for
938 % beginning position
939
940 CheckWidth SignatureLineHeight CheckHeight mul moveto
941 RightMargin neg 0 rmoveto
942 -2.5 inch 0 rmoveto
943 2.5 inch 0 inch rlineto
944
945} def
946
947/DrawAmountLine {
948 CheckWidth AmountLineHeight CheckHeight mul moveto
949 RightMargin neg 0 rmoveto
950 (DOLLARS) stringwidth pop neg 0 rmoveto
951 (DOLLARS) show
952 (DOLLARS) stringwidth pop neg 0 rmoveto
953 -2 0 rmoveto
954 LeftMargin AmountLineHeight CheckHeight mul lineto
955} def
956
957/DrawAccountHolderInfo {
958 LeftMargin CheckHeight moveto
959 0 TopMargin neg rmoveto
960 0 StandardFontSize neg rmoveto
961
962 % make room for Logo if specified
963 /LogoForm where {
964 pop % discard dict
965 LogoWidth
966 /LogoBorder where {
967 pop % discard dict
968 LogoBorder 2 div add
969 } if
970 /LogoPadding where {
971 pop % discard dict
972 LogoPadding 2 div add
973 } if
974 0 rmoveto
975 } if
976
977 StandardFontSize Name1 ShowAndCR
978 StandardFontSize Name2 ShowAndCR
979
980 StandardFontName findfont
981 StandardFontSize 1 sub scalefont
982 setfont
983
984 StandardFontSize 1 sub Address1 ShowAndCR
985 StandardFontSize 1 sub Address2 ShowAndCR
986 StandardFontSize 1 sub CityStateZip ShowAndCR
987 StandardFontSize 1 sub PhoneNumber ShowAndCR
988
989 StandardFontName findfont
990 StandardFontSize 1 add scalefont
991 setfont
992} def
993
994/DrawDateLine {
995 0.6 CheckWidth mul DateLineHeight CheckHeight mul moveto
996 (Date) show
997 1 inch 0 rlineto
998} def
999
1000/DrawBankInfo {
1001 LeftMargin BankInfoHeight CheckHeight mul moveto
1002
1003 StandardFontSize BankName ShowAndCR
1004
1005 StandardFontName findfont
1006 StandardFontSize 1 sub scalefont
1007 setfont
1008
1009 StandardFontSize 1 sub BankAddr1 ShowAndCR
1010 StandardFontSize 1 sub BankAddr2 ShowAndCR
1011 StandardFontSize 1 sub BankCityStateZip ShowAndCR
1012
1013 StandardFontName findfont
1014 StandardFontSize 1 add scalefont
1015 setfont
1016} def
1017
1018/DrawPayeeLine {
1019
1020 LeftMargin PayeeLineHeight CheckHeight mul moveto
1021 (ORDER OF) show
1022 (ORDER OF) stringwidth pop neg StandardFontSize rmoveto
1023 (PAY TO THE) show
1024 0 StandardFontSize neg rmoveto
1025 4 0 rmoveto
1026 currentpoint mark
1027
1028 CheckWidth PayeeLineHeight CheckHeight mul moveto
1029 RightMargin neg 0 rmoveto
1030 AmountBoxWidth neg 0 rmoveto
1031
1032 0 AmountBoxHeight rlineto
1033 AmountBoxWidth 0 rlineto
1034 0 AmountBoxHeight neg rlineto
1035 AmountBoxWidth neg 0 rlineto
1036
1037 -4 0 rmoveto
1038
1039 /Helvetica-Bold findfont
1040 14 scalefont
1041 setfont
1042
1043 ($) stringwidth pop neg 0 rmoveto
1044 ($) show
1045 ($) stringwidth pop neg 0 rmoveto
1046
1047 -4 0 rmoveto
1048 cleartomark
1049 lineto
1050
1051 StandardFontName findfont
1052 StandardFontSize scalefont
1053 setfont
1054
1055} def
1056
1057/DrawCheckNumber {
1058 CheckWidth CheckHeight moveto
1059 RightMargin neg TopMargin neg rmoveto
1060 CheckNumFontName findfont
1061 CheckNumFontSize scalefont
1062 setfont
1063
1064 CheckNumberString stringwidth pop neg 0 rmoveto
1065 0 -14 rmoveto
1066 CheckNumberString show
1067
1068 StandardFontName findfont
1069 StandardFontSize scalefont
1070 setfont
1071} def
1072
1073/DrawFraction {
1074 0.6 CheckWidth mul CheckHeight moveto
1075 0 TopMargin neg rmoveto
1076 0 StandardFontSize neg rmoveto
1077 Fraction show
1078} def
1079
1080/DrawStub {
1081 CheckHorOffset 2 inch ge {
1082 save
1083 newpath
1084 CheckHorOffset neg 0 translate
1085 StandardFontName findfont
1086 StandardFontSize 1 sub scalefont
1087 setfont
1088 /StubSpacing {CheckHeight 6 div} def
1089 CheckHorOffset 2 div StubSpacing 5 mul moveto
1090 CheckNumberString show
1091 0.3 inch StubSpacing 4 mul moveto
1092 (Date ) show
1093 CheckHorOffset 0.3 inch sub StubSpacing 4 mul lineto
1094 0.3 inch StubSpacing 3 mul moveto
1095 (Payee ) show
1096 CheckHorOffset 0.3 inch sub StubSpacing 3 mul lineto
1097 0.3 inch StubSpacing 2 mul moveto
1098 (Amount ) show
1099 CheckHorOffset 0.3 inch sub StubSpacing 2 mul lineto
1100 0.3 inch StubSpacing 1 mul moveto
1101 (Memo ) show
1102 CheckHorOffset 0.3 inch sub StubSpacing 1 mul lineto
1103 stroke
1104 restore
1105 } if
1106} def
1107
1108/DrawOriginalCheckBody {
1109 DrawBankInfo
1110 DrawAccountHolderInfo
1111 DrawMemoLine
1112 DrawSignatureLine
1113 DrawAmountLine
1114 DrawPayeeLine
1115 DrawCheckNumber
1116 DrawFraction
1117 DrawDateLine
1118 /DrawLogo where { pop DrawLogo } if
1119 DrawStub
1120} def
1121
1122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1123% QStandard & QWallet Feature Printing Routines %
1124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1125
1126%%BeginProcSet: nextline
1127%%Creator: James Klicman <james@klicman.org>
1128%%CreationDate: October 2002
1129%%Version: 0.3
1130
1131%
1132% state used by initline and nextline
1133%
1134/LINESTATE <<
1135 /x 0
1136 /y 0
1137 /rx 0
1138 /ry 0
1139>> def
1140
1141%
1142% LineHeight initline -
1143%
1144/initline {
1145 LINESTATE begin
1146 currentpoint
1147 /y exch def
1148 /x exch def
1149 /ty exch def
1150 /tx exch def
1151 end
1152} def
1153
1154%
1155% - nextline -
1156%
1157/nextline {
1158 LINESTATE begin
1159 x tx add
1160 dup /x exch def % x += tx
1161 y ty add
1162 dup /y exch def % y += ty
1163 moveto % x y moveto
1164 end
1165} def
1166%%EndProcSet
1167
1168
1169%%BeginProcSet: alignment
1170%%Creator: James Klicman <james@klicman.org>
1171%%CreationDate: October 2002
1172%%Version: 0.3
1173%
1174% (string) centeralign (string)
1175%
1176/centeralign {
1177 dup % dup (string)
1178 stringwidth % calculate string xWidth, yHeight
1179 pop % discard yHeight
1180 2 div neg % -(xWidth / 2)
1181 0 rmoveto % rmoveto center
1182} def
1183
1184%
1185% (string) rightalign (string)
1186%
1187/rightalign {
1188 dup stringwidth % calculate string xWidth, yHeight
1189 pop % discard yHeight
1190 neg 0 rmoveto % -xWidth 0 rmoveto
1191} def
1192
1193%
1194% (string) stringbbox x1 y1 x2 y2
1195%
1196% This procedure is based on the method described in Chapter 5 page 333
1197% of the PostScript Language Reference third edition.
1198%
1199/stringbbox {
1200 gsave
1201 newpath 0 0 moveto false charpath flattenpath pathbbox % x1 y1 x2 y2
1202 grestore
1203} def
1204
1205%
1206% (string) topalign (string)
1207%
1208/topalign {
1209 dup stringbbox % ^+ x1 y1 x2 y2
1210 neg 0 exch rmoveto % 0 -y2 rmoveto
1211 pop % x2
1212 pop % y1
1213 pop % x1
1214} def
1215
1216%
1217% (string) bottomalign (string)
1218%
1219/bottomalign {
1220 dup stringbbox % ^+ x1 y1 x2 y2
1221 pop % y2
1222 pop % x2
1223 neg 0 exch rmoveto % 0 -y1 rmoveto
1224 pop % x1
1225} def
1226%%EndProcSet
1227
1228
1229%%BeginProcSet: qchecks
1230%%Creator: James Klicman <james@klicman.org>
1231%%CreationDate: October 2002
1232%%Version: 0.3
1233
1234/QStandardConfig <<
1235 /RightMarginX CheckWidth RightMargin sub
1236 /UnderlineOffset -3
1237 /MemoLineWidth 3.25 inch
1238 /SignatureLineWidth 3.25 inch
1239 /PayToTheOrderOf {
1240 currentpoint % oldpoint
1241 0 StandardFontSize rmoveto % move up one line
1242 (PAY TO THE) show
1243 moveto % oldpoint moveto
1244 (ORDER OF ) show
1245 }
1246 % QStandard Coords, Check Size 8.5" x 3.5"
1247 /Date [ 503.08 183.44]
1248 /Amount [ 499.96 147.44 ]
1249 /Verbal [ 36.04 123.44 ]
1250 /Payee [ 84.04 147.44 ]
1251 /Memo [ 63.16 39.44 ]
1252 /Address [ 72.04 99.44 ]
1253 /Stub false
1254>> def
1255
1256/QWalletConfig <<
1257 /RightMarginX CheckWidth RightMargin sub
1258 /UnderlineOffset -2
1259 /MemoLineWidth 2.5 inch
1260 /SignatureLineWidth 2.5 inch
1261 /PayToTheOrderOf {
1262 0 StandardFontSize 2 mul rmoveto % move up two lines
1263 0 StandardFontSize neg initline
1264 (PAY) show nextline
1265 (TO THE) show nextline
1266 (ORDER OF ) show
1267 }
1268 % QWallet Coords, Check Size 6" x 2.8333"
1269 /Date [ 346.12 147.44 ]
1270 /Amount [ 331.96 135.44 ]
1271 /Verbal [ 24.04 123.44 ]
1272 /Payee [ 46.12 135.44 ]
1273 /Address [ 25.0 99.44 ]
1274 /Memo [ 45.16 39.44 ]
1275 /Stub true
1276 /StubDate [ 31.96 147.44 ]
1277 /StubPayee [ 31.96 123.44 ]
1278 /StubAmount [ 52.12 87.44 ]
1279 /StubMemo [ 31.96 63.44 ]
1280 /StubCategory [ 31.96 39.44 ]
1281 /StubAccount [ 31.96 15.44 ]
1282>> def
1283
1284
1285%
1286% /name (label) DrawQLabeline-rightmargin -
1287%
1288% draw label and underline to right margin
1289%
1290/DrawQLabeline-rightmargin {
1291 % show label
1292 % ^ /name (label)
1293 exch QCONFIG exch get aload pop % ^ (label) X Y
1294 2 copy % ^ (label) X Y X Y
1295 moveto % X Y moveto
1296 3 -1 roll % (label) X Y -> X Y (label)
1297 rightalign show % (label) rightalign show
1298
1299 % ^ X Y
1300
1301 Underline { % if
1302 % underline
1303 % line goes from end of label to right margin
1304 % ^ X Y
1305 exch ( ) stringwidth pop sub exch % backup X one space
1306 QCONFIG /UnderlineOffset get add % adjust underline position
1307 newpath
1308 dup % UnderlineY dup
1309 3 1 roll % X, Y, Y -> Y, X, Y
1310 moveto % X Y moveto
1311 % UnderlineY is on the stack
1312
1313 QCONFIG /RightMarginX get
1314 exch lineto % RightMarginX UnderlineY lineto
1315 stroke
1316 }
1317 % else
1318 { pop pop }
1319 ifelse
1320} def
1321
1322/DrawQDate {
1323 /Date (Date ) DrawQLabeline-rightmargin
1324} def
1325
1326/DrawQAmount {
1327 /Amount ($ ) DrawQLabeline-rightmargin
1328} def
1329
1330/DrawQPayee {
1331 % label: PAY TO THE ORDER OF
1332 LeftMargin
1333 QCONFIG /Payee get 1 get % PayeeY
1334 moveto % LeftMargin PayeeY moveto
1335 QCONFIG /PayToTheOrderOf get exec
1336
1337 Underline { % if
1338 % underline: Payee
1339 % line goes from end of "ORDER OF" to beginning of "$ amount"
1340 currentpoint
1341 QCONFIG /UnderlineOffset get add % CurrentY + UnderlineOffset
1342 newpath
1343 dup % UnderlineY dup
1344 3 1 roll % X, Y, Y -> Y, X, Y
1345 moveto % X Y moveto
1346 % ^ UnderlineY
1347
1348 QCONFIG /Amount get 0 get % AmountX
1349 ( $ ) stringwidth pop % AdjustX
1350 sub % PayeeLineEndX = AmountX - AdjustX
1351
1352 exch lineto % PayeeLineEndX UnderlineY lineto
1353 stroke
1354 } if
1355} def
1356
1357/DrawQVerbal {
1358 % label: Dollars
1359 QCONFIG /RightMarginX get
1360 ( DOLLARS) stringwidth
1361 pop % discard yHeight
1362 sub % RightMarginX - StringWidthX
1363
1364 % ^ LabelX
1365
1366 QCONFIG /Verbal get 1 get % VerbalY
1367 2 copy % LabelX VerbalY 2 copy
1368 moveto % LabelX VerbalY moveto
1369 ( DOLLARS) show
1370
1371 % ^ LabelX VerbalY
1372
1373 Underline { % if
1374 newpath
1375 QCONFIG /UnderlineOffset get add % VerbalY + UnderlineOffset
1376 dup % dup UnderlineY
1377 3 1 roll % X Y Y -> Y X Y
1378 moveto % LabelX UnderlineY moveto
1379
1380 LeftMargin exch lineto % LeftMargin UnderlineY lineto
1381
1382 stroke
1383 }
1384 % else
1385 { pop pop }
1386 ifelse
1387} def
1388
1389/DrawQMemo {
1390 % label: Memo
1391 LeftMargin
1392 QCONFIG /Memo get 1 get % MemoY
1393 moveto % LeftMargin MemoY moveto
1394 (Memo ) show
1395
1396 Underline { % if
1397 % underline: Memo
1398 0 QCONFIG /UnderlineOffset get rmoveto % 0 UnderlineOffset rmoveto
1399 currentpoint
1400 newpath
1401 moveto % currentpoint moveto
1402 QCONFIG /MemoLineWidth get 0 rlineto
1403 stroke
1404 } if
1405} def
1406
1407/DrawQSignature {
1408 QCONFIG /RightMarginX get
1409
1410 % if
1411 userdict /SignatureLineHeight known
1412 {
1413 SignatureLineHeight
1414 }
1415 % else
1416 {
1417 QCONFIG /Memo get 1 get % MemoY
1418 QCONFIG /UnderlineOffset get % UnderlineOffset
1419 add % MemoY UnderlineOffset add
1420 } ifelse
1421
1422 % ^ RightMarginX SignatureY
1423 newpath
1424 moveto % RightMarginX UnderlineY moveto
1425 QCONFIG /SignatureLineWidth get neg 0 rlineto
1426 stroke
1427} def
1428
1429%
1430% [(string) ...] boldlines DrawQInfo -
1431%
1432% Draw array of strings as separate lines of text centered and topaligned
1433% to the currentpoint. Null strings are skipped. If the string is non-null
1434% and it's index is less than boldlines, the bold font is used.
1435%
1436/DrawQInfo {
1437 0 % counter
1438 false % istopaligned
1439 % ^ [(string)] boldlines counter istopaligned
1440 4 -1 roll % ^ boldlines counter istopaligned [(string)]
1441 {
1442 % ^ boldlines counter istopaligned (string)
1443 dup length 0 gt { % if
1444
1445 % bold font if one of boldlines
1446 2 index % counter
1447 4 index % boldlines
1448 lt {
1449 currentfont % save font to stack
1450 BoldFontName findfont
1451 StandardFontSize scalefont
1452 setfont
1453 5 1 roll % ^ font boldlines counter istopaligned (string)
1454 } if
1455
1456 exch % ^ (string) istopaligned
1457 % if istopaligned
1458 {
1459 nextline
1460 true % istopaligned
1461 }
1462 % else
1463 {
1464 topalign
1465 0 StandardFontSize neg initline
1466 true % istopaligned
1467 }
1468 ifelse
1469
1470 exch % ^ istopaligned (string)
1471 centeralign show % (string) centeralign show
1472
1473 % ^ boldlines counter istopaligned
1474
1475 % restore font if one of boldlines
1476 1 index % counter
1477 3 index % boldlines
1478 lt {
1479 % ^ font boldlines counter istopaligned
1480 4 -1 roll % ^ boldlines counter istopaligned font
1481 setfont % restore font from stack
1482 } if
1483 }
1484 % else
1485 { pop } % discard (string)
1486 ifelse
1487
1488 exch 1 add exch % increment counter
1489 } forall
1490 pop % discard istopaligned
1491 pop % discard counter
1492 pop % discard boldlines
1493} def
1494
1495/DrawQBankInfo {
1496 QCONFIG /Date get 0 get 4 div 3 mul % DraweeX
1497 CheckHeight TopMargin sub % DraweeY
1498 moveto % DraweeX DraweeY moveto
1499 [ BankName BankAddr1 BankAddr2 BankCityStateZip ] 1 DrawQInfo
1500} def
1501
1502/DrawQAccountHolderInfo {
1503 QCONFIG /Date get 0 get 3 div % DraweeX
1504 CheckHeight TopMargin sub % DrawerY
1505 moveto % DrawerX DrawerY moveto
1506 [ Name1 Name2 Address1 Address2 CityStateZip PhoneNumber ] 2 DrawQInfo
1507} def
1508
1509/DrawQCheckNumberAndFraction {
1510 currentfont % save font to stack
1511 CheckNumFontName findfont
1512 CheckNumFontSize scalefont
1513 setfont
1514
1515 CheckWidth RightMargin sub % NumberX
1516 CheckHeight TopMargin sub % NumberY
1517 moveto % NumberX NumberY moveto
1518 CheckNumberString topalign
1519 0 StandardFontSize 1.25 mul neg initline
1520 rightalign show
1521 nextline
1522
1523 FractionFontName findfont
1524 FractionFontSize scalefont
1525 setfont
1526
1527 Fraction topalign rightalign show
1528
1529 setfont % restore font from stack
1530} def
1531
1532%
1533% LeftX RightX Y (label) DrawQStubLabeline -
1534%
1535/DrawQStubLabeline {
1536 4 -1 roll % ^ RightX Y (label) LeftX
1537 2 index % Y index
1538 moveto % LeftX Y moveto
1539 % ^ RightX Y (label)
1540 show % (label) show
1541 % ^ RightX Y
1542 QCONFIG /UnderlineOffset get % ^ RightX Y UnderlineOffset
1543 dup 0 exch rmoveto % Offset start of line
1544 add % Y UnderlineOffset add
1545 lineto % RightX Y lineto
1546} def
1547
1548/DrawQStub {
1549 CheckHorOffset 2 inch ge
1550 QCONFIG /Stub get
1551 and { % if
1552 gsave
1553
1554 CheckHorOffset neg 0 translate
1555
1556 newpath
1557
1558 StandardFontName findfont
1559 StandardFontSize 1 sub scalefont
1560 setfont
1561
1562 0.1875 inch % ^ LeftX
1563 dup CheckHorOffset exch sub % ^ LeftX RightX
1564
1565 2 copy % LeftX RightX
1566 QCONFIG /StubDate get 1 get % DateY
1567 (DATE )
1568 DrawQStubLabeline
1569
1570 2 copy % LeftX RightX
1571 QCONFIG /StubPayee get 1 get % PayeeY
1572 (PAYEE )
1573 DrawQStubLabeline
1574
1575 2 copy % LeftX RightX
1576 QCONFIG /StubAmount get 1 get % AmountY
1577 (AMOUNT )
1578 DrawQStubLabeline
1579
1580 2 copy % LeftX RightX
1581 QCONFIG /StubMemo get 1 get % MemoY
1582 (MEMO )
1583 DrawQStubLabeline
1584
1585 2 copy % LeftX RightX
1586 QCONFIG /StubCategory get 1 get % CategoryY
1587 (CATG. )
1588 DrawQStubLabeline
1589
1590 2 copy % LeftX RightX
1591 QCONFIG /StubAccount get 1 get % AccountY
1592 (ACCT. )
1593 DrawQStubLabeline
1594
1595 Underline { stroke } if
1596
1597 CheckNumFontName findfont
1598 CheckNumFontSize scalefont
1599 setfont
1600
1601 % ^ LeftX RightX
1602 CheckHeight TopMargin sub moveto % RightX TextTop moveto
1603 CheckNumberString topalign rightalign show
1604
1605 pop % LeftX
1606
1607 grestore
1608 } if
1609} def
1610
1611/DrawQCheckBody {
1612 DrawQDate
1613 DrawQAmount
1614 DrawQPayee
1615 DrawQVerbal
1616 DrawQMemo
1617 DrawQSignature
1618 DrawQBankInfo
1619 DrawQAccountHolderInfo
1620 DrawQCheckNumberAndFraction
1621 DrawQStub
1622 /DrawLogo where { pop DrawLogo } if
1623} def
1624
1625/DrawQStandardCheckBody {
1626 /QCONFIG QStandardConfig def
1627 DrawQCheckBody
1628} def
1629
1630/DrawQWalletCheckBody {
1631 /QCONFIG QWalletConfig def
1632 DrawQCheckBody
1633} def
1634%%EndProcSet
1635
1636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1637% Standard Feature Printing Routines %
1638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639
1640/DrawMICR {
1641 % 0.25 high, 5.6875 from right edge should be in the middle
1642 % of the tolerance band
1643 CheckWidth 0.25 inch moveto
1644 -5.6875 inch 0 inch rmoveto
1645 MICRHorTweak MICRVerTweak rmoveto
1646 % Now we're at the nominal start of the routing number
1647
1648 MICRFontName findfont
1649 MICRFontSize scalefont
1650 setfont
1651
1652 % Number of digits in the CheckNumberString
1653 /CheckNumDigit CheckNumberString length 1 sub def
1654
1655 CheckNumInAuxOnUs {
1656 CheckNumEnd -1 CheckNumStart {
1657 CheckNumDigit 0 ge {
1658 AuxOnUs exch CheckNumberString CheckNumDigit get put
1659 /CheckNumDigit CheckNumDigit 1 sub def
1660 } {
1661 AuxOnUs exch (0) 0 get put
1662 } ifelse
1663 } for
1664 } if
1665
1666
1667 AuxOnUs stringwidth pop neg 0 rmoveto
1668 AuxOnUs show
1669
1670 Routing show
1671
1672 CheckNumInOnUs {
1673 CheckNumEnd -1 CheckNumStart {
1674 CheckNumDigit 0 ge {
1675 OnUs exch CheckNumberString CheckNumDigit get put
1676 /CheckNumDigit CheckNumDigit 1 sub def
1677 } {
1678 OnUs exch (0) 0 get put
1679 } ifelse
1680 } for
1681 } if
1682
1683 OnUs show
1684
1685 StandardFontName findfont
1686 StandardFontSize scalefont
1687 setfont
1688} def
1689
1690
1691/DrawVOID {
1692 save
1693 StandardFontName findfont
1694 50 scalefont
1695 setfont
1696 newpath
1697 CheckWidth 2 div 1 inch moveto
1698 30 rotate
1699 (V O I D) stringwidth pop 0 moveto
1700 (V O I D) true charpath
1701 stroke
1702 restore
1703} def
1704
1705/DrawCheck {
1706
1707 % Convert CheckNumber integer to a string
1708 CheckNumber CheckNumberString cvs
1709 pop % discard reference to CheckNumberString
1710
1711 PrintCheckBody {
1712 CheckLayoutDict CheckLayout get exec
1713 } if
1714
1715 PrintMICRLine {
1716 DrawMICR
1717 } if
1718
1719 PrintVOID {
1720 % Draw border around check, and print "VOID" for testing
1721 0 0 moveto
1722 CheckWidth 0 lineto
1723 CheckWidth CheckHeight lineto
1724 0 CheckHeight lineto
1725
1726 0 0 lineto
1727
1728 DrawVOID
1729 } if
1730
1731} def
1732
1733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1734% Main Printing Procedure %
1735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1736
1737/CurrentPage 1 def
1738
1739% Replace symbol placeholders with actual glyphs
1740% Also get starting and ending position for check number
1741FixMICR
1742
1743NumPages { % repeat
1744 /CheckNumber CheckNumber ChecksPerPage add def
1745 CheckHorOffset CheckVerOffset translate
1746
1747 StandardFontName findfont
1748 StandardFontSize scalefont
1749 setfont
1750
1751 LineWidth setlinewidth
1752
1753 % Loop through printing checks, starting with the bottom one
1754
1755 ChecksPerPage { % repeat
1756 /CheckNumber CheckNumber 1 sub def
1757 newpath
1758 DrawCheck
1759 stroke
1760 0 CheckHeight translate
1761 } repeat
1762
1763 showpage
1764
1765 /CheckNumber CheckNumber ChecksPerPage add def
1766 /CurrentPage CurrentPage 1 add def
1767} repeat
1768

Built with git-ssb-web