.NET C#实现图片/PDF/Word多格式文件打印预览技术问询
Hey there! The problem you're facing is totally expected right now—your current code only works with image files because it directly loads and draws them to the print graphics context. PDFs and Word documents have complex internal structures, so we need to add format-specific logic to render them correctly for print preview. Let's walk through how to implement this step by step.
Your printDocument1_PrintPage method assumes every file is an image, so when it tries to load a PDF/Word file with Image.FromFile(), it throws an exception (which you're catching, hence no preview shows up). We need to:
- Detect the file type by extension
- Use appropriate libraries to render each format to the print graphics
- Handle multi-page documents (since PDFs and Word files often have multiple pages)
First, install these NuGet packages to handle the different formats:
- For PDFs:
PdfiumViewer(a lightweight, reliable library to render PDF pages to Graphics) - For Word documents:
FreeSpire.Doc(a free library that doesn't depend on Microsoft Office being installed)
Let's modify your existing code to add support for PDFs and Word files:
First, add the necessary using directives:
using PdfiumViewer; using Spire.Doc; using Spire.Doc.Documents; using System.Drawing.Printing; using System.IO;
Update your form-level variables to track multi-page documents:
private List<string> elements = new List<string>(); private int currentFileIndex = 0; private int currentPageInFile = 0; private PdfDocument pdfDoc = null; private Document wordDoc = null;
Modify the button1_Click method (clean up state before loading new files):
private void button1_Click(object sender, EventArgs e) { try { elements.Clear(); var Files = new DirectoryInfo(@"E:\Desktop\").GetFilesByExtensions(".png", ".pdf", ".doc", ".docx"); foreach (FileInfo file in Files) { elements.Add(file.FullName); } // Reset state for new print job currentFileIndex = 0; currentPageInFile = 0; pdfDoc?.Dispose(); wordDoc?.Dispose(); pdfDoc = null; wordDoc = null; printPreviewDialog1.Document = printDocument1; printPreviewDialog1.ShowDialog(); } catch (Exception ex) { MessageBox.Show($"Error loading files: {ex.Message}"); } }
Update printDocument1_BeginPrint to reset state:
private void printDocument1_BeginPrint(object sender, PrintEventArgs e) { currentFileIndex = 0; currentPageInFile = 0; // Clean up any leftover documents pdfDoc?.Dispose(); wordDoc?.Dispose(); pdfDoc = null; wordDoc = null; }
The key update: printDocument1_PrintPage with format-specific rendering:
private void printDocument1_PrintPage(object sender, PrintPageEventArgs e) { try { if (currentFileIndex >= elements.Count) { e.HasMorePages = false; return; } string filePath = elements[currentFileIndex]; string extension = Path.GetExtension(filePath).ToLower(); switch (extension) { case ".png": // Handle images with aspect ratio scaling using (Image img = Image.FromFile(filePath)) { float scale = Math.Min(e.MarginBounds.Width / (float)img.Width, e.MarginBounds.Height / (float)img.Height); int scaledWidth = (int)(img.Width * scale); int scaledHeight = (int)(img.Height * scale); int x = e.MarginBounds.Left + (e.MarginBounds.Width - scaledWidth) / 2; int y = e.MarginBounds.Top + (e.MarginBounds.Height - scaledHeight) / 2; e.Graphics.DrawImage(img, x, y, scaledWidth, scaledHeight); } currentFileIndex++; currentPageInFile = 0; break; case ".pdf": // Load PDF if not already loaded if (pdfDoc == null) { pdfDoc = PdfDocument.Load(filePath); } // Render current PDF page if (currentPageInFile < pdfDoc.PageCount) { using (var pageBitmap = pdfDoc.RenderPage(currentPageInFile, e.MarginBounds.Width, e.MarginBounds.Height, PdfRenderFlags.Annotations)) { e.Graphics.DrawImage(pageBitmap, e.MarginBounds.Location); } currentPageInFile++; // Check for more pages in this PDF e.HasMorePages = currentPageInFile < pdfDoc.PageCount; // Move to next file if PDF is done if (!e.HasMorePages) { currentFileIndex++; currentPageInFile = 0; pdfDoc.Dispose(); pdfDoc = null; e.HasMorePages = currentFileIndex < elements.Count; } } break; case ".doc": case ".docx": // Load Word document if not already loaded if (wordDoc == null) { wordDoc = new Document(); wordDoc.LoadFromFile(filePath); } // Render current Word page if (currentPageInFile < wordDoc.PageCount) { using (Bitmap pageBitmap = wordDoc.SaveToImages(currentPageInFile, ImageType.Bitmap)) { float scale = Math.Min(e.MarginBounds.Width / (float)pageBitmap.Width, e.MarginBounds.Height / (float)pageBitmap.Height); int scaledWidth = (int)(pageBitmap.Width * scale); int scaledHeight = (int)(pageBitmap.Height * scale); int x = e.MarginBounds.Left + (e.MarginBounds.Width - scaledWidth) / 2; int y = e.MarginBounds.Top + (e.MarginBounds.Height - scaledHeight) / 2; e.Graphics.DrawImage(pageBitmap, x, y, scaledWidth, scaledHeight); } currentPageInFile++; // Check for more pages in Word doc e.HasMorePages = currentPageInFile < wordDoc.PageCount; // Move to next file if Word doc is done if (!e.HasMorePages) { currentFileIndex++; currentPageInFile = 0; wordDoc.Dispose(); wordDoc = null; e.HasMorePages = currentFileIndex < elements.Count; } } break; default: // Handle unsupported formats e.Graphics.DrawString($"Unsupported file type: {extension}", new Font("Arial", 12), Brushes.Red, e.MarginBounds.Left, e.MarginBounds.Top); currentFileIndex++; currentPageInFile = 0; break; } // Final check for remaining files if (!e.HasMorePages) { e.HasMorePages = currentFileIndex < elements.Count; } } catch (Exception ex) { MessageBox.Show($"Error printing page: {ex.Message}"); // Move to next file to avoid getting stuck currentFileIndex++; currentPageInFile = 0; e.HasMorePages = currentFileIndex < elements.Count; } }
- Resource Management: We use
usingstatements and explicit disposal to avoid memory leaks from open documents. - Scaling: All content is scaled to fit within the print margin bounds while maintaining aspect ratio, which improves preview readability.
- Office Alternative: If you prefer using
Microsoft.Office.Interop.Wordinstead ofFreeSpire.Doc, you'll need to adjust the Word handling logic to use the Interop library's printing methods, but note this requires Office to be installed on the end user's machine.
Add a FormClosing handler to dispose of any open documents when the form closes:
private void Form1_FormClosing(object sender, FormClosingEventArgs e) { pdfDoc?.Dispose(); wordDoc?.Dispose(); }
内容的提问来源于stack exchange,提问作者Let's Enkindle

