% % w2-1997.ps % % Written by : Stephen J. Friedl % Software Consultant % Southern California USA % steve@unixwiz.net % % ========================================================= % Published with the permission of the contracting customer % ========================================================= % % This is a 1997 W2 form for Payroll Company, Inc. The idea is that % we perform all the "base" text for the three stubs plus the % top half, then take the user parameters and plug them info % the form boxes. % % The page is drawn more or less like this: % % +--------------------------------+ % | PAYROLL CO | % | Return Addr | % | user text | % | user text | % | user text | % | user text | % | Mailing addr user text | % | user text | % | user text | % | | % | | % |________________________________| % | | | | % | Stub | Stub | Stub | % | | | | % | | | | % | | | | % | | | | % ^ | | | | % | | | | | % | | | | | % Y | | | | % | | | | % | | | | % +--------------------------------+ % 0,0 X ---> % % PostScript is a stack-based language (sort of like Forth % in that respect), and the syntax is fairly straightforward % for what we need to accomplish with this system. The "hard" % work has already been done, so the user need only to build % the input based on this template. % % The best way to describe this is by example, staring with % printing a reference page. % % Send a job with this content: % % w2start % testdata % w2end % % via the printer with the proper lp command. This will % be probably something like: % % lp -dhp5a -opsform=w2-1997 < datafile % % This produces a full W2 layout with test data overlayed % that describes each box. These box names will be used % later when "filling in" the form. Keep this reference % page handy. % % The "w2start" and "w2end" words will ALWAYS surround each % page, but the text in the middle will differ. % % THE REFERENCE PAGE % ------------------ % % The reference page has the same base text as a standard % W2, but the data are filled in with predetermined text % that describes each box. Generally speaking, the format % is "[nn].......boxn". The initial [nn] is the number % of characters that fit, and the final part is the actual % name of the box. % % Names in PostScript actually are prefixed with a /, so % the names of the boxes are: % % /box1 Wages, tips, & other compensation % /box2 Federal income tax withheld % /box3 Social Security Wages % /box4 Social Security taxes % /box5 Medicare Wages & Tips % /box6 Medicare Tax Withheld % /box7 Social Security Tips % /box8 Allocated Tips % /box9 Advance EIC Payment % /box10 Dependent Care Benefits % /box11 Nonqualified Plans % /box12 Benefits included in Box 1 % /box13 (3 lns) "See Instructions" % /box14 (3 lns) Other % /boxa Control number % /dept Department % /client Client/Company % /boxc (4 lns) Employer's name (also: return address) % /boxb Employer's ID number % /boxd Employee's Social Security Number % /box15a (ckbox) Statutory Employee % /box15b (ckbox) Deceased % /box15c (ckbox) Pension Plan % /box15d (ckbox) Legal Representative % /box15e (ckbox) Household Employee % /box15f (ckbox) Subtotal % /box15g (ckbox) Deferred Compensation % /boxe (4 lns) Employee's name & address (& mailing address) % /box16 Employer's state ID number % /state State name % /box17 State Wages, Tips, etc. % /box18 State Income tax % /box19 Locality name % /box20 Local Wages, Tips, etc. % /box21 Local Income Tax % /suppldata Array of many lines for the supplemental % info at the top. % % From the user's point of view, each page is constructed % by starting with 'w2start', filling in the data, and % finishing with 'w2end'. The "filling in of the data" is % the tricky part. % % SENDING A W2 % ------------ % % The way a W2 form is sent should be in this form: % % w2start % % { set individual W2 box data } % % w2end % % Setting the box data involves "name=value" pairs, though % this uses the PostScript stack notation rather than the % more familiar equals sign. Even though the W2 has % primarily numeric data, we treat all of it as strings. % Oddly enough, strings in PostScript are surrounded by % parentheses, not quotes. % % So, to bind a value to a name we use the "def" operator % this is done like: % % /box1 ( 4,717.24) def % % Note the spaces between the parens are part of the literal % string text, and it's the responsibility of the caller to % perform alignment as required. % % If any string must actually *contain* parentheses, it's best % to escape them with \ characters. If the string contains % *matched* parens, this is not strictly necessary, but it is % probably a good idea to simply do it all the time: % % /name (401\(k\) 123.45) def % % The backslash ( \ ) must also be escaped always. % % Some boxes are meant to contain multiple lines, and % if this is the case the PostScript array notation is % used. This is done with [ and ], so to build (for % instance) box14, it would look like: % % /box14 [ (CASDI 23.59) (LINE2 43.23) ] def % % Tokens can be spread across multiple lines, and white % space is generally ignored, so the above could also be % written as: % % /box14 [ % (CASDI 23.59) % (LINE2 43.23) % ] def % or % % /box14 % [ % (CASDI 23.59) % (LINE2 43.23) % ] % def % % All boxes are processed the same way, so you can % provide the array notation if you need more than % one line, or just a simple assignment if you need % only one. % % This means a one-line box14 could be either: % % /box14 [ (CASDI 23.59) ] def % or % /box14 (CASDI 23.59) def % % Note that this is a property of this program, not % of PostScript in general where you can't normally % mix and match types. % % We do not detect cases where you try to fit more % than one line into a box that is designed for just % one. Be careful. % % It doesn't matter what order you provide the data % in -- these are just filling a dictionary for later % -- and you may omit values that are unused. We take % care to "clear" the dictionary at the start of each % new W-2. % % SETTING CONTROL VARIABLES % ------------------------- % % For debugging the program supports a few "global" % variables that control behavior. These are all % boolean values (which default to "false") that you % can set *before* the first W2 to control the % behavior of all that follow. % % These are % % /align? true def % /perfs? true def % /addrbox? true def % % If /align? is true, we print an alignment cross at exactly % 1" down and to the right of the upper left corner. If you % print this and it's not *exactly* in the right spot, we can % adjust this internally. % % if /perfs? is true, we print thin dotted lines that % represent the perforations of the underlying paper. % There is also a thin line about 1/3 of the way across % on the top half. This represents the limit of what can % be seen through the envelope's window, and we are not % to print anything to the left of this. % % if /addrbox? is true, we print a thin box around the % mailing and return addresses. % % Comments in PostScript start with % and go to the rest % of the line. % common measurements /inch { 72 mul } bind def /mm { 25.4 div 72 mul } bind def %------------------------------------------------------------------------ % Pull from either tray 2 or tray 3 (alternately) % % Tuned for customer's HP LaserJet equipment (not sure if this is general) % << /PageSize [612 792] % letter size /MediaPosition 0 % 0 = tray 2 % 1 = Tray 3 % 2 = Envelope Feeder % 3 = Tray 1 % 4 = Tray 4 >> setpagedevice %------------------------------------------------------------------------ % Key measurement parameters % % bxwidth - the width of one of the stubs (should be roughly % 8.5 inches divided by three % % bxheight - height of the smallest W2 stub boxes % % stubtop - location of the top of the three W2 stub boxes. % % align? - true to print alignment markers % perfs? - true to print perforation markers % addrbox? - true to print boxes around the mailing/return addresses /bxwidth 2.5 inch def /bxheight 0.250 inch def /middle 5.50 inch def /stubtop 5.5 inch % centerline 2 mm sub % adjust down a bit def /align? false def /perfs? false def /addrbox? true def %------------------------------------------------------------------------ % compensates for laser printer physical limitations (these vary on % a per-printer basis). The move the zero point to where the rest of % the form can count on proper placement. % /xoffset 0 def /yoffset 0 def % /yoffset 1 16 div inch def % SJF's HP4M+ % /xoffset 1 mm neg def xoffset yoffset translate %------------------------------------------------------------------------ % These define some of the common fonts we'll use throughout the form. % We could probably do this another way, but for now it seems to be OK. % /Helv4 /Helvetica findfont 4 scalefont def /Helv6 /Helvetica findfont 6 scalefont def /Helv8 /Helvetica findfont 8 scalefont def /Helv8B /Helvetica-Bold findfont 8 scalefont def /Cour8 /Courier findfont 8 scalefont def /Cour8B /Courier-Bold findfont 8 scalefont def /Cour9 /Courier findfont 9 scalefont def /Cour10B /Courier-Bold findfont 10 scalefont def /Cour10 /Courier findfont 10 scalefont def % ------------------------------------------------------------------------ % boxtype: wtype height % % This routine takes box info and pushes the size of the box on % the stack. It is used to print a single full-width, half-width, % or third-width box, and we automatically calculate the proper % size for the box based on the scale factors involved: % % wtype - width factor % % 1 = full width of column % 2 = half width of column % 3 = third width of column % % height - multipler of minimum box height (1, 1.5, 2, 3, etc.) % % Left on the stack are the actual width and height values % % Examples: assume that bxwidth is 2 inches and bxheight is % .25 inch: % % 1 1 boxtype --> 1.00 inch .25 inch % 2 1 boxtype --> 0.50 inch .25 inch % 3 1 boxtype --> 0.33 inch .25 inch % /boxtype { bxheight mul exch % multiply height bxwidth exch div exch } bind def % ------------------------------------------------------------------------ % drawbox: width height % % Given the *upper right* point of a box, draw the box with the % given width and height (with height travelling *down* the page). % % This procedure does not alter the graphics state of the program. % % The line width is assumed to be set already % /drawbox { gsave 1 index 0 rlineto % draw top line neg 0 exch rlineto % draw right side neg 0 rlineto % draw bottom edge closepath stroke grestore } bind def % ------------------------------------------------------------------------ % Given a name, fetch it from the current dict and return the value of % this dict entry (which might be an array!). % % input: /name % % Returns: (value) true if found % false if not found % % This does not modify the graphics state % /getW2value { dup % stack: /name /name currentdict exch % stack: /name dict /name known % stack: /name bf { currentdict % stack: /name dict exch % stack: dict /name get % stack: (value) true % stack: (value) true } { % stack: /name pop false % stack: false } ifelse } bind def % ------------------------------------------------------------------------ % ballotbox % % This draws a single little ballot box, the associated text, and % draws the "X" in the box if it's required by the presense of the % name in our w2 dictionary. % % params: % % /dictname (topline) (botline) xloc yloc ballotbox % % /dictname -- the entry into w2dict that is either found or % not. If it's found it is printed literally (should % be "X"). % % (topline) -- the upper descriptive line % % (botline) -- the bottom descriptive line (can be empty) % % xloc yloc -- location of the top of the ballot box with % respect to the upper right of the enclosing box. % /ballotbox { gsave % stack: /nm (top) (bot) xl yl moveto % stack: /nm (top) (bot) %---------------------------------------------------------------- % draw the standard ballot box itself % 2 mm 8 drawbox %---------------------------------------------------------------- % Draw the upper and lower text boxes % gsave -2 mm 1 mm rmoveto % back up the baseline gsave show grestore % print lower line 0 1.55 mm rmoveto % to lower print line gsave show grestore grestore %---------------------------------------------------------------- % fetch the value of this ballot box from the user and display it % in the box. This is optimized to display an "X" properly and % won't size things right if something else is used. Test first. % getW2value % stack: (value) true % or: false { Cour10B setfont 0 -7 rmoveto show % probably an "X" } if grestore } bind def % ------------------------------------------------------------------------ % % This draws a single W2 box with proper text label and size. We also % pass in a name that is pulled from the W2 dict and printed if it is % found. % % inputs: /name (text) wtype hmul w2box % outputs: -none- % % The wtype and hmul are inputs to boxinfo, which produce a % real live width and height. These are used to first draw a % physical box. Then the text label is laid down in the upper % left of the box. % % Finally is the /name param is used as a key into w2dict. If % this is found, we print the full copy of the text found % there (an array if necessary) in the proper Courier font. /w2box { boxtype % stack: /name (text) width height 3 -1 roll % stack: /name width height (text) 2 index % stack: /name width height (text) width 2 index % stack: /name width height (text) width height gsave drawbox % stack: /name width height (text) %---------------------------------------------------------------- % Now actually draw the text, and this is where we decide just % how far to move down and to the right to lay down the label % text. This value (2, -4.0 points) is for the fixed label. % gsave 2 -5.0 rmoveto show % stack: /name width height grestore 3 -1 roll % stack: width height /name getW2value % stack: width height (val) true % or: width height false { Cour8B setfont % 1 % X indent (from left of box) -13 % Y indent (down from top of box) rmoveto dup type % stack: width height (val) type /arraytype eq { { gsave show grestore 0 -8 rmoveto } bind forall } { show } ifelse } if grestore exch % stack: height width 0 rmoveto % move to the right of the current box currentpoint pop % stack: height xloc bxwidth .1 inch sub lt { pop % toss the height part } { % stack: height currentpoint % stack: height x y exch pop % stack: height y exch sub % stack: newy 0 exch moveto } ifelse } bind def % ------------------------------------------------------------------------ % show the perforations as they would appear on the paper. This includes % a horizontal dashed line that is exactly in the center of the page, plus % % This procedure takes no parameters and does not alter the current % graphics state. % /showperfs { gsave %---------------------------------------------------------------- % set the line type to be very thin and dashed. % 0 setlinewidth [2 3] 11 setdash %---------------------------------------------------------------- % Go to the left center of the page which should split the page % in half. % 0 inch 5.5 inch moveto % left center of the page gsave 10 inch 0 rlineto stroke % long horizontal line grestore 8.5 inch 3 div 0 rmoveto % top left of second stub gsave 0 -6 inch rlineto stroke % ... long vertical line grestore 8.5 inch 3 div 0 rmoveto % top left of third stub 0 -6 inch rlineto stroke % ... long vertical line % as an added benefit, we mark the area that we can print % in on the right side of the top half. It's 5-1/8" from % the left margin % 0 setlinewidth 5.125 inch 5.5 inch moveto 0 99 inch rlineto stroke grestore } bind def % ------------------------------------------------------------------------ % w2stub - copyname bolden % % This produces one of the three lower stub copies at the current % location, and this includes laying down the relevant user text % along with the static text and boxes. % % There are two parameters: % % copyname - 'Copy' string -- second line printed % % bolden - "true" to thicken boxes 1, 2, and 9, else % these boxes are the same size as the rest % % This routine does not alter the graphics state. % /w2stub { /bwidth exch def gsave currentpoint translate bwidth setlinewidth Helv4 setfont /box1 (1 WAGES, TIPS, OTHER COMPENSATION) 2 1 w2box /box2 (2 FEDERAL INCOME TAX WITHHELD) 2 1 w2box 1 setlinewidth /box3 (3 SOCIAL SECURITY WAGES) 2 1 w2box /box4 (4 SOCIAL SECURITY TAXES) 2 1 w2box /box5 (5 MEDICARE WAGES & TIPS) 2 1 w2box /box6 (6 MEDICARE TAX WITHHELD) 2 1 w2box /box7 (7 SOCIAL SECURITY TIPS) 2 1 w2box /box8 (8 ALLOCATED TIPS) 2 1 w2box bwidth setlinewidth /box9 (9 ADVANCE EIC PAYMENT) 2 1 w2box 1 setlinewidth /box10 (10 DEPENDENT CARE BENEFITS) 2 1 w2box /box11 (11 NONQUALIFIED PLANS) 2 1 w2box /box12 (12 BENEFITS INCLUDED IN BOX 1) 2 1 w2box /box13 (13 SEE INSTRUCTIONS FOR BOX 13) 2 2 w2box /box14 (14 OTHER) 2 2 w2box /boxa (a CONTROL NUMBER) 3 1 w2box /dept (DEPARTMENT) 3 1 w2box /client (CLIENT/COMPANY) 3 1 w2box /boxc (c EMPLOYER'S NAME, ADDRESS AND ZIP CODE) 1 2.2 w2box /boxb (b EMPLOYER'S IDENTIFICATION NUMBER) 2 1 w2box /boxd (d EMPLOYEE'S SOCIAL SECURITY NUMBER) 2 1 w2box %---------------------------------------------------------------- % draw the seven little ballot boxes. We make an outer enclosing % box with the box number (15) but with a dummy name that won't % ever actually look up, then we draw each individual little % ballot box. % /x (15) 1 1.5 w2box gsave currentpoint translate 0.5 setlinewidth % 1/2 point thickness /box15a (STATUTORY) (EMPLOYEE) 5 mm 4 mm ballotbox /box15b (DECEASED) () 15 mm 4 mm ballotbox /box15c (PENSION) (PLAN) 24 mm 4 mm ballotbox /box15d (LEGAL) (REP.) 33 mm 4 mm ballotbox /box15e (HSHLD) (EMPL.) 41 mm 4 mm ballotbox /box15f (SUBTOTAL) () 48 mm 4 mm ballotbox /box15g (DEFERRED) (COMP.) 57 mm 4 mm ballotbox grestore /boxe (e,f EMPLOYEE'S NAME, ADDRESS AND ZIP CODE) 1 2.2 w2box /box16 (16 EMPLOYER'S STATE I.D. NUMBER) 1 1 w2box /state ( STATE NAME) 3 1 w2box /box17 (17 STATE WAGES,TIPS,ETC) 3 1 w2box /box18 (18 STATE INCOME TAX) 3 1 w2box /box19 (19 LOCALITY NAME) 3 1 w2box /box20 (20 LOCAL WAGES, TIPS,ETC) 3 1 w2box /box21 (21 LOCAL INCOME TAX) 3 1 w2box %---------------------------------------------------------------- % now for the stuff at the bottom of the page. This is the "fine % print" that prints the eform name, copy name, the treasury % notice, etc. % Helv8 setfont 0 mm -3 mm rmoveto gsave (Form W-2 Wage and Tax Statement 1997) show grestore Helv6 setfont 0 mm -2 mm rmoveto % user's "Copy X" notice gsave show grestore 0 mm -2.1 mm rmoveto gsave (Dept. of the Treasury -- Internal Revenue Service) show grestore 0 mm -2.1 mm rmoveto gsave (This information is being furnished to the Internal Revenue Service) show grestore 0 mm -4 mm rmoveto gsave (OMB No. 1545-0008) show grestore grestore } bind def %------------------------------------------------------------------------ % allstubs % % This produces the three W2 stubs at the bottom of the page. It % is here that we provide the locations of all these items along % with the "Copy X" notices. /allstubs { 5 mm stubtop moveto (Copy B - To be filed with employee's FEDERAL tax return) 2.0 w2stub 75 mm stubtop moveto (Copy 2 - To be filed with employee's STATE, CITY or LOCAL tax return) 1.0 w2stub 146 mm stubtop moveto (Copy C - For EMPLOYEE's RECORDS) 1.0 w2stub } bind def %------------------------------------------------------------------------ % alignment % % This procedure draws a + at 1" 1" from the top of the page % (with appropriate X and Y offsets) to assist the user in % aligning the output. % % Initially the user prints an alignment page with the X and Y % offsets at zero and then measures how far the cross is from % the ideal 1" location from the upper left. From this we then % modify the /xoffset and /yoffset values to reflect this new % position. % % Note that while the values of /xoffset and /yoffset are % printed for reference, they are not actually used in this % procedure. Very early in the prolog we perform a "translate" % using these offsets, so we expect to already have taken this % into account. % % This procedure takes no parameters and does not modify the % graphics state. % /alignment { gsave 0 setlinewidth 1.00 inch 10.00 inch translate -0.5 inch 0 inch moveto % draw horizontal line 1.0 inch 0 inch rlineto stroke 0.0 inch -.5 inch moveto % draw vertical line 0.0 inch 1.0 inch rlineto stroke % now start drawing the offset values 0.10 inch 0.3 inch moveto % show offset values Cour8 setfont gsave (xoffset = ) show xoffset 72 div 20 string cvs show grestore 0 inch -0.15 inch rmoveto (yoffset = ) show yoffset 72 div 20 string cvs show grestore } bind def %------------------------------------------------------------------------ % addressbox % % This prints one of the two address boxes: the mailing address or % the return address. We always use the current font. % % Parameters are: % % [ strings ] leading width height box? llx lly addressbox % % llx - X position of the lower left corner of the box % lly - Y position of the lower left corner of the box % box? - TRUE to draw a thin box line around the label area % width - width of the outside of the box % height - height of the outside of the box % leading - points of leading between each line % [ strings ] - array of strings to print % % This assumes that the current font is the one to use. % /addressbox { % (-------------\n) print pstack (------------- end\n) print flush gsave %---------------------------------------------------------------- % move to the lower left of the enclosing box % % STACK: [strs] ldg width height box? llx lly translate % STACK: [strs] ldg width height box? %---------------------------------------------------------------- % draw outer box if requested. This is really only for debugging. % { dup 0 exch moveto 0 setlinewidth 1 index % dup width 1 index % dup height % 0 0 moveto drawbox % draw the box! } if %---------------------------------------------------------------- % Translate our cursor to the *top* of the box and indented just % a bit (sort of like a left margin for the box). We don't need % the width any longer either. % % v % +-*-----------------------------+ % | | % | | % | | % | | % +-------------------------------+ % % STACK: [str] ldg width height 0.15 inch exch % STACK: [str] ldg width .15" hht translate pop % STACK: [str] ldg %---------------------------------------------------------------- % The leading is at the top of the stack, and it's a positive % number. Adjust it negative to represent *downward* movement, % and add a little something to the first one % neg % STACK: [strs] -ldg % calculate the "top margin", which is leading + 20% dup .2 mul % STACK: [strs] -ldg -offset % move down that little bit from the top 0 exch translate % STACK: [strs] -ldg 0 0 moveto % give us a current point exch % STACK: leading [strings] { 1 index 0 exch rmoveto gsave show grestore } forall pop % dump the leading grestore } bind def %------------------------------------------------------------------------ % returnaddress % mailingaddress % % Display an array of strings in the return address position. We are % given % % [strings] leading box? returnaddress % % and we provide the location and size of the box. % /returnaddress { % width height 3.0625 inch 0.75 inch % STACK: [strs] ldg box? wid ht 3 -1 roll % STACK: [strs] ldg wid ht box? % lower X lower Y 0.8125 inch 9.3750 inch % STACK: [strs] ldg wid ht box llx lly addressbox } bind def /mailingaddress { % width height = 13/16" 3.5000 inch .8125 inch % STACK: [strs] ldg box? wid ht 3 -1 roll % STACK: [strs] ldg wid ht box? % lower X lower Y 0.750 inch 7.625 inch % STACK: [strs] ldg wid ht box? llx lly addressbox } bind def %------------------------------------------------------------------------ % addresses % % Draw the return and mailing addresses, and the single param % passed is TRUE if we're to print a box around all the names % and FALSE if not. % /addresses { /boxc getW2value % employer's name { Cour9 setfont 9.9 % leading 2 index % box? returnaddress } if /boxe getW2value % employee's name { Cour10B setfont 11 % leading 2 index % box? mailingaddress } if pop % dump the box? flag } bind def %------------------------------------------------------------------------ % tstr % % Given a string, replace the first few chars with the size % of the string. This is used for the test page so that we % don't have to count these by hand. % % Example: % % (.........box9) tstr --> ([13].....box9) % /tstr { dup % stack: str str str str dup dup 0 ([ ]) % stack: str str str str 0 ([..]) putinterval % stack: str str str length % stack: str str length 10 string % stack: str str length str cvs % stack: str str lstr 1 % stack: str str lstr 1 exch % stack: str str 1 lstr putinterval % stack: str } bind def %------------------------------------------------------------------------ % show_prnumber % % This displays the client number % /show_prnumber { /prnumber getW2value { 3.7 inch 10.2 inch moveto Helv8 setfont show } if } bind def %------------------------------------------------------------------------ % show_suppdata % % This displays the data at the top right of the page. This is free- % form data that the programmer can use to display most anything. % /show_suppdata { /suppdata getW2value { gsave Cour10 setfont 5.25 inch 10.20 inch moveto % upper left of box dup type /arraytype eq { { gsave show grestore 0 -11 rmoveto } forall } { show } ifelse grestore } if } bind def %------------------------------------------------------------------------ % testdata % % simulate one page of test data. Our intent is to include all printable % locations so our programs can know where to put everything without % needing to use a ruler or count spaces. We have hardcoded all of these % strings and texts. % % NOTE: if the width of the entire stub is changed (/bxwidth), it may % be required to change the widths of the texts too. It is technically % possible to determine these sizes automatically, but this is *way* % too much work when the hand method is so easy. % % We rely on the "tstr" procedure to stuff the string's length in % at the start surrounded by [xx]. % % This procedure performs no printing and does not alter the gstate % /testdata { /box1 (..............box1) tstr def /box2 (..............box2) tstr def /box3 (..............box3) tstr def /box4 (..............box4) tstr def /box5 (..............box5) tstr def /box6 (..............box6) tstr def /box7 (..............box7) tstr def /box8 (..............box8) tstr def /box9 (..............box9) tstr def /box10 (.............box10) tstr def /box11 (.............box11) tstr def /box12 (.............box12) tstr def /box13 [ (.....line.1..box13) tstr (.....line.2..box13) tstr (.....line.3..box13) tstr ] def /box14 [ (.....line.1..box14) tstr (.....line.2..box14) tstr (.....line.3..box14) tstr ] def /boxa (........boxa) tstr def /dept (........dept) tstr def /client (......client) tstr def /boxc [ (..........................line 1 boxc) tstr (..........................line 2 boxc) tstr (..........................line 3 boxc) tstr (..........................line 4 boxc) tstr ] def /boxb (..............boxb) tstr def /boxd (..............boxd) tstr def /box15a (a) def % statutory employee /box15b (b) def % deceased /box15c (c) def % pension plan /box15d (d) def % legal rep /box15e (e) def % hshld empl /box15f (f) def % subtotal /box15g (g) def % deferred comp /boxe [ (..........................line.1.boxe) tstr (..........................line.2.boxe) tstr (..........................line.3.boxe) tstr (..........................line.4.boxe) tstr ] def /box16 (................................box16) tstr def /state (.......state) tstr def /box17 (.......box17) tstr def /box18 (.......box18) tstr def /box19 (.......box19) tstr def /box20 (.......box20) tstr def /box21 (...... box21) tstr def /suppdata [ (.............................suppdata) tstr 29 { dup } repeat ] def } bind def %------------------------------------------------------------------------ % statictext % % This prints some of the overlay static text at the top of the form. % /statictext { /descline 5.6 inch def %---------------------------------------------------------------- % The big title at the top of the page % /Helvetica-Bold findfont 20 scalefont setfont 1.5 inch 10.6 inch moveto (1997 FORM W-2 AND SUPPORTING DATA) show %---------------------------------------------------------------- % now the little info just above the middle perfs % % Copyright ... DETACH HERE DETACH HERE % Helv8B setfont 0.23 inch descline moveto (Copyright 1997 by Payroll Company, Inc.) show Helv6 setfont 2.56 inch descline moveto (DETACH HERE) show 6.7 inch descline moveto (DETACH HERE) show } bind def %------------------------------------------------------------------------ % w2start % % This starts the W2 page by first printing the alignment info (if % requested) and then creating the new dictionary. We always stick % "w2dict" into this dictionary so we know which one is ours, and % perhaps someday we will add a bit of error checking. % /w2start { statictext % stuff at the top perfs? { showperfs } if % perforation simulators align? { alignment } if % alignment markers 100 dict begin } bind def /w2end { allstubs % all three stubs on the bottom show_prnumber (show_suppdata) show_suppdata addrbox? addresses % return address and the like end % dump the dictionary showpage } bind def % for testing, just print an overlay showing all form % labels and their lengths w2start testdata w2end