I'm using C# and the PDFium library to print a PDF to a particular label printer. When I print this PDF via Chrome, Edge, or my application, the quality is questionable. When I print through Adobe Reader or Foxit Reader, the quality is exactly what I want.
Here is an image on imgur of the differences: https://i.stack.imgur.com/twhPD.jpg
My application is the one labeled "Network Print". As you can see in the image, its quality matches what browsers are doing. In particular, the small text on the right is my concern.
So what are the desktop PDF readers doing differently when printing from them?
Here's the bit of code that actually prints the PDF in C#:
public static Boolean Print(PrintQueue printer, byte[] content, Boolean landscape)
{
using (MemoryStream stream = new MemoryStream(content))
{
PdfDocument doc = PdfDocument.Load(stream);
PrintDocument pd = GetPrintDocumentAsPDF(printer.Name, doc, landscape);
pd.Print();
return true;
}
}
private static PrintDocument GetPrintDocumentAsPDF(String printerName, PdfDocument doc, Boolean landscape)
{
PdfPrintMultiplePages multiPages = new PdfPrintMultiplePages(1, 1, landscape ? System.Windows.Forms.Orientation.Horizontal : System.Windows.Forms.Orientation.Vertical, 0);
PdfPrintSettings settings = new PdfPrintSettings(PdfPrintMode.CutMargin, multiPages);
PrintDocument pd = doc.CreatePrintDocument(settings);
pd.PrinterSettings.PrinterName = printerName;
Rectangle firstPage = GetSizeForDoc(doc, 0);
pd.DefaultPageSettings.Landscape = landscape;
// Find the closest matching media profile based on the size of the first page
PaperSize bestFit = GetBestFitMediaProfile(firstPage.Width, firstPage.Height, landscape, pd.PrinterSettings.PaperSizes);
if (bestFit != null)
{
pd.DefaultPageSettings.PaperSize = bestFit;
}
else
{
Util.RestLog("!!! No matching media profile. Using default !!!");
}
return pd;
}
/// <summary>
/// Calculates the size of a page from a document
/// </summary>
/// <param name="doc">the document to get the page from</param>
/// <param name="page">the page number to get the size for</param>
/// <returns>a rectangle with the width and height of the page</returns>
private static Rectangle GetSizeForDoc(PdfDocument doc, int page)
{
// Calculate the actual size of the document
SizeF docSize = doc.PageSizes[page];
Rectangle docBounds = new Rectangle(0, 0, (int)Math.Floor(docSize.Width / DOT_PER_INCH * 100),
(int)Math.Floor(docSize.Height / DOT_PER_INCH * 100));
return docBounds;
}
/// <summary>
/// For a given width and height (of a document page), determines the smallest available media profile
/// that can be printed to while still encompassing the entire page
/// </summary>
/// <param name="width">width of the page to print</param>
/// <param name="height">height of the page to print</param>
/// <param name="mediaProfiles">the media profiles available on the print being printed to</param>
/// <returns></returns>
private static PaperSize GetBestFitMediaProfile(int width, int height, bool landscape, PrinterSettings.PaperSizeCollection mediaProfiles)
{
PaperSize mediaProfile = null;
double docLong = Math.Round((landscape ? width : height) * 1f, 2);
double docShort = Math.Round((landscape ? height : width) * 1f, 2);
double profileLong;
double profileShort;
foreach (PaperSize profile in mediaProfiles)
{
Util.RestLog("Found media profile: " + profile.Width + " x " + profile.Height);
double profileWidth = Math.Round(profile.Width * 1f, 2);
double profileHeight = Math.Round(profile.Height * 1f, 2);
profileLong = landscape ? profileWidth : profileHeight;
profileShort = landscape ? profileHeight : profileWidth;
if (mediaProfile == null)
{
// Grab the first media profile that is larger than the document in both width and height
if (profileLong >= docLong && profileShort >= docShort)
{
mediaProfile = profile;
}
}
else
{
// If this profile is closer to the document size than the current one
if (profileLong >= docLong && profileShort >= docShort &&
GetArea(profileWidth, profileHeight) < GetArea(mediaProfile.Width, mediaProfile.Height))
{
mediaProfile = profile;
}
}
}
return mediaProfile;
}
/// <summary>
/// Calculates an area give a width and a height
/// </summary>
/// <param name="width">the width</param>
/// <param name="height">the height</param>
/// <returns>the area of the width and height</returns>
private static double GetArea(double width, double height)
{
return width * height;
}
Essentially, the main thing this does is selects the correct media profile for the size of the PDF document being printed. I don't believe anyone will need to see the methods that have to do with finding the correct size (GetSizeForDoc and GetBestFitMediaProfile), but I can post them if someone needs.