• 图片压缩之处理小图片压缩策略


    在进行图片压缩的时候。有时候会碰到要压缩的图片尺寸小于指定的压缩尺寸,若直接压缩会导致图片失真。

    当然。最好的方式是挑选合适尺寸图片进行上传。

    这里给出的方法是:对不足尺寸部分进行空白填充。

    详细參见下面代码

    using System;
    using System.Drawing.Drawing2D;
    using System.Drawing;
    using System.IO;
    using System.Drawing.Imaging;
    
    namespace CommonLib
    {
        public class ImageUtils
        {
    
            /// <summary>
            /// 创建缩略图像,缩略图是一个正方型的小图片
            /// </summary>
            /// <param name="thumbnilWidth">缩略图的宽度</param>
            /// <param name="inputFileName">原始图像文件名称</param>
            /// <param name="outputFileName">输出的所略图文件名称</param>
            public static void Thumbnil(int thumbnilWidth, string inputFileName, string outputFileName)
            {
    
                Image src = Image.FromFile(inputFileName);
                Image pThumbnail = Thumbnil(thumbnilWidth, src);
                pThumbnail.Save(outputFileName);
            }
    
            public static void Thumbnil(int thumbnilWidth, string inputFileName, string outputFileName, ImageFormat format)
            {
    
                Image src = Image.FromFile(inputFileName);
                Image pThumbnail = Thumbnil(thumbnilWidth, src);
                SaveImage(outputFileName, format, pThumbnail, (long)98);
    
            }
    
            /// <summary>
            /// 创建缩略图像,缩略图是一个正方型的小图片
            /// </summary>
            /// <param name="thumbnilWidth"></param>
            /// <param name="inputStream"></param>
            /// <param name="outputFileName"></param>
            /// <param name="format"></param>
            public static void Thumbnil(int thumbnilWidth, Stream inputStream, string outputFileName, ImageFormat format)
            {
                Image src = Image.FromStream(inputStream);
                Image pThumbnail = Thumbnil(thumbnilWidth, src);
                SaveImage(outputFileName, format, pThumbnail, (long)98);
            }
    
            /// <summary>
            /// 创建缩略图像,缩略图是一个正方型的小图片
            /// </summary>
            /// <param name="thumbnilWidth"></param>
            /// <param name="inputStream"></param>
            /// <param name="outputFileName"></param>
            public static void Thumbnil(int thumbnilWidth, Stream inputStream, string outputFileName)
            {
                Image src = Image.FromStream(inputStream);
                Image pThumbnail = Thumbnil(thumbnilWidth, src);
                pThumbnail.Save(outputFileName);
                src.Dispose();
                pThumbnail.Dispose();
            }
    
            /// <summary>
            /// 缩略图
            /// </summary>
            /// <param name="maxWidth">最大宽度</param>
            /// <param name="maxHeight">最大的高度</param>
            /// <param name="inputStream">图片流</param>
            /// <param name="outputFileName">输出路径</param>
            public static void Thumbnil(int maxWidth, int maxHeight, Stream inputStream, string outputFileName)
            {
                string fileDirectory = Path.GetDirectoryName(outputFileName);
                if (!Directory.Exists(fileDirectory))
                {
                    DirectoryInfo di = Directory.CreateDirectory(fileDirectory);//创建一个文件
                }
                System.Drawing.Image img = System.Drawing.Image.FromStream(inputStream);
                if (img.Width > maxWidth || img.Height > maxHeight)
                {
                    int pwidth = 0;
                    if (img.Height / maxHeight > img.Width / maxWidth)
                    {
                        pwidth = Convert.ToInt16(((decimal)img.Width) * maxHeight / img.Height);
                    }
                    else
                    {
                        pwidth = maxWidth;
                    }
                    Thumbnil(pwidth, inputStream, outputFileName);
                }
                else
                {
                    Thumbnil(img.Width, inputStream, outputFileName);
                }
                img.Dispose();
            }
    
            public static void Thumbnil(int thumbnilWidth, Stream inputStream, Stream outputStream, ImageFormat format)
            {
                Image src = Image.FromStream(inputStream);
                Image pThumbnail = Thumbnil(thumbnilWidth, src);
                SaveImage(outputStream, format, pThumbnail, (long)98);
            }
    
            public static Image Thumbnil(int thumbnilWidth, Image src)
            {
                int width_heigh = src.Width;
                if (src.Height < src.Width)
                    width_heigh = src.Height;
    
                RectangleF sourceRect = new RectangleF((src.Width - width_heigh) / 2,
                    (src.Height - width_heigh) / 2, width_heigh, width_heigh);
    
                RectangleF destinationRect = new RectangleF(0, 0, thumbnilWidth, thumbnilWidth);
                Image pThumbnail = new Bitmap(thumbnilWidth, thumbnilWidth);
                Graphics g = Graphics.FromImage(pThumbnail);
                g.InterpolationMode = InterpolationMode.High;
                g.DrawImage(src, destinationRect, sourceRect, GraphicsUnit.Pixel);
                return pThumbnail;
            }
    
            private static void SaveImage(string outputFileName, ImageFormat format, Image image)
            {
                SaveImage(outputFileName, format, image, (long)95);
            }
    
            private static void SaveImage(string outputFileName, ImageFormat format, Image image, long qualityValue)
            {
                if (format == ImageFormat.Jpeg)
                {
                    EncoderParameters ep = new EncoderParameters();
                    ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qualityValue);
    
                    ImageCodecInfo ici = null;
                    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
                    foreach (ImageCodecInfo codec in codecs)
                    {
                        if (codec.MimeType == "image/jpeg")
                        {
                            ici = codec;
                            break;
                        }
                    }
    
                    if (ici != null)
                        image.Save(outputFileName, ici, ep);
                    else
                        image.Save(outputFileName, format);
                }
                else
                    image.Save(outputFileName, format);
            }
    
            private static void SaveImage(Stream outputStream, ImageFormat format, Image image)
            {
                SaveImage(outputStream, format, image, (long)95);
            }
    
            private static void SaveImage(Stream outputStream, ImageFormat format, Image image, long qualityValue)
            {
                if (format == ImageFormat.Jpeg)
                {
                    EncoderParameters ep = new EncoderParameters();
                    ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qualityValue);
    
                    ImageCodecInfo ici = null;
                    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
                    foreach (ImageCodecInfo codec in codecs)
                    {
                        if (codec.MimeType == "image/jpeg")
                        {
                            ici = codec;
                            break;
                        }
                    }
    
                    if (ici != null)
                        image.Save(outputStream, ici, ep);
                    else
                        image.Save(outputStream, format);
                }
                else
                    image.Save(outputStream, format);
            }
    
            /// <summary>
            /// 按图片原始比例创建缩略图像
            /// </summary>
            public static void ScaleImage(int maxPixel, string inputFileName, string outputFileName, string waterMarkText, InterpolationMode interpolationMode, ImageFormat imageFormat)
            {
                Image src = Image.FromFile(inputFileName);
                int src_height = src.Height;
                int src_width = src.Width;
                int destW = maxPixel;
                int destH = maxPixel;
    
                double wh_Ratio = src_width * 1.0 / src_height * 1.0;
    
                if (src_height <= maxPixel && src_width <= maxPixel)
                {
                    File.Copy(inputFileName, outputFileName);
                    src.Dispose();
                    return;
                }
                else if (wh_Ratio <= 1)
                {
                    destW = (int)Math.Round(destH * wh_Ratio);
                    if (destW == 0)
                        destW = 1;
                }
                else if (wh_Ratio > 1)
                {
                    destH = (int)Math.Round(destW / wh_Ratio);
                    if (destH == 0)
                        destH = 1;
                }
    
                RectangleF sourceRect = new RectangleF(0, 0, src_width, src_height);
                RectangleF destinationRect = new RectangleF(0, 0, destW, destH);
    
                Image destImg = new Bitmap(destW, destH);
    
                Graphics g = Graphics.FromImage(destImg);
    
                if (interpolationMode == InterpolationMode.Bilinear)
                    interpolationMode = InterpolationMode.High;
    
                g.InterpolationMode = interpolationMode;
                g.DrawImage(src, destinationRect, sourceRect, GraphicsUnit.Pixel);
    
                #region 增加水印的算法
                //WaterMark(destImg, GetWaterMarkImage());
                WaterMarkText(destImg, waterMarkText);
                #endregion
    
                long qulityValue = 95;
                if (destW < 200 || destH < 200)
                    qulityValue = 98;
    
                //destImg.Save(outputFileName, imageFormat);
                SaveImage(outputFileName, imageFormat, destImg, qulityValue);
    
                destImg.Dispose();
                src.Dispose();
                g.Dispose();
                return;
            }
    
            /// <summary>
            /// 按图片原始比例创建缩略图像
            /// </summary>
            public static void ScaleImage(int maxPixel, Stream inputStream, string outputFileName, string waterMarkText, InterpolationMode interpolationMode, ImageFormat imageFormat)
            {
                Image src = Image.FromStream(inputStream);
                int src_height = src.Height;
                int src_width = src.Width;
                int destW = maxPixel;
                int destH = maxPixel;
    
                double wh_Ratio = src_width * 1.0 / src_height * 1.0;
    
                if (src_height <= maxPixel && src_width <= maxPixel)
                {
                    src.Save(outputFileName, imageFormat);
                    src.Dispose();
                    return;
                }
                else if (wh_Ratio <= 1)
                {
                    destW = (int)Math.Round(destH * wh_Ratio);
                }
                else if (wh_Ratio > 1)
                {
                    destH = (int)Math.Round(destW / wh_Ratio);
                }
    
                RectangleF sourceRect = new RectangleF(0, 0, src_width, src_height);
                RectangleF destinationRect = new RectangleF(0, 0, destW, destH);
    
                Image destImg = new Bitmap(destW, destH);
    
                Graphics g = Graphics.FromImage(destImg);
    
                if (interpolationMode == InterpolationMode.Bilinear)
                    interpolationMode = InterpolationMode.High;
    
                g.InterpolationMode = interpolationMode;
                g.DrawImage(src, destinationRect, sourceRect, GraphicsUnit.Pixel);
    
                #region 增加水印的算法
                //WaterMark(destImg, GetWaterMarkImage());
                WaterMarkText(destImg, waterMarkText);
                #endregion
    
                //默认处理。大图片就减少一些画质
                long qulityValue = 95;
                if (destW < 200 || destH < 200)
                    qulityValue = 98;
                //destImg.Save(outputFileName, imageFormat);
                SaveImage(outputFileName, imageFormat, destImg, qulityValue);
    
                destImg.Dispose();
                src.Dispose();
                g.Dispose();
                return;
            }
    
            /// <summary>
            /// 图片压缩
            /// </summary>
            /// <param name="maxWidth">最大宽度</param>
            /// <param name="maxHeight">最大高度</param>
            /// <param name="inputStream">图片流</param>
            /// <param name="outputFileName">输出路径</param>
            /// <param name="waterMarkText">水印文字</param>
            /// <param name="interpolationMode">生成格式</param>
            /// <param name="imageFormat">图片格式化</param>
            public static void ScaleImage(int maxWidth, int maxHeight, Stream inputStream, string outputFileName, string waterMarkText, InterpolationMode interpolationMode, ImageFormat imageFormat)
            {
                string fileDirectory = Path.GetDirectoryName(outputFileName);
                if (!Directory.Exists(fileDirectory))
                {
                    DirectoryInfo di = Directory.CreateDirectory(fileDirectory);//创建一个文件
                }
                System.Drawing.Image img = System.Drawing.Image.FromStream(inputStream);
                if (img.Width > 770 || img.Height > 560)
                {
                    int pwidth = 0;
                    if (img.Height / maxHeight > img.Width / maxWidth)
                    {
                        pwidth = Convert.ToInt16(((decimal)img.Width) * maxHeight / img.Height);
                    }
                    else
                    {
                        pwidth = maxWidth;
                    }
                    ScaleImage(pwidth, inputStream, outputFileName, waterMarkText, interpolationMode, imageFormat);
                }
                else
                {
                    ScaleImage(img.Width, inputStream, outputFileName, waterMarkText, interpolationMode, imageFormat);
                }
                img.Dispose();
            }
    
            public static void WaterMarkText(Image srcImg, string waterMarkText)
            {
                try
                {
                    if (string.IsNullOrEmpty(waterMarkText))
                        return;
    
                    if (srcImg.Width <= 100)
                        return;
    
                    int waterMarkWidth = srcImg.Width;
                    int waterMarkHeight = 20; //px;
    
                    WaterMarkText(srcImg, waterMarkText, 0, srcImg.Height - waterMarkHeight, waterMarkHeight, waterMarkWidth, new Font("微软雅黑", 12, GraphicsUnit.Pixel));
                }
                catch
                {
                    throw;
                }
    
            }
    
    
            public static void WaterMarkText(Image srcImg, string waterMarkText, int left, int top, int waterMarkHeight, int waterMarkWidth, Font font)
            {
                try
                {
    
                    Graphics g = Graphics.FromImage(srcImg);
    
                    Rectangle rect = new Rectangle(left, top, waterMarkWidth, waterMarkHeight);
    
                    //画半透明确色底色
                    Brush brush = new SolidBrush(Color.FromArgb(99, Color.White));
                    g.FillRectangle(brush, rect);
    
                    //画文字
                    rect.Width = rect.Width - 10;
                    rect.Y = rect.Y + 2;
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                    StringFormat sf = new StringFormat();
                    sf.Alignment = StringAlignment.Far;
                    g.DrawString(waterMarkText, font, Brushes.Black, rect, sf);
    
                    //存盘
                    g.Save();
                    #region 释放此函数创建的GDI+资源
                    brush.Dispose();
                    font.Dispose();
                    sf.Dispose();
    
                    g.Dispose();
                    #endregion
                }
                catch
                {
                    throw;
                }
    
            }
    
            private static void WaterMark(Image srcImg, Image waterMarkImage)
            {
                if (waterMarkImage == null)
                    return;
    
                if (waterMarkImage.Width > (srcImg.Width - 20))
                    return;
    
                if (waterMarkImage.Height > (srcImg.Height - 20))
                    return;
    
                //水印在右下角。距离边6px位置
                Rectangle rect = new Rectangle(0, 0, waterMarkImage.Width, waterMarkImage.Height);
    
                #region 生成一个暂时Image
                Image tempImage = new Bitmap(waterMarkImage.Width, waterMarkImage.Height);
    
                float[][] ptsArray ={ 
    				new float[] {1, 0, 0, 0, 0},
    				new float[] {0, 1, 0, 0, 0},
    				new float[] {0, 0, 1, 0, 0},
    				new float[] {0, 0, 0, 0.5f, 0}, //注意:此处为0.5f,图像为半透明
    				new float[] {0, 0, 0, 0, 1}};
    
                ColorMatrix clrMatrix = new ColorMatrix(ptsArray);
                Graphics tempGraphics = Graphics.FromImage(tempImage);
    
                //将原图的要被水印覆盖的位置copy到暂时Image
                Rectangle srcRect = new Rectangle(srcImg.Width - waterMarkImage.Width - 6, srcImg.Height - waterMarkImage.Height - 6,
                    waterMarkImage.Width, waterMarkImage.Height);
    
                tempGraphics.DrawImage(srcImg, rect, srcRect, GraphicsUnit.Pixel);
    
                ImageAttributes tempImgAttributes = new ImageAttributes();
                tempImgAttributes.SetColorMatrix(clrMatrix, ColorMatrixFlag.SkipGrays, ColorAdjustType.Bitmap);
    
                //将水印图片贴到暂时区,跳过gray颜色。

    白色也是一种gray。将是透明色 tempGraphics.DrawImage(waterMarkImage, rect, 0, 0, waterMarkImage.Width, waterMarkImage.Height, GraphicsUnit.Pixel, tempImgAttributes); tempGraphics.Save(); #endregion #region 将暂时Image以透明贴图的方式绘至原图 ImageAttributes imgAttributes = new ImageAttributes(); imgAttributes.SetColorKey(Color.White, Color.White); //绘图像 Graphics g = Graphics.FromImage(srcImg); //srcRect 是原图要覆盖的区域,此时作为目标区域 g.DrawImage(tempImage, srcRect, 0, 0, tempImage.Width, tempImage.Height, GraphicsUnit.Pixel, imgAttributes); g.Save(); #endregion #region 释放此函数创建的资源 g.Dispose(); tempGraphics.Dispose(); tempImage.Dispose(); #endregion } private static Image waterMarkImage = null; public static Image GetWaterMarkImage() { return waterMarkImage; } public static void SetWaterMarkImage(Image image) { waterMarkImage = image; } } /// <summary> /// 图片处理:缩略图片 /// </summary> public class ImageDealLib { /// <summary> /// 图片保存类型 /// JPEG:.jpg格式; /// GIF:.gif格式; /// PNG:.png格式; /// </summary> public enum ImageType { JPEG, GIF, PNG } /// <summary> /// 水印模式 /// Center:中间; /// CenterUp:中上; /// CenterDown:中下; /// LeftUp:左上; /// LeftDown:左下; /// RightUp:右上; /// RightDown:右下; /// Random:随机; /// </summary> public enum WaterType { Center, CenterUp, CenterDown, LeftUp, LeftDown, RightUp, RightDown, Random } /// <summary> /// 缩略模式 /// X--按宽度缩放,高着宽比例; /// Y--按高度缩放,宽着宽比例; /// XY--按给定mwidth,mheight(此模式mwidth,mheight为必须值)进行缩略; /// </summary> public enum ResizeType { X, Y, XY } /// <summary> /// 文件检測模式 /// M:不检測文件是否存在,返回ServerMapPath; /// C:检測文件是否存在,返回ServerMapPath; /// </summary> public enum FileCheckModel { M, C } /// <summary> /// 原图文件是否保存 /// Delete:保存 /// Save:不保存,删除 /// </summary> public enum FileCache { Save, Delete } /// <summary> /// 依据指定:缩略宽、高,缩略图片并保存 /// 返回图片虚拟路径,和一个警告信息,可依据此信息获取图片合成信息 /// </summary> /// <param name="picpath">原图路径</param> /// <param name="model">缩略模式[X,Y,XY](默认XY模式)</param> /// <param name="spath">文件保存路径(默认跟路径)</param> /// <param name="imgtype">图片保存类型</param> /// <param name="mwidth">缩略宽度(默认原图高度)</param> /// <param name="mheight">缩略高度(默认原图高度)</param> /// <param name="filecache">原文件处理方式</param> /// <param name="warning">处理警告信息</param> /// <returns>错误,返回错误信息;成功,返回图片路径</returns> public static string Resizepic(double? mwidth, double?

    mheight, string picpath, string spath, ResizeType model, ImageType imgtype, FileCache filecache, out string warning) { //反馈信息 System.Text.StringBuilder checkmessage = new System.Text.StringBuilder(); //原图路径 if (string.IsNullOrWhiteSpace(picpath)) { checkmessage.Append("请输入原图路径。"); warning = checkmessage.ToString().TrimEnd(';'); return string.Empty; } //文件保存路径 if (string.IsNullOrWhiteSpace(spath)) { checkmessage.Append("请输入保存路径。"); warning = checkmessage.ToString().TrimEnd(';'); return string.Empty; } else { string fileDirectory = Path.GetDirectoryName(spath); if (!Directory.Exists(fileDirectory)) { DirectoryInfo di = Directory.CreateDirectory(fileDirectory);//创建一个文件 } } //缩略宽度 double swidth = mwidth.HasValue ?

    double.Parse(mwidth.ToString()) : 0; //缩略高度 double sheight = mheight.HasValue ? double.Parse(mheight.ToString()) : 0; //从指定源图片,创建image对象 string _sourceimg_common_mappath = ""; //检測源文件 bool checkfile = false; checkfile = System.IO.File.Exists(picpath);//FileExistMapPath(picpath, FileCheckModel.C, out _sourceimg_common_mappath); System.Drawing.Image _sourceimg_common = null; System.Drawing.Bitmap _currimg_common = null; System.Drawing.Graphics _g_common = null; if (checkfile) { //从源文件创建imgage _sourceimg_common = System.Drawing.Image.FromFile(picpath); #region 缩略模式 //缩略模式 switch (model) { case ResizeType.X: #region X模式 //依据给定尺寸,获取绘制比例 double _width_scale = swidth / _sourceimg_common.Width; //高着比例 sheight = _sourceimg_common.Height * _width_scale; #endregion ; break; case ResizeType.Y: #region Y模式 //依据给定尺寸,获取绘制比例 double _height_scale = sheight / _sourceimg_common.Height; //宽着比例 swidth = _sourceimg_common.Width * _height_scale; #endregion ; break; case ResizeType.XY: #region XY模式 //当选择XY模式时,mwidth,mheight为必须值 if (swidth < 0 || sheight < 0) { checkmessage.Append("error:XY模式,mwidth,mheight为必须值;"); } #endregion ; break; default: #region 默认XY模式 //当默认XY模式时,mwidth,mheight为必须值 if (swidth < 0 || sheight < 0) { checkmessage.Append("error:你当前未选择缩略模式,系统默认XY模式,mwidth,mheight为必须值;"); } ; break; #endregion } #endregion } else { checkmessage.Append("error:未能找到缩略原图片," + picpath + ";"); } if (string.IsNullOrEmpty(checkmessage.ToString())) { //创建bitmap对象 _currimg_common = new System.Drawing.Bitmap((int)swidth, (int)sheight); _g_common = Graphics.FromImage(_currimg_common); //画半透明确色底色 Brush brush = new SolidBrush(Color.FromArgb(99, Color.White)); _g_common.FillRectangle(brush, 0, 0, (float)swidth, (float)sheight); //设置画笔 _g_common.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver; _g_common.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; _g_common.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; int left = Math.Max(0, ((int)swidth - _sourceimg_common.Width) / 2);//图片左距离 int top = Math.Max(0, ((int)sheight - _sourceimg_common.Height) / 2);//图片上距离 int des_width = (int)swidth; int des_height = (int)sheight; int s_width = _sourceimg_common.Width; int s_height = _sourceimg_common.Height; if (des_width < s_width) { des_width = s_width; } if (des_height < s_height) { des_height = s_height; } //绘制图片 _g_common.DrawImage(_sourceimg_common, new Rectangle(left, top, Math.Min(_sourceimg_common.Width, (int)swidth), Math.Min(_sourceimg_common.Height, (int)sheight)), new Rectangle(0, 0, _sourceimg_common.Width, _sourceimg_common.Height), GraphicsUnit.Pixel); //保存图片 string _spath_common_mappath = ""; //获取图片类型的hashcode值,生成图片后缀名 int extro = imgtype.GetHashCode(); string extend = extro == 0 ? ".jpg" : (extro == 1 ?

    ".gif" : (extro == 2 ?

    ".png" : ".jpg")); //全局文件名称 // spath = spath + Guid.NewGuid().ToString() + extend; // FileExistMapPath(spath, FileCheckModel.M, out _spath_common_mappath); switch (imgtype) { case ImageType.JPEG: _currimg_common.Save(spath, System.Drawing.Imaging.ImageFormat.Jpeg); break; case ImageType.GIF: _currimg_common.Save(spath, System.Drawing.Imaging.ImageFormat.Gif); break; case ImageType.PNG: _currimg_common.Save(spath, System.Drawing.Imaging.ImageFormat.Png); break; } //释放 _sourceimg_common.Dispose(); _currimg_common.Dispose(); _g_common.Dispose(); //处理原文件 int filecachecode = filecache.GetHashCode(); //文件缓存方式:Delete,删除原文件 if (filecachecode == 1) { System.IO.File.Delete(picpath); } //返回相对虚拟路径 warning = ""; return spath; } //释放 if (_sourceimg_common != null) { _sourceimg_common.Dispose(); } if (_currimg_common != null) { _currimg_common.Dispose(); } if (_g_common != null) { _g_common.Dispose(); } warning = checkmessage.ToString().TrimEnd(';'); return ""; } } }


    调用实例:

     ImageDealLib.Resizepic(
                            480,
                            480,
                            goodPicPath,
                            thumbPath,
                            CommonLib.ImageDealLib.ResizeType.X,
                            CommonLib.ImageDealLib.ImageType.JPEG,
                            CommonLib.ImageDealLib.FileCache.Save,
                            out warning);


     

  • 相关阅读:
    [Angualr 2] Watch for changes
    [Angular 2] Custom Validtors
    [Angular 2] The form export from NgFormControl
    [Angular 2] Validation
    [Angualr 2] Using FormBuilder
    [Angular 2] ng-control & ng-control-group
    [Angular 2] NgNonBindable
    [Ruby] LEVEL 2 Methods and Classes
    [Rails Level 2] Ground up
    [AngularJS] 5 simple ways to speed up your AngularJS application
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/6814205.html
Copyright © 2020-2023  润新知