July 90 - MEET PRGENERAL, THE TRAP THAT MAKES THE MOST OF THE PRINTING MANAGER
MEET PRGENERAL, THE TRAP THAT MAKES THE MOST OF THE
PRINTING MANAGER
PETE "LUKE" ALEXANDER
The Printing Manager has been expanded and enhanced by the addition of the trap
PrGeneral. This little-known trap-- available in ImageWriter® driver versions 2.5
and later, and LaserWriter ® driver versions 4.0 and later--can pass five operation
codes that solve special problems and improve a printer's performance. This article
describes the trap and its opcodes. The accompanying sample application on the
Developer Essentials disc enables you to experiment with the opcodes as you print
images we provide.
The little-known trap PrGeneral, through its five operation codes, can give your
application the ability to achieve highest-resolution print output, verify page
orientation, and increase performance by avoiding the need to spool. These
enhancements to the Printing Manager come in handy in a variety of situations.
The sample application PrGeneral Play lets you print images with and without the
PrGeneral opcodes. That way you can compare the images and see for yourself the
effects of the opcodes. We'll look at fragments of the sample application in the course of
this article.
ABOUT PRGENERAL
PrGeneral is a multipurpose call that can perform a number of different functions,
depending on the opcode used with it. PrGeneral currently can pass five
opcodes:GetRslData, SetRsl, GetRotn,DraftBits, andNoDraftBits.
• GetRslData enables an application to determine the resolutions that the
currently selected printer supports.
• SetRsl specifies the resolution to print with, so that your application can
achieve the highest-resolution print output.
• GetRotnenables an application to determine if the landscape orientation
has been selected in the style dialog, useful if your image will only fit on a
page when printed in landscape orientation.
• DraftBits forces draft printing, thereby avoiding the need to spool large
quantities of data to disk, while also enabling printing of bitmaps and pixel
maps.
• NoDraftBits cancels the effect of DraftBits.
PrGeneral is declared like this in C:
pascal void PrGeneral (Ptr pData);
The pData parameter is a pointer to a record called TGnlData. The first eight bytes
comprise a header shared by all the PrGeneral calls:
struct TGnlData {
short iOpCode;
short iError;
long lReserved;
};
The first field in the record,iOpCode, contains the opcode that is passed through the call
toPrGeneral to obtain the requested feature. The second field,iError, contains the
result code returned by the call toPrGeneral. The final field,lReserved, is reserved
for future use by the Printing Manager and/or the Printer Driver. Additional fields
followlReserved, depending on the opcode that is used.
After each call to PrGeneral, your application should check the value in the iError
field. Three possible result codes can be returned:
#define noErr 0 /* You've seen this one before. */
#define NoSuchRsl 1 /* Only defined for PrGeneral. */
#define OpNotImpl 2 /* Only defined for PrGeneral. */
If PrGeneral accomplishes your request, it returns noErr in the iErrorfield. If you
request a resolution that is not supported by the currently selected printer, the call to
PrGeneral returns theNoSuchRsl error code. Finally, some printer drivers might not
support one of the opcodes described here, in which case the call toPrGeneral returns
the OpNotImpl error code. ImageWriter driver versions 2.5 and later, and
LaserWriter driver versions 4.0 and later support all of the PrGeneral opcodes.
Your application should also check PrError (which returns the result code left by the
last Printing Manager routine) after checking iError, to be sure that no additional
error was generated by the Printing Manager or the Printer Driver. See Technical
Note #72, Optimizing for the LaserWriter, for a complete list of the possible result
codes returned by the Printing Manager or the LaserWriter driver.
If resNotFound is returned by PrError, then the current Printer Driver doesn't
support PrGeneral. This shouldn't be a major problem for your application, but your
application must be prepared to deal with this error. If you do receive the resNotFound
error back from PrError, you should clear the error with PrSetError(0);
otherwise, PrError might still contain this error the next time you check it.
If an error is returned by PrError, be sure that all of the Printing Manager calls
receive theircorresponding close calls before you report the error to the user. This
enables the Printing Manager and the Printer Driver to clean up their worlds before
you exit. See Technical Note #161, When to Call PrOpen and PrClose, for a
demonstration of the technique.
If noErr is returned by PrError, you can then proceed.
ACHIEVING HIGHEST-RESOLUTION OUTPUT
Your application can use theSetRsl opcode to set print resolution to the highest
supported resolution of the current printer. But before doing this, it needs to
determine the resolutions supported by the current printer, using theGetRslData
opcode. The data returned byGetRslDatais essential because there are now over 50
different models of printers that can be connected to the Mac, each with its own unique
imaging capabilities. GetRslDatasaves your application from having to make
assumptions about which resolution would or would not work.
To illustrate the benefits of setting print resolution to the highest supported
resolution of the current device, let's compare the two graphs shown in Figures 1 and
2, printed on a LaserWriter II/NTX.
As you can see, the results without using SetRsl are not too impressive. (The graph is
printed at 72 dpi.) The same graph printed using SetRsl looks quite a bit better. (The
graph is printed at 300 dpi.) You can demonstrate the effects of using SetRsl for
yourself with the sample application PrGeneralPlay on the Developer Essentials disc.
Figure 1 A Graph Printed Without Using SetRsl
Figure 2 The Same Graph Printed Using SetRsl
USING GETRSLDATA
GetRslData (iOpCode = 4) requests that the Printer Driver return resolution
information about the current printer. Three records are used to convey the resolution
information: TRslRg, TRslRec, andTGetRslBlk. We'll look at these records in detail
after some basic information about resolution.
A printer supports either discrete or variable resolution. Discrete resolution means
that the application can choose from a limited number of resolutions (expressed in
dots per inch, or dpi, in the X and Y directions) predefined by the Printer Driver. For
example, the ImageWriter driver supports four discrete resolutions: 72 x 72 dpi,
144 x 144 dpi, 80 x 72 dpi, and 160 x 144 dpi. If a printer supports variable
resolution, the application can define any resolution within a range bounded by
minimum and maximum values. The LaserWriter driver supports variable resolution
within a range from 25 dpi to 1500 dpi in both the X and Y directions.
Best quality output is always obtained by choosing a square resolution, meaning one in
which the resolutions for the X and Y directions are equal. Some devices support
nonsquare resolutions-that is, where the resolution for the X direction does not equal
the resolution for the Y direction-but using a nonsquare resolution will result in
distortion of the printed image.
Let's look now at the records that convey resolution information.
struct TRslRg {
short iMin;
short iMax;
};
The TRslRg record returns information about the resolution supported by the current
printer. If the printer supports only discrete resolutions, which is the case for the
ImageWriter, iMin and iMax are set to 0. Otherwise, if the printer supports variable
resolution, as the LaserWriter does, these fields are set to the minimum and maximum
resolutions supported.struct
TRslRec {
short iXRsl;
short iYRsl;
};
The TRslRec record specifies a discrete resolution supported by the printer. The iXRsl
field specifies the discrete resolution for the X direction, and iYRsl for the Y direction.
A printer driver can have up to 27 separate TRslRec resolution records. The
ImageWriter driver contains 4 such records, which are returned when you use the
GetRslData opcode. In this case, your application will need to choose one of these
records to be used by SetRsl. Our application PrGeneral Play when printing to an
ImageWriter uses the highest square resolution that the ImageWriter supports, which
is 144 x 144 dpi.
struct TGetRslBlk {
short iOpCode;
short iError;
long lReserved;
short iRgType;
TRslRg xRslRg;
TRslRg yRslRg;
short iRslRecCnt;
TRslRec rgRslRec[27];
The TGetRslBlk record is the complete structure passed to PrGeneral when using the
GetRsl opcode. It contains the iOpCode, iError, and lReserved fields, which we've
already discussed, plus some others.
iRgType is a version number returned by the Printer Driver. The version number is
all your application needs to determine that a particular set of functionality is or is
not present. The LaserWriter and the ImageWriter will always return 1. If it's not 1,
don't use the data.
xRslRg and yRslRg are the resolution ranges supported for the X and Y directions by a
variable- resolution printer. If the current printer doesn't support variable
resolution, the value in these fields is 0.
iRslRecCnt returns the number of resolution records used by a particular printer
driver. As mentioned earlier, up to 27 are allowed.
rgRslRec is an array of resolution records, each specifying a discrete resolution at
which the current printer can print an image. In the arrays returned by Apple printer
drivers, the last record represents the highest supported resolution. We recommend
that other printer drivers do the same.
The records shown in Figure 3 are returned by PrGeneral for the LaserWriter and the
ImageWriter, respectively.
Figure 3 The Records for the LaserWriter and the ImageWriter
Note that in the LaserWriter record, the resolution range shown is 25 through 1500
dpi. Inside Macintosh , volume V, page 413, shows the minimum value as 72; this is
an error. And although up to 1500 dpi is supported by the Printer Driver, the device
itself is only capable of a maximum resolution of 300 x 300 dpi. Accordingly, the
single resolution record indicates that the printer will only support a maximum
resolution of 300 x 300 dpi. Other devices can achieve higher resolutions, up to the
maximum supported by the driver.
In the ImageWriter record, all the resolution range values are 0, because the printer
only supports discrete resolutions. The four resolution records returned give your
application the option to choose one of these discrete resolutions. Note that the highest
supported resolution is represented by the last record.
USING SETRSL SetRsl (iOpcode = 5) tells the Printer Driver the desired imaging
resolution requested by the application. The contents of the record are as follows:
struct TSetRslBlk {
short iOpCode;
short iError;
long lReserved;
THPrint hPrint;
short iXRsl;
short iYRsl;
We have already discussed the iOpCode, iError, and lReserved fields, so we'll start
with the hPrint field. hPrint contains a handle to a print record that has previously
been created and passed through PrDefault to make sure that all of the information
contained in the handle is good. If you are using a print record that was saved as a
resource, you will want to call PrValidate on it to make sure that the contents of the
handle will work with the current version of the Printing Manager and the printer
driver. Because the SetRsl opcode may require the Printer Driver to change the
appearance of the style and/or job dialogs, we want to determine and set the resolution
before the print dialogs are presented to the user. This is why we need a good
handle--the same handle that is passed to the dialogs.
The iXRsl and iYRsl fields contain the resolutions that you would like the Printer
Driver to image with. If iError returns a value of 0 (noErr), the print record will be
updated with this new resolution, which can be used at print time. If the requested
resolution isn't supported by the current printer, iError will return NoSuchRsl, and
the printer driver will revert to the previous setting.
You can undo a previous call to PrGeneral with the SetRsl opcode, by calling PrGeneral
with theSetRsl opcode again, this time with the original resolutions used by the
Printer Driver before your call to SetRsl. (Inside Macintosh, volume V, page 414,
suggests making another call that specifies an unsupported resolution, such as 0 x 0.
This doesn't work.) If you save the resolutions contained in the iVRes and iHRes fields
of the TPrinfo record, you can then pass these values in the iXRsl and iYRsl fields of