95 lines
4.0 KiB
C#
95 lines
4.0 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Printing;
|
|
|
|
namespace Elwig.Helpers.Printing {
|
|
public class PdfPrinter {
|
|
|
|
public string PrinterName { get; init; }
|
|
|
|
public PdfPrinter(string? printerName = null) {
|
|
PrinterName = printerName ?? GetDefaultPrinterName() ?? throw new InvalidOperationException("No default Windows printer is configured.");
|
|
}
|
|
|
|
public void Print(string pdfPath, int copies = 1, bool doublePaged = false) {
|
|
if (!File.Exists(pdfPath)) throw new FileNotFoundException("PDF file not found.", pdfPath);
|
|
|
|
IntPtr document = PdfiumNative.FPDF_LoadDocument(pdfPath, null);
|
|
if (document == IntPtr.Zero) throw new InvalidOperationException("PDFium could not open the PDF.");
|
|
|
|
try {
|
|
int pageCount = PdfiumNative.FPDF_GetPageCount(document);
|
|
if (pageCount <= 0)
|
|
return;
|
|
|
|
using var printer = new Win32Printer.Printer(PrinterName);
|
|
printer.TrySetDuplex(doublePaged ? Duplexing.TwoSidedLongEdge : Duplexing.OneSided);
|
|
for (int i = 0; i < copies; i++) {
|
|
printer.StartDocument(Path.GetFileName(pdfPath));
|
|
bool documentStarted = true;
|
|
try {
|
|
for (int j = 0; j < pageCount; j++) {
|
|
PrintPage(document, printer, j);
|
|
}
|
|
printer.EndDocument();
|
|
documentStarted = false;
|
|
} finally {
|
|
if (documentStarted) printer.AbortDocument();
|
|
}
|
|
}
|
|
} finally {
|
|
PdfiumNative.FPDF_CloseDocument(document);
|
|
}
|
|
}
|
|
|
|
private static void PrintPage(IntPtr document, Win32Printer.Printer printer, int pageIndex) {
|
|
if (!PdfiumNative.FPDF_GetPageSizeByIndex(document, pageIndex, out double pageWidthPt, out double pageHeightPt)) {
|
|
throw new InvalidOperationException($"Unable to obtain PDF page {pageIndex} size.");
|
|
}
|
|
|
|
IntPtr page = PdfiumNative.FPDF_LoadPage(document, pageIndex);
|
|
if (page == IntPtr.Zero)
|
|
throw new InvalidOperationException($"Unable to load PDF page {pageIndex}.");
|
|
|
|
try {
|
|
// PDF coordinates are points (1/72 inch).
|
|
//
|
|
// HORZRES/VERTRES are the printable area in
|
|
// device pixels for the current printer DC.
|
|
int widthPx = printer.PixelWidth;
|
|
int heightPx = printer.PixelHeight;
|
|
|
|
// Preserve aspect ratio.
|
|
double scaleX = widthPx / pageWidthPt;
|
|
double scaleY = heightPx / pageHeightPt;
|
|
double scale = Math.Min(scaleX, scaleY);
|
|
int renderWidth = Math.Max(1, (int)Math.Round(pageWidthPt * scale));
|
|
int renderHeight = Math.Max(1, (int)Math.Round(pageHeightPt * scale));
|
|
int offsetX = (widthPx - renderWidth) / 2;
|
|
int offsetY = (heightPx - renderHeight) / 2;
|
|
|
|
printer.StartPage();
|
|
try {
|
|
PdfiumNative.FPDF_RenderPage(printer.Hdc, page, offsetX, offsetY, renderWidth, renderHeight, 0, PdfiumNative.FPDF_PRINTING | PdfiumNative.FPDF_ANNOT);
|
|
} finally {
|
|
printer.EndPage();
|
|
}
|
|
} finally {
|
|
PdfiumNative.FPDF_ClosePage(page);
|
|
}
|
|
}
|
|
|
|
private static string? GetDefaultPrinterName() {
|
|
using var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\Windows");
|
|
string? printer = key?.GetValue("Device") as string;
|
|
if (string.IsNullOrWhiteSpace(printer))
|
|
return null;
|
|
|
|
// Device has the form:
|
|
// Printer Name,winspool,PORT
|
|
int comma = printer.IndexOf(',');
|
|
return comma >= 0 ? printer[..comma] : printer;
|
|
}
|
|
}
|
|
}
|