在打印图片时,经常会碰到一种情况: 图片的大小会超过纸张的大小; 此时,我们需要对图片进行缩放,来适应纸张的大小.
那么如何来实现呢?方法有二,
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
注意:使用此方法的一个弊端是会降低图片分辨率,从而导致打印出来的图片有闪烁(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
注意:此方法没有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
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