如何实现打印时,根据纸张大小来自动缩放图片
在打印图片时,经常会碰到一种情况: 图片的大小会超过纸张的大小; 此时,我们需要对图片进行缩放,来适应纸张的大小.
那么如何来实现呢?方法有二,
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, 0, 0)
20 End Using
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, 0, 0)
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(0, 0, width, height), m_delegate)
10
11 ' Clean up
12 m_delegate = Nothing
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(0, 0, width, height), m_delegate)
10
11 ' Clean up
12 m_delegate = Nothing
注意:此方法没有1)中的闪烁问题,实现也比较简单,推荐使用.
完整的一个打印示例如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 Object, ByVal 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(0, 0, 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 - 1) Is 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 Integer, ByVal dataSize As Integer, ByVal 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
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 Object, ByVal 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(0, 0, 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 - 1) Is 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 Integer, ByVal dataSize As Integer, ByVal 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