Previous Thread
Next Thread
Print Thread
Generating forms on demand #809 15 Apr 11 03:08 PM
Joined: Jun 2001
Posts: 11,645
J
Jack McGregor Online Content OP
Member
OP Online Content
Member
J
Joined: Jun 2001
Posts: 11,645
GDI printing opens up the possibility of replacing pre-printed forms with computer-generated forms-on-demand (created on plain paper at the same time as the data that is printed on the form). This can result in significant convenience and cost savings, but there are choices to be made and possible obstacles to be overcome on the road to implementation. The remainder of this topic is an attempt to provide some guidance on the subject for anyone thinking of going down this path.

Scanned vs manually "drawn": There are two basic approaches to reproducing the existing pre-printed form: scanning it, or recreating it with GDI primitives. For simple forms, recreating the layout with primitives such as //RECTANGLE , //LINETO , and //TEXTOUT , etc., has the advantage of minimizing the potential difficulties related to aligning the form data with the form background. Since you must explicitly position the various boxes which make up the form, there is no doubt as to how to explicitly position the data to go in those boxes. Plus, the form can be easily adjusted over time (unlike a scanned form which may require re-scanning or treatment in an image editor to make changes).

However, in order to successfully recreate a form from GDI primitives, the form has to be simple enough to consist of only lines, boxes, ellipses, polygons, uniformly shaded areas, and of course text. In addition, images (such as logos) can be accommodated using the //IMAGE directive (provided you can supply the artwork in one of the supported file formats). Some forms may simply be too complicated to recreate this way. (Or it may be possible but require too many hours with a ruler and trial-and-error.) Note that if you go this route, a utility allowing you to view the report on the screen, such as APEX , will be invaluable.

Scanning the entire form into a single image file has the advantage of giving you essentially a perfect copy of the form while eliminating the time otherwise required tinkering with individual GDI directives to render the individual elements of the form. (In particular, forms with very small tightly-spaced text can be particularly difficult because of the sometimes impossibility of reproducing the exact inter-character spacing that was used on the original form.)

If you choose the scanning route, the following tips can save you a lot of frustration down the road:

- Make sure your form is perfectly aligned on the scanner (or use some software to de-skew the result). The slightest skew will become obvious when the horizontal and vertical lines in the form are printed.

- Use sufficient resolution to avoid chunky dithering effects. (200 dpi may be sufficient for most forms, but if there are rounded edges of graphics, you may need to go to at least 300 dpi to avoid stair-stepped edges.)

- Trim (crop) at least 1/4" of border space around the scanned image, so that the image size at 100% is no larger than the printable area of the typical page/printer. (Most laser printers, for example, have a built-in hardware margin of about 1/4", so that the actual print area is about 1/2" smaller, in each dimension, than the physical paper size. (This hardware margin may vary slightly between printers, but 1/4" is probably safe.)

- Calculate the right coordinates for your //IMAGE statement: To render the form on the page, you'll use an //IMAGE statement (at the top of each page). Getting the coordinates right requires a bit of arithmetic which may not seem critical but will go a long way towards both simplifying your task of aligning the data on the form, and making the form truly device independent.

Ideally, you want the scale of the computer-printed form to match the pre-printed form exactly. (This should allow you to preserve your existing spacing when printing the data on the form.) To accomplish this, you must make the size of the rectangle specified in the //IMAGE statement equivalent to the size of the scanned image (normalized back to the same real-world dimensions).

An example will make this clear. Let's assume your original form is 8.5 x 11 (letter), and that we can afford to crop 1/4" off all sizes (just white space being lost). We scan the original at 200 dpi, and then use some kind of editor to crop it. After saving the image as a JPG, we see that the exact dimensions of the saved image are 1550 x 2050 pixels. (At 200 dpi, this is equivalent to 7.75 x 10.25 inches, meaning that we actually cropped a little more than we needed to, but that's ok - it's better to error on the small side, as long as we didn't lose anything important in the cropping operation.)

If we use a map mode of LOENGLISH (units of 0.01 inches), our //IMAGE rectangle them becomes simply:

//IMAGE,filespec,0,0,775,1025

Note that it's ok, and indeed preferable, to use 0,0 as the upper left corner - we'll deal with aligning that to logical upper corner of the page using the XORIGIN and YORIGIN (below).

But first, let's consider the case where it is impossible to match the IMAGE rectangle exactly to the physical scanned form size. This can happen for one of two reasons:

a) The original form has printing that goes right to the edge (so we can't just crop off 1/4" on all sides).

b) The original form is an odd size (say, 9 x 12), and we'd rather render it in a similar but standard size, like LETTER.

In either of the above cases, we'll have no choice but to scale the scanned image. This will complicate the task of aligning the data to the form, but we can still make it easier and device-independent by maintaining the aspect ratio. Taking the example of a 9 x 12 form, with printing right to the edge so we can't crop it, we'll end up with an image (assuming 200 dpi) of 1800 x 2400 pixels. That's an aspect ratio of .75 (width/length). The maximum print rectangle on letter sized paper for most laser printers will be 8 x 10.5, which is an aspect ratio of .76. Not exact, but close enough that we can make it exact by just increasing the horizontal margins slightly. 10.5 (the printable paper length) x .75 (aspect ratio of the image) gives us 7.875 inches wide. In other words, if we maintain the original .75 aspect ratio and shrink the image to fit within the typical printable area of a letter-sized page, we'll end up with .125 inches extra margin on the side (which we can split between the two sides, or put all on one edge).

Splitting it roughly in half (now using HIENGLISH, or .001 inch units), we might use:

//IMAGE,filespec,063,0,7937,10500

Our spacing (for the data) will have to be adjusted to fit the scaled-down printed image of the form, but at least we've maintained the aspect ratio (so it won't look distorted), and it should print consistently on any printer (provided it supports at least 8 x 10.5 of printable area on the page).

Depending on the form and the difference in aspect ratios, you might decide that it is better to fill the page as much as possible by stretching the image to fill the maximum print rectangle, using the IMGF_STRETCH option. That's perfectly fine too, as long as it doesn't look funny. In either case, whenever there is stretching or scaling, you'll need to re-engineer the spacing of the data to match the form (more about that in a minute).

First, it's time to deal with the fact that not every printer has the same hardware margins. Although 1/4" is fairly standard, it's quite possible that it could be slightly less (or more, although I haven't seen that). And it is not unusual for the side margin to be slightly different than the top margin. To get the form reliably and consistently positioned on the page, the trick is to use the XORIGIN and YORIGIN GDI directives (or the equivalent Printer Init Commands ). Assuming we can trust 1/4" as being sufficient, use:

//XORIGIN,360
//YORIGIN,360

(Units for these directives are always in twips, or 1440 to the inch). The effect is to set the 0,0 position (used as a basis for all of the other GDI directives) to a point 1/4" from the top and left sides of the physical page (provided that is not less than the actual physical margin of the printer, which explains the disclaimer of assuming 1/4" is sufficient). So the rectangle of 0,0,775,1050 in the IMAGE statement will be effectively shifted down and to the left by 1/4". Using XORIGIN and YORIGIN to perform this shift is easier than doing it individually on every GDI statement.

Finally, we come to aligning the data to the form. If you managed to render the form at exactly the same scale as the original, then you probably don't need to change your print spacing logic at all. But if you had to resort to scaling, or you are switching from a dot-matrix printer to a laser, resulting in a different font, line spacing, etc., then here's what you must do:

1) Print out a sample form with sample data

2) Use a ruler and calculate the necessary vertical spacing (lines per inch) needed. For example, you may have originally used 6 LPI, but now the form is slightly smaller than the original, so you need something more like 6.5 LPI. Convert that to spacing from one line to the next. 6.5 LPI is .15384 inches per line. That's a very awkward number, so we may need to switch to a more precise mapping unit. Even in twips, that's 221.54 twips per line. HIMETRIC (.01 millimeters) is the most precise, and even there we get 390.8 per line, but rounding that to 391 will probably be precise enough. So:

//;use units of 1/100 mm (1/2540 in)
//SETMAPMODE,HIMETRIC
//;set spacing to achieve approx 6.5 LPI
//SETVMI,391

3) Make the same kind of calculation for the horizontal spacing. Let's assume your original was using 10 CPI, but now because of scaling you need to shrink that to 10.6 CPI. We can adjust the CPI of the printout in one of two ways, either via the PITCH =AUTO and
CPP statements in the printer init file, or via the width parameter of //SETFONT . The former requires converting the desired CPI (characters per inch) to CPP (characters per page width), which requires knowing the exact logical width of the page. We have been assuming a logical/printable width of 8 inches, so 10.6 CPI would be 10.6x8 = 84.8, which we can round to 85 CPP. So in this case we could add to our printer init file:

PITCH = AUTO
CPP = 85

Using //SETFONT, the units are tenths of points (720/inch). So 10.6 CPI would be a character width of 67.9, which we'll round to 70. We'll also need to set an appropriate font height (something that fits in 6.5 LPI). Again the units are tenths of points, so 6.5 LPI is about 110 units. So our SETFONT directive might be something like:

//SETFONT,110,Courier,FIXED_PITCH,ANSI_CHARSET,FW_MEDIUM,FS_UPRIGHT,0,70

We'll have to insert the //SETMAPMODE, //SETFONT, and //SETVMI statements into the top of the printfile, plus a //IMAGE statement at the top of each page (unless we download the image into the printer as a macro, but that's outside the scope of this discussion). Note that //SETFONT does not change the vertical spacing set by //SETVMI, so we could adopt a slightly smaller font height (100 vs 110, i.e. 10 points vs 11 points), without changing the alignment.

With those adjustments, we should be able to get the spacing of the printed data to match up with the spacing of the form. But we may still need to shift all of the text horizontally or vertically to align with the form (equivalent to adjusting the paper position in the dot matrix printer). You can do that with the XOFFSET and YOFFSET directives. These are similar to the XORIGIN and YORIGIN, but they do not affect the position of the image.

So for example, if you want to shift all of the text over to the right by 1/2 inch, and down by 1/3 inch, you can add:

//XOFFSET,720
//YOFFSET,480

Of course, you can also insert //MOVETO directives to reposition the "cursor" on the page, or position each token of text with an individual //TEXTOUT command, but the above techniques should allow you to adjust the spacing of your existing plain text (by scaling and/or shifting it in both dimensions) to match the form. And if you followed the guidelines about getting the //IMAGE rectangle to fit within the logical area of the page on every printer you are interested in printing on, you should be able to get near perfect device independence (i.e. should be able to print the same printfile on different printers with the same results).

And it was all accomplished with minimal changes to the existing program (just adding a few //GDI commands to the printfile). You might even be able to eliminate those changes and leave the original program untouched, by using features in the printer init file instead of the //GDI directives inserted into the print file. For example, the GDI directives inserted at the top of the print file could instead be put into a separate file referenced by the PREFIX statement. And the //IMAGE statement to render the form at the top of each page could be put into another separate file referenced by the
OVERLAY statement.

So you have a pretty good set of tools in A-Shell/Windows for converting old-fashioned dot matrix reports on pre-printed forms into more cost-effective, convenient, and possibly better looking laser forms, with minimal (or in some cases, no) changes to your existing report programs. The key though is to be aware of the issues relating to the difference between the physical and logical/printable paper size, and to be systematic in your approach. If you just use trial-and-error to get it working on your in-house laser, you may find that it isn't quite aligned on your customer's printer, leading to a lot of extra work, confusion, and frustration for all involved.

Re: Generating forms on demand #810 20 May 11 07:24 AM
Joined: Jul 2001
Posts: 453
J
Joe Leibel Offline
Member
Offline
Member
J
Joined: Jul 2001
Posts: 453
That sure covers all of the aspects of reproducing existing forms using the GDI commands. All kinds of things are possible. I find that it usually comes down to trial and error - tweaking the horizontal and vertical until it fits.

As a kind of summary of all of the above; here is what I ended up with in a project where I used APEX to display customer invoices that are printed on a multi-part dot-matrix pin-fed form. Once they are in apex they can then be printed to a laser printer or emailed to the customer using PDF.

It boiled down to adding a few GDI commands at the beginning of each invoices and every time I encountered a CHR$(12) then printing the invoices exactly as it would be printed on the pin-fed form....

//; USE TWIPS AT 1440 dots per inch
//SETMAPMODE,TWIPS
//; 240 / 1440 = 6 lpi - rounded down to fit
//SETVMI,220
//; Print a scan of their invoice form
//IMAGE,INVOICE.JPG,0,0,11520,15120,1,20
//; Set the font to fit across the page correctly
//SETFONT,120,LUCIDA CONSOLE,1,0,700,0,0,65"
//; Start the form down and over a little
//TEXTINDENT,610,110,
//; Print the text of the form

I hope this is helpful.

Re: Generating forms on demand #811 20 May 11 08:46 AM
Joined: Sep 2002
Posts: 5,450
F
Frank Online Content
Member
Online Content
Member
F
Joined: Sep 2002
Posts: 5,450
You are the "King of Forms!" smile

Re: Generating forms on demand #812 20 May 11 12:38 PM
Joined: Jun 2001
Posts: 11,645
J
Jack McGregor Online Content OP
Member
OP Online Content
Member
J
Joined: Jun 2001
Posts: 11,645
I'm glad to see that my complicated recipe can be boiled down to a few simple steps to achieve a useful real-world result.

Just one minor technical point - I think you have a spurious quote (") at the end of your SETFONT line. It probably gets ignored, since val(65") is still 65, but it might confuse someone.

As an aside, the width of 65 (65/720 of an inch) is equivalent to about 11.08 characters per inch. Presumably you arrived at that by trial and error, and the difference between it and the original dot matrix spacing (which was probably 10 CPI) is due to the reproduced form image being slightly smaller, or at least narrower, than the original.

Thanks for sharing your example - I'm sure it will be useful to someone.

Re: Generating forms on demand #813 27 Jan 14 04:22 PM
Joined: Sep 2002
Posts: 5,450
F
Frank Online Content
Member
Online Content
Member
F
Joined: Sep 2002
Posts: 5,450
Starter this chain of thought in another topic, but I think this would be the correct place to post this question.

Starting to explore this since we have now adopted the use of APEX in our new version. I have a jpg of a insurance form (that i converted from PDF) so the alignment is pretty much what it is. Thanks to help from the previous post i am able to get the image into the output and merge it with the data from the form.

Of course it doesnt line up straight away - but the initial problem i have is that the image of the form is smaller than when i look at it in say, paint. I tried to stretch it and no changes were observed. I am sure ive missed a trick or two. Here are my commands to start out - any help would be appreciated. I'd like to start just getting the form to be at the 1/4" border. If i can start there i think i can jigger the image to match the output since both are based on a strict 10cpi fixed pitch font scheme.

Thanks.
"//SETFONT,120,Lucida Console,FIXED_PITCH,ANSI_CHARSET,FW_NORMAL,FS_UPRIGHT,0,-80"
"//SETMAPMODE,LOENGLISH" ! Set measurements to 1/100 of inch..
"//SETPENEX,0,1" ! Set thickness of line drawing commands
"//MOVETO,1,1"
"//IMAGE,c:\zoom\1500_claim_form.jpg,0,0,0,0,IMGF_STRETCH"

Re: Generating forms on demand #814 27 Jan 14 07:04 PM
Joined: Nov 2006
Posts: 2,192
S
Stephen Funkhouser Online Content
Member
Online Content
Member
S
Joined: Nov 2006
Posts: 2,192
I think you want to look at some combination of //XORIGIN, //YORIGIN and //XOFFSET, //YOFFSET


Stephen Funkhouser
Diversified Data Solutions
Re: Generating forms on demand #815 27 Jan 14 08:36 PM
Joined: Jun 2001
Posts: 3,376
J
Jorge Tavares - UmZero Online Content
Member
Online Content
Member
J
Joined: Jun 2001
Posts: 3,376
Hi Frank,

I don't know how complex is that form in your JPEG image but, I guess, it should be a combination of lines, rectangles and text that you can easily reproduce using the GDI commands.

So, maybe, it would be easier to build the form using GDI commands to create an OVL (overlay) file and fill it with the corresponding data precisely aligned considereing that is using the same metric for the x,y coordinates of the form in the overlay.

Just guessing.


Jorge Tavares

UmZero - SoftwareHouse
Brasil/Portugal
Re: Generating forms on demand #816 28 Jan 14 08:28 AM
Joined: Sep 2002
Posts: 5,450
F
Frank Online Content
Member
Online Content
Member
F
Joined: Sep 2002
Posts: 5,450
Thanks for the replies - i will try out those commands Stephen. I expected the form.jpg to stretch all the way to the edge of the paper by default but it looks restricted in some way.

Jorge - unfortunately it is a complex government form but if not i would take your advice smile

Re: Generating forms on demand #817 29 Jan 14 06:01 PM
Joined: Jun 2001
Posts: 11,645
J
Jack McGregor Online Content OP
Member
OP Online Content
Member
J
Joined: Jun 2001
Posts: 11,645
I suspect that the reason the image doesn't seem to stretch all the way to the 1/4" border is that it may contain some border/whitespace of its own around the outside. (This would be typical if you scanned it, since the scanner is likely to not be limited by the 1/4" border problem that laser printers have.) If you try the same test with a photo or some other image that has no whitespace, I think it would work as expected. (You may need to use an image editing program to eliminate that whitespace from the scanned image.)

Re: Generating forms on demand #818 29 Jan 14 06:02 PM
Joined: Jun 2001
Posts: 11,645
J
Jack McGregor Online Content OP
Member
OP Online Content
Member
J
Joined: Jun 2001
Posts: 11,645
That said, I don't recommend using the stretch option for reproducing scanned forms. It may seem like a handy shortcut, but it is likely to result in a fuzzy-looking form, particularly if it contains fine print.

Re: Generating forms on demand #819 29 Jan 14 09:10 PM
Joined: Sep 2002
Posts: 5,450
F
Frank Online Content
Member
Online Content
Member
F
Joined: Sep 2002
Posts: 5,450
Thanks Jack. You are spot on here. I had to edit the form in paint to chop it right to the border of the form. As far as using stretch, i understand your point here. For some reason it lines up better WITH this option set, and it took quite a bit of tinkering to get it to line up. This form has about a zillion boxes and there is absolutely no room for play as it is scanned by the insurance carriers. With that being said, i will try again to remove the stretch and play with the form just a bit more.

Re: Generating forms on demand #820 05 Oct 16 11:51 AM
Joined: Nov 2001
Posts: 154
G
Gary Guilbert Offline
Member
Offline
Member
G
Joined: Nov 2001
Posts: 154
Jack,
In trying to print small jewelry labels I want to leave some "room" on the left and top for form variations (just had that happen when a new set of forms were printed 3/16" different from old forms and changed origin in PQI, to fix).

In discussion you say that the typical 8.5x11 paper has 1/4" white space on edges.

Q: So how do I know the "white space" unprintable on my small labels?

I guess I can brute force by printing a stack of labels starting with xorigin, yorigin = 0 then increase it by 45 twips until the text starts to move.

Q: Is there another way?

ps - I owe you a cerveza for the one easy change of reducing the xorigin in the customers PQI for the new form from xorigin=540 to xorigin=450.

G

Re: Generating forms on demand #821 05 Oct 16 12:08 PM
Joined: Jun 2001
Posts: 11,645
J
Jack McGregor Online Content OP
Member
OP Online Content
Member
J
Joined: Jun 2001
Posts: 11,645
There are a couple of ways to determine the hardware margin of the printer. (Note: it's not clear to me this varies with paper size; my guess is that it is more likely to be semi-fixed for each printer.)

1. Open the debug message window and activate the LP trace. Then print a small file. (You can even use the APEX preview for this to eliminate paper use, provided that you specify the actual printer and paper so that APEX uses the right settings.) Look for this trace:

120 09:54:45 Final page size: 5100 x 6600 pixels (600 x 600 dpi); print area: 150,100,4950,6500

As you can see, I'm printing to an 8.5 x 11 paper, which 5100 x 6600 pixels at 600 dpi. But the print area (left,top,right,bottom) is 150,100,4950,6500, meaning that there are 150 unused pixels on the left (1/4") and 100 unused pixels on top (1/6"), with the same margins at the right and bottom.

2. Use an actual print file consisting of "X" in the first position, and then just use a ruler to measure the left and top offsets.

If your goal is to print as close to the edge as possible, set xorigin and yorigin to 0 (or anything <= the physical margins). If your goal is to smooth out the differences in the hardware margins between printers, then set xorigin and yorigin to be at least as large as the largest hardware margins you think you'll encounter.

One other tip: some printers allow you to adjust the hardware margin, either in the control panel, or in the case of some PCL printers, via an ESC sequence. In the latter case, you may be able to use the //ESCAPE GDI directive to send the ESC sequence along with the file. But I wouldn't count on that.

Re: Generating forms on demand #822 05 Oct 16 02:14 PM
Joined: Nov 2001
Posts: 154
G
Gary Guilbert Offline
Member
Offline
Member
G
Joined: Nov 2001
Posts: 154
I'll try the debug method and see what I get.

If that doesn't work then I'll
set the origins to 0 and then
print the big X to see how close it is to the
upper left corner.

Then add some to the origins.

Re: Generating forms on demand #823 31 May 18 03:55 PM
Joined: Jun 2001
Posts: 11,645
J
Jack McGregor Online Content OP
Member
OP Online Content
Member
J
Joined: Jun 2001
Posts: 11,645
Regarding the problem of getting the printed output to match up with a form background (either one that was pre-printed, or one that you generate from a scanned image), another technique that you can now use (as of 6.5.1635.0) is //SETTRANSFORM

In addition to providing another way to do simple vertical or horizontal shifting (as you can with the //XOFFSET and //YOFFSET directives), you can also shrink or stretch (not to mention rotate) the printed output. And you can do it independently on each access. For example, you can stretch your printed output vertically by 5%, and shrink it horizontally by 7%, simply by inserting the following command at the top* of your document:

//SETTRANSFORM, .93, 0, 0, 1.05, 0, 0

* Actually, the command only affects the remainder of the document, so you can insert it in the middle if you only want to transform the last part. And like //XOFFSET and //YOFFSET, you can insert multiple //SETTRANSFORM commands in order to apply different transformations to different parts of the document.


Moderated by  Jack McGregor, Ty Griffin 

Powered by UBB.threads™ PHP Forum Software 7.7.3