Cracking the Code: Print-Optimized PDFs
Printing PDFs can be a little unpredictable. Some PDFs are built for print, and some are built for online distribution on the web. The way your PDFs are built will determine how they are sent to you from your customers, and how they are printed. The tools you have available will determine the effectiveness of your printed PDFs. If you are in an industry that relies on the accurate printing of PDF files, it’s important to have a print-optimized workflow.
Benefits of Print-Optimized PDFs
- Reduce your time to print by printing correctly the first time
- Improve the quality of your printed documents
- Reduce time spent to get a good file and minimize the time it takes to find errors
- You don’t want to wait to find a problem with your files until you are going to press
- Save money by only having to print once
With our printing code samples for the Adobe PDF Library, you can see print optimization for PDFs in action. Let’s take a look at them.
Please note, the samples featured here are written in C++, but we have more available in .NET, .NET Framework, Java/Maven, Kotlin, and VB.NET
PDFPrintDefault
This sample allows a user to send a PDF document to a printer using a Windows print interface. This is helpful for anyone needing to make sure their PDF prints correctly the first time.
/* Printing Support */
#include "InitializeLibrary.h"
#include "APDFLDoc.h"
#include "PDFLPrint.h"
#include "SetupPrintParams.h"
#ifdef MAC_PLATFORM
#include "Cocoa/Cocoa.h"
#include
#include
#endif
#define defaultDocument "../../../../Resources/Sample_Input/printpdf.pdf"
int main(int argc, char **argv) {
APDFLib lib; // Initialize the Adobe PDF Library
ASErrorCode errCode = 0; // This will catch error codes thrown during library usage
if (lib.isValid() == false) // If it failed to initialize, return the error code
return lib.getInitError();
DURING
//=====================================================================================================================
// Step 1) Open the input PDF
//=====================================================================================================================
char inPath[2048];
// If a file name is not specified on the command line, use the default name
if (argc < 2)
strcpy(inPath, defaultDocument);
else
strcpy(inPath, argv[1]);
std::wcout << L"Opening the input document - " << inPath << std::endl;
APDFLDoc inAPDoc(inPath, true); // Open the input document, repairing it if necessary.
PDDoc inDoc = inAPDoc.getPDDoc();
//=====================================================================================================================
// Step 2) Initialize print parameters
//=====================================================================================================================
std::wcout << L"Initializing print parameters." << std::endl;
// Set defaults (see SetupPrintParams files in Common folder)
PDPrintParamsRec psParams;
SetupPDPrintParams(&psParams);
PDFLPrintUserParamsRec userParams;
SetupPDFLPrintUserParams(&userParams);
// Link print params to userParams
userParams.printParams = &psParams;
// Override defaults with specifics for this sample
userParams.emitToFile = false; // Print to printer
userParams.emitToPrinter = true;
// All platforms require start and end pages, and number of copies
userParams.startPage = 0; /* Start with the first page */
userParams.endPage = PDDocGetNumPages(inDoc) - 1; /* end with the last. */
userParams.nCopies = 1; /* Always one copy */
// All platforms allow specification of paper width and height.
userParams.paperWidth = 0; /* When left zero, defaults to 8.5 inches */
userParams.paperHeight = 0; /* When left zero, defaults to 11 inches */
// All platforms allow specification of a list of fonts not to download
// This list is generally empty
userParams.dontEmitListLen = 0;
userParams.dontEmitList = NULL;
//=====================================================================================================================
// Step 3) Establish printer destination
//=====================================================================================================================
#ifdef MAC_PLATFORM
/* Leaving all fields at thier default settings will print
** to the last print device used, or the default printer,
** according to the mac printer settings */
/* These values an be set for a Mac printer */
userParams.shrinkToFit = true;
userParams.printAnnots = false;
userParams.psLevel = 3;
userParams.binaryOK = true;
userParams.emitHalftones = false;
userParams.reverse = false; /* print pages in reverse order */
userParams.doOPP = false;
NSPrintInfo *thePrintInfo = [NSPrintInfo sharedPrintInfo];
userParams.printSession = (PMPrintSession)[thePrintInfo PMPrintSession]; /* Pointer to a PMPrintSession */
userParams.printSettings =
(PMPrintSettings)[thePrintInfo PMPrintSettings]; /* Pointer to a PMPrintSettings */
userParams.pageFormat = (PMPageFormat)[thePrintInfo PMPageFormat]; /* Pointer to a PMPageFormat */
const char *name = thePrintInfo.printer.name.UTF8String;
std::cout << "Sending to the printer " << name << std::endl;
#endif
#ifdef WIN_ENV
// Use a PrintDLg call to obtain the name of the default printer
PRINTDLGW printDialog;
// Initialize the PRINTDLG structure.
memset(&printDialog, 0, sizeof(printDialog));
printDialog.lStructSize = sizeof(printDialog);
// Set the print dialog flags
// In this case, return information for he default printer.
printDialog.Flags = PD_RETURNDEFAULT;
// Invoke the printer dialog box.
if (PrintDlgW(&printDialog)) {
// Make a copy of the DEVMODE structure to send to APDFL which contains information
// on the number of copies requested and whether to collate them or not.
LPDEVMODEW devMode = (LPDEVMODEW)(GlobalLock(printDialog.hDevMode));
userParams.pDevModeW = (DEVMODEW *)malloc(devMode->dmSize + devMode->dmDriverExtra);
memcpy(userParams.pDevModeW, devMode, devMode->dmSize + devMode->dmDriverExtra);
GlobalUnlock(printDialog.hDevMode);
// Need to retrieve the printer name from the hDevNames structure. It is also available
// in the hDevMode structure but can be truncated due to the dmDeviceName field only
// being capable of holding CCHDEVICENAME (32) characters.
LPDEVNAMES devNames = (LPDEVNAMES)(GlobalLock(printDialog.hDevNames));
std::wstring dmDeviceName((WCHAR *)(devNames) + devNames->wDeviceOffset);
std::wstring dmFileName((WCHAR *)(devNames) + devNames->wOutputOffset);
GlobalUnlock(printDialog.hDevNames);
size_t lenDeviceName = dmDeviceName.length();
userParams.deviceNameW = new ASUns16[lenDeviceName + 1];
memcpy(userParams.deviceNameW, dmDeviceName.data(), lenDeviceName * sizeof(ASUns16));
userParams.deviceNameW[lenDeviceName] = 0;
}
// These fields may be set in the user params for a windows printer
userParams.inFileName = inPath; /* Specifies the name of the input file , as a char array */
userParams.inFileNameW = NULL; /* Specifies the name of theinput file, as a wide char array */
userParams.outFileName = NULL; /* Forces output to a file, rather than to the printer, */
userParams.outFileNameW = NULL; /* using either a char array, or a wide char array */
userParams.deviceName = NULL; /* Specifies the printer to use. The wide array form is used above */
userParams.driverName = NULL; /* Specifies driver to use. Usually "winspool", May be left */
userParams.driverNameW = NULL; /* empty, and APDFL will fill in correctly */
userParams.portName = NULL; /* Specifies the port to reach the printer,May be left */
userParams.portNameW = NULL; /* empty, and APDFL will fill in correctly. */
userParams.pDevMode = NULL; /* Allows the user to provide a DevMode block, to specify */
userParams.pDevModeW =
NULL; /* divergent print options. If not supplied, the default printer options will be used. */
userParams.hDC = NULL; /* You should supply a Device Context only if you wish your application
** to control StartDoc and EndDoc. */
userParams.shrinkToFit = true;
userParams.printAnnots = false;
userParams.psLevel = 3;
userParams.binaryOK = true;
userParams.emitHalftones = false;
userParams.reverse = false; /* print pages in reverse order */
userParams.doOPP = false;
userParams.farEastFontOpt = 0;
userParams.forceGDIPrint =
false; /* When true, we will print via the GDI interface, even if the selected printer supports postscript. */
std::cout << "Sending to the printer " << userParams.deviceNameW << std::endl;
#endif
userParams.transQuality = 100;
#ifdef UNIX_ENV
// print to the printer lp0, suppress reporting job number to stdout.
userParams.command = "lp -s";
std::cout << "Sending to the printer LP0." << std::endl;
#endif
//=====================================================================================================================
// Step 4) Write to printer or file and clean up
//=====================================================================================================================
DURING
PDFLPrintDoc(inDoc, &userParams);
HANDLER
errCode = ERRORCODE;
lib.displayError(errCode); // If there was an error, display it
END_HANDLER
std::wcout << L"Closing documents and cleaning up." << std::endl;
// Cleanup and free memory
#ifdef WIN_ENV
// NOTE: if we set the value of userParams.inFileName to &path,
// set it back to null here, or we will attempt tofree it in
// the dispose logic.
if (userParams.inFileName)
userParams.inFileName = NULL;
#endif
DisposePDPrintParams(&psParams);
DisposePDFLPrintUserParams(&userParams);
PDDocClose(inDoc); // Close the input document
HANDLER
errCode = ERRORCODE;
lib.displayError(errCode); // If there was an error, display it
END_HANDLER
return errCode; // APDFLib's destructor terminates the APDFL
};
PDFPrintGUI
This sample utilizes a printer UI dialog to drive the printing of a PDF document. It works on Windows or MacOS. This gives users more control of how their PDFs are printed.
/* Printing Support */
#include "InitializeLibrary.h"
#include "APDFLDoc.h"
#include "PDFLPrint.h"
#include "SetupPrintParams.h"
#ifdef MAC_PLATFORM
#include "Cocoa/Cocoa.h"
#include
#include
#endif
#define defaultDocument "../../../../Resources/Sample_Input/printpdf.pdf"
int main(int argc, char **argv) {
APDFLib lib; // Initialize the Adobe PDF Library
ASErrorCode errCode = 0; // This will catch error codes thrown during library usage
if (lib.isValid() == false) // If it failed to initialize, return the error code
return lib.getInitError();
DURING
//=====================================================================================================================
// Step 1) Open the input PDF
//=====================================================================================================================
char inPath[2048];
// If a file name is not specified on the command line, use the default name
if (argc < 2)
strcpy(inPath, defaultDocument);
else
strcpy(inPath, argv[1]);
std::wcout << L"Opening the input document - " << inPath << std::endl;
APDFLDoc inAPDoc(inPath, true); // Open the input document, repairing it if necessary.
PDDoc inDoc = inAPDoc.getPDDoc();
//=====================================================================================================================
// Step 2) Initialize print parameters
//=====================================================================================================================
std::wcout << L"Initializing print parameters." << std::endl;
// Set defaults (see SetupPrintParams files in Common folder)
PDPrintParamsRec psParams;
SetupPDPrintParams(&psParams);
PDFLPrintUserParamsRec userParams;
SetupPDFLPrintUserParams(&userParams);
// Link print params to userParams
userParams.printParams = &psParams;
// Override defaults with specifics for this sample
userParams.emitToFile = false; // Print to printer
userParams.emitToPrinter = true;
//=====================================================================================================================
// Step 3) Open the Print Dialog UI and gather user input
//=====================================================================================================================
#ifdef MAC_PLATFORM
/* set up dialog, and handle print settings */
Boolean accepted = true;
NSPrintInfo *thePrintInfo = [NSPrintInfo sharedPrintInfo];
[NSApplication sharedApplication];
NSPrintPanel *printPanel = [NSPrintPanel printPanel];
accepted = [printPanel runModalWithPrintInfo:thePrintInfo];
userParams.printSession = (PMPrintSession)[thePrintInfo PMPrintSession];
userParams.printSettings = (PMPrintSettings)[thePrintInfo PMPrintSettings];
userParams.pageFormat = (PMPageFormat)[thePrintInfo PMPageFormat];
UInt32 first, last, numCopies;
PMGetFirstPage(userParams.printSettings, &first);
userParams.startPage = first;
PMGetLastPage(userParams.printSettings, &last);
userParams.endPage = last;
PMGetCopies(userParams.printSettings, &numCopies);
userParams.nCopies = numCopies;
if (!accepted) {
std::wcout << L"Print Canceled by user" << std::endl;
DisposePDPrintParams(&psParams);
DisposePDFLPrintUserParams(&userParams);
PDDocClose(inDoc);
return (-1);
}
const char *name = thePrintInfo.printer.name.UTF8String;
std::cout << "Sending to the printer " << name << std::endl;
#else
PRINTDLGW printDialog;
// Initialize the PRINTDLG structure.
memset(&printDialog, 0, sizeof(printDialog));
printDialog.lStructSize = sizeof(printDialog);
// Set the print dialog flags
// Necessary to set PD_USEDEVMODECOPIESANDCOLLATE since the DEVMODE structure is being used by
// APDFL to gather the number of copies and whether to collate or not.
// This will also disable the Collate check box and the Number of Copies edit control unless
// the printer driver supports multiple copies and collation.
printDialog.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_NOSELECTION;
// Set the minimum and maximum page to allow in print dialog Pages selection
printDialog.nMinPage = 1;
printDialog.nMaxPage = inAPDoc.numPages();
// Invoke the printer dialog box.
if (PrintDlgW(&printDialog)) {
// Make a copy of the DEVMODE structure to send to APDFL which contains information
// on the number of copies requested and whether to collate them or not.
LPDEVMODEW devMode = (LPDEVMODEW)(GlobalLock(printDialog.hDevMode));
userParams.pDevModeW = (DEVMODEW *)malloc(devMode->dmSize + devMode->dmDriverExtra);
memcpy(userParams.pDevModeW, devMode, devMode->dmSize + devMode->dmDriverExtra);
GlobalUnlock(printDialog.hDevMode);
// Need to retrieve the printer name from the hDevNames structure. It is also available
// in the hDevMode structure but can be truncated due to the dmDeviceName field only
// being capable of holding CCHDEVICENAME (32) characters.
LPDEVNAMES devNames = (LPDEVNAMES)(GlobalLock(printDialog.hDevNames));
std::wstring dmDeviceName((WCHAR *)(devNames) + devNames->wDeviceOffset);
std::wstring dmFileName((WCHAR *)(devNames) + devNames->wOutputOffset);
GlobalUnlock(printDialog.hDevNames);
size_t lenDeviceName = dmDeviceName.length();
userParams.deviceNameW = new ASUns16[lenDeviceName + 1];
memcpy(userParams.deviceNameW, dmDeviceName.data(), lenDeviceName * sizeof(ASUns16));
userParams.deviceNameW[lenDeviceName] = 0;
// Print specific pages if requested in the print dialog box.
// Otherwise, the All was left selected and all pages will be printed.
if (printDialog.Flags & PD_PAGENUMS) {
psParams.ranges[0].startPage = printDialog.nFromPage - 1; // Specify starting page
psParams.ranges[0].endPage = printDialog.nToPage - 1; // Specify ending page
}
// Check to see if "Print to a file" has been selected.
// If "Print to file" is selected, all we need to do is set the outFileNameW to the
// returned dmFileName which will be returned as "FILE:". No need to change any other
// APDFL parameters such as emitToFile or emitToPrinter. Windows takes care of
// prompting for the output file and saves to the file instead of sending it
// to the printer.
if (printDialog.Flags & PD_PRINTTOFILE) {
size_t lenFileName = dmFileName.length();
userParams.outFileNameW = new ASUns16[lenFileName + 1];
memcpy(userParams.outFileNameW, dmFileName.data(), lenFileName * sizeof(ASUns16));
userParams.outFileNameW[lenFileName] = 0;
}
userParams.printParams = &psParams; // Connect the two structures
if (printDialog.Flags & PD_PRINTTOFILE) {
std::wcout << L"Sending to the file." << std::endl;
} else {
std::wcout << L"Sending to the printer." << std::endl;
}
} else {
std::wcout << L"Print Canceled by user" << std::endl;
DisposePDPrintParams(&psParams);
DisposePDFLPrintUserParams(&userParams);
PDDocClose(inDoc);
return (-1);
}
#endif
//=====================================================================================================================
// Step 4) Write to printer or file and clean up
//=====================================================================================================================
DURING
PDFLPrintDoc(inDoc, &userParams);
HANDLER
errCode = ERRORCODE;
lib.displayError(errCode); // If there was an error, display it
END_HANDLER
std::wcout << L"Closing documents and cleaning up." << std::endl;
// Cleanup and free memory
DisposePDPrintParams(&psParams);
DisposePDFLPrintUserParams(&userParams);
PDDocClose(inDoc); // Close the input document
HANDLER
errCode = ERRORCODE;
lib.displayError(errCode); // If there was an error, display it
END_HANDLER
return errCode; // APDFLib's destructor terminates the APDFL
};
To learn more about how APDFL handles printing, we invite you to download a free trial today!