git ssb

0+

cel / freecheck



Tree: 8ddda7e41aec774df0ba03110c7a5b5e7d2cc3bc

Files: 8ddda7e41aec774df0ba03110c7a5b5e7d2cc3bc / freecheck

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

Built with git-ssb-web