1. 程式人生 > 實用技巧 >ImageSharp一個專注於NetCore平臺影象處理的開源專案

ImageSharp一個專注於NetCore平臺影象處理的開源專案

ImageSharp:

專注於NetCore平臺影象處理的開源專案,這個專案在影象處理方面有很多功能,如:縮放,裁剪,繪畫,組合圖片等;今天主要講的是用她怎麼來繪圖和生成驗證碼的實際例子。

  • 簡單介紹ImageSharp
  • 試試畫兩條線(實線和虛線)
  • 生成個縮圖
  • 在圖片上畫字
  • 製作一個驗證碼圖片
  • 結合RazorPage模板,展示驗證碼圖片

ImageSharp的git專案地址:https://github.com/SixLabors/ImageSharp。如果您的專案和我一樣是2.0版本(2.0以前的略過),那麼直接可以通過vs的nuget控制檯下載對應的包,注意繪圖的話需要分別下載如下兩個包:

Install-Package SixLabors.ImageSharp -Version1.0.0-beta0001

Install-Package SixLabors.ImageSharp.Drawing -Version1.0.0-beta0001

畫線

            //畫線
            using (Image<Rgba32> image = new Image<Rgba32>(500, 500))   //畫布大小
            {
                //畫實線
                image.Mutate(x => x.BackgroundColor(Color.HotPink).DrawLines(
                            Color.Black, 
//字型顏色 5, //字型大小 new PointF[]{ new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) } //兩點一線座標 ) );
//畫虛線 image.Mutate(x => x.BackgroundColor(Color.HotPink).DrawLines( Pens.Dash(Color.Black, 5), //虛線 new PointF[]{ new Vector2(10, 10), new Vector2(200, 200), new Vector2(350, 350) } //兩點一線座標 ) ); image.Save($"bar1.jpg"); //儲存 }

畫字:

//畫字,將C:\Windows\Fonts目錄下的ttf檔案拷貝到專案根目錄
            var install_Family = new FontCollection().Install(
                System.IO.Path.Combine(Directory.GetCurrentDirectory(), "ebrima.ttf"));
            var font = new Font(install_Family, 50);  //字型
            using (Image image = Image.Load($"bar.jpg"))
            {
                image.Mutate(x => x
                     .DrawText(
                        "fanfan",   //文字內容
                         font,
                         Color.HotPink,
                         new Vector2(50, 150))
                     );
                image.Save($"bar2.png");
            }

縮圖:

IImageFormat format;
            using (Image image = Image.Load(@"bar.jpg", out format))
            {
                image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2));
                image.Save($"bar.{format.FileExtensions.First()}");
            }

長寬畫素是原來一半

圖片裁剪:

製作一個驗證碼圖片

下面我們將用她來畫一個驗證碼型別的圖片,通常驗證碼都有一些點和線來干擾,上面已經有畫線例子了,這裡展示怎麼畫點:

//畫點(規則的點,其他的各位自行寫演算法) 
            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("我是神牛");returnPage();能得到如圖驗證碼圖片的效果:

文字看起來好像在點的前面,不過沒關係只需要把畫點和畫字的先後順序修改下就行了,這裡不貼圖了;

結合RazorPage模板,展示驗證碼圖片

上面一節是生成了驗證碼圖片,當然實際場景中我們是不需要生成驗證碼物理圖片的,只需要返回一個流或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,然後得到如圖效果:

轉:https://www.cnblogs.com/wangrudong003/p/7656842.html