git ssb

0+

cel / freecheck



Tree: ff3eb6182008ac4289c03fd10df56dc7118f7fea

Files: ff3eb6182008ac4289c03fd10df56dc7118f7fea / freecheck

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

Built with git-ssb-web