git ssb

0+

cel / freecheck



Tree: 5f80e5a7a9fb3a8d20a94f1d14fa513ff8283f5f

Files: 5f80e5a7a9fb3a8d20a94f1d14fa513ff8283f5f / freecheck

44266 bytesRaw
1#!/usr/bin/perl
2
3#---------------
4#
5# FreeCheck - a free check printing application released
6# under the GNU General Public Licene.
7#
8# Copyright (C) 2000 Eric Sandeen <sandeen-freecheck@sandeen.net>
9# Copyright (C) 2002 James Klicman <james@klicman.org>
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation; either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; if not, write to the Free Software
23# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24#
25#---------------
26
27$version = "0.30.1";
28$systemConfigFile = "/etc/freecheck/freecheck.cfg";
29$ConfigFile = $ENV{"HOME"} . "/.freecheck.cfg";
30
31use Getopt::Long;
32use File::Copy qw(copy);
33
34
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 ($ENV{"HOME"} . "/.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\"\n";
750 die "\n";
751}
752
753sub Print_Defs {
754 # Go through each def in the hash table, and print according to the
755 # formatting hash
756 while ( ($key, $val) = each (%Definitions) ) {
757 print "/$key\t";
758 $_ = $Formats{$key};
759 s/value/$val/;
760 print;
761 print " def\n";
762 }
763}
764# End of Perl
765__END__
766
767% This is the main body of the postscript file, that acts on all of the
768% definitions we got from the config file.
769
770% Available Check Layouts
771/CheckLayoutDict <<
772 /Original { DrawOriginalCheckBody }
773 /QStandard { DrawQStandardCheckBody }
774 /QWallet { DrawQWalletCheckBody }
775>> def
776
777% Other Constants:
778
779% Size of the rectangular box for the amount (digits)
780/AmountBoxWidth {1 inch} def
781/AmountBoxHeight {0.25 inch} def
782
783% Max number of digits in check number, and allocate string
784/CheckNumDigits 4 def
785/CheckNumberString CheckNumber log floor 1 add cvi string def
786
787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
788% Helpful Printing Routines %
789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790
791% Shows a line, then does a "carriage return / line feed"
792% But only if the string exists (more than 0 chars)
793% (How do we get the current font size (height)?)
794
795/ShowAndCR {
796 % if
797 dup length 0 gt % First copy
798 {
799 dup show % Second copy
800 stringwidth pop neg 0 rmoveto % Original copy & move back
801 neg 0 exch rmoveto % line down
802 }
803 % else
804 {
805 pop % discard (string)
806 pop % discard height
807 }
808 ifelse
809} def
810
811%%BeginProcSet: substitute
812%%Creator: James Klicman <james@klicman.org>
813%%CreationDate: October 2002
814%%Version: 0.3
815%
816% (string) (O) (N) substitute -
817%
818% example: (A?C) (?) (B) substitute -> (ABC)
819%
820/substitute {
821 0 get exch 0 get exch % convert (O) and (N) to char codes
822 0 % counter
823 3 index % (string) {} forall
824 {
825 % ^ (string) O N counter C
826 3 index % (O)[0]
827 eq % (string)[i] == (O)[0]
828 {
829 % ^ (string) O N counter
830 3 index % (string)
831 % ^ (string) O N counter (string)
832 1 index % counter
833 % ^ (string) O N counter (string) counter
834 3 index % N
835 % ^ (string) O N counter (string) counter N
836 put % (string) counter N put
837 } if
838 1 add % increment counter
839 } forall
840 pop % counter
841 pop % N
842 pop % O
843 pop % (string)
844} def
845%%EndProcSet
846
847% Fix up the MICR line components (replace placeholders with MICR
848% characters)
849% Argh... surely there's a better way - anyone? use "forall?"
850
851/FixMICR {
852
853 /CheckNumStart -1 def
854 /CheckNumEnd -1 def
855 /CheckNumInOnUs false def
856 /CheckNumInAuxOnUs false def
857
858 % Get starting and ending positions for check number in
859 % (Aux)OnUs field
860 % (This will break if check number is entered in both fields)
861
862 OnUs length 1 sub -1 0 {
863 dup % dups the index
864 OnUs exch get (C) 0 get eq {
865 /CheckNumInOnUs true def
866 % If end number not yet defined, define it
867 CheckNumEnd 0 lt {
868 /CheckNumEnd exch def
869 } {
870 /CheckNumStart exch def
871 } ifelse
872
873 } {
874 pop
875 } ifelse
876 } for
877
878 AuxOnUs length 1 sub -1 0 {
879 dup % dups the index
880 AuxOnUs exch get (C) 0 get eq {
881 /CheckNumInAuxOnUs true def
882 % If end number not yet defined, define it
883 CheckNumEnd 0 lt {
884 /CheckNumEnd exch def
885 } {
886 /CheckNumStart exch def
887 } ifelse
888
889 } {
890 pop
891 } ifelse
892 } for
893
894
895 % Replace "R" in routing number with actual transit number symbol
896 % That's it - should be no spaces, dashes, or anything but digits
897 Routing (R) TransitSymbol substitute
898
899 % Replace "S" with space character in AuxOnUs
900 AuxOnUs (S) ( ) substitute
901
902 % Replace "-" with dash character in AuxOnUs
903 AuxOnUs (-) DashSymbol substitute
904
905 % Replace "P" with OnUs character in AuxOnUs
906 AuxOnUs (P) OnUsSymbol substitute
907
908 % Replace "S" with space character in OnUs
909 OnUs (S) ( ) substitute
910
911 % Replace "-" with dash character in OnUs
912 OnUs (-) DashSymbol substitute
913
914 % Replace "P" with OnUs character in OnUs
915 OnUs (P) OnUsSymbol substitute
916
917} def
918
919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
920% Original Feature Printing Routines %
921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
922
923/DrawMemoLine {
924 LeftMargin MemoLineHeight CheckHeight mul moveto
925 2.5 inch 0 inch rlineto
926 -2.5 inch 0 inch rmoveto
927 0 2 rmoveto
928 (for) show
929} def
930
931/DrawSignatureLine { % Expects height of signature line
932 % and right edge of check for
933 % beginning position
934
935 CheckWidth SignatureLineHeight CheckHeight mul moveto
936 RightMargin neg 0 rmoveto
937 -2.5 inch 0 rmoveto
938 2.5 inch 0 inch rlineto
939
940} def
941
942/DrawAmountLine {
943 CheckWidth AmountLineHeight CheckHeight mul moveto
944 RightMargin neg 0 rmoveto
945 (DOLLARS) stringwidth pop neg 0 rmoveto
946 (DOLLARS) show
947 (DOLLARS) stringwidth pop neg 0 rmoveto
948 -2 0 rmoveto
949 LeftMargin AmountLineHeight CheckHeight mul lineto
950} def
951
952/DrawAccountHolderInfo {
953 LeftMargin CheckHeight moveto
954 0 TopMargin neg rmoveto
955 0 StandardFontSize neg rmoveto
956
957 % make room for Logo if specified
958 /LogoForm where {
959 pop % discard dict
960 LogoWidth
961 /LogoBorder where {
962 pop % discard dict
963 LogoBorder 2 div add
964 } if
965 /LogoPadding where {
966 pop % discard dict
967 LogoPadding 2 div add
968 } if
969 0 rmoveto
970 } if
971
972 StandardFontSize Name1 ShowAndCR
973 StandardFontSize Name2 ShowAndCR
974
975 StandardFontName findfont
976 StandardFontSize 1 sub scalefont
977 setfont
978
979 StandardFontSize 1 sub Address1 ShowAndCR
980 StandardFontSize 1 sub Address2 ShowAndCR
981 StandardFontSize 1 sub CityStateZip ShowAndCR
982 StandardFontSize 1 sub PhoneNumber ShowAndCR
983
984 StandardFontName findfont
985 StandardFontSize 1 add scalefont
986 setfont
987} def
988
989/DrawDateLine {
990 0.6 CheckWidth mul DateLineHeight CheckHeight mul moveto
991 (Date) show
992 1 inch 0 rlineto
993} def
994
995/DrawBankInfo {
996 LeftMargin BankInfoHeight CheckHeight mul moveto
997
998 StandardFontSize BankName ShowAndCR
999
1000 StandardFontName findfont
1001 StandardFontSize 1 sub scalefont
1002 setfont
1003
1004 StandardFontSize 1 sub BankAddr1 ShowAndCR
1005 StandardFontSize 1 sub BankAddr2 ShowAndCR
1006 StandardFontSize 1 sub BankCityStateZip ShowAndCR
1007
1008 StandardFontName findfont
1009 StandardFontSize 1 add scalefont
1010 setfont
1011} def
1012
1013/DrawPayeeLine {
1014
1015 LeftMargin PayeeLineHeight CheckHeight mul moveto
1016 (ORDER OF) show
1017 (ORDER OF) stringwidth pop neg StandardFontSize rmoveto
1018 (PAY TO THE) show
1019 0 StandardFontSize neg rmoveto
1020 4 0 rmoveto
1021 currentpoint mark
1022
1023 CheckWidth PayeeLineHeight CheckHeight mul moveto
1024 RightMargin neg 0 rmoveto
1025 AmountBoxWidth neg 0 rmoveto
1026
1027 0 AmountBoxHeight rlineto
1028 AmountBoxWidth 0 rlineto
1029 0 AmountBoxHeight neg rlineto
1030 AmountBoxWidth neg 0 rlineto
1031
1032 -4 0 rmoveto
1033
1034 /Helvetica-Bold findfont
1035 14 scalefont
1036 setfont
1037
1038 ($) stringwidth pop neg 0 rmoveto
1039 ($) show
1040 ($) stringwidth pop neg 0 rmoveto
1041
1042 -4 0 rmoveto
1043 cleartomark
1044 lineto
1045
1046 StandardFontName findfont
1047 StandardFontSize scalefont
1048 setfont
1049
1050} def
1051
1052/DrawCheckNumber {
1053 CheckWidth CheckHeight moveto
1054 RightMargin neg TopMargin neg rmoveto
1055 CheckNumFontName findfont
1056 CheckNumFontSize scalefont
1057 setfont
1058
1059 CheckNumberString stringwidth pop neg 0 rmoveto
1060 0 -14 rmoveto
1061 CheckNumberString show
1062
1063 StandardFontName findfont
1064 StandardFontSize scalefont
1065 setfont
1066} def
1067
1068/DrawFraction {
1069 0.6 CheckWidth mul CheckHeight moveto
1070 0 TopMargin neg rmoveto
1071 0 StandardFontSize neg rmoveto
1072 Fraction show
1073} def
1074
1075/DrawStub {
1076 CheckHorOffset 2 inch ge {
1077 save
1078 newpath
1079 CheckHorOffset neg 0 translate
1080 StandardFontName findfont
1081 StandardFontSize 1 sub scalefont
1082 setfont
1083 /StubSpacing {CheckHeight 6 div} def
1084 CheckHorOffset 2 div StubSpacing 5 mul moveto
1085 CheckNumberString show
1086 0.3 inch StubSpacing 4 mul moveto
1087 (Date ) show
1088 CheckHorOffset 0.3 inch sub StubSpacing 4 mul lineto
1089 0.3 inch StubSpacing 3 mul moveto
1090 (Payee ) show
1091 CheckHorOffset 0.3 inch sub StubSpacing 3 mul lineto
1092 0.3 inch StubSpacing 2 mul moveto
1093 (Amount ) show
1094 CheckHorOffset 0.3 inch sub StubSpacing 2 mul lineto
1095 0.3 inch StubSpacing 1 mul moveto
1096 (Memo ) show
1097 CheckHorOffset 0.3 inch sub StubSpacing 1 mul lineto
1098 stroke
1099 restore
1100 } if
1101} def
1102
1103/DrawOriginalCheckBody {
1104 DrawBankInfo
1105 DrawAccountHolderInfo
1106 DrawMemoLine
1107 DrawSignatureLine
1108 DrawAmountLine
1109 DrawPayeeLine
1110 DrawCheckNumber
1111 DrawFraction
1112 DrawDateLine
1113 /DrawLogo where { pop DrawLogo } if
1114 DrawStub
1115} def
1116
1117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1118% QStandard & QWallet Feature Printing Routines %
1119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1120
1121%%BeginProcSet: nextline
1122%%Creator: James Klicman <james@klicman.org>
1123%%CreationDate: October 2002
1124%%Version: 0.3
1125
1126%
1127% state used by initline and nextline
1128%
1129/LINESTATE <<
1130 /x 0
1131 /y 0
1132 /rx 0
1133 /ry 0
1134>> def
1135
1136%
1137% LineHeight initline -
1138%
1139/initline {
1140 LINESTATE begin
1141 currentpoint
1142 /y exch def
1143 /x exch def
1144 /ty exch def
1145 /tx exch def
1146 end
1147} def
1148
1149%
1150% - nextline -
1151%
1152/nextline {
1153 LINESTATE begin
1154 x tx add
1155 dup /x exch def % x += tx
1156 y ty add
1157 dup /y exch def % y += ty
1158 moveto % x y moveto
1159 end
1160} def
1161%%EndProcSet
1162
1163
1164%%BeginProcSet: alignment
1165%%Creator: James Klicman <james@klicman.org>
1166%%CreationDate: October 2002
1167%%Version: 0.3
1168%
1169% (string) centeralign (string)
1170%
1171/centeralign {
1172 dup % dup (string)
1173 stringwidth % calculate string xWidth, yHeight
1174 pop % discard yHeight
1175 2 div neg % -(xWidth / 2)
1176 0 rmoveto % rmoveto center
1177} def
1178
1179%
1180% (string) rightalign (string)
1181%
1182/rightalign {
1183 dup stringwidth % calculate string xWidth, yHeight
1184 pop % discard yHeight
1185 neg 0 rmoveto % -xWidth 0 rmoveto
1186} def
1187
1188%
1189% (string) stringbbox x1 y1 x2 y2
1190%
1191% This procedure is based on the method described in Chapter 5 page 333
1192% of the PostScript Language Reference third edition.
1193%
1194/stringbbox {
1195 gsave
1196 newpath 0 0 moveto false charpath flattenpath pathbbox % x1 y1 x2 y2
1197 grestore
1198} def
1199
1200%
1201% (string) topalign (string)
1202%
1203/topalign {
1204 dup stringbbox % ^+ x1 y1 x2 y2
1205 neg 0 exch rmoveto % 0 -y2 rmoveto
1206 pop % x2
1207 pop % y1
1208 pop % x1
1209} def
1210
1211%
1212% (string) bottomalign (string)
1213%
1214/bottomalign {
1215 dup stringbbox % ^+ x1 y1 x2 y2
1216 pop % y2
1217 pop % x2
1218 neg 0 exch rmoveto % 0 -y1 rmoveto
1219 pop % x1
1220} def
1221%%EndProcSet
1222
1223
1224%%BeginProcSet: qchecks
1225%%Creator: James Klicman <james@klicman.org>
1226%%CreationDate: October 2002
1227%%Version: 0.3
1228
1229/QStandardConfig <<
1230 /RightMarginX CheckWidth RightMargin sub
1231 /UnderlineOffset -3
1232 /MemoLineWidth 3.25 inch
1233 /SignatureLineWidth 3.25 inch
1234 /PayToTheOrderOf {
1235 currentpoint % oldpoint
1236 0 StandardFontSize rmoveto % move up one line
1237 (PAY TO THE) show
1238 moveto % oldpoint moveto
1239 (ORDER OF ) show
1240 }
1241 % QStandard Coords, Check Size 8.5" x 3.5"
1242 /Date [ 503.08 183.44]
1243 /Amount [ 499.96 147.44 ]
1244 /Verbal [ 36.04 123.44 ]
1245 /Payee [ 84.04 147.44 ]
1246 /Memo [ 63.16 39.44 ]
1247 /Address [ 72.04 99.44 ]
1248 /Stub false
1249>> def
1250
1251/QWalletConfig <<
1252 /RightMarginX CheckWidth RightMargin sub
1253 /UnderlineOffset -2
1254 /MemoLineWidth 2.5 inch
1255 /SignatureLineWidth 2.5 inch
1256 /PayToTheOrderOf {
1257 0 StandardFontSize 2 mul rmoveto % move up two lines
1258 0 StandardFontSize neg initline
1259 (PAY) show nextline
1260 (TO THE) show nextline
1261 (ORDER OF ) show
1262 }
1263 % QWallet Coords, Check Size 6" x 2.8333"
1264 /Date [ 346.12 147.44 ]
1265 /Amount [ 331.96 135.44 ]
1266 /Verbal [ 24.04 123.44 ]
1267 /Payee [ 46.12 135.44 ]
1268 /Address [ 25.0 99.44 ]
1269 /Memo [ 45.16 39.44 ]
1270 /Stub true
1271 /StubDate [ 31.96 147.44 ]
1272 /StubPayee [ 31.96 123.44 ]
1273 /StubAmount [ 52.12 87.44 ]
1274 /StubMemo [ 31.96 63.44 ]
1275 /StubCategory [ 31.96 39.44 ]
1276 /StubAccount [ 31.96 15.44 ]
1277>> def
1278
1279
1280%
1281% /name (label) DrawQLabeline-rightmargin -
1282%
1283% draw label and underline to right margin
1284%
1285/DrawQLabeline-rightmargin {
1286 % show label
1287 % ^ /name (label)
1288 exch QCONFIG exch get aload pop % ^ (label) X Y
1289 2 copy % ^ (label) X Y X Y
1290 moveto % X Y moveto
1291 3 -1 roll % (label) X Y -> X Y (label)
1292 rightalign show % (label) rightalign show
1293
1294 % ^ X Y
1295
1296 Underline { % if
1297 % underline
1298 % line goes from end of label to right margin
1299 % ^ X Y
1300 exch ( ) stringwidth pop sub exch % backup X one space
1301 QCONFIG /UnderlineOffset get add % adjust underline position
1302 newpath
1303 dup % UnderlineY dup
1304 3 1 roll % X, Y, Y -> Y, X, Y
1305 moveto % X Y moveto
1306 % UnderlineY is on the stack
1307
1308 QCONFIG /RightMarginX get
1309 exch lineto % RightMarginX UnderlineY lineto
1310 stroke
1311 }
1312 % else
1313 { pop pop }
1314 ifelse
1315} def
1316
1317/DrawQDate {
1318 /Date (Date ) DrawQLabeline-rightmargin
1319} def
1320
1321/DrawQAmount {
1322 /Amount ($ ) DrawQLabeline-rightmargin
1323} def
1324
1325/DrawQPayee {
1326 % label: PAY TO THE ORDER OF
1327 LeftMargin
1328 QCONFIG /Payee get 1 get % PayeeY
1329 moveto % LeftMargin PayeeY moveto
1330 QCONFIG /PayToTheOrderOf get exec
1331
1332 Underline { % if
1333 % underline: Payee
1334 % line goes from end of "ORDER OF" to beginning of "$ amount"
1335 currentpoint
1336 QCONFIG /UnderlineOffset get add % CurrentY + UnderlineOffset
1337 newpath
1338 dup % UnderlineY dup
1339 3 1 roll % X, Y, Y -> Y, X, Y
1340 moveto % X Y moveto
1341 % ^ UnderlineY
1342
1343 QCONFIG /Amount get 0 get % AmountX
1344 ( $ ) stringwidth pop % AdjustX
1345 sub % PayeeLineEndX = AmountX - AdjustX
1346
1347 exch lineto % PayeeLineEndX UnderlineY lineto
1348 stroke
1349 } if
1350} def
1351
1352/DrawQVerbal {
1353 % label: Dollars
1354 QCONFIG /RightMarginX get
1355 ( DOLLARS) stringwidth
1356 pop % discard yHeight
1357 sub % RightMarginX - StringWidthX
1358
1359 % ^ LabelX
1360
1361 QCONFIG /Verbal get 1 get % VerbalY
1362 2 copy % LabelX VerbalY 2 copy
1363 moveto % LabelX VerbalY moveto
1364 ( DOLLARS) show
1365
1366 % ^ LabelX VerbalY
1367
1368 Underline { % if
1369 newpath
1370 QCONFIG /UnderlineOffset get add % VerbalY + UnderlineOffset
1371 dup % dup UnderlineY
1372 3 1 roll % X Y Y -> Y X Y
1373 moveto % LabelX UnderlineY moveto
1374
1375 LeftMargin exch lineto % LeftMargin UnderlineY lineto
1376
1377 stroke
1378 }
1379 % else
1380 { pop pop }
1381 ifelse
1382} def
1383
1384/DrawQMemo {
1385 % label: Memo
1386 LeftMargin
1387 QCONFIG /Memo get 1 get % MemoY
1388 moveto % LeftMargin MemoY moveto
1389 (Memo ) show
1390
1391 Underline { % if
1392 % underline: Memo
1393 0 QCONFIG /UnderlineOffset get rmoveto % 0 UnderlineOffset rmoveto
1394 currentpoint
1395 newpath
1396 moveto % currentpoint moveto
1397 QCONFIG /MemoLineWidth get 0 rlineto
1398 stroke
1399 } if
1400} def
1401
1402/DrawQSignature {
1403 QCONFIG /RightMarginX get
1404
1405 % if
1406 userdict /SignatureLineHeight known
1407 {
1408 SignatureLineHeight
1409 }
1410 % else
1411 {
1412 QCONFIG /Memo get 1 get % MemoY
1413 QCONFIG /UnderlineOffset get % UnderlineOffset
1414 add % MemoY UnderlineOffset add
1415 } ifelse
1416
1417 % ^ RightMarginX SignatureY
1418 newpath
1419 moveto % RightMarginX UnderlineY moveto
1420 QCONFIG /SignatureLineWidth get neg 0 rlineto
1421 stroke
1422} def
1423
1424%
1425% [(string) ...] boldlines DrawQInfo -
1426%
1427% Draw array of strings as separate lines of text centered and topaligned
1428% to the currentpoint. Null strings are skipped. If the string is non-null
1429% and it's index is less than boldlines, the bold font is used.
1430%
1431/DrawQInfo {
1432 0 % counter
1433 false % istopaligned
1434 % ^ [(string)] boldlines counter istopaligned
1435 4 -1 roll % ^ boldlines counter istopaligned [(string)]
1436 {
1437 % ^ boldlines counter istopaligned (string)
1438 dup length 0 gt { % if
1439
1440 % bold font if one of boldlines
1441 2 index % counter
1442 4 index % boldlines
1443 lt {
1444 currentfont % save font to stack
1445 BoldFontName findfont
1446 StandardFontSize scalefont
1447 setfont
1448 5 1 roll % ^ font boldlines counter istopaligned (string)
1449 } if
1450
1451 exch % ^ (string) istopaligned
1452 % if istopaligned
1453 {
1454 nextline
1455 true % istopaligned
1456 }
1457 % else
1458 {
1459 topalign
1460 0 StandardFontSize neg initline
1461 true % istopaligned
1462 }
1463 ifelse
1464
1465 exch % ^ istopaligned (string)
1466 centeralign show % (string) centeralign show
1467
1468 % ^ boldlines counter istopaligned
1469
1470 % restore font if one of boldlines
1471 1 index % counter
1472 3 index % boldlines
1473 lt {
1474 % ^ font boldlines counter istopaligned
1475 4 -1 roll % ^ boldlines counter istopaligned font
1476 setfont % restore font from stack
1477 } if
1478 }
1479 % else
1480 { pop } % discard (string)
1481 ifelse
1482
1483 exch 1 add exch % increment counter
1484 } forall
1485 pop % discard istopaligned
1486 pop % discard counter
1487 pop % discard boldlines
1488} def
1489
1490/DrawQBankInfo {
1491 QCONFIG /Date get 0 get 4 div 3 mul % DraweeX
1492 CheckHeight TopMargin sub % DraweeY
1493 moveto % DraweeX DraweeY moveto
1494 [ BankName BankAddr1 BankAddr2 BankCityStateZip ] 1 DrawQInfo
1495} def
1496
1497/DrawQAccountHolderInfo {
1498 QCONFIG /Date get 0 get 3 div % DraweeX
1499 CheckHeight TopMargin sub % DrawerY
1500 moveto % DrawerX DrawerY moveto
1501 [ Name1 Name2 Address1 Address2 CityStateZip PhoneNumber ] 2 DrawQInfo
1502} def
1503
1504/DrawQCheckNumberAndFraction {
1505 currentfont % save font to stack
1506 CheckNumFontName findfont
1507 CheckNumFontSize scalefont
1508 setfont
1509
1510 CheckWidth RightMargin sub % NumberX
1511 CheckHeight TopMargin sub % NumberY
1512 moveto % NumberX NumberY moveto
1513 CheckNumberString topalign
1514 0 StandardFontSize 1.25 mul neg initline
1515 rightalign show
1516 nextline
1517
1518 FractionFontName findfont
1519 FractionFontSize scalefont
1520 setfont
1521
1522 Fraction topalign rightalign show
1523
1524 setfont % restore font from stack
1525} def
1526
1527%
1528% LeftX RightX Y (label) DrawQStubLabeline -
1529%
1530/DrawQStubLabeline {
1531 4 -1 roll % ^ RightX Y (label) LeftX
1532 2 index % Y index
1533 moveto % LeftX Y moveto
1534 % ^ RightX Y (label)
1535 show % (label) show
1536 % ^ RightX Y
1537 QCONFIG /UnderlineOffset get % ^ RightX Y UnderlineOffset
1538 dup 0 exch rmoveto % Offset start of line
1539 add % Y UnderlineOffset add
1540 lineto % RightX Y lineto
1541} def
1542
1543/DrawQStub {
1544 CheckHorOffset 2 inch ge
1545 QCONFIG /Stub get
1546 and { % if
1547 gsave
1548
1549 CheckHorOffset neg 0 translate
1550
1551 newpath
1552
1553 StandardFontName findfont
1554 StandardFontSize 1 sub scalefont
1555 setfont
1556
1557 0.1875 inch % ^ LeftX
1558 dup CheckHorOffset exch sub % ^ LeftX RightX
1559
1560 2 copy % LeftX RightX
1561 QCONFIG /StubDate get 1 get % DateY
1562 (DATE )
1563 DrawQStubLabeline
1564
1565 2 copy % LeftX RightX
1566 QCONFIG /StubPayee get 1 get % PayeeY
1567 (PAYEE )
1568 DrawQStubLabeline
1569
1570 2 copy % LeftX RightX
1571 QCONFIG /StubAmount get 1 get % AmountY
1572 (AMOUNT )
1573 DrawQStubLabeline
1574
1575 2 copy % LeftX RightX
1576 QCONFIG /StubMemo get 1 get % MemoY
1577 (MEMO )
1578 DrawQStubLabeline
1579
1580 2 copy % LeftX RightX
1581 QCONFIG /StubCategory get 1 get % CategoryY
1582 (CATG. )
1583 DrawQStubLabeline
1584
1585 2 copy % LeftX RightX
1586 QCONFIG /StubAccount get 1 get % AccountY
1587 (ACCT. )
1588 DrawQStubLabeline
1589
1590 Underline { stroke } if
1591
1592 CheckNumFontName findfont
1593 CheckNumFontSize scalefont
1594 setfont
1595
1596 % ^ LeftX RightX
1597 CheckHeight TopMargin sub moveto % RightX TextTop moveto
1598 CheckNumberString topalign rightalign show
1599
1600 pop % LeftX
1601
1602 grestore
1603 } if
1604} def
1605
1606/DrawQCheckBody {
1607 DrawQDate
1608 DrawQAmount
1609 DrawQPayee
1610 DrawQVerbal
1611 DrawQMemo
1612 DrawQSignature
1613 DrawQBankInfo
1614 DrawQAccountHolderInfo
1615 DrawQCheckNumberAndFraction
1616 DrawQStub
1617 /DrawLogo where { pop DrawLogo } if
1618} def
1619
1620/DrawQStandardCheckBody {
1621 /QCONFIG QStandardConfig def
1622 DrawQCheckBody
1623} def
1624
1625/DrawQWalletCheckBody {
1626 /QCONFIG QWalletConfig def
1627 DrawQCheckBody
1628} def
1629%%EndProcSet
1630
1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632% Standard Feature Printing Routines %
1633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1634
1635/DrawMICR {
1636 % 0.25 high, 5.6875 from right edge should be in the middle
1637 % of the tolerance band
1638 CheckWidth 0.25 inch moveto
1639 -5.6875 inch 0 inch rmoveto
1640 MICRHorTweak MICRVerTweak rmoveto
1641 % Now we're at the nominal start of the routing number
1642
1643 MICRFontName findfont
1644 MICRFontSize scalefont
1645 setfont
1646
1647 % Number of digits in the CheckNumberString
1648 /CheckNumDigit CheckNumberString length 1 sub def
1649
1650 CheckNumInAuxOnUs {
1651 CheckNumEnd -1 CheckNumStart {
1652 CheckNumDigit 0 ge {
1653 AuxOnUs exch CheckNumberString CheckNumDigit get put
1654 /CheckNumDigit CheckNumDigit 1 sub def
1655 } {
1656 AuxOnUs exch (0) 0 get put
1657 } ifelse
1658 } for
1659 } if
1660
1661
1662 AuxOnUs stringwidth pop neg 0 rmoveto
1663 AuxOnUs show
1664
1665 Routing show
1666
1667 CheckNumInOnUs {
1668 CheckNumEnd -1 CheckNumStart {
1669 CheckNumDigit 0 ge {
1670 OnUs exch CheckNumberString CheckNumDigit get put
1671 /CheckNumDigit CheckNumDigit 1 sub def
1672 } {
1673 OnUs exch (0) 0 get put
1674 } ifelse
1675 } for
1676 } if
1677
1678 OnUs show
1679
1680 StandardFontName findfont
1681 StandardFontSize scalefont
1682 setfont
1683} def
1684
1685
1686/DrawVOID {
1687 save
1688 StandardFontName findfont
1689 50 scalefont
1690 setfont
1691 newpath
1692 CheckWidth 2 div 1 inch moveto
1693 30 rotate
1694 (V O I D) stringwidth pop 0 moveto
1695 (V O I D) true charpath
1696 stroke
1697 restore
1698} def
1699
1700/DrawCheck {
1701
1702 % Convert CheckNumber integer to a string
1703 CheckNumber CheckNumberString cvs
1704 pop % discard reference to CheckNumberString
1705
1706 PrintCheckBody {
1707 CheckLayoutDict CheckLayout get exec
1708 } if
1709
1710 PrintMICRLine {
1711 DrawMICR
1712 } if
1713
1714 PrintVOID {
1715 % Draw border around check, and print "VOID" for testing
1716 0 0 moveto
1717 CheckWidth 0 lineto
1718 CheckWidth CheckHeight lineto
1719 0 CheckHeight lineto
1720
1721 0 0 lineto
1722
1723 DrawVOID
1724 } if
1725
1726} def
1727
1728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1729% Main Printing Procedure %
1730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1731
1732/CurrentPage 1 def
1733
1734% Replace symbol placeholders with actual glyphs
1735% Also get starting and ending position for check number
1736FixMICR
1737
1738NumPages { % repeat
1739 /CheckNumber CheckNumber ChecksPerPage add def
1740 CheckHorOffset CheckVerOffset translate
1741
1742 StandardFontName findfont
1743 StandardFontSize scalefont
1744 setfont
1745
1746 LineWidth setlinewidth
1747
1748 % Loop through printing checks, starting with the bottom one
1749
1750 ChecksPerPage { % repeat
1751 /CheckNumber CheckNumber 1 sub def
1752 newpath
1753 DrawCheck
1754 stroke
1755 0 CheckHeight translate
1756 } repeat
1757
1758 showpage
1759
1760 /CheckNumber CheckNumber ChecksPerPage add def
1761 /CurrentPage CurrentPage 1 add def
1762} repeat
1763

Built with git-ssb-web