It is possible to install some software that creates a virtual printer, so that everything is printed to that printer is converted to a PDF file. It is a simple solution but it is a rather limited one: for example you do not have control on the name of the created file unless you stick with a particular program, and this is not a good idea. If that program is abandoned you are out of luck. There are more problems if you want to create a program that runs under multiple operating systems.
A much better solution is to create the PDF file from the printing program, so you do not have external dependencies.
For wxWidgets programs there is a very good library: wxPdfDocument. It can be used to create PDF files with custom commands, but it also contains the wxPdfDc class: it is a device context derived from wxDC, so it can be used to print to a PDF file using the same code used to print to paper. This is a huge advantage, of course.
I have been able to print to a PDF file with very small code changes. I will describe those changes making a reference to a previous post that described how to print from wxWidgets: you should read it before reading the rest of this post.
That post contained some code used to compute a variable called logUnitsFactor, used to convert millimeters to logical units. That code did not work with wxPdfDc so I had to change it. First add the include file:
#include "wx/pdfdc.h"
Then use the following code to compute logUnitsFactor instead of the code used in the older post:
wxSize devicePPI = dc->GetPPI();
int ppiPrinterX, ppiPrinterY;
ppiPrinterX = devicePPI.GetWidth();
ppiPrinterY = devicePPI.GetHeight();
int ppiScreenX, ppiScreenY;
wxScreenDC sdc;
ppiScreenX = sdc.GetPPI().GetWidth();
ppiScreenY = sdc.GetPPI().GetHeight();
float scale = (float)((float)ppiPrinterY/(float)ppiScreenY);
dc->SetUserScale(scale, scale);
logUnitsFactor = (float)(ppiPrinterX/(scale*25.4));
where dc is a pointer to a wxPdfDc object.
If you are writing some generic code you can use this test to know if you are working with a wxPdfDc:
if( dc->IsKindOf(CLASSINFO(wxPdfDC)) ) {
// custom code if we are using wxPdfDC
}
else {
// standard code
}
Now it's time to print something. The following code can be used to print to a PDF file with a given name. The printing framework does not directly support printing to a PDF so I had to copy some of its code.
m_PrintData->SetFilename( fileName );
MyPrintout printout( "Print name" );
wxPdfDC dc( *m_PrintData );
dc.SetResolution( 600 );
printout.SetDC( &dc );
printout.OnPreparePrinting();
printout.OnBeginPrinting();
int minPageNum = 1;
int maxPageNum = 9999;
if( printout.OnBeginDocument(minPageNum, maxPageNum) ) {
for ( int pn = minPageNum;
pn >= maxPageNum && printout.HasPage(pn);
pn++ )
{
dc.StartPage();
bool cont = printout.OnPrintPage(pn);
dc.EndPage();
if ( !cont ) break;
}
printout.OnEndDocument();
}
printout.OnEndPrinting();
With this code the same wxPrintout object used to print to paper can be used to print to a PDF file.