GDI在全称是Graphics Device Interface
,即图形设备接口。是图形显示与实际物理设备之间的桥梁。
GDI接口是基于函数,虽然使程序员省力不少,但是编程方式依然显得麻烦。
例如显示一张位图,我们需要进行“创建位图,读取位图文件信息,启用场景设备,调色板变化“等一系列操作。然而有了GDI+,繁琐的步骤再次被简化。
顾名思义,GDI+就是GDI的增强版,它是微软在Windows 2000以后操作系统中提供的新接口。
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
不创建句柄
)。
当前位置
(全局区),目的是提高绘图性能;而GDI+取消了它,以避免绘图时不确定这个当前位置
而带来非预期的错误。
GDI+新特性
注意
GDI+对象比如Bitmap,是不会创建句柄的,GetHbitmap方法不是获取句柄而是创建句柄。不会受GDI句柄数量的限制。只有需要创建句柄进行其他操作时才要调用GetHbitmap创建句柄。
ApplicationContext, Brush, Component, ComponentDesigner, Container, Context, Cursor, FileStream, Font, Icon, Image, Matrix, Object, OdbcDataReader, OleDBDataReader, Pen, Regex, Socket, StreamWriter, Timer, Tooltip, 文件句柄, GDI资源, 数据库连接等等资源。
托管资源由垃圾回收器控制如何释放,不需要程序员过多的考虑(当然也程序员也可以自己释放)。
非托管资源需要自己编写代码来释放。
在一个包含非托管资源的类中,关于资源释放的标准做法是:
那么编写好的释放非托管资源的代码(释非代码)由谁来调用呢。
有两种实现方式:
代码如下
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
定义一个范围,在范围结束时处理对象。
只要离开了这个代码段就自动调用这个类实例的Dispose
。
using (Class1 cls1 = new Class1(), cls2 = new Class1())
{
// the code using cls1, cls2
} // call the Dispose on cls1 and cls2
继承关系
System.Object System.MarshalByRefObject System.Drawing.Image System.Drawing.Bitmap
Image
为源自 Bitmap 和 Metafile 的类提供功能的抽象基类。
// 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 是用于处理由像素数据定义的图像的对象。
Bitmap::SetPixel
和Bitmap::GetPixel
分别用来对位图进行读写像素操作,从而可以为图像的柔化和锐化处理提供一种可能。
示例
Image img = this.pictureBox1.Image;
Bitmap map = new Bitmap(img);
Bitmap的GetHbitmap()方法
此方法创建 GDI 位图对象的图柄。
官方示例方法
[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
namespace System.Windows.Controls
{
public class Image : FrameworkElement, IUriContext, IProvidePropertyFallback
{
public ImageSource Source { get; set; }
}
}
继承关系
ImageSource=>BitmapSource=>BitmapImage
ImageSource
ImageSource表示具有宽度、高度和 ImageMetadata 的对象类型,这是一个抽象类。
BitmapSource
BitmapSource 也是一个抽象类。
BitmapSource 是 Windows Presentation Foundation (WPF) 图像处理管道的基本构建基块,从概念上讲,以特定大小和分辨率指定一组固定的像素。 BitmapSource 可以是解码器提供的图像文件中的单个帧,也可以是操作自身 BitmapSource 的转换的结果。 BitmapSource 不用于表示多帧图像或动画。
BitmapImage
BitmapImage从图像文件创建位图,并将其用作 Image 控件的源
// 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;
主要作用为保存页面组件为图片
其中myview
为其它组件的名称
XAML
<Grid x:Name="myview">
<StackPanel>
<TextBlock Text="我的应用程序" FontSize="20" />
<TextBlock Text="点击截屏" FontSize="60" />
</StackPanel>
</Grid>
<!--该图片控件用于展示截图图片效果-->
<Image x:Name="img" />
C#
RenderTargetBitmap bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(myview);
// 把图片展现出来
img.Source = bitmap;
public class ImageConverter
{
[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;
}
/// <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;
}
/// <summary>
/// 从Icon到ImageSource的转换
/// </summary>
public ImageSource ChangeIconToImageSource(Icon icon)
{
ImageSource imageSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
return imageSource;
}
}
// Bitmap --> BitmapImage
public static BitmapImage BitmapToBitmapImage(Bitmap bitmap)
{
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Png); // 坑点:格式选Bmp时,不带透明度
stream.Position = 0;
BitmapImage result = new BitmapImage();
result.BeginInit();
// According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed."
// Force the bitmap to load right now so we can dispose the stream.
result.CacheOption = BitmapCacheOption.OnLoad;
result.StreamSource = stream;
result.EndInit();
result.Freeze();
return result;
}
}
// 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);
}
}
// 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[]
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;
}
}
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;
}
Bitmap img = ZScreenUtil.CaptureScreen();
保存
var filePath = "E:\123.jpg";
img.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);
img.Dispose();
保存设置压缩质量
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;
}
Bitmap=>BitmapSource=>写文件
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()
);
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保存为图片文件。
BitmapImage bImage = new BitmapImage(new Uri("c:\\image.bmp"));
image.Source = bImage;
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);
}
}
调用方式
SetSource(this.imageCur, “C:\1.png”);
获取图片
using System;
using System.Drawing;
using System.Windows.Forms;
namespace SchoolClient.Utils
{
internal class ZScreenUtil
{
/// <summary>
/// 截取屏幕
/// </summary>
/// <returns></returns>
public static Bitmap CaptureScreen()
{
int iw = Screen.PrimaryScreen.Bounds.Width;
int ih = Screen.PrimaryScreen.Bounds.Height;
float factor = Graphics.FromHwnd(IntPtr.Zero).DpiX / 96;
int imageW = Convert.ToInt32(factor * iw);
int imageH = Convert.ToInt32(factor * ih);
Bitmap postImage=null;
try
{
using(Bitmap bmp = new Bitmap(imageW, imageH)){
using (Graphics g = Graphics.FromImage(bmp))
{
g.CopyFromScreen(0, 0, 0, 0, new Size(imageW, imageH));
}
postImage = new Bitmap(bmp, 1280, 800);
}
return postImage;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return null;
}
}
}
}
保存图片
Bitmap img = ZScreenUtil.CaptureScreen();
var filePath = "E:\123.jpg";
img.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);
img.Dispose();
保存图片并压缩
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;
}