Banding is a technique used to implement the full functionality of the Windows graphics device interface (GDI) in printer drivers that can print graphics only by using bitmaps. An application that exploits the banding process can enhance its printing performance.
Most dot-matrix printers and many laser printers can print only bitmaps and text. When an application that uses such GDI graphic objects as polygons and lines prints to a device that does not support these objects, the printer driver does not send output directly to the printer. Rather, the printer driver generates a bitmap in memory. When all graphics have been rendered into the bitmap, the bitmap itself is printed.
For most printers, this bitmap can be very large. For example, a 300-dots-per-inch (dpi) laser printer requires nearly a megabyte to render a single letter-size page. If memory is limited, the image is broken into a sequence of smaller rectangles, called bands, which cover the page. Each of these individual rectangles is rendered and sent to the printer separately.
There are two ways that the graphics calls can be duplicated on each band. If the application does not exploit the banding process, GDI will capture all graphics calls for a page into a metafile. When the application calls the EndPage function or the NEWFRAME (next page) escape, GDI plays the entire metafile into each band. Alternatively, the application may request a band from the printer driver and produce the output itself. This optimizes printing significantly, because in this case GDI does not create, write, and reread a disk-based metafile.
Whether GDI or the application requests the band from the driver, the process is very similar. Banding printer drivers implement the NEXTBAND escape. This escape causes the printer driver to send the previous band to the printer (if any) and to initialize itself to render the new band. It also returns a rectangle defining the bounds of the band bitmap relative to the whole page. Output calls made to the driver's device context after using the NEXTBAND escape go directly to the printer driver.
GDI (or the banding application) calls the NEXTBAND escape to retrieve the coordinates of the first band. Then it calls NEXTBAND again after each band is rendered so that the printer driver can send the current band to the print manager and retrieve the coordinates of the next band. When all bands have been printed, NEXTBAND causes the printer driver to eject the page and return an empty rectangle to the application, indicating the end of a page.
Note:
An application that uses banding should determine the end of a page by waiting for NEXTBAND to return an empty rectangle. A banding application should not use the NEXTFRAME escape.
To use banding to print an image, follow these steps:
1.Use the CreateDC function to retrieve a device context for the printer.
2.Use the Escape function and the NEXTBAND escape to retrieve the coordinates of a band:
Escape
(hdcPrinter, NEXTBAND, 0, (LPSTR) NULL, &rcRect);
The function sets the rcRect structure to the coordinates of the current band. The coordinates are in device units, and all subsequent GDI calls are clipped to this rectangle.
3.Determine whether the rcRect structure specifies an empty rectangle. (An empty rectangle marks the end of a page.) If the rectangle is empty, terminate the banding operation.
4.Use the DPtoLP function to translate the rcRect coordinates from device units to logical units.
DPtoLP
(hdcPrinter, (POINT FAR*) &rcRect, 2);
5.Use GDI output functions and other functions to draw within the band. To save time, the application should carry out only those GDI functions that affect the current band. If an application does not need to save time, GDI will clip all output that does not appear in the band, so no special action is required.
6.Repeat steps 2 through 5.
Once the banding operation is complete, use the DeleteDC function to remove the printer device context.
The following example shows how to print using banding:
DOCINFO
DocInfo; hdcPrint = CreateDC(lpPrintDriver, /* values from GetProfileString */ lpPrintDevice, lpPrintPort, (LPSTR) NULL); if (hdcPrinter != NULL) { DocInfo.cbSize = sizeof(DOCINFO); DocInfo.lpszDocName = "Test"; DocInfo.lpszOutput = (LPSTR) NULL; StartDoc(hdcPrinter, &DocInfo); for (;;) { Escape(hdcPrinter, NEXTBAND, 0, (LPSTR) NULL, &rcRect); if (IsRectEmpty(&rcRect) break; DPtoLP(hdcPrinter, (POINT FAR*) &rcRect, 2); /* * Place output function here. To save time, use rcRect to * filter output functions that do not fall in this band. */ } EndDoc(hdcPrinter); DeleteDC(hdcPrinter); }