如何实现打印时,根据纸张大小来自动缩放图片

在打印图片时,经常会碰到一种情况: 图片的大小会超过纸张的大小; 此时,我们需要对图片进行缩放,来适应纸张的大小.

那么如何来实现呢?方法有二,

1) 根据打印机和打印纸张的设置, 直接转换图片的分辨率(Resolution).

   

 1 'm_metafile是Metafile的一个实例 
 2 
 3 Using bmp As New Bitmap(m_metafile)
 4                     'if image is large that printable area, scale it to fix page size
 5                     If bmp.Width > settings.PrintableArea.Width OrElse bmp.Height > settings.PrintableArea.Height Then
 6                         Dim wRatio As Single
 7                         Dim hRatio As Single
 8 
 9                         hRatio = bmp.Height / settings.PrintableArea.Height
10                         wRatio = bmp.Width / settings.PrintableArea.Width
11 
12                         If wRatio > hRatio Then
13                             bmp.SetResolution(hRatio * 100, hRatio * 100)
14                         Else
15                             bmp.SetResolution(wRatio * 100, wRatio * 100)
16                         End If
17                     End If
18                     'draw image
19                     g.DrawImage(bmp, 00)
20                 End Using


注意:使用此方法的一个弊端是会降低图片分辨率,从而导致打印出来的图片有闪烁(dithering).因此它不适用有打印分辨率高的场合;例如在打印条形码(barcode)时,低分辨率有可能会造成无法被机器识别.


2) 使用Public Sub EnumerateMetafile(ByVal metafile As System.Drawing.Imaging.Metafile, ByVal destRect As System.Drawing.Rectangle, ByVal callback As System.Drawing.Graphics.EnumerateMetafileProc)

 1 'm_metafile为Metafile的一个实例;
 2 'g是Graphics的一个实例
 3 Dim width As Integer = m_metafile.Width
 4             Dim height As Integer = m_metafile.Height
 5 
 6             m_delegate = New Graphics.EnumerateMetafileProc(AddressOf MetafileCallback)
 7 
 8             '-- YOU MUST PASS THE SIZE TO EnumerateMetafile, OTHERWIZE, THE PAGE IS NOT AUTO SCALED.
 9             g.EnumerateMetafile(m_metafile, New Rectangle(00, width, height), m_delegate)
10 
11             ' Clean up 
12             m_delegate = Nothing


注意:此方法没有1)中的闪烁问题,实现也比较简单,推荐使用.

 

完整的一个打印示例如下:

代码
  1 Imports System
  2 Imports System.IO
  3 Imports System.Web.Services.Protocols
  4 Imports System.Data
  5 Imports System.Xml
  6 Imports System.Drawing
  7 Imports System.Drawing.Imaging
  8 Imports System.Drawing.Printing
  9 Imports System.Runtime.InteropServices
 10 Imports System.Collections.Generic
 11 
 12 
 13 Public Class AutoScalePrint
 14 
 15     Private m_renderedReport As Byte()()
 16     Private m_delegate As Graphics.EnumerateMetafileProc = Nothing
 17     Private m_currentPageStream As MemoryStream
 18     Private m_metafile As Metafile = Nothing
 19     Private m_numberOfPages As Integer
 20     Private m_currentPrintingPage As Integer
 21     Private m_lastPrintingPage As Integer
 22     Private m_PrintSettings As RTSystems.Framework.Printing.IPrintSetting
 23     Private m_ReportProxy As Framework.Reporting.IReportProxy
 24     Private ctlJob As New PrintQueueController
 25 
 26     Private Sub pd_PrintPage(ByVal sender As ObjectByVal ev As PrintPageEventArgs)
 27         ev.HasMorePages = False
 28         If m_currentPrintingPage <= m_lastPrintingPage AndAlso MoveToPage(m_currentPrintingPage) Then
 29             ' Draw the page 
 30             DrawPage(ev.Graphics, ev.PageSettings)
 31             ' If the next page is less than or equal to the last page, 
 32             ' print another page. 
 33             If System.Threading.Interlocked.Increment(m_currentPrintingPage) <= m_lastPrintingPage Then
 34                 ev.HasMorePages = True
 35             End If
 36         End If
 37     End Sub
 38 
 39     ' Method to draw the current emf memory stream 
 40     Private Sub DrawPage(ByVal g As Graphics, ByRef settings As PageSettings)
 41         If m_currentPageStream Is Nothing OrElse 0 = m_currentPageStream.Length OrElse m_metafile Is Nothing Then
 42             Exit Sub
 43         End If
 44         SyncLock Me
 45             Dim width As Integer = m_metafile.Width
 46             Dim height As Integer = m_metafile.Height
 47 
 48             m_delegate = New Graphics.EnumerateMetafileProc(AddressOf MetafileCallback)
 49 
 50             '-- YOU MUST PASS THE SIZE TO EnumerateMetafile, OTHERWIZE, THE PAGE IS NOT AUTO SCALED.
 51             g.EnumerateMetafile(m_metafile, New Rectangle(00, width, height), m_delegate)
 52 
 53             ' Clean up 
 54             m_delegate = Nothing
 55 
 56         End SyncLock
 57     End Sub
 58 
 59     Private Function MoveToPage(ByVal page As Int32) As Boolean
 60         ' Check to make sure that the current page exists in 
 61         ' the array list 
 62         If Me.RenderedPage(m_currentPrintingPage - 1Is Nothing Then
 63             Return False
 64         End If
 65         ' Set current page stream equal to the rendered page 
 66         m_currentPageStream = New MemoryStream(Me.RenderedReport(m_currentPrintingPage - 1))
 67         ' Set its postion to start. 
 68         m_currentPageStream.Position = 0
 69         ' Initialize the metafile 
 70         If m_metafile IsNot Nothing Then
 71             m_metafile.Dispose()
 72             m_metafile = Nothing
 73         End If
 74         ' Load the metafile image for this page 
 75         m_metafile = New Metafile(DirectCast(m_currentPageStream, Stream))
 76         Return True
 77     End Function
 78 
 79     Private Function MetafileCallback(ByVal recordType As EmfPlusRecordType, ByVal flags As IntegerByVal dataSize As IntegerByVal data As IntPtr, ByVal callbackData As PlayRecordCallback) As Boolean
 80         Dim dataArray As Byte() = Nothing
 81         ' Dance around unmanaged code. 
 82         If data <> IntPtr.Zero Then
 83             ' Copy the unmanaged record to a managed byte buffer 
 84             ' that can be used by PlayRecord. 
 85             dataArray = New Byte(dataSize - 1) {}
 86             Marshal.Copy(data, dataArray, 0, dataSize)
 87         End If
 88         ' play the record. 
 89         m_metafile.PlayRecord(recordType, flags, dataSize, dataArray)
 90 
 91         Return True
 92     End Function
 93 
 94     Public Property RenderedPage() As Byte()()
 95         Get
 96             Return m_renderedReport
 97         End Get
 98         Set(ByVal value As Byte()())
 99             m_renderedReport = value
100         End Set
101     End Property
102 
103     Public Sub Print() Implements Framework.Printing.IPrintProxy.Print
104         'set data to RenderedPage  in Byte()() format
105 
106         m_numberOfPages = Me.RenderedPage.Length
107 
108         If m_numberOfPages < 1 Then
109             Return
110         End If
111 
112         Dim pd As New PrintDocument()
113         Dim printerSettings As New PrinterSettings()
114 
115         printerSettings.MaximumPage = m_numberOfPages
116         printerSettings.MinimumPage = 1
117         printerSettings.PrintRange = PrintRange.SomePages
118         printerSettings.FromPage = 1
119         printerSettings.ToPage = m_numberOfPages
120         printerSettings.PrinterName = job.Printer.PrinterName
121 
122         m_currentPrintingPage = 1
123         m_lastPrintingPage = m_numberOfPages
124         pd.PrinterSettings = printerSettings
125 
126         AddHandler pd.PrintPage, AddressOf Me.pd_PrintPage
127 
128         Try
129             pd.Print()
130         Finally
131             pd.Dispose()
132         End Try
133     End Sub
134 End Class
135 


 

 

 

 

posted @ 2010-01-13 16:40  Rickey Hu  阅读(11151)  评论(0编辑  收藏  举报