git ssb

0+

cel / freecheck



Tree: 5ebee715c8d25d27986880fee066b574f50ef9d0

Files: 5ebee715c8d25d27986880fee066b574f50ef9d0 / freecheck

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

Built with git-ssb-web