WPF图片(Image)处理相关

图片相关类

常见的类

关系

image-20230627122520503

Image和Bitmap

继承关系

System.Object
System.MarshalByRefObject
System.Drawing.Image
System.Drawing.Bitmap

Image

为源自 BitmapMetafile 的类提供功能的抽象基类。

1
2
3
4
5
6
// Create image.
Image newImage = Image.FromFile("SampImag.jpg");
// Create Point for upper-left corner of image.
Point ulCorner = new Point(100, 100);
// Draw image to screen.
e.Graphics.DrawImage(newImage, ulCorner);

Bitmap

封装 GDI+ 位图,此位图由图形图像及其属性的像素数据组成。

Bitmap 是用于处理由像素数据定义的图像的对象。

  • 位图由图形图像及其属性的像素数据组成。

    有许多标准格式可用于将位图保存到文件。

    GDI+ 支持以下文件格式: BMP、GIF、EXIF、JPG、PNG 和 TIFF。

    有关支持的格式的详细信息,请参阅位图类型

  • 您可以通过使用 Bitmap 构造函数之一,从文件、流和其他源创建图像,并使用 Save 方法将它们保存到流或文件系统。

    使用 Graphics 对象的 DrawImage 方法将图像绘制到屏幕或内存。

  • Bitmap是从Image类继承的一个图像类,它封装了Windows位图操作的常用功能。

    例如:Bitmap::SetPixelBitmap::GetPixel分别用来对位图进行读写像素操作,从而可以为图像的柔化和锐化处理提供一种可能。

示例

1
2
Image img = this.pictureBox1.Image;
Bitmap map = new Bitmap(img);

GetHbitmap

Bitmap的GetHbitmap()方法

官方文档

此方法创建 GDI 位图对象的图柄。

官方示例方法

1
2
3
4
5
6
7
8
9
10
11
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

private void DemonstrateGetHbitmap()
{
Bitmap bm = new Bitmap("Picture.jpg");
IntPtr hBitmap = bm.GetHbitmap();

// Do something with hBitmap.
DeleteObject(hBitmap);
}

Image和ImageSource

从源码中可以看出

我们加载图片的组件Image设置的是ImageSource

1
2
3
4
5
6
7
namespace System.Windows.Controls
{
public class Image : FrameworkElement, IUriContext, IProvidePropertyFallback
{
public ImageSource Source { get; set; }
}
}

ImageSource/BitmapSource/BitmapImage

继承关系

ImageSource=>BitmapSource=>BitmapImage

ImageSource

ImageSource表示具有宽度、高度和 ImageMetadata 的对象类型,这是一个抽象类。

BitmapSource

BitmapSource 也是一个抽象类。

BitmapSource 是 Windows Presentation Foundation (WPF) 图像处理管道的基本构建基块,从概念上讲,以特定大小和分辨率指定一组固定的像素。 BitmapSource 可以是解码器提供的图像文件中的单个帧,也可以是操作自身 BitmapSource 的转换的结果。 BitmapSource 不用于表示多帧图像或动画。

BitmapImage

BitmapImage从图像文件创建位图,并将其用作 Image 控件的源

1
2
3
4
5
6
7
8
9
10
11
12
13
// Create the image element.
Image simpleImage = new Image();
simpleImage.Width = 200;
simpleImage.Margin = new Thickness(5);

// Create source.
BitmapImage bi = new BitmapImage();
// BitmapImage.UriSource must be in a BeginInit/EndInit block.
bi.BeginInit();
bi.UriSource = new Uri(@"/sampleImages/cherries_larger.jpg",UriKind.RelativeOrAbsolute);
bi.EndInit();
// Set the image source.
simpleImage.Source = bi;

RenderTargetBitmap

主要作用为保存页面组件为图片

其中myview为其它组件的名称

XAML

1
2
3
4
5
6
7
8
9
<Grid x:Name="myview">
<StackPanel>
<TextBlock Text="我的应用程序" FontSize="20" />
<TextBlock Text="点击截屏" FontSize="60" />
</StackPanel>
</Grid>

<!--该图片控件用于展示截图图片效果-->
<Image x:Name="img" />

C#

1
2
3
4
RenderTargetBitmap bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(myview);
// 把图片展现出来
img.Source = bitmap;

RenderTargetBitmap和BitmapImage

RenderTargetBitmap和BitmapImage都是用于表示位图的类,但是两者有不同的用途和区别:

  1. 目标渲染位图(RenderTargetBitmap)是一个用于创建位图的WPF元素,它可以在屏幕上渲染一个WPF视觉对象,并将其转换为位图。它通常用于将WPF视觉元素转换为图片,如截图等操作。
  2. 位图图像(BitmapImage)是一个预定义的位图图像,它可以从本地文件或网络中加载。它通常用于显示图像,如在Image控件中显示图片。

因此,如果需要从WPF视觉元素创建位图,则使用RenderTargetBitmap;如果需要从本地或网络中加载位图,则使用BitmapImage。

图片转换

Bitmap <=> BitmapImage

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
/// <summary>
/// Bitmap --> BitmapImage
/// </summary>
/// <param name="bitmap"></param>
/// <returns></returns>
public static BitmapImage BitmapToBitmapImage(Bitmap bitmap)
{
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Png);
stream.Position = 0;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
}

// BitmapImage --> Bitmap
public static Bitmap BitmapImageToBitmap(BitmapImage bitmapImage)
{
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapImage));
enc.Save(outStream);
Bitmap bitmap = new Bitmap(outStream);

return new Bitmap(bitmap);
}
}

ImagePath => BitmapImage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static BitmapImage GetImage(string imagePath)
{
BitmapImage bi = new BitmapImage();
if (File.Exists(imagePath))
{
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
using (Stream ms = new MemoryStream(File.ReadAllBytes(imagePath)))
{
bi.StreamSource = ms;
bi.EndInit();
bi.Freeze();
}
}
return bi;
}

Bitmap <=> ImageSource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[DllImport("gdi32.dll", SetLastError = true)]
private static extern bool DeleteObject(IntPtr hObject);
/// <summary>
/// 从bitmap转换成ImageSource
/// </summary>
/// <param name="icon"></param>
/// <returns></returns>
public static ImageSource ChangeBitmapToImageSource(Bitmap bitmap)
{
IntPtr hBitmap = bitmap.GetHbitmap();
ImageSource wpfBitmap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions()
);
if (!DeleteObject(hBitmap))//记得要进行内存释放。否则会有内存不足的报错。
{
throw new System.ComponentModel.Win32Exception();
}
return wpfBitmap;
}

Bitmap => BitmapSource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/// <summary>
/// 从Bitmap转换成BitmapSource
/// </summary>
/// <param name="bmp"></param>
/// <returns></returns>
public static BitmapSource ChangeBitmapToBitmapSource(Bitmap bmp)
{
BitmapSource returnSource;
try
{
returnSource = Imaging.CreateBitmapSourceFromHBitmap(
bmp.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions()
);
}
catch
{
returnSource = null;
}
return returnSource;
}

Icon => ImageSource

1
2
3
4
5
6
7
8
9
10
11
/// <summary>
/// 从Icon到ImageSource的转换
/// </summary>
public ImageSource ChangeIconToImageSource(Icon icon)
{
ImageSource imageSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
return imageSource;
}

RenderTargetBitmap => BitmapImage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// RenderTargetBitmap --> BitmapImage
public static BitmapImage ConvertRenderTargetBitmapToBitmapImage(RenderTargetBitmap wbm)
{
BitmapImage bmp = new BitmapImage();
using (MemoryStream stream = new MemoryStream())
{
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(wbm));
encoder.Save(stream);
bmp.BeginInit();
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
bmp.StreamSource = new MemoryStream(stream.ToArray()); //stream;
bmp.EndInit();
bmp.Freeze();
}
return bmp;
}

BitmapImage <=> byte[]

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
// BitmapImage --> byte[]
public static byte[] BitmapImageToByteArray(BitmapImage bmp)
{
byte[] bytearray = null;
try
{
Stream smarket = bmp.StreamSource; ;
if (smarket != null && smarket.Length > 0)
{
//设置当前位置
smarket.Position = 0;
using (BinaryReader br = new BinaryReader(smarket))
{
bytearray = br.ReadBytes((int)smarket.Length);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return bytearray;
}


// byte[] --> BitmapImage
public static BitmapImage ByteArrayToBitmapImage(byte[] array)
{
using (var ms = new System.IO.MemoryStream(array))
{
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad; // here
image.StreamSource = ms;
image.EndInit();
image.Freeze();
return image;
}
}

byte[] <=> Bitmap

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
public static System.Drawing.Bitmap ConvertByteArrayToBitmap(byte[] bytes)
{
System.Drawing.Bitmap img = null;
try
{
if (bytes != null && bytes.Length != 0)
{
MemoryStream ms = new MemoryStream(bytes);
img = new System.Drawing.Bitmap(ms);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return img;
}

/// <summary>
/// Bitmap转byte[]
/// </summary>
/// <param name="bitmap"></param>
/// <returns></returns>
public static byte[] BitmapToBytes(Bitmap bitmap)
{
MemoryStream stream = new MemoryStream();
bitmap.Save(stream, ImageFormat.Jpeg);
byte[] data = new byte[stream.Length];
stream.Seek(0, SeekOrigin.Begin);
stream.Read(data, 0, Convert.ToInt32(stream.Length));
stream.Dispose();
return data;
}

图片保存

Bitmap保存

1
Bitmap img = ZScreenUtil.CaptureScreen();

保存

1
2
3
var filePath = "E:\123.jpg";
img.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);
img.Dispose();

保存设置压缩质量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static string CaptureScreenSave(string filePath)
{
ImageCodecInfo myImageCodecInfo = GetEncoderInfo("image/jpeg");
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(Encoder.Quality, 60L);
myEncoderParameters.Param[0] = myEncoderParameter;
img.Save(filePath, myImageCodecInfo, myEncoderParameters);
img.Dispose();
}

private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
for (int j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}

BitmapSource保存

Bitmap=>BitmapSource

BitmapSource=>写文件

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
float factor = Graphics.FromHwnd(IntPtr.Zero).DpiX / 96;
int imageW = Convert.ToInt32(pwidth * factor);
int imageH = Convert.ToInt32(pHeight * factor);
using (
Bitmap image = new Bitmap(
imageW, imageH, System.Drawing.Imaging.PixelFormat.Format32bppArgb
)
)
{
using (Graphics g = Graphics.FromImage(image))
{
g.CopyFromScreen(
0,
0,
0,
0,
new System.Drawing.Size(imageW, imageH),
CopyPixelOperation.SourceCopy
);
IntPtr intPtr = image.GetHbitmap();
BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(
intPtr,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions()
);

//BitmapSource=>写文件
string filepath = getImagePath();
using (FileStream file = new FileStream(filepath, FileMode.Create, FileAccess.Write))
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.QualityLevel = 90;
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
encoder.Save(file);
}
ImageHelper.DeleteObject(intPtr);
}
}

注意

上面的这种保存图片的方式是没有意义的,只是为了展示怎么把BitmapSource保存为图片文件。

BitmapSource=>写文件

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
/// <summary>
/// 保存图片到文件
/// </summary>
/// <param name="image">图片数据</param>
/// <param name="filePath">保存路径</param>
private void SaveImageToFile(BitmapSource image, string filePath)
{
BitmapEncoder encoder = GetBitmapEncoder(filePath);
encoder.Frames.Add(BitmapFrame.Create(image));

using (var stream = new FileStream(filePath, FileMode.Create))
{
encoder.Save(stream);
}
}

/// <summary>
/// 根据文件扩展名获取图片编码器
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns>图片编码器</returns>
private BitmapEncoder GetBitmapEncoder(string filePath)
{
var extName = Path.GetExtension(filePath).ToLower();
if (extName.Equals(".png"))
{
return new PngBitmapEncoder();
}
else
{
return new JpegBitmapEncoder();
}
}

组件转图片

RenderTargetBitmap=>Bitmap

示例:获取组件的Bitmap

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
public static Bitmap SaveUi2Bitmap(FrameworkElement element)
{
// 获取FrameworkElement的大小
int width = (int)element.ActualWidth;
int height = (int)element.ActualHeight;

// 创建RenderTargetBitmap对象,并将FrameworkElement渲染到其中
RenderTargetBitmap bitmap = new RenderTargetBitmap
(
width,
height,
96,
96,
PixelFormats.Pbgra32
);
bitmap.Render(element);

// 创建Bitmap对象,并将RenderTargetBitmap的像素复制到其中
Bitmap bmp = new Bitmap
(
width,
height,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb
);
BitmapData bmpData = bmp.LockBits
(
new Rectangle
(
0,
0,
bmp.Width,
bmp.Height
),
ImageLockMode.WriteOnly,
bmp.PixelFormat
);
bitmap.CopyPixels
(
Int32Rect.Empty,
bmpData.Scan0,
bmpData.Height * bmpData.Stride,
bmpData.Stride
);
bmp.UnlockBits(bmpData);
return bmp;
}

组件转文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void SaveUI2JpegFile(FrameworkElement frameworkElement, int width, int height, string filepath)
{
using (FileStream outStream = new FileStream(filepath, FileMode.Create, FileAccess.Write))
{
RenderTargetBitmap bmp = new RenderTargetBitmap(
(int)frameworkElement.ActualWidth,
(int)frameworkElement.ActualHeight,
96,
96,
PixelFormats.Default
);
bmp.Render(frameworkElement);
JpegBitmapEncoder encoder = new JpegBitmapEncoder
{
QualityLevel = 80
};
encoder.Frames.Add(BitmapFrame.Create(bmp));
encoder.Save(outStream);
}
}

组件转BitmapImage

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
public static Bitmap SaveUi2Bitmap(FrameworkElement element)
{
// 获取FrameworkElement的大小
int width = (int)element.ActualWidth;
int height = (int)element.ActualHeight;

// 创建RenderTargetBitmap对象,并将FrameworkElement渲染到其中
RenderTargetBitmap bitmap = new RenderTargetBitmap
(
width,
height,
96,
96,
PixelFormats.Pbgra32
);
bitmap.Render(element);

// 创建Bitmap对象,并将RenderTargetBitmap的像素复制到其中
Bitmap bmp = new Bitmap
(
width,
height,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb
);
BitmapData bmpData = bmp.LockBits
(
new Rectangle
(
0,
0,
bmp.Width,
bmp.Height
),
ImageLockMode.WriteOnly,
bmp.PixelFormat
);
bitmap.CopyPixels
(
Int32Rect.Empty,
bmpData.Scan0,
bmpData.Height * bmpData.Stride,
bmpData.Stride
);
bmp.UnlockBits(bmpData);
return bmp;
}

// Bitmap --> BitmapImage
public static BitmapImage BitmapToBitmapImage(Bitmap bitmap)
{
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Png);
stream.Position = 0;
BitmapImage result = new BitmapImage();
result.BeginInit();
result.CacheOption = BitmapCacheOption.OnLoad;
result.StreamSource = stream;
result.EndInit();
result.Freeze();
return result;
}
}

public static BitmapImage SaveUi2BitmapImage(FrameworkElement frameworkElement)
{
using var bitmap = SaveUi2Bitmap(frameworkElement);
return BitmapToBitmapImage(bitmap);
}

截屏保存

获取图片

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
using System;
using System.Drawing;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using Size = System.Drawing.Size;

namespace JieTu.Utils
{
class ZScreenUtil
{
public static void ScreenShot(string savePath)
{
using (Bitmap bmp = new Bitmap(
Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height,
System.Drawing.Imaging.PixelFormat.Format32bppArgb
))
{
using (Graphics g = Graphics.FromImage(bmp))
{
g.CopyFromScreen(0, 0, 0, 0, bmp.Size);
bmp.Save(savePath, ImageFormat.Jpeg);
}
}
}
}
}

保存图片

1
2
var filePath = "E:\123.jpg";
ZScreenUtil.ScreenShot(filePath);

图片压缩

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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace card_scanner.util
{
public class ZImageUtil
{
/// <summary>
/// 压缩图片
/// </summary>
/// <param name="sourcePath"></param>
/// <param name="targetPath"></param>
/// <param name="targetLen">压缩后的大小单位kb</param>
public static void ZipImage(string sourcePath, string targetPath, long targetLen)
{
Image img = Image.FromFile(sourcePath);
using (Image img2 = ZipImage(img, GetImageFormat(targetPath), targetLen))
{
//解除之前文件占用
img.Dispose();
img2.Save(targetPath);
}
}

/// <summary>
/// 图片压缩
/// </summary>
/// <param name="stream"></param>
/// <param name="targetPath"></param>
/// <param name="targetLen">压缩后的大小单位kb</param>
public static void ZipImage(Stream stream, string targetPath, long targetLen)
{
Image img = Image.FromStream(stream);
using (Image img2 = ZipImage(img, GetImageFormat(targetPath), targetLen))
{
img.Dispose();
img2.Save(targetPath);
}
}

/// <summary>
/// 压缩图片
/// </summary>
/// <param name="img">图片</param>
/// <param name="format">图片格式</param>
/// <param name="targetLen">压缩后大小(kb)</param>
/// <param name="srcLen">原始大小</param>
/// <returns>压缩后的图片</returns>
public static Image ZipImage(Image img, ImageFormat format, long targetLen, long srcLen = 0)
{
//设置大小偏差幅度 10kb
const long nearlyLen = 10240;
//内存流 如果参数中原图大小没有传递 则使用内存流读取
var ms = new MemoryStream();
if (0 == srcLen)
{
img.Save(ms, format);
srcLen = ms.Length;
}

//单位 由Kb转为byte 若目标大小高于原图大小,则满足条件退出
targetLen *= 1024;
if (targetLen > srcLen)
{
ms.SetLength(0);
ms.Position = 0;
img.Save(ms, format);
img = Image.FromStream(ms);
return img;
}

//获取目标大小最低值
var exitLen = targetLen - nearlyLen;

//初始化质量压缩参数 图像 内存流等
var quality = (long)Math.Floor(100.00 * targetLen / srcLen);
var parms = new EncoderParameters(1);

//获取编码器信息
ImageCodecInfo formatInfo = null;
var encoders = ImageCodecInfo.GetImageEncoders();
foreach (ImageCodecInfo icf in encoders)
{
if (icf.FormatID == format.Guid)
{
formatInfo = icf;
break;
}
}

//使用二分法进行查找 最接近的质量参数
long startQuality = quality;
long endQuality = 100;
quality = (startQuality + endQuality) / 2;

while (true)
{
//设置质量
parms.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);

//清空内存流 然后保存图片
ms.SetLength(0);
ms.Position = 0;
img.Save(ms, formatInfo, parms);

//若压缩后大小低于目标大小,则满足条件退出
if (ms.Length >= exitLen && ms.Length <= targetLen)
{
break;
}
else if (startQuality >= endQuality) //区间相等无需再次计算
{
break;
}
else if (ms.Length < exitLen) //压缩过小,起始质量右移
{
startQuality = quality;
}
else //压缩过大 终止质量左移
{
endQuality = quality;
}

//重新设置质量参数 如果计算出来的质量没有发生变化,则终止查找。这样是为了避免重复计算情况{start:16,end:18} 和 {start:16,endQuality:17}
var newQuality = (startQuality + endQuality) / 2;
if (newQuality == quality)
{
break;
}
quality = newQuality;
}
img = Image.FromStream(ms);
return img;
}

/// <summary>
/// 根据尺寸按比例压缩
/// </summary>
/// <param name="bitmap">图片</param>
/// <param name="destWidth">目标的宽</param>
/// <param name="destHeight">目标的高</param>
/// <returns></returns>
public static Image ZoomImage(Image bitmap, int destWidth, int destHeight)
{
try
{
System.Drawing.Image sourImage = bitmap;
int width = 0, height = 0;
//按比例缩放
int sourWidth = sourImage.Width;
int sourHeight = sourImage.Height;
if (sourHeight > destHeight || sourWidth > destWidth)
{
if ((sourWidth * destHeight) > (sourHeight * destWidth))
{
width = destWidth;
height = (destWidth * sourHeight) / sourWidth;
}
else
{
height = destHeight;
width = (sourWidth * destHeight) / sourHeight;
}
}
else
{
width = sourWidth;
height = sourHeight;
}
Bitmap destBitmap = new Bitmap(destWidth, destHeight);
Graphics g = Graphics.FromImage(destBitmap);
g.Clear(Color.Transparent);
//设置画布的描绘质量
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.DrawImage(sourImage, new Rectangle((destWidth - width) / 2, (destHeight - height) / 2, width, height), 0, 0, sourImage.Width, sourImage.Height, GraphicsUnit.Pixel);
g.Dispose();
//设置压缩质量
System.Drawing.Imaging.EncoderParameters encoderParams = new System.Drawing.Imaging.EncoderParameters();
long[] quality = new long[1];
quality[0] = 100;
System.Drawing.Imaging.EncoderParameter encoderParam = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
encoderParams.Param[0] = encoderParam;
sourImage.Dispose();
return destBitmap;
}
catch (Exception)
{
return bitmap;
}
}

/// <summary>
///获取图片格式
/// </summary>
/// <param name="img">图片</param>
/// <returns>默认返回JPEG</returns>
public static ImageFormat GetImageFormat(Image img)
{
if (img.RawFormat.Equals(ImageFormat.Jpeg))
{
return ImageFormat.Jpeg;
}
if (img.RawFormat.Equals(ImageFormat.Gif))
{
return ImageFormat.Gif;
}
if (img.RawFormat.Equals(ImageFormat.Png))
{
return ImageFormat.Png;
}
if (img.RawFormat.Equals(ImageFormat.Bmp))
{
return ImageFormat.Bmp;
}
return ImageFormat.Jpeg;//根据实际情况选择返回指定格式还是null
}

/// <summary>
/// 根据目标路径获取图片格式
/// </summary>
/// <param name="imgPath"></param>
/// <returns></returns>
public static ImageFormat GetImageFormat(string imgPath)
{
string imagePathNew = imgPath.ToLower();
if (imagePathNew.EndsWith("gif"))
{
return ImageFormat.Gif;
}
else if (imagePathNew.EndsWith("png"))
{
return ImageFormat.Png;
}
else if (imagePathNew.EndsWith("bmp"))
{
return ImageFormat.Bmp;
}
else
{
return ImageFormat.Jpeg;
}
}

/// <summary>
/// 获取图片的新路径
/// </summary>
/// <param name="sourcePath"></param>
/// <returns></returns>
public static string GetImagePathNew(string sourcePath)
{
string targetPath = "";
Console.WriteLine("sourcePath: " + sourcePath);
try
{
FileInfo fi = new FileInfo(sourcePath);
var di = fi.Directory;
if (!di.Exists)
{
di.Create();
}
string filename = fi.Name;
string filenameNoSuff = filename.Substring(0, filename.LastIndexOf("."));
string suff = filename.Substring(filename.LastIndexOf("."));
targetPath = Path.Combine(di.FullName, filenameNoSuff + "_new" + suff);
}
catch (Exception)
{
}

return targetPath;
}
}
}

图片加载

加载本地

1
2
BitmapImage bImage = new BitmapImage(new Uri("c:\\image.bmp"));
image.Source = bImage;

加载本地图片并缩放

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
private void SetSource(System.Windows.Controls.Image image, string fileName)
{
System.Drawing.Image sourceImage = System.Drawing.Image.FromFile(fileName);
int imageWidth = 0, imageHeight = 0;
InitializeImageSize(sourceImage, image, out imageWidth, out imageHeight);
Bitmap sourceBmp = new Bitmap(sourceImage, imageWidth, imageHeight);
IntPtr hBitmap = sourceBmp.GetHbitmap();
BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions()
);
bitmapSource.Freeze();
WriteableBitmap writeableBmp = new WriteableBitmap(bitmapSource);
sourceImage.Dispose();
sourceBmp.Dispose();
image.Source = writeableBmp;
}

/// <summary>
/// 设置图片大小
/// </summary>
/// <param name="sourceImage"></param>
/// <param name="image"></param>
/// <param name="imageWidth"></param>
/// <param name="imageHeight"></param>
private static void InitializeImageSize(
System.Drawing.Image sourceImage,
System.Windows.Controls.Image image,
out int imageWidth, out int imageHeight
)
{
int width = sourceImage.Width;
int height = sourceImage.Height;
float aspect = (float)width / (float)height;
if (image.Height != double.NaN)
{
imageHeight = Convert.ToInt32(image.Height);
imageWidth = Convert.ToInt32(aspect * imageHeight);
}
else if (image.Width != double.NaN)
{
imageWidth = Convert.ToInt32(image.Width);
imageHeight = Convert.ToInt32(image.Width / aspect);
}
else
{
imageHeight = 100;
imageWidth = Convert.ToInt32(aspect * imageHeight);
}
}

调用方式

1
SetSource(this.imageCur, “C:\1.png”);

JPEG转WEBP

添加依赖

1
Install-Package Imazen.WebP -Version 10.0.1

下载DLL

https://www.dll-files.com/libwebp.dll.html

注意32位和64位,我这里用的32位

项目根目录添加DLL文件夹,把libwebp.dll放进去

属性=>生成事件=>生成前事件命令行添加

1
xcopy /Y /d $(ProjectDir)\DLL\libwebp.dll $(TargetDir)

转为WEBP

1
2
3
4
5
6
7
8
9
10
11
if (targetFilePath.EndsWith("webp"))
{
using (Bitmap bitmap = new Bitmap(sourceFilePath))
{
using (var saveImageStream = System.IO.File.Open(targetFilePath, FileMode.Create))
{
var encoder = new SimpleEncoder();
encoder.Encode(bitmap, saveImageStream, 80);
}
}
}

封装的工具类

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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
using Imazen.WebP;

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace SchoolClient.Utils
{
internal class ZScreenUtil
{
/// <summary>
/// 屏幕截图
/// </summary>
/// <param name="savePath">
/// </param>
public static void ScreenShot(string savePath)
{
using (Bitmap bmp = new Bitmap(
Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height,
System.Drawing.Imaging.PixelFormat.Format32bppArgb
))
{
using (Graphics g = Graphics.FromImage(bmp))
{
g.CopyFromScreen(0, 0, 0, 0, bmp.Size);
bmp.Save(savePath, ImageFormat.Jpeg);
}
}
}

/// <summary>
/// 截图并缩放
/// </summary>
/// <param name="targetPath">
/// </param>
/// <returns>
/// </returns>
public static void CaptureScreenSave(string targetPath)
{
int lastindex = targetPath.LastIndexOf(Path.DirectorySeparatorChar);
if (lastindex < targetPath.Length)
{
string fileFolder = targetPath.Substring(0, lastindex);
string filename = targetPath.Substring(lastindex + 1);
string filenameNoSuff = filename.Substring(0, filename.LastIndexOf("."));
string tempFilePath = fileFolder + Path.DirectorySeparatorChar + "z_" + filenameNoSuff + ".jpg";

//截屏
ScreenShot(tempFilePath);

int Width = Screen.PrimaryScreen.Bounds.Width;
int Height = Screen.PrimaryScreen.Bounds.Height;

int maxHeight = 1080;
int quality = 80;
if (Height > maxHeight || targetPath.EndsWith("webp"))
{
// 图片需要缩放或者需要转WEBP
float ratio = 1.0f * Height / maxHeight;
Width = (int)(1.0d * Width / ratio);
Height = (int)(1.0d * Height / ratio);
Bitmap bitmp = PicScale(tempFilePath, Width, Height);
try
{
if (targetPath.EndsWith("webp"))
{
Pic2Webp(bitmp, targetPath, quality);
}
else
{
PicCompress(bitmp, targetPath, quality);
}
}
catch (Exception)
{
}
bitmp.Dispose();

//删除原图
PicDel(tempFilePath);
}
else
{
// 图片不用转换为WEBP,并且文件大小未改变,直接重命名
try
{
FileInfo fi = new FileInfo(tempFilePath);
if (fi.Exists)
{
fi.MoveTo(targetPath);
}
}
catch (Exception)
{
}
}
}
}

/// 图片缩放
/// <param name="sourcePath">
/// 原图片
/// </param>
/// <param name="targetWidth">
/// 宽度
/// </param>
/// <param name="targetHeight">
/// 高度
/// </param>
/// <returns>
/// </returns>
public static Bitmap PicScale(string sourcePath, int targetWidth, int targetHeight)
{
Bitmap bitmp = null;
using (Image sourceImage = Image.FromFile(sourcePath))
{
//用指定的大小和格式初始化Bitmap类的新实例
using (Bitmap bitmap = new Bitmap(targetWidth, targetHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
{
//从指定的Image对象创建新Graphics对象
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.DrawImage(sourceImage, new Rectangle(0, 0, targetWidth, targetHeight));
}
bitmp = new Bitmap(bitmap);
}
}

return bitmp;
}

/// <summary>
/// 图片删除
/// </summary>
/// <param name="sourcePath">
/// </param>
public static void PicDel(string sourcePath)
{
try
{
// 防止文件占用导致的异常
FileInfo di = new FileInfo(sourcePath);
if (di.Exists)
{
di.Delete();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}

/// <summary>
/// 图片压缩(降低质量以减小文件的大小)
/// </summary>
/// <param name="bitmap">
/// 传入的Bitmap对象
/// </param>
/// <param name="targetPath">
/// 压缩后的文件路径
/// </param>
/// <param name="quality">
/// 压缩等级,0到100,0 最差质量,100 最佳
/// </param>
public static void PicCompress(Bitmap bitmap, string targetPath, long quality)
{
using (Stream destStream = new FileStream(targetPath, FileMode.Create))
{
ImageCodecInfo myImageCodecInfo;
EncoderParameters myEncoderParameters;

//获取表示jpeg编解码器的imagecodecinfo对象
myImageCodecInfo = GetEncoderInfo("image/jpeg");
myEncoderParameters = new EncoderParameters(1);

myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality); ;
bitmap.Save(destStream, myImageCodecInfo, myEncoderParameters);
bitmap.Dispose();
GC.Collect();
}
}

/// <summary>
/// 图片转WEBP
/// </summary>
/// <param name="bitmp">
/// </param>
/// <param name="targetPath">
/// </param>
/// <param name="quality">
/// </param>
public static void Pic2Webp(Bitmap bitmp, string targetPath, long quality)
{
using (var saveImageStream = File.Open(targetPath, FileMode.Create))
{
var encoder = new SimpleEncoder();
encoder.Encode(bitmp, saveImageStream, quality);
bitmp.Dispose();
}
}

/// <summary>
/// 获取解码器
/// </summary>
/// <param name="mimeType">
/// </param>
/// <returns>
/// </returns>
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
{
return encoders[j];
}
}
return null;
}

/// <summary>
/// 保存界面为图片
/// </summary>
/// <param name="frameworkElement">
/// </param>
/// <param name="filepath">
/// </param>
public static void SaveUI2JpegFile(FrameworkElement frameworkElement, string filepath)
{
using (FileStream outStream = new FileStream(filepath, FileMode.Create, FileAccess.Write))
{
RenderTargetBitmap bmp = new RenderTargetBitmap(
(int)frameworkElement.ActualWidth,
(int)frameworkElement.ActualHeight,
96,
96,
PixelFormats.Default
);
bmp.Render(frameworkElement);

JpegBitmapEncoder encoder = new JpegBitmapEncoder
{
QualityLevel = 80
};
encoder.Frames.Add(BitmapFrame.Create(bmp));
encoder.Save(outStream);
}
}

/// <summary>
/// 根据路径获取BitmapImage
/// </summary>
/// <param name="imagePath">
/// </param>
/// <returns>
/// </returns>
public static BitmapImage GetImage(string imagePath)
{
BitmapImage bi = new BitmapImage();
if (File.Exists(imagePath))
{
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
using (Stream ms = new MemoryStream(File.ReadAllBytes(imagePath)))
{
bi.StreamSource = ms;
bi.EndInit();
bi.Freeze();
}
}
return bi;
}

/// <summary>
/// 截取图片指定部分
/// </summary>
/// <param name="imgPath">
/// 图片路径
/// </param>
/// <param name="cutWidth">
/// 容器内截取的宽度
/// </param>
/// <param name="cutHeight">
/// 容器内截取的高度
/// </param>
/// <param name="cutX">
/// 容器内开始截取处的坐标X值
/// </param>
/// <param name="cutY">
/// 容器内开始截取处的坐标Y值
/// </param>
/// <param name="containerW">
/// 图片容器宽度
/// </param>
/// <param name="containerH">
/// 图片容器高度
/// </param>
public static Bitmap PicCrop(string imgPath, int cutWidth, int cutHeight, int cutX, int cutY, int containerW, int containerH)
{
Image originalImg = Image.FromFile(imgPath);
float ratioW = 1.0f * originalImg.Width / containerW;
float ratioH = 1.0f * originalImg.Height / containerH;

//原图位置(默认从原图中截取的图片大小等于目标图片的大小)
Rectangle origRect = new Rectangle(
new System.Drawing.Point((int)(ratioW * cutX), (int)(ratioH * cutY)),
new System.Drawing.Size((int)(ratioW * cutWidth), (int)(ratioH * cutHeight))
);

int targetW = (int)(ratioW * cutWidth);
int targetH = (int)(ratioH * cutHeight);
//目标位置
Rectangle destRect = new Rectangle(
new System.Drawing.Point(0, 0),
new System.Drawing.Size(targetW, targetH)
);

Bitmap partImg = new Bitmap(targetW, targetH);
Graphics graphics = Graphics.FromImage(partImg);
graphics.DrawImage(originalImg, destRect, origRect, GraphicsUnit.Pixel);
graphics.Dispose();
return partImg;
}
}
}

相关概念

GDI和GDI+

GDI在全称是Graphics Device Interface,即图形设备接口。是图形显示与实际物理设备之间的桥梁。

GDI接口是基于函数,虽然使程序员省力不少,但是编程方式依然显得麻烦。

例如显示一张位图,我们需要进行“创建位图,读取位图文件信息,启用场景设备,调色板变化“等一系列操作。然而有了GDI+,繁琐的步骤再次被简化。

顾名思义,GDI+就是GDI的增强版,它是微软在Windows 2000以后操作系统中提供的新接口。

GDI+主要提供以下三种功能:

  1. 二维矢量图形:GDI+提供了存储图形基元自身信息的类(或结构体)、存储图形基元绘制方式信息的类以及实际进行绘制的类;

  2. 图像处理:大多数图片都难以划定为直线和曲线的集合,无法使用二维矢量图形方式进行处理。因此,GDI+为我们提供了Bitmap、Image等类,它们可用于显示、操作和保存BMP、JPG、GIF等图像格式。

  3. 文字显示:GDI+支持使用各种字体、字号和样式来显示文本。

相比于GDI,GDI+是基于C++类的对象化的应用程序接口,因此用起来更为简单。

GDI的核心是设备上下文,GDI函数都依赖于设备上下文句柄,其编程方式是基于句柄的;

GDI+无需时刻依赖于句柄或设备上下文,用户只需创建一个Graphics 对象,就可以用面向对象的方式调用其成员函数进行图形操作,编程方式是基于对象的。

GDI +提供了Image、Bitmap 和Metafile 类,方便用户进行图像格式的加载、操作和保存。

GDI+支持的图像格式有BMP、GIF、JPEG、EXIF、PNG、TIFF、ICON、WMF、 EMF等,几乎涵盖了所有的常用图像格式。

GDI+和GDI区别以及一些新特征

GDI+与GDI

  1. GDI是硬件加速的,而GDI+不是的,而且GDI+2.0比GDI+更快。

  2. GDI是有状态的,而GDI+是无状态的。

  3. GDI绘图要使用设备环境和句柄;而GDI+全部交由Graphics类管理(不创建句柄)。

  4. GDI绘图时可以使用SelectObject频繁切换图形对象,而GDI+的图形对象是独立的。

  5. GDI中存在一个当前位置(全局区),目的是提高绘图性能;而GDI+取消了它,以避免绘图时不确定这个当前位置而带来非预期的错误。

  6. GDI总是将画笔和画刷绑定在一起,即使不需要填充一个区域也必须指定一个画刷;而GDI+则可以使用不同的函数分开使用画笔和画刷。

GDI+新特性

  1. 改进了颜色管理。GDI+不仅提供了更多可供选择使用的颜色,使其支持Alpha通道合成运算,而且还保持了与其他颜色的兼容性。

  2. 绘图支持反锯齿。通过设置GDI+对象的相关属性,GDI+可以与相关的显示驱动程序搭配完成图形绘制时的反锯齿功能,使得绘制的图形更加平滑,美观,而整个过程是由GDI+对象自动计算完成的。

  3. 提供渐变画刷。GDI+拓展了GDI的功能,提供线性渐变和路径渐变画刷来填充图形、路径和区域,甚至也可用来绘制直线、曲线等。

  4. 独立的路径对象。GDI+使用Graphics对象来进行绘图操作,并将路径操作从Graphics对象分离出来,提供一个Graphics类供用户使用,用户不必担心对象会受到Graphics对象操作的影响,从而可以使用同一个操作对象进行多次的路径绘制操作。

  5. 样条曲线。GDI+封装了绘制基数样条曲线和贝塞尔样条曲线的方法。

  6. 变形和矩阵运算。GDI+提供了功能强大的Matrix类来实现矩阵的旋转,错切、平移、比例等变换操作,以便产生复杂的新图形。

  7. 多图片格式的支持。GDI+该进了图形处理能力,通过GDI+,用户能够访问多种格式的图片文件,转换文件格式等,还能进行图像重新着色、色彩修正、消除走样等图像处理。

注意

GDI+对象比如Bitmap,是不会创建句柄的,GetHbitmap方法不是获取句柄而是创建句柄。不会受GDI句柄数量的限制。只有需要创建句柄进行其他操作时才要调用GetHbitmap创建句柄。

托管资源和非托管资源

概念

  • 托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源。托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收。

  • 非托管资源指的是.NET不知道如何回收的资源,最常见的一类非托管资源是包装操作系统资源的对象,

    例如文件,窗口,网络连接,数据库连接,画刷,图标等。

    这类资源,垃圾回收器在清理的时候会调用Object.Finalize()方法。默认情况下,方法是空的,对于非托管对象,需要在此方法中编写回收非托管资源的代码,以便垃圾回收器正确回收资源。

常见的非托管资源

ApplicationContext, Brush, Component, ComponentDesigner, Container, Context, Cursor, FileStream, Font, Icon, Image, Matrix, Object, OdbcDataReader, OleDBDataReader, Pen, Regex, Socket, StreamWriter, Timer, Tooltip, 文件句柄, GDI资源, 数据库连接等等资源。

非托管资源的释放

托管资源由垃圾回收器控制如何释放,不需要程序员过多的考虑(当然也程序员也可以自己释放)。

非托管资源需要自己编写代码来释放。

在一个包含非托管资源的类中,关于资源释放的标准做法是:

  1. 继承IDisposable接口;

  2. 实现Dispose()方法,在其中释放托管资源和非托管资源,并将对象本身从垃圾回收器中移除(垃圾回收器不在回收此资源);

  3. 实现类析构函数,在其中释放非托管资源。

那么编写好的释放非托管资源的代码(释非代码)由谁来调用呢。

有两种实现方式:

  1. 将释非代码放到构造函数析构函数中,由系统自动调用,系统会在资源对象不再使用了,会在某个时间调用构造函数析构函数来释放非托管资源。构造函数析构函数的目的就是用来释放或清理非托管资源的。但它有一个问题是调用的时间是系统说了算,不能在程序中自己想要调用时调用析构函数,这是C#规定的。那么就产生了第二种方式。

  2. 将释非代码放到另外一个函数中,当自己想调用时就调用。将释非代码放在一个方法中共用。

代码如下

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
MyClass:IDisposable
{
private bool disposed = false;
~MyClass()
{
Dispose(false);
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
if(disposed == false)
{
if(disposing == true)
{
// 释托管代码
// ......
}
// 释非代码
// ......
}
disposed = true;
}
}

标准清理模式中多了一句GC.SuppressFinalize(this);【该方法通知CLR不要调用该方法的析构函数,因为它已经被清理了。】如果没有这句代码,我认为不影响程序的正确性,不会发生安全问题,他只是告诉系统不要再调用构造函数了。那么为什么要加上这句代码呢?如果在调用了Dispose()之后再调用析构函数只是多此一举,所以告诉系统不要再调用了。这一点应该和性能有关系。【如果不需要构造函数就不要执行构造函数,他们会带来性能上的开销】。

释放非托管资源可参看:

https://www.cnblogs.com/niaomingjian/p/3516083.html

using

定义一个范围,在范围结束时处理对象。
只要离开了这个代码段就自动调用这个类实例的Dispose

1
2
3
4
using (Class1 cls1 = new Class1(), cls2 = new Class1())
{
// the code using cls1, cls2
} // call the Dispose on cls1 and cls2

图片与Base64互转

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
using System;
using System.Drawing;
using System.IO;

namespace Z.Common
{
public class ZBase64Util
{
/// <summary>
/// base64 转 Image
/// </summary>
/// <param name="base64"></param>
public static void Base64ToImage(string base64, string filePath)
{
base64 = base64
.Replace("data:image/png;base64,", "")
.Replace("data:image/jgp;base64,", "")
.Replace("data:image/jpg;base64,", "")
.Replace("data:image/jpeg;base64,", "");//将base64头部信息替换
byte[] bytes = Convert.FromBase64String(base64);
MemoryStream memStream = new MemoryStream(bytes);
Image mImage = Image.FromStream(memStream);
Bitmap bp = new Bitmap(mImage);
bp.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);
}

/// <summary>
/// Image 转成 base64
/// </summary>
/// <param name="filePath"></param>
public static string ImageToBase64(string filePath)
{
string prefix = "data:image/jpeg;base64,";
try
{
Bitmap bmp = new Bitmap(filePath);
MemoryStream ms = new MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] arr = new byte[ms.Length]; ms.Position = 0;
ms.Read(arr, 0, (int)ms.Length); ms.Close();
return prefix + Convert.ToBase64String(arr);
}
catch (Exception)
{
return null;
}
}

/// <summary>
/// 图片转Base64
/// </summary>
/// <param name="bmp"></param>
/// <returns></returns>
public static string ImageToBase64(Bitmap bmp)
{
string prefix = "data:image/jpeg;base64,";
try
{
MemoryStream ms = new MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] arr = new byte[ms.Length]; ms.Position = 0;
ms.Read(arr, 0, (int)ms.Length); ms.Close();
return prefix + Convert.ToBase64String(arr);
}
catch (Exception)
{
return null;
}
}
}
}