首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> C# 入門

C# 列印大圖片完整方案:縮放列印與分頁分割列印雙模式實作

     編輯:C# 入門

前言

列印超過紙張尺寸的大圖片 (如掃描圖、海報、工程圖) 有兩種主流需求:

  1. 縮放列印:等比例縮小至紙張可列印區域,單頁輸出
  2. 分頁分割列印:維持原始解析度,將大圖切割為多頁,拼貼後還原完整圖片

本文提供雙模式完整實作,含 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; // 分頁模式重疊毫米數,方便拼貼對齊
}

PrintDocument 實作


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;
        }
    }
}

UI 介面與預覽效果

  • 模式選擇: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 讓使用者列印前確認排版,並提供重疊、品質、方向等參數調整,即可滿足工程圖面、海報、長圖文檔等多樣化列印需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved