// COPYRIGHT (C) Tom. ALL RIGHTS RESERVED. // THE AntdUI PROJECT IS AN WINFORM LIBRARY LICENSED UNDER THE Apache-2.0 License. // LICENSED UNDER THE Apache License, VERSION 2.0 (THE "License") // YOU MAY NOT USE THIS FILE EXCEPT IN COMPLIANCE WITH THE License. // YOU MAY OBTAIN A COPY OF THE LICENSE AT // // http://www.apache.org/licenses/LICENSE-2.0 // // UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SOFTWARE // DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING PERMISSIONS AND // LIMITATIONS UNDER THE License. // GITEE: https://gitee.com/antdui/AntdUI // GITHUB: https://github.com/AntdUI/AntdUI // CSDN: https://blog.csdn.net/v_132 // QQ: 17379620 using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; namespace AntdUI { partial class Helper { #region 文本布局 /// /// 文本布局 /// /// 垂直(上下) /// 水平(前后) public static StringFormat SF(StringAlignment tb = StringAlignment.Center, StringAlignment lr = StringAlignment.Center) { return new StringFormat(StringFormat.GenericTypographic) { LineAlignment = tb, Alignment = lr }; } /// /// 文本布局(不换行) /// /// 垂直(上下) /// 水平(前后) public static StringFormat SF_NoWrap(StringAlignment tb = StringAlignment.Center, StringAlignment lr = StringAlignment.Center) { var sf = new StringFormat(StringFormat.GenericTypographic) { LineAlignment = tb, Alignment = lr }; sf.FormatFlags |= StringFormatFlags.NoWrap; return sf; } /// /// 文本布局(超出省略号) /// /// 垂直(上下) /// 水平(前后) public static StringFormat SF_Ellipsis(StringAlignment tb = StringAlignment.Center, StringAlignment lr = StringAlignment.Center) { return new StringFormat(StringFormat.GenericTypographic) { LineAlignment = tb, Alignment = lr, Trimming = StringTrimming.EllipsisCharacter }; } /// /// 文本布局(超出省略号+不换行) /// /// 垂直(上下) /// 水平(前后) public static StringFormat SF_ALL(StringAlignment tb = StringAlignment.Center, StringAlignment lr = StringAlignment.Center) { var sf = new StringFormat(StringFormat.GenericTypographic) { LineAlignment = tb, Alignment = lr, Trimming = StringTrimming.EllipsisCharacter }; sf.FormatFlags |= StringFormatFlags.NoWrap; return sf; } public static StringFormat SF_MEASURE_FONT() { var sf = new StringFormat(StringFormat.GenericTypographic) { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }; sf.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces; return sf; } #endregion /// /// 画刷(渐变色) /// /// 渐变代码H5 /// 区域 /// 默认颜色 public static Brush BrushEx(this string? code, Rectangle rect, Color def) { if (code != null) { var arr = code.Split(','); if (arr.Length > 1) { if (arr.Length > 2 && float.TryParse(arr[0], out float deg)) return new LinearGradientBrush(rect, arr[1].Trim().ToColor(), arr[2].Trim().ToColor(), 270 + deg); else return new LinearGradientBrush(rect, arr[0].Trim().ToColor(), arr[1].Trim().ToColor(), 270F); } } return new SolidBrush(def); } public static Graphics High(this Graphics g) { Config.SetDpi(g); g.SmoothingMode = SmoothingMode.AntiAlias; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = PixelOffsetMode.HighQuality; if (Config.TextRenderingHint.HasValue) g.TextRenderingHint = Config.TextRenderingHint.Value; return g; } public static Graphics HighLay(this Graphics g) { Config.SetDpi(g); g.SmoothingMode = SmoothingMode.AntiAlias; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; return g; } public static void GDI(Action action) { using (var bmp = new Bitmap(1, 1)) { using (var g = Graphics.FromImage(bmp)) { Config.SetDpi(g); action(g); } } } public static T GDI(Func action) { using (var bmp = new Bitmap(1, 1)) { using (var g = Graphics.FromImage(bmp)) { Config.SetDpi(g); return action(g); } } } public static SolidBrush Brush(this Color? color, Color default_color) { if (color.HasValue) return new SolidBrush(color.Value); return new SolidBrush(default_color); } public static SolidBrush Brush(this Color? color, Color default_color, Color enabled_color, bool enabled) { if (enabled) { if (color.HasValue) return new SolidBrush(color.Value); return new SolidBrush(default_color); } else return new SolidBrush(enabled_color); } #region 圆角 public static GraphicsPath RoundPath(this Rectangle rect, float radius) { return RoundPathCore(rect, radius); } public static GraphicsPath RoundPath(this RectangleF rect, float radius) { return RoundPathCore(rect, radius); } internal static GraphicsPath RoundPath(this RectangleF rect, float radius, TShape shape) { return RoundPath(rect, radius, shape == TShape.Round); } internal static GraphicsPath RoundPath(this Rectangle rect, float radius, bool round) { if (round) return CapsulePathCore(rect); return RoundPathCore(rect, radius); } internal static GraphicsPath RoundPath(this RectangleF rect, float radius, bool round) { if (round) return CapsulePathCore(rect); return RoundPathCore(rect, radius); } internal static GraphicsPath RoundPath(this Rectangle rect, float radius, TAlignMini shadowAlign) { switch (shadowAlign) { case TAlignMini.Top: return RoundPath(rect, radius, true, true, false, false); case TAlignMini.Bottom: return RoundPath(rect, radius, false, false, true, true); case TAlignMini.Left: return RoundPath(rect, radius, true, false, false, true); case TAlignMini.Right: return RoundPath(rect, radius, false, true, true, false); case TAlignMini.None: default: return RoundPathCore(rect, radius); } } /// /// 自定义圆角 /// /// 区域 /// 圆角大小 /// ↖ /// ↗ /// ↘ /// ↙ public static GraphicsPath RoundPath(this Rectangle rect, float radius, bool TL, bool TR, bool BR, bool BL) { var path = new GraphicsPath(); if (radius <= 0F) path.AddRectangle(rect); else { float diameter = radius * 2F; var arc = new RectangleF(rect.X, rect.Y, diameter, diameter); // TL if (TL) path.AddArc(arc, 180, 90); else path.AddLine(rect.X, rect.Y, rect.Right - diameter, rect.Y); // TR arc.X = rect.Right - diameter; if (TR) path.AddArc(arc, 270, 90); else path.AddLine(rect.Right, rect.Y, rect.Right, rect.Bottom - diameter); // BR arc.Y = rect.Bottom - diameter; if (BR) path.AddArc(arc, 0, 90); else path.AddLine(rect.Right, rect.Bottom, rect.X + diameter, rect.Bottom); // BL arc.X = rect.Left; if (BL) path.AddArc(arc, 90, 90); else path.AddLine(rect.X, rect.Bottom, rect.X, rect.Y + diameter); path.CloseFigure(); } return path; } /// /// 自定义圆角 /// /// 区域 /// 圆角大小 /// ↖ /// ↗ /// ↘ /// ↙ public static GraphicsPath RoundPath(this RectangleF rect, float radius, bool TL, bool TR, bool BR, bool BL) { var path = new GraphicsPath(); if (radius <= 0F) path.AddRectangle(rect); else { float diameter = radius * 2F; var arc = new RectangleF(rect.X, rect.Y, diameter, diameter); // TL if (TL) path.AddArc(arc, 180, 90); else path.AddLine(rect.X, rect.Y, rect.Right - diameter, rect.Y); // TR arc.X = rect.Right - diameter; if (TR) path.AddArc(arc, 270, 90); else path.AddLine(rect.Right, rect.Y, rect.Right, rect.Bottom - diameter); // BR arc.Y = rect.Bottom - diameter; if (BR) path.AddArc(arc, 0, 90); else path.AddLine(rect.Right, rect.Bottom, rect.X + diameter, rect.Bottom); // BL arc.X = rect.Left; if (BL) path.AddArc(arc, 90, 90); else path.AddLine(rect.X, rect.Bottom, rect.X, rect.Y + diameter); path.CloseFigure(); } return path; } static GraphicsPath RoundPathCore(RectangleF rect, float radius) { var path = new GraphicsPath(); if (radius > 0F) { if (radius >= (Math.Min(rect.Width, rect.Height) / 2F)) AddCapsule(path, rect); else { float diameter = radius * 2F; var arc = new RectangleF(rect.X, rect.Y, diameter, diameter); // TL path.AddArc(arc, 180, 90); // TR arc.X = rect.Right - diameter; path.AddArc(arc, 270, 90); // BR arc.Y = rect.Bottom - diameter; path.AddArc(arc, 0, 90); // BL arc.X = rect.Left; path.AddArc(arc, 90, 90); path.CloseFigure(); } } else path.AddRectangle(rect); return path; } static GraphicsPath CapsulePathCore(RectangleF rect) { var path = new GraphicsPath(); AddCapsule(path, rect); return path; } static void AddCapsule(GraphicsPath path, RectangleF rect) { float diameter; RectangleF arc; if (rect.Width > 0 && rect.Height > 0) { if (rect.Width > rect.Height) { // Horizontal capsule diameter = rect.Height; SizeF sizeF = new SizeF(diameter, diameter); arc = new RectangleF(rect.Location, sizeF); path.AddArc(arc, 90, 180); arc.X = rect.Right - diameter; path.AddArc(arc, 270, 180); } else if (rect.Width < rect.Height) { // Vertical capsule diameter = rect.Width; SizeF sizeF = new SizeF(diameter, diameter); arc = new RectangleF(rect.Location, sizeF); path.AddArc(arc, 180, 180); arc.Y = rect.Bottom - diameter; path.AddArc(arc, 0, 180); } else { // Circle path.AddEllipse(rect); } } else path.AddEllipse(rect); path.CloseFigure(); } #endregion #region 图片渲染 public static void PaintImg(this Graphics g, RectangleF rect, Image image, TFit fit, float radius, bool round) { if (round || radius > 0) { using (var bmp = new Bitmap((int)rect.Width, (int)rect.Height)) { using (var g2 = Graphics.FromImage(bmp).High()) { PaintImg(g2, new RectangleF(0, 0, rect.Width, rect.Height), image, fit); } using (var brush = new TextureBrush(bmp, WrapMode.Clamp)) { brush.TranslateTransform(rect.X, rect.Y); if (round) g.FillEllipse(brush, rect); else { using (var path = rect.RoundPath(radius)) { g.FillPath(brush, path); } } } } } else PaintImg(g, rect, image, fit); } public static void PaintImg(this Graphics g, RectangleF rect, Image image, TFit fit, float radius, TShape shape) { if (shape == TShape.Circle || shape == TShape.Round || radius > 0) { using (var bmp = new Bitmap((int)rect.Width, (int)rect.Height)) { using (var g2 = Graphics.FromImage(bmp).High()) { PaintImg(g2, new RectangleF(0, 0, rect.Width, rect.Height), image, fit); } using (var brush = new TextureBrush(bmp, WrapMode.Clamp)) { brush.TranslateTransform(rect.X, rect.Y); if (shape == TShape.Circle) g.FillEllipse(brush, rect); else { using (var path = rect.RoundPath(radius)) { g.FillPath(brush, path); } } } } } else PaintImg(g, rect, image, fit); } internal static void PaintImg(this Graphics g, RectangleF rect, Image image, TFit fit) { switch (fit) { case TFit.Fill: g.DrawImage(image, rect); break; case TFit.None: g.DrawImage(image, new RectangleF(rect.X + (rect.Width - image.Width) / 2, rect.Y + (rect.Height - image.Height) / 2, image.Width, image.Height)); break; case TFit.Contain: PaintImgContain(g, image, rect); break; case TFit.Cover: PaintImgCover(g, image, rect); break; } } internal static void PaintImgCover(this Graphics g, Image image, RectangleF rect) { float originWidth = image.Width, originHeight = image.Height; if (originWidth == originHeight) { if (rect.Width == rect.Height) g.DrawImage(image, rect); else if (rect.Width > rect.Height) g.DrawImage(image, new RectangleF(0, (rect.Height - rect.Width) / 2, rect.Width, rect.Width)); else g.DrawImage(image, new RectangleF((rect.Width - rect.Height) / 2, 0, rect.Height, rect.Height)); return; } float destWidth = rect.Width, destHeight = rect.Height; float currentWidth, currentHeight; if ((originWidth * destHeight) > (originHeight * destWidth)) { currentHeight = destHeight; currentWidth = (originWidth * destHeight) / originHeight; } else { currentWidth = destWidth; currentHeight = (destWidth * originHeight) / originWidth; } g.DrawImage(image, new RectangleF(rect.X + (destWidth - currentWidth) / 2, rect.Y + (destHeight - currentHeight) / 2, currentWidth, currentHeight), new RectangleF(0, 0, originWidth, originHeight), GraphicsUnit.Pixel); } internal static void PaintImgContain(this Graphics g, Image image, RectangleF rect) { float originWidth = image.Width, originHeight = image.Height; if (originWidth == originHeight) { if (rect.Width == rect.Height) g.DrawImage(image, rect); else if (rect.Width > rect.Height) g.DrawImage(image, new RectangleF((rect.Width - rect.Height) / 2, 0, rect.Height, rect.Height)); else g.DrawImage(image, new RectangleF(0, (rect.Height - rect.Width) / 2, rect.Width, rect.Width)); return; } float destWidth = rect.Width, destHeight = rect.Height; float currentWidth, currentHeight; if ((originWidth * destHeight) > (originHeight * destWidth)) { currentWidth = destWidth; currentHeight = (destWidth * originHeight) / originWidth; } else { currentHeight = destHeight; currentWidth = (originWidth * destHeight) / originHeight; } g.DrawImage(image, new RectangleF(rect.X + (destWidth - currentWidth) / 2, rect.Y + (destHeight - currentHeight) / 2, currentWidth, currentHeight), new RectangleF(0, 0, originWidth, originHeight), GraphicsUnit.Pixel); } #endregion #region 图标渲染 internal static void PaintIcons(this Graphics g, TType icon, Rectangle rect) { switch (icon) { case TType.Success: using (var bmp = SvgExtend.GetImgExtend(SvgDb.IcoSuccess, rect, Style.Db.Success)) { if (bmp == null) return; g.DrawImage(bmp, rect); } break; case TType.Info: using (var bmp = SvgExtend.GetImgExtend(SvgDb.IcoInfo, rect, Style.Db.Info)) { if (bmp == null) return; g.DrawImage(bmp, rect); } break; case TType.Warn: using (var bmp = SvgExtend.GetImgExtend(SvgDb.IcoWarn, rect, Style.Db.Warning)) { if (bmp == null) return; g.DrawImage(bmp, rect); } break; case TType.Error: using (var bmp = SvgExtend.GetImgExtend(SvgDb.IcoError, rect, Style.Db.Error)) { if (bmp == null) return; g.DrawImage(bmp, rect); } break; } } internal static void PaintIcons(this Graphics g, TType icon, Rectangle rect, Color back) { using (var brush = new SolidBrush(back)) { g.FillEllipse(brush, new Rectangle(rect.X + 1, rect.Y + 1, rect.Width - 2, rect.Height - 2)); } switch (icon) { case TType.Success: using (var bmp = SvgExtend.GetImgExtend(SvgDb.IcoSuccess, rect, Style.Db.Success)) { if (bmp == null) return; g.DrawImage(bmp, rect); } break; case TType.Info: using (var bmp = SvgExtend.GetImgExtend(SvgDb.IcoInfo, rect, Style.Db.Info)) { if (bmp == null) return; g.DrawImage(bmp, rect); } break; case TType.Warn: using (var bmp = SvgExtend.GetImgExtend(SvgDb.IcoWarn, rect, Style.Db.Warning)) { if (bmp == null) return; g.DrawImage(bmp, rect); } break; case TType.Error: using (var bmp = SvgExtend.GetImgExtend(SvgDb.IcoError, rect, Style.Db.Error)) { if (bmp == null) return; g.DrawImage(bmp, rect); } break; } } internal static void PaintIconGhosts(this Graphics g, TType icon, Rectangle rect, Color color) { switch (icon) { case TType.Success: using (var bmp = SvgExtend.GetImgExtend(SvgDb.IcoSuccessGhost, rect, color)) { if (bmp == null) return; g.DrawImage(bmp, rect); } break; case TType.Info: using (var bmp = SvgExtend.GetImgExtend(SvgDb.IcoInfoGhost, rect, color)) { if (bmp == null) return; g.DrawImage(bmp, rect); } break; case TType.Warn: using (var bmp = SvgExtend.GetImgExtend(SvgDb.IcoWarnGhost, rect, color)) { if (bmp == null) return; g.DrawImage(bmp, rect); } break; case TType.Error: using (var bmp = SvgExtend.GetImgExtend(SvgDb.IcoErrorGhost, rect, color)) { if (bmp == null) return; g.DrawImage(bmp, rect); } break; } } internal static void PaintIconClose(this Graphics g, Rectangle rect, Color color) { PaintIconCore(g, rect, SvgDb.IcoErrorGhost, color); } internal static void PaintIconClose(this Graphics g, Rectangle rect, Color color, float dot) { PaintIconCore(g, rect, SvgDb.IcoErrorGhost, color, dot); } /// /// 绘制带圆背景的镂空图标 /// internal static void PaintIconCoreGhost(this Graphics g, Rectangle rect, string svg, Color back, Color fore) { using (var brush = new SolidBrush(back)) { g.FillEllipse(brush, rect); } g.GetImgExtend(svg, rect, fore); } internal static void PaintIconCore(this Graphics g, Rectangle rect, string svg, Color back, Color fore) { using (var brush = new SolidBrush(back)) { g.FillEllipse(brush, new Rectangle(rect.X + 1, rect.Y + 1, rect.Width - 2, rect.Height - 2)); } g.GetImgExtend(svg, rect, fore); } internal static void PaintIconCore(this Graphics g, Rectangle rect, string svg, Color color) => g.GetImgExtend(svg, rect, color); internal static void PaintIconCore(this Graphics g, Rectangle rect, string svg, Color color, float dot) { int size = (int)(rect.Height * dot); var rect_ico = new Rectangle(rect.X + (rect.Width - size) / 2, rect.Y + (rect.Height - size) / 2, size, size); g.GetImgExtend(svg, rect_ico, color); } #endregion #region 图片透明度 public static void DrawImage(this Graphics g, Bitmap bmp, Rectangle rect, float opacity) { using (var attributes = new ImageAttributes()) { var matrix = new ColorMatrix { Matrix33 = opacity }; attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); g.DrawImage(bmp, rect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes); } } public static void DrawImage(this Graphics g, Image bmp, Rectangle rect, float opacity) { if (opacity >= 1F) { g.DrawImage(bmp, rect); return; } using (var attributes = new ImageAttributes()) { var matrix = new ColorMatrix { Matrix33 = opacity }; attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); g.DrawImage(bmp, rect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes); } } #endregion #region 阴影/徽标 #region 徽标 public static void PaintBadge(this IControl control, Graphics g) { control.PaintBadge(control.ReadRectangle, g); } public static void PaintBadge(this IControl control, RectangleF rect, Graphics g) { var color = control.BadgeBack ?? Style.Db.Error; if (control.Badge != null) { using (var brush_fore = new SolidBrush(Style.Db.ErrorColor)) { float borsize = 1F * Config.Dpi; using (var font = new Font(control.Font.FontFamily, control.Font.Size * control.BadgeSize)) { if (string.IsNullOrEmpty(control.Badge) || control.Badge == "" || control.Badge == " ") { var size = (int)Math.Floor(g.MeasureString(Config.NullText, font).Width / 2); var rect_badge = new RectangleF(rect.Right - size - control.BadgeOffsetX * Config.Dpi, control.BadgeOffsetY * Config.Dpi, size, size); using (var brush = new SolidBrush(color)) { if (control.BadgeMode) { float b2 = borsize * 2, rr = size * 0.2F, rr2 = rr * 2; g.FillEllipse(brush_fore, new RectangleF(rect_badge.X - borsize, rect_badge.Y - borsize, rect_badge.Width + b2, rect_badge.Height + b2)); using (var path = rect_badge.RoundPath(1, true)) { path.AddEllipse(new RectangleF(rect_badge.X + rr, rect_badge.Y + rr, rect_badge.Width - rr2, rect_badge.Height - rr2)); g.FillPath(brush, path); } } else { g.FillEllipse(brush, rect_badge); using (var pen = new Pen(brush_fore.Color, borsize)) { g.DrawEllipse(pen, rect_badge); } } } } else { using (var s_f = SF_NoWrap()) { var size = g.MeasureString(control.Badge, font); var size_badge = size.Height * 1.2F; if (size.Height > size.Width) { var rect_badge = new RectangleF(rect.Right - size_badge - control.BadgeOffsetX * Config.Dpi, control.BadgeOffsetY * Config.Dpi, size_badge, size_badge); using (var brush = new SolidBrush(color)) { g.FillEllipse(brush, rect_badge); using (var pen = new Pen(brush_fore.Color, borsize)) { g.DrawEllipse(pen, rect_badge); } } g.DrawStr(control.Badge, font, brush_fore, rect_badge, s_f); } else { var w_badge = size.Width * 1.2F; var rect_badge = new RectangleF(rect.Right - w_badge - control.BadgeOffsetX * Config.Dpi, control.BadgeOffsetY * Config.Dpi, w_badge, size_badge); using (var brush = new SolidBrush(color)) { using (var path = rect_badge.RoundPath(rect_badge.Height)) { g.FillPath(brush, path); using (var pen = new Pen(brush_fore.Color, borsize)) { g.DrawPath(pen, path); } } } g.DrawStr(control.Badge, font, brush_fore, rect_badge, s_f); } } } } } } } public static void PaintBadge(this IControl control, DateBadge badge, Font font, RectangleF rect, Graphics g) { var color = badge.Fill ?? control.BadgeBack ?? Style.Db.Error; using (var brush_fore = new SolidBrush(Style.Db.ErrorColor)) { float borsize = 1F * Config.Dpi; if (badge.Count == 0) { var rect_badge = new RectangleF(rect.Right - 10F, rect.Top + 2F, 8, 8); using (var brush = new SolidBrush(color)) { g.FillEllipse(brush, rect_badge); using (var pen = new Pen(brush_fore.Color, borsize)) { g.DrawEllipse(pen, rect_badge); } } } else { using (var s_f = SF_NoWrap()) { string countStr; if (badge.Count == 999) countStr = "999"; else if (badge.Count > 1000) countStr = (badge.Count / 1000).ToString().Substring(0, 1) + "K+"; else if (badge.Count > 99) countStr = "99+"; else countStr = badge.Count.ToString(); var size = g.MeasureString(countStr, font); var size_badge = size.Height * 1.2F; if (size.Height > size.Width) { var rect_badge = new RectangleF(rect.Right - size_badge + 6F, rect.Top - 8F, size_badge, size_badge); using (var brush = new SolidBrush(color)) { g.FillEllipse(brush, rect_badge); using (var pen = new Pen(brush_fore.Color, borsize)) { g.DrawEllipse(pen, rect_badge); } } g.DrawStr(countStr, font, brush_fore, rect_badge, s_f); } else { var w_badge = size.Width * 1.2F; var rect_badge = new RectangleF(rect.Right - w_badge + 6F, rect.Top - 8F, w_badge, size_badge); using (var brush = new SolidBrush(color)) { using (var path = rect_badge.RoundPath(rect_badge.Height)) { g.FillPath(brush, path); using (var pen = new Pen(brush_fore.Color, borsize)) { g.DrawPath(pen, path); } } } g.DrawStr(countStr, font, brush_fore, rect_badge, s_f); } } } } } #endregion public static void PaintShadow(this Graphics g, ShadowConfig config, Rectangle _rect, Rectangle rect, float radius, bool round) { int shadow = (int)(config.Shadow * Config.Dpi), shadowOffsetX = (int)(config.ShadowOffsetX * Config.Dpi), shadowOffsetY = (int)(config.ShadowOffsetY * Config.Dpi); using (var bmp_shadow = new Bitmap(_rect.Width, _rect.Height)) { using (var g_shadow = Graphics.FromImage(bmp_shadow)) { using (var path = RoundPath(rect, radius, round)) { using (var brush = config.ShadowColor.Brush(Style.Db.TextBase)) { g_shadow.FillPath(brush, path); } } Blur(bmp_shadow, shadow); } using (var attributes = new ImageAttributes()) { var matrix = new ColorMatrix { Matrix33 = config.ShadowOpacity }; attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); g.DrawImage(bmp_shadow, new Rectangle(_rect.X + shadowOffsetX, _rect.Y + shadowOffsetY, _rect.Width, _rect.Height), 0, 0, _rect.Width, _rect.Height, GraphicsUnit.Pixel, attributes); } } } #endregion #region 图像处理 #region 模糊 public static void Blur(Bitmap bmp, int range) { Blur(bmp, range, new Rectangle(0, 0, bmp.Width, bmp.Height)); } public static void Blur(Bitmap bmp, int range, Rectangle rect) { if (range > 1) { using (UnsafeBitmap unsafeBitmap = new UnsafeBitmap(bmp, true)) { BlurHorizontal(unsafeBitmap, range, rect); BlurVertical(unsafeBitmap, range, rect); BlurHorizontal(unsafeBitmap, range, rect); BlurVertical(unsafeBitmap, range, rect); } } } private static void BlurHorizontal(UnsafeBitmap unsafeBitmap, int range, Rectangle rect) { int left = rect.X; int top = rect.Y; int right = rect.Right; int bottom = rect.Bottom; int halfRange = range / 2; ColorBgra[] newColors = new ColorBgra[unsafeBitmap.Width]; for (int y = top; y < bottom; y++) { int hits = 0; int r = 0; int g = 0; int b = 0; int a = 0; for (int x = left - halfRange; x < right; x++) { int oldPixel = x - halfRange - 1; if (oldPixel >= left) { ColorBgra color = unsafeBitmap.GetPixel(oldPixel, y); if (color.Bgra != 0) { r -= color.Red; g -= color.Green; b -= color.Blue; a -= color.Alpha; } hits--; } int newPixel = x + halfRange; if (newPixel < right) { ColorBgra color = unsafeBitmap.GetPixel(newPixel, y); if (color.Bgra != 0) { r += color.Red; g += color.Green; b += color.Blue; a += color.Alpha; } hits++; } if (x >= left) { newColors[x] = new ColorBgra((byte)(b / hits), (byte)(g / hits), (byte)(r / hits), (byte)(a / hits)); } } for (int x = left; x < right; x++) { unsafeBitmap.SetPixel(x, y, newColors[x]); } } } private static void BlurVertical(UnsafeBitmap unsafeBitmap, int range, Rectangle rect) { int left = rect.X; int top = rect.Y; int right = rect.Right; int bottom = rect.Bottom; int halfRange = range / 2; ColorBgra[] newColors = new ColorBgra[unsafeBitmap.Height]; for (int x = left; x < right; x++) { int hits = 0; int r = 0; int g = 0; int b = 0; int a = 0; for (int y = top - halfRange; y < bottom; y++) { int oldPixel = y - halfRange - 1; if (oldPixel >= top) { ColorBgra color = unsafeBitmap.GetPixel(x, oldPixel); if (color.Bgra != 0) { r -= color.Red; g -= color.Green; b -= color.Blue; a -= color.Alpha; } hits--; } int newPixel = y + halfRange; if (newPixel < bottom) { ColorBgra color = unsafeBitmap.GetPixel(x, newPixel); if (color.Bgra != 0) { r += color.Red; g += color.Green; b += color.Blue; a += color.Alpha; } hits++; } if (y >= top) { newColors[y] = new ColorBgra((byte)(b / hits), (byte)(g / hits), (byte)(r / hits), (byte)(a / hits)); } } for (int y = top; y < bottom; y++) { unsafeBitmap.SetPixel(x, y, newColors[y]); } } } #endregion #region 阴影 public static Bitmap PaintShadow(this GraphicsPath path, int width, int height, int range = 10) { return PaintShadow(path, width, height, Color.Black, range); } public static Bitmap PaintShadow(this GraphicsPath path, int width, int height, Color color, int range = 10) { var bmp_shadow = new Bitmap(width, height); using (var g = Graphics.FromImage(bmp_shadow)) { using (var brush = new SolidBrush(color)) { g.FillPath(brush, path); } Blur(bmp_shadow, range); } return bmp_shadow; } #endregion #endregion } }