/
MetafileCanvas.cs
143 lines (127 loc) · 4.48 KB
/
MetafileCanvas.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//
// Swiss QR Bill Generator for .NET
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace Codecrete.SwissQRBill.Windows
{
/// <summary>
/// Canvas for generating Windows Metafiles (EMF).
/// <para>
/// For this class to generate correct EMF files, the application must be configured to be
/// *dpiAware*, either by adding an application manifest and uncommenting the relevant section
/// or by calling <c>SetProcessDPIAware()</c> at application start.
/// </para>
/// <code>
/// [System.Runtime.InteropServices.DllImport("user32.dll")]
/// private static extern bool SetProcessDPIAware();
/// </code>
/// </summary>
public class MetafileCanvas : SystemDrawingCanvas
{
private MemoryStream _stream;
private Metafile _metafile;
/// <summary>
/// Creates a new canvas.
/// </summary>
/// <param name="width">Width of resulting bitmap, in mm</param>
/// <param name="height">Height of resulting bitmap, in mm</param>
/// <param name="fontFamilyList">A list font family names, separated by comma (same syntax as for CSS). The first installed font family will be used.</param>
public MetafileCanvas(double width, double height, string fontFamilyList)
: base(fontFamilyList)
{
_stream = new MemoryStream();
using (var offScreenGraphics = Graphics.FromHwndInternal(IntPtr.Zero))
{
var scale = offScreenGraphics.DpiX / 25.4f;
_metafile = new Metafile(
_stream,
offScreenGraphics.GetHdc(),
new RectangleF(0, 0, (float)width * scale, (float)height * scale),
MetafileFrameUnit.Pixel,
EmfType.EmfPlusDual
);
offScreenGraphics.ReleaseHdc();
var graphics = Graphics.FromImage(_metafile);
graphics.PageUnit = GraphicsUnit.Pixel;
SetOffset(0, (float)height * scale);
InitGraphics(graphics, true, scale);
}
}
/// <inheritdoc />
public override byte[] ToByteArray()
{
Close();
_metafile.Dispose();
_metafile = null;
return _stream.ToArray();
}
/// <summary>
/// Returns the result as a metafile instance.
/// <para>
/// The caller must take ownership of the metafile and dispose it.
/// </para>
/// <para>
/// This method can only be called once. Thereafter, it is no longer
/// possible to draw to this canvas or to call this method a second time.
/// </para>
/// </summary>
/// <returns>The metafile.</returns>
public Metafile ToMetafile()
{
var metafile = _metafile;
_metafile = null;
Close();
return metafile;
}
/// <summary>
/// Writes the enhanced metafile (EMF) to the specified stream.
/// <para>
/// The canvas can no longer be used for drawing after calling this method.</para>
/// </summary>
/// <param name="stream">The stream to write to.</param>
public void WriteTo(Stream stream)
{
Close();
_metafile.Dispose();
_metafile = null;
_stream.CopyTo(stream);
_stream.Dispose();
_stream = null;
}
/// <summary>
/// Writes the enhanced metafile (EMF) to the specified file path.
/// <para>
/// The canvas can no longer be used for drawing after calling this method.</para>
/// </summary>
/// <param name="path">The path (file name) to write to.</param>
public void SaveAs(string path)
{
Close();
_metafile.Dispose();
_metafile = null;
using (var stream = File.OpenWrite(path))
{
_stream.CopyTo(stream);
}
_stream.Dispose();
_stream = null;
}
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
if (!disposing)
{
return;
}
_metafile?.Dispose();
_stream?.Dispose();
Close();
}
}
}