git ssb

0+

cel / freecheck



Tree: ba55f8a45e338d63c2092fb15fdc09218f9a404f

Files: ba55f8a45e338d63c2092fb15fdc09218f9a404f / freecheck

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

Built with git-ssb-web