图片相关类 常见的类 关系
Image和Bitmap 继承关系
System.Object System.MarshalByRefObject System.Drawing.Image System.Drawing.Bitmap
Image
为源自 Bitmap 和 Metafile 的类提供功能的抽象基类。
1 2 3 4 5 6 Image newImage = Image.FromFile("SampImag.jpg" ); Point ulCorner = new Point(100 , 100 ); e.Graphics.DrawImage(newImage, ulCorner);
Bitmap
封装 GDI+ 位图,此位图由图形图像及其属性的像素数据组成。
Bitmap 是用于处理由像素数据定义的图像的对象。
位图由图形图像及其属性的像素数据组成。
有许多标准格式可用于将位图保存到文件。
GDI+ 支持以下文件格式: BMP、GIF、EXIF、JPG、PNG 和 TIFF。
有关支持的格式的详细信息,请参阅位图类型 。
您可以通过使用 Bitmap 构造函数之一,从文件、流和其他源创建图像,并使用 Save 方法将它们保存到流或文件系统。
使用 Graphics 对象的 DrawImage 方法将图像绘制到屏幕或内存。
Bitmap是从Image类继承的一个图像类,它封装了Windows位图操作的常用功能。
例如:Bitmap::SetPixel和Bitmap::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(); 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 Image simpleImage = new Image(); simpleImage.Width = 200 ; simpleImage.Margin = new Thickness(5 ); BitmapImage bi = new BitmapImage(); bi.BeginInit(); bi.UriSource = new Uri(@"/sampleImages/cherries_larger.jpg" ,UriKind.RelativeOrAbsolute); bi.EndInit(); 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都是用于表示位图的类,但是两者有不同的用途和区别:
目标渲染位图(RenderTargetBitmap)是一个用于创建位图的WPF元素,它可以在屏幕上渲染一个WPF视觉对象,并将其转换为位图。它通常用于将WPF视觉元素转换为图片,如截图等操作。
位图图像(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 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; } } 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 ) ;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 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 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 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()); 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 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; } public static BitmapImage ByteArrayToBitmapImage (byte [] array ){ using (var ms = new System.IO.MemoryStream(array)) { var image = new BitmapImage(); image.BeginInit(); image.CacheOption = BitmapCacheOption.OnLoad; 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; } 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() ); 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 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); } } 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 ){ int width = (int )element.ActualWidth; int height = (int )element.ActualHeight; RenderTargetBitmap bitmap = new RenderTargetBitmap ( width, height, 96 , 96 , PixelFormats.Pbgra32 ); bitmap.Render(element); 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 ){ int width = (int )element.ActualWidth; int height = (int )element.ActualHeight; RenderTargetBitmap bitmap = new RenderTargetBitmap ( width, height, 96 , 96 , PixelFormats.Pbgra32 ); bitmap.Render(element); 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; } 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 { 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); } } 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); } } public static Image ZipImage (Image img, ImageFormat format, long targetLen, long srcLen = 0 ) { const long nearlyLen = 10240 ; var ms = new MemoryStream(); if (0 == srcLen) { img.Save(ms, format); srcLen = ms.Length; } 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; } var newQuality = (startQuality + endQuality) / 2 ; if (newQuality == quality) { break ; } quality = newQuality; } img = Image.FromStream(ms); return img; } 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; } } 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; } 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; } } 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; } 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 { 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); } } } 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" )) { float ratio = 1.0f * Height / maxHeight; Width = (int )(1.0 d * Width / ratio); Height = (int )(1.0 d * 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 { try { FileInfo fi = new FileInfo(tempFilePath); if (fi.Exists) { fi.MoveTo(targetPath); } } catch (Exception) { } } } } public static Bitmap PicScale (string sourcePath, int targetWidth, int targetHeight ) { Bitmap bitmp = null ; using (Image sourceImage = Image.FromFile(sourcePath)) { using (Bitmap bitmap = new Bitmap(targetWidth, targetHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { using (Graphics graphics = Graphics.FromImage(bitmap)) { graphics.DrawImage(sourceImage, new Rectangle(0 , 0 , targetWidth, targetHeight)); } bitmp = new Bitmap(bitmap); } } return bitmp; } public static void PicDel (string sourcePath ) { try { FileInfo di = new FileInfo(sourcePath); if (di.Exists) { di.Delete(); } } catch (Exception e) { Console.WriteLine(e.Message); } } public static void PicCompress (Bitmap bitmap, string targetPath, long quality ) { using (Stream destStream = new FileStream(targetPath, FileMode.Create)) { ImageCodecInfo myImageCodecInfo; EncoderParameters myEncoderParameters; 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(); } } 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(); } } 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 ; } 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); } } 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; } 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+主要提供以下三种功能:
二维矢量图形:GDI+提供了存储图形基元自身信息的类(或结构体)、存储图形基元绘制方式信息的类以及实际进行绘制的类;
图像处理:大多数图片都难以划定为直线和曲线的集合,无法使用二维矢量图形方式进行处理。因此,GDI+为我们提供了Bitmap、Image等类,它们可用于显示、操作和保存BMP、JPG、GIF等图像格式。
文字显示: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+2.0比GDI+更快。
GDI是有状态的,而GDI+是无状态的。
GDI绘图要使用设备环境和句柄;而GDI+全部交由Graphics类管理(不创建句柄)。
GDI绘图时可以使用SelectObject频繁切换图形对象,而GDI+的图形对象是独立的。
GDI中存在一个当前位置(全局区),目的是提高绘图性能;而GDI+取消了它,以避免绘图时不确定这个当前位置而带来非预期的错误。
GDI总是将画笔和画刷绑定在一起,即使不需要填充一个区域也必须指定一个画刷;而GDI+则可以使用不同的函数分开使用画笔和画刷。
GDI+新特性
改进了颜色管理。GDI+不仅提供了更多可供选择使用的颜色,使其支持Alpha通道合成运算,而且还保持了与其他颜色的兼容性。
绘图支持反锯齿。通过设置GDI+对象的相关属性,GDI+可以与相关的显示驱动程序搭配完成图形绘制时的反锯齿功能,使得绘制的图形更加平滑,美观,而整个过程是由GDI+对象自动计算完成的。
提供渐变画刷。GDI+拓展了GDI的功能,提供线性渐变和路径渐变画刷来填充图形、路径和区域,甚至也可用来绘制直线、曲线等。
独立的路径对象。GDI+使用Graphics对象来进行绘图操作,并将路径操作从Graphics对象分离出来,提供一个Graphics类供用户使用,用户不必担心对象会受到Graphics对象操作的影响,从而可以使用同一个操作对象进行多次的路径绘制操作。
样条曲线。GDI+封装了绘制基数样条曲线和贝塞尔样条曲线的方法。
变形和矩阵运算。GDI+提供了功能强大的Matrix类来实现矩阵的旋转,错切、平移、比例等变换操作,以便产生复杂的新图形。
多图片格式的支持。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资源, 数据库连接等等资源。
非托管资源的释放 托管资源由垃圾回收器控制如何释放,不需要程序员过多的考虑(当然也程序员也可以自己释放)。
非托管资源需要自己编写代码来释放。
在一个包含非托管资源的类中,关于资源释放的标准做法是:
继承IDisposable接口;
实现Dispose()方法,在其中释放托管资源和非托管资源,并将对象本身从垃圾回收器中移除(垃圾回收器不在回收此资源);
实现类析构函数,在其中释放非托管资源。
那么编写好的释放非托管资源的代码(释非代码)由谁来调用呢。
有两种实现方式:
将释非代码放到构造函数析构函数中,由系统自动调用,系统会在资源对象不再使用了,会在某个时间调用构造函数析构函数来释放非托管资源。构造函数析构函数的目的就是用来释放或清理非托管资源的。但它有一个问题是调用的时间是系统说了算,不能在程序中自己想要调用时调用析构函数,这是C#规定的。那么就产生了第二种方式。
将释非代码放到另外一个函数中,当自己想调用时就调用。将释非代码放在一个方法中共用。
代码如下
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()){ }
图片与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 { 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," , "" ); 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); } 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 ; } } 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 ; } } } }