列印超過紙張尺寸的大圖片 (如掃描圖、海報、工程圖) 有兩種主流需求:
本文提供雙模式完整實作,含 UI 介面、預覽、列印設定。
public enum LargeImagePrintMode
{
FitToPage, // 縮放列印
SplitPages // 分頁分割
}
public class LargeImagePrintJob
{
public string ImagePath { get; set; }
public LargeImagePrintMode Mode { get; set; } = LargeImagePrintMode.FitToPage;
public int OverlapMM { get; set; } = 5; // 分頁模式重疊毫米數,方便拼貼對齊
}
using System.Drawing;
using System.Drawing.Printing;
public class LargeImagePrinter
{
private readonly LargeImagePrintJob _job;
private Image _image;
private int _currentPage = 0;
private int _totalPages = 0;
private Rectangle[] _pageRects; // 分頁模式下每頁對應的圖片來源矩形
public LargeImagePrinter(LargeImagePrintJob job)
{
_job = job;
}
public void Print(bool preview = false)
{
_image = Image.FromFile(_job.ImagePath);
CalculatePagination();
var doc = new PrintDocument();
doc.PrintPage += OnPrintPage;
doc.DefaultPageSettings.Landscape = _image.Width > _image.Height;
if (preview)
{
var dlg = new PrintPreviewDialog { Document = doc, WindowState = FormWindowState.Maximized };
dlg.ShowDialog();
}
else
{
doc.Print();
}
}
private void CalculatePagination()
{
if (_job.Mode == LargeImagePrintMode.FitToPage)
{
_totalPages = 1;
return;
}
// 分頁模式:計算需要多少頁
using (var testDoc = new PrintDocument())
{
var pageBounds = testDoc.DefaultPageSettings.Bounds; // 含邊界
var margins = testDoc.DefaultPageSettings.Margins;
int printableW = pageBounds.Width - margins.Left - margins.Right;
int printableH = pageBounds.Height - margins.Top - margins.Bottom;
// 重疊像素 (100 dpi 基準換算)
int overlapPx = (int)(_job.OverlapMM * 100 / 25.4);
int cols = (int)Math.Ceiling((double)_image.Width / (printableW - overlapPx));
int rows = (int)Math.Ceiling((double)_image.Height / (printableH - overlapPx));
_totalPages = cols * rows;
_pageRects = new Rectangle[_totalPages];
int idx = 0;
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < cols; c++)
{
int srcX = c * (printableW - overlapPx);
int srcY = r * (printableH - overlapPx);
int srcW = Math.Min(printableW, _image.Width - srcX);
int srcH = Math.Min(printableH, _image.Height - srcY);
_pageRects[idx++] = new Rectangle(srcX, srcY, srcW, srcH);
}
}
}
}
private void OnPrintPage(object sender, PrintPageEventArgs e)
{
var g = e.Graphics;
var bounds = e.MarginBounds;
if (_job.Mode == LargeImagePrintMode.FitToPage)
{
// 等比例縮放繪製
float ratio = Math.Min(
(float)bounds.Width / _image.Width,
(float)bounds.Height / _image.Height);
int drawW = (int)(_image.Width * ratio);
int drawH = (int)(_image.Height * ratio);
int x = bounds.Left + (bounds.Width - drawW) / 2;
int y = bounds.Top + (bounds.Height - drawH) / 2;
g.DrawImage(_image, x, y, drawW, drawH);
}
else // SplitPages
{
if (_currentPage >= _totalPages)
{
e.HasMorePages = false;
return;
}
var srcRect = _pageRects[_currentPage];
g.DrawImage(_image, bounds, srcRect, GraphicsUnit.Pixel);
_currentPage++;
e.HasMorePages = _currentPage < _totalPages;
}
}
}
RadioButton (縮放/分頁)NumericUpDown (分頁模式專用,預設 5mm)Print(true)Print(false)

private void OnPrintPage(object sender, PrintPageEventArgs e)
{
// 設定高品質插值模式
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
// ... 繪圖代碼
}
| 問題 | 原因 | 解決 |
|---|---|---|
| 列印出來模糊 | 圖片解析度低 / 插值模式預設 | 確保原圖 300+ DPI,設定 InterpolationMode.HighQualityBicubic |
| 分頁邊界留白不一 | 印表機硬體邊界不同 | 使用 e.MarginBounds 而非 e.PageBounds,並在 PageSetupDialog 校正 |
| 記憶體不足 | 大圖 (如 10000x10000) 載入完整 Bitmap | 分頁模式改用 Image.FromStream + Bitmap.Clone(srcRect) 只解碼所需區塊 |
| 分頁順序錯誤 | 行優先/列優先邏輯不符預期 | UI 提供「按行/按列」切換,預覽確認後再列印 |
| 重疊區域對不齊 | 印表機機械誤差 | 增加重疊至 10-15mm,列印後以對齊標記微調 |
大圖片列印雙模式核心在於 PrintPage 事件中依模式計算來源矩形與目標矩形。縮放模式單頁處理,邏輯簡單;分頁模式需預先分頁計算、管理頁碼狀態、處理重疊對齊。搭配 PrintPreviewDialog 讓使用者列印前確認排版,並提供重疊、品質、方向等參數調整,即可滿足工程圖面、海報、長圖文檔等多樣化列印需求。