今天你們分享的是一個專一於NetCore平臺圖像處理的開源項目,老實說爲這篇文章取名字想了5分鐘,多是詞窮亦或是想更好的表達出這款開源項目的做用;這個項目在圖像處理方面有不少功能,如:縮放,裁剪,繪畫,組合圖片等;今天主要講的是用她怎麼來繪圖和生成驗證碼的實際例子。前端
ImageSharp是對NetCore平臺擴展的一個圖像處理方案,在寫下本文爲止它最新的nuget下載量爲4,034次,做者團隊最近一個月剛更新的包;沒錯這裏說最新是由於她前身和以前的版本都很受歡迎下載量也超高;她的git項目地址:https://github.com/SixLabors/ImageSharp。若是您的項目和我同樣是2.0版本(2.0之前的略過),那麼直接能夠經過vs的nuget控制檯下載對應的包,注意繪圖的話須要分別下載以下兩個包:linux
Install-Package SixLabors.ImageSharp -Version 1.0.0-beta0001 git
Install-Package SixLabors.ImageSharp.Drawing -Version 1.0.0-beta0001 github
ImageSharp用法有朋友以前寫過,不過都主要針對於以前的版本,本章主要用到的都是最新的,有部分寫法可能不相同。web
這裏將用她來畫兩條直線並保存成圖片,主要起到一個介紹做用,先來看實線以下代碼:算法
var path = @"D:\F\學習\vs2017\netcore\Study.AspNetCore\WebApp02-1\wwwroot\images"; //默認實線 using (Image<Rgba32> image = new Image<Rgba32>(500, 500)) //畫布大小 { image.Mutate(x => x. BackgroundColor(Rgba32.WhiteSmoke). //畫布背景 DrawLines( Rgba32.HotPink, //字體顏色 5, //字體大小 new SixLabors.Primitives.PointF[]{ new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) } //兩點一線座標 ) ); image.Save($"{path}/1.png"); //保存 }
總要步驟我都備註上文字了,這裏主要經過兩點一線來繪製圖形,Vector2對象值得注意就是C#二維座標(x,y)對象,其實除了Vector2還有Vector3(三維座標)等,這對於作u3d的朋友來講不會陌生,老實說這個也是我在接觸u3d時候才知道有這個類的。下面來看效果圖:windows
由兩個兩點一線構造的一個角,下面來看下虛線繪製:數組
//虛線 using (Image<Rgba32> image = new Image<Rgba32>(500, 500)) //畫布大小 { image.Mutate(x => x. BackgroundColor(Rgba32.WhiteSmoke). //畫布背景 DrawLines( Pens.Dash(Rgba32.HotPink, 5), //字體大小 new SixLabors.Primitives.PointF[]{ new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) } //兩點一線座標 ) ); image.Save($"{path}/2.png"); //保存 }
步驟都差很少,只是調用了DrawLines的擴展方法而已,其餘線條例子就很少說了各位自行實驗。dom
對於圖片類型的網站來講縮略圖是常見的,這裏用ImageSharp生成縮略圖很簡單,本實例用8.png作樣原本生成縮略圖8-1.png,直接看例子以下是netstandard 1.3+的例子:ide
//縮略圖 using (Image<Rgba32> image = Image.Load($"{path}/8.png")) { image.Mutate(x => x .Resize(image.Width / 2, image.Height / 2) ); image.Save($"{path}/8-1.png"); }
爲了更好的對比縮略圖和原圖的區別這裏對接拿兩圖的屬性作對好比:
能很好的看出縮略圖文件大小和像素都減半了,實際縮略的時候不必定減半,這全由參數控制Resize(width,height);
畫字:在圖片上畫咱們想要的字,其實相似於水印的一種需求,下面是在圖片上畫字的代碼:
//畫字 var install_Family = new FontCollection().Install( System.IO.Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/bak", "STKAITI.TTF") //@"C:\Windows\Fonts\STKAITI.TTF" //字體文件 ); var font = new Font(install_Family, 50); //字體 using (Image<Rgba32> image = Image.Load($"{path}/8.png")) { image.Mutate(x => x .DrawText( "大家好,我是神牛", //文字內容 font, Rgba32.HotPink, new Vector2(50, 150), TextGraphicsOptions.Default) ); image.Save($"{path}/8-2.png"); }
這裏用ImageSharp在圖片上畫字的時候須要注意:字體,由於windows系統自帶了字體問題這裏以STKAITI.TTF字體文件爲例,它存儲於 C:\Windows\Fonts\STKAITI.TTF 目錄,固然您能夠直接把它拷貝到咱們項目中以下我這裏的例子同樣作法(這裏只測試了windows下可用,還沒有測試linux下直接使用該字體文件是否可行);
下面咱們將用她來畫一個驗證碼類型的圖片,一般驗證碼都有一些點和線來干擾,上面已經有畫線例子了,這裏展現怎麼畫點:
//畫點(規則的點,其餘的各位自行寫算法) var dianWith = 1; //點寬度 var xx = 300; //圖片寬度 var yy = 200; //圖片高度 var xx_space = 10; //點與點之間x座標間隔 var yy_space = 5; //y座標間隔 var listPath = new List<IPath>(); for (int i = 0; i < xx / xx_space; i++) { for (int j = 0; j < yy / yy_space; j++) { var position = new Vector2(i * xx_space, j * yy_space); var linerLine = new LinearLineSegment(position, position); var shapesPath = new SixLabors.Shapes.Path(linerLine); listPath.Add(shapesPath); } } using (Image<Rgba32> image = new Image<Rgba32>(xx, yy)) //畫布大小 { image.Mutate(x => x. BackgroundColor(Rgba32.WhiteSmoke). //畫布背景 Draw( Pens.Dot(Rgba32.HotPink, dianWith), //大小 new SixLabors.Shapes.PathCollection(listPath) //座標集合 ) ); image.Save($"{path}/9.png"); //保存 }
這裏直接利用IImageProcessingContext<TPixel>擴展方法Draw來繪製有規則的點,如圖所示:
比較單調,或許您們能作的更好看些;下面來作驗證碼圖片,主要由:畫點+畫字=驗證碼圖片,這裏我封裝了一個方法直接生成驗證碼圖片:
/// <summary> /// 畫點+畫字=驗證碼圖片 /// </summary> /// <param name="content">驗證碼</param> /// <param name="outImgPath">輸出圖片路徑</param> /// <param name="fontFilePath">字體文件</param> /// <param name="x">圖片寬度</param> /// <param name="y">圖片高度</param> public void GetValidCode( string content = "我是神牛", string outImgPath = "D:/F/學習/vs2017/netcore/Study.AspNetCore/WebApp02-1/wwwroot/images/10.png", string fontFilePath = @"D:\F\學習\vs2017\netcore\Study.AspNetCore\WebApp02-1\wwwroot\bak\STKAITI.TTF", int xx = 150, int yy = 25) { var dianWith = 1; //點寬度 var xx_space = 10; //點與點之間x座標間隔 var yy_space = 5; //y座標間隔 var wenZiLen = content.Length; //文字長度 var maxX = xx / wenZiLen; //每一個文字最大x寬度 var prevWenZiX = 0; //前面一個文字的x座標 var size = 16;//字體大小 //字體 var install_Family = new FontCollection().Install( fontFilePath //@"C:\Windows\Fonts\STKAITI.TTF" //windows系統下字體文件 ); var font = new Font(install_Family, size); //字體 //點座標 var listPath = new List<IPath>(); for (int i = 0; i < xx / xx_space; i++) { for (int j = 0; j < yy / yy_space; j++) { var position = new Vector2(i * xx_space, j * yy_space); var linerLine = new LinearLineSegment(position, position); var shapesPath = new SixLabors.Shapes.Path(linerLine); listPath.Add(shapesPath); } } //畫圖 using (Image<Rgba32> image = new Image<Rgba32>(xx, yy)) //畫布大小 { image.Mutate(x => { //畫點 var imgProc = x.BackgroundColor(Rgba32.WhiteSmoke). //畫布背景 Draw( Pens.Dot(Rgba32.HotPink, dianWith), //大小 new SixLabors.Shapes.PathCollection(listPath) //座標集合 ); //逐個畫字 for (int i = 0; i < wenZiLen; i++) { //當前的要輸出的字 var nowWenZi = content.Substring(i, 1); //文字座標 var wenXY = new Vector2(); var maxXX = prevWenZiX + (maxX - size); wenXY.X = new Random().Next(prevWenZiX, maxXX); wenXY.Y = new Random().Next(0, yy - size); prevWenZiX = Convert.ToInt32(Math.Floor(wenXY.X)) + size; //畫字 imgProc.DrawText( nowWenZi, //文字內容 font, i % 2 > 0 ? Rgba32.HotPink : Rgba32.Red, wenXY, TextGraphicsOptions.Default); } }); //保存到圖片 image.Save(outImgPath); } }
經過簡單的調用 GetValidCode("我是神牛");return Page(); 能獲得如圖驗證碼圖片的效果:
文字看起來好像在點的前面,不過不要緊只須要把畫點和畫字的前後順序修改下就好了,這裏不貼圖了;
上面一節是生成了驗證碼圖片,固然實際場景中咱們是不須要生成驗證碼物理圖片的,只須要返回一個流或base64等方式輸出到web界面上就好了,咱們能夠來看看 Image<TPixel> 保存時候的擴展方法:
// // 摘要: // Saves the image to the given stream using the currently loaded image format. // // 參數: // source: // The source image // // filePath: // The file path to save the image to. // // 類型參數: // TPixel: // The Pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static void Save<TPixel>(this Image<TPixel> source, string filePath) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the image to the given stream using the currently loaded image format. // // 參數: // source: // The source image // // filePath: // The file path to save the image to. // // encoder: // The encoder to save the image with. // // 類型參數: // TPixel: // The Pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the encoder is null. public static void Save<TPixel>(this Image<TPixel> source, string filePath, IImageEncoder encoder) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the image to the given stream using the currently loaded image format. // // 參數: // source: // The source image // // stream: // The stream to save the image to. // // format: // The format to save the image to. // // 類型參數: // TPixel: // The Pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static void Save<TPixel>(this Image<TPixel> source, Stream stream, IImageFormat format) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the image to the given stream with the bmp format. // // 參數: // source: // The image this method extends. // // stream: // The stream to save the image to. // // 類型參數: // TPixel: // The pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static void SaveAsBmp<TPixel>(this Image<TPixel> source, Stream stream) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the image to the given stream with the bmp format. // // 參數: // source: // The image this method extends. // // stream: // The stream to save the image to. // // encoder: // The encoder to save the image with. // // 類型參數: // TPixel: // The pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static void SaveAsBmp<TPixel>(this Image<TPixel> source, Stream stream, BmpEncoder encoder) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the image to the given stream with the gif format. // // 參數: // source: // The image this method extends. // // stream: // The stream to save the image to. // // encoder: // The options for the encoder. // // 類型參數: // TPixel: // The pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static void SaveAsGif<TPixel>(this Image<TPixel> source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the image to the given stream with the gif format. // // 參數: // source: // The image this method extends. // // stream: // The stream to save the image to. // // 類型參數: // TPixel: // The pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static void SaveAsGif<TPixel>(this Image<TPixel> source, Stream stream) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the image to the given stream with the jpeg format. // // 參數: // source: // The image this method extends. // // stream: // The stream to save the image to. // // encoder: // The options for the encoder. // // 類型參數: // TPixel: // The pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static void SaveAsJpeg<TPixel>(this Image<TPixel> source, Stream stream, JpegEncoder encoder) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the image to the given stream with the jpeg format. // // 參數: // source: // The image this method extends. // // stream: // The stream to save the image to. // // 類型參數: // TPixel: // The pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static void SaveAsJpeg<TPixel>(this Image<TPixel> source, Stream stream) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the image to the given stream with the png format. // // 參數: // source: // The image this method extends. // // stream: // The stream to save the image to. // // 類型參數: // TPixel: // The pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static void SaveAsPng<TPixel>(this Image<TPixel> source, Stream stream) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the image to the given stream with the png format. // // 參數: // source: // The image this method extends. // // stream: // The stream to save the image to. // // encoder: // The options for the encoder. // // 類型參數: // TPixel: // The pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static void SaveAsPng<TPixel>(this Image<TPixel> source, Stream stream, PngEncoder encoder) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the raw image to the given bytes. // // 參數: // source: // The source image // // buffer: // The buffer to save the raw pixel data to. // // 類型參數: // TPixel: // The Pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static void SavePixelData<TPixel>(this ImageFrame<TPixel> source, byte[] buffer) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the raw image to the given bytes. // // 參數: // source: // The source image // // 類型參數: // TPixel: // The Pixel format. // // 返回結果: // A copy of the pixel data as bytes from this frame. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static byte[] SavePixelData<TPixel>(this ImageFrame<TPixel> source) where TPixel : struct, IPixel<TPixel>; // // 摘要: // Saves the raw image to the given bytes. // // 參數: // source: // The source image // // buffer: // The buffer to save the raw pixel data to. // // 類型參數: // TPixel: // The Pixel format. // // 異常: // T:System.ArgumentNullException: // Thrown if the stream is null. public static void SavePixelData<TPixel>(this Image<TPixel> source, byte[] buffer) where TPixel : struct, IPixel<TPixel>;
好吧有點多,咱們只須要明白她能轉base64,stream,保存爲圖片等就好了;這裏咱們將用到 SaveAsPng(Stream) 方法,而後獲取他的byte[],以下代碼:
/// <summary> /// 畫點+畫字=驗證碼byte[] /// </summary> /// <param name="content">驗證碼</param> /// <param name="outImgPath">輸出圖片路徑</param> /// <param name="fontFilePath">字體文件</param> /// <param name="x">圖片寬度</param> /// <param name="y">圖片高度</param> public byte[] GetValidCodeByte( string content = "我是神牛", string fontFilePath = @"D:\F\學習\vs2017\netcore\Study.AspNetCore\WebApp02-1\wwwroot\bak\STKAITI.TTF", int xx = 150, int yy = 25) { var bb = default(byte[]); try { var dianWith = 1; //點寬度 var xx_space = 10; //點與點之間x座標間隔 var yy_space = 5; //y座標間隔 var wenZiLen = content.Length; //文字長度 var maxX = xx / wenZiLen; //每一個文字最大x寬度 var prevWenZiX = 0; //前面一個文字的x座標 var size = 16;//字體大小 //字體 var install_Family = new FontCollection().Install( fontFilePath //@"C:\Windows\Fonts\STKAITI.TTF" //windows系統下字體文件 ); var font = new Font(install_Family, size); //字體 //點座標 var listPath = new List<IPath>(); for (int i = 0; i < xx / xx_space; i++) { for (int j = 0; j < yy / yy_space; j++) { var position = new Vector2(i * xx_space, j * yy_space); var linerLine = new LinearLineSegment(position, position); var shapesPath = new SixLabors.Shapes.Path(linerLine); listPath.Add(shapesPath); } } //畫圖 using (Image<Rgba32> image = new Image<Rgba32>(xx, yy)) //畫布大小 { image.Mutate(x => { var imgProc = x; //逐個畫字 for (int i = 0; i < wenZiLen; i++) { //當前的要輸出的字 var nowWenZi = content.Substring(i, 1); //文字座標 var wenXY = new Vector2(); var maxXX = prevWenZiX + (maxX - size); wenXY.X = new Random().Next(prevWenZiX, maxXX); wenXY.Y = new Random().Next(0, yy - size); prevWenZiX = Convert.ToInt32(Math.Floor(wenXY.X)) + size; //畫字 imgProc.DrawText( nowWenZi, //文字內容 font, i % 2 > 0 ? Rgba32.HotPink : Rgba32.Red, wenXY, TextGraphicsOptions.Default); } //畫點 imgProc.BackgroundColor(Rgba32.WhiteSmoke). //畫布背景 Draw( Pens.Dot(Rgba32.HotPink, dianWith), //大小 new SixLabors.Shapes.PathCollection(listPath) //座標集合 ); }); using (MemoryStream stream = new MemoryStream()) { image.SaveAsPng(stream); bb = stream.GetBuffer(); } } } catch (Exception ex) { } return bb; }
該方法返回了一個byte[]數組,而後經過HttpGet方式請求Razor接口,前端就可以獲取到這個驗證碼圖片byte[]了;
/// <summary> /// Get獲取驗證碼圖片byte[] /// </summary> /// <returns></returns> public FileResult OnGetValidCode() { var codebb = GetValidCodeByte(DateTime.Now.ToString("mmssfff")); return File(codebb, "image/png"); }
咱們經過get請求獲取驗證碼: http://localhost:1120/login?handler=ValidCode ,而後獲得如圖效果:
本篇內容到此就結束了,若是對您有好的幫助,不妨點個「贊」;一塊兒努力推進NetCore發展吧,謝謝。