First published on TECHNET on Jun 20, 2008
There are sometimes situations where printing of very large documents containing high resolution graphics, text and images is needed. With the growing technology of high end cameras flourishing in the market, image sizes are growing larger and larger. Additionally, image editing applications present endless opportunities to enhance and modify images to your heart's content. Due to the amount of information stored in images like this, the final spool job can sometimes reach multiple gigabytes in size. There are some issues seen when we print extremely large print jobs – our focus today will be on those issues, as well as some solutions. Let’s get started with having a look at the issues first.
When a print job reaches 3.99 GB in size, the counter for the job size resets to 0 and it starts growing again.
While printing the job, the printer prints the initial data and then suddenly spits out the paper as if the print job is over. On restarting the print job, it starts printing again from the beginning.
To keep the scope of our discussion within reason, the environment in our example is Windows XP/ Windows Vista/Windows Server 2003 x64 clients and Windows Server 2003 or Windows Server 2008 x64 as the print server. To begin with, it is often thought that a print job cannot grow over 4 GB in size, but this is not true. The spool file (.spl file) which gets created can actually grow easily to over 4 GB in size. Thus, the obvious question, why do very large print jobs fail to print as expected? There are two reasons for this behavior:
The first aspect is when we are seeing the print job go to 3.99 GB and reset to zero and start over again. This behavior is just a benign issue of the display of the print job and has no actual effect on the actual printing of the Job. The issue with the UI showing the wrong size is known and does not impact the actual print job. The UI only displays 32-bit sizes and wraps larger values. Internally print job sizes are kept as 64-bit values.
The second issue is why the print job itself actually fails. First, it is essential to know which application is being used to generate the print job - is it a 32-bit application or 64-bit native application We normally see this issue when we have a 32-bit application printing to a 64-bit server. Here is what happens. When the application is printing, there are two ways the job may be programmatically created, as we can see in the diagram below (we also discussed several aspects of printing in our post on
Basic Printing Architecture
Printing via GDI
Printing directly through the Print Spooler (winspool.drv) bypassing GDI
The Graphics Device Interface (GDI) enables applications to use graphics and formatted text on both the video display and the printer. Microsoft Windows based applications do not access the graphics hardware directly. Instead, the GDI interacts with device drivers on behalf of applications. The GDI can be used in all Windows-based applications. When a print job is created via the GDI interface, there is a limitation of 4 GB per page. If a single page is over 4 GB in size, it will not print properly. If a job is made up of multiple pages, but no single page is over 4 GB in size, you should not have a problem. So, what is the solution for printing large documents?
In the case of a single job for instance, you can select the option to 'Print directly to the printer' on the Advanced tab under the printer properties. However, it would not be recommended to configure this as the default setting, since that basically defeats the purpose of having a print server.
The application you are using may allow you to resize or spread out the images so that a single page will not be over 4 GB in size. The problem with this of course is knowing which pages will be of what size until you try to print and it fails.
There is another way to make this work - if you are the developer of the application in question. You can use certain API's to facilitate large print jobs. The application can generate a printer-ready PDL of any size and complexity and use the AddJob, ScheduleJob, StartDocPrinter, WritePrinter and EndDocPrinter API's to spool the raw PDL. PDL stands for Page Description Language, and is basically the format by which a page is put together into a print job. You can think of it as sort of the most basic format of a print job. PCL and PostScript for instance are forms of PDL.
Winspool.drv is the client interface into the spooler. It exports the functions that make up the spooler's Win32 API, and provides RPC stubs for accessing the server. The OpenPrinter, StartDocPrinter, StartPagePrinter, WritePrinter, EndPagePrinter, and EndDocPrinters functions mentioned above are all provided by winspool.drv. The functions in winspool.drv are mainly RPC stubs to the local spooler service (Spoolsv.exe). By using these API's to create the job, the spooler will be able to bypass GDI and send the PDL directly to the printer via Winspool. Here is how a print job would be created with help of these API's:
Application calls OpenPrinter to get a handle to a printer from the Spooler.
Application calls StartDocPrinter to notify the Spooler that a print job is started. If successful, a job id is returned to represent the job created by the Spooler.
Application calls StartPagePrinter, WritePrinter, and EndPagePrinter repeatedly to define pages and write data to the printer.
Application calls EndDocPrinter to end the print job. In your code it may look similar to the following:
StartPagePrinter() (This starts a new page)
WritePrinter() (This writes data to the page)
EndPagePrinter() (This ends the page. Repeat the last three steps until all pages are done)
And with that, we’ve reached the end of this post. Hopefully this information helps you understand some of the challenges involved with very large print jobs.
- Ashish Sangave