C# 类CSS3盒阴影实现/算法

C# 类CSS3盒阴影实现/算法,c#,.net,gdi+,dropshadow,C#,.net,Gdi+,Dropshadow,我正在寻找或尝试实现一种算法来绘制方框阴影(如CSS 3规范中所述),该算法接受以下参数: 水平偏移 垂直偏移 插图 散布 模糊 颜色 (可选:不透明度) 从哪里开始 我已经寻找了Firefox/Chrome的源代码,看看我是否可以从那里得到一个实现,没有这样的运气 我研究过线性梯度算法,用方框画,这种方法很有效,除了圆形矩形,它在阴影中留下空像素,可能是因为边缘的半径 我正在用GDI+在.NET中执行此操作。我的目标不是为图像创建阴影。我已经看过这方面的文章了。我想为用GDI+绘制的形状创

我正在寻找或尝试实现一种算法来绘制方框阴影(如CSS 3规范中所述),该算法接受以下参数:

  • 水平偏移
  • 垂直偏移
  • 插图
  • 散布
  • 模糊
  • 颜色
  • (可选:不透明度)
从哪里开始

我已经寻找了Firefox/Chrome的源代码,看看我是否可以从那里得到一个实现,没有这样的运气

我研究过线性梯度算法,用方框画,这种方法很有效,除了圆形矩形,它在阴影中留下空像素,可能是因为边缘的半径

我正在用GDI+在.NET中执行此操作。我的目标不是为图像创建阴影。我已经看过这方面的文章了。我想为用GDI+绘制的形状创建阴影


感谢您的帮助

我为您编写了一个DropShadowPanel,用于处理其中的控件,并根据控件标记的要求添加阴影(外部或内部)

正如您在图像控件中所看到的,这些控件按照定义获取其阴影:

标签:

文本框:DropShadow:5,5,10,000000,noinset

日历:DropShadow:10,10,80,30,#0000FF,noinset

图片框左上角:DropShadow:-50,20,50,10,8888,noinset

图片框左下:DropShadow:10,10,20,20,#442200,插图

图片框右下:DropShadow:0,0,50,50,#442200,noinset

以下是面板的代码: (在绘制到控件gdi对象之前,它将中间图形用于图像,以避免表单爬行-这实际上运行得非常快)

使用系统;
使用System.Collections.Generic;
使用系统图;
使用System.Drawing.Drawing2D;
使用System.Linq;
使用系统文本;
使用System.Windows.Forms;
命名空间Windows窗体应用程序4
{
公共类DropShadowPanel:面板
{
已添加受保护的覆盖无效OnControlAdded(ControlEventArgs e)
{
e、 Control.Paint+=新的PaintEventHandler(Control\u Paint);
添加的碱基(e);
}
无效控件\u绘制(对象发送器,PaintEventArgs e)
{
CheckDrawInnerShadow(发送方作为控件,例如图形);
}
私有void CheckDrawInnerShadow(控制发送器,图形g)
{
var dropShadowStruct=GetDropShadowStruct(发送方);
if(dropShadowStruct==null | |!dropShadowStruct.Inset)
{
返回;
}
DrawInsetShadow(发送方作为控件,g);
}
受保护的覆盖无效OnControlRemoved(ControlEventArgs e)
{
e、 Control.Paint-=新的PaintEventHandler(Control\u Paint);
}
受保护的覆盖无效OnPaint(PaintEventArgs e)
{
基础漆(e);
DrawShadow(Controls.OfType(),其中(c=>c.Tag!=null&&c.Tag.ToString().StartsWith(“DropShadow”)),例如Graphics);
}
void DrawInsertShadow(控件,图形g)
{
var dropShadowStruct=GetDropShadowStruct(控制);
var rInner=新矩形(Point.Empty,control.Size);
var img=新位图(rInner.Width,rInner.Height,g);
var g2=图形。来自图像(img);
g2.CompositingMode=CompositingMode.SourceCopy;
g2.FillRectangle(新的SolidBrush(dropShadowStruct.Color),0,0,control.Width,control.Height);
rInner.Offset(dropShadowStruct.HShadow、dropShadowStruct.VShadow);
充气(dropShadowStruct.Blur,dropShadowStruct.Blur);
充气(-dropShadowStruct.Spread,-dropShadowStruct.Spread);
双模糊大小=dropShadowStruct.Blur;
双模糊开始大小=模糊大小;
做
{
var transparency=blurSize/blurStartSize;
var color=color.FromArgb(((int)(255*(透明度*透明度))),dropShadowStruct.color);
充气(-1,-1);
DrawRoundedRectangle(g2,rInner,(int)blurSize,钢笔。透明,彩色);
模糊尺寸--;
}而(模糊度>0);
g、 绘图图像(img,0,0);
g、 冲洗();
g2.Dispose();
img.Dispose();
}
void DrawShadow(IEnumerable控件,图形g)
{
foreach(控件中的var控件)
{
var dropShadowStruct=GetDropShadowStruct(控制);
if(dropShadowStruct.Inset)
{
continue;//必须由控件本身处理
}
DrawOutsetShadow(g,dropShadowStruct,control);
}
}
//由于速度原因,在图像上绘制循环
私有void DrawOutsetShadow(图形g、动态dropShadowStruct、控件)
{
var路由器=control.Bounds;
var rInner=control.Bounds;
rInner.Offset(dropShadowStruct.HShadow、dropShadowStruct.VShadow);
充气(-dropShadowStruct.Blur,-dropShadowStruct.Blur);
路由器。充气(dropShadowStruct.Spread,dropShadowStruct.Spread);
rOuter.Offset(dropShadowStruct.HShadow、dropShadowStruct.VShadow);
var originalOuter=路由器;
var img=新位图(originalOuter.Width,originalOuter.Height,g);
var g2=图形。来自图像(img);
var currentBlur=0;
做
{
变量透明度=(rOuter.Height-rInner.Height)/(double)(dropShadowStruct.Blur*2+dropShadowStruct.Spread*2);
var color=color.FromArgb(((int)(255*(透明度*透明度))),dropShadowStruct.color);
var-rOutput=rInner;
线路输出偏移量(-originalOuter.Left,-originalOuter.Top);
DrawRoundedRectangle(g2、rOutput、currentBlur、Pens.透明、彩色);
充气(1,1);
currentBlur=(int)((双精度)dropShadowStruct.Blur*(1-(透明度*透明度));
}while(rOuter.Contains(rInner));
g2.Flush();
g2.Dispose();
g、 DrawImage(img,origina
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{
    public class DropShadowPanel : Panel
    {
        protected override void OnControlAdded(ControlEventArgs e)
        {
            e.Control.Paint += new PaintEventHandler(Control_Paint);
            base.OnControlAdded(e);
        }

    void Control_Paint(object sender, PaintEventArgs e)
    {
        CheckDrawInnerShadow(sender as Control, e.Graphics);
    }

    private void CheckDrawInnerShadow(Control sender, Graphics g)
    {
        var dropShadowStruct = GetDropShadowStruct(sender);

        if (dropShadowStruct == null || !dropShadowStruct.Inset)
        {
            return;
        }

        DrawInsetShadow(sender as Control, g);

    }

    protected override void  OnControlRemoved(ControlEventArgs e)
    {
        e.Control.Paint -= new PaintEventHandler(Control_Paint);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        DrawShadow(Controls.OfType<Control>().Where(c => c.Tag != null && c.Tag.ToString().StartsWith("DropShadow")), e.Graphics);
    }

    void DrawInsetShadow(Control control, Graphics g)
    {
        var dropShadowStruct = GetDropShadowStruct(control);

        var rInner = new Rectangle(Point.Empty, control.Size);

        var img = new Bitmap(rInner.Width, rInner.Height, g);
        var g2 = Graphics.FromImage(img);

        g2.CompositingMode = CompositingMode.SourceCopy;
        g2.FillRectangle(new SolidBrush(dropShadowStruct.Color), 0, 0, control.Width, control.Height);

        rInner.Offset(dropShadowStruct.HShadow, dropShadowStruct.VShadow);
        rInner.Inflate(dropShadowStruct.Blur, dropShadowStruct.Blur);
        rInner.Inflate(-dropShadowStruct.Spread, -dropShadowStruct.Spread);

        double blurSize = dropShadowStruct.Blur;
        double blurStartSize = blurSize;

        do
        {
            var transparency = blurSize/blurStartSize;
            var color = Color.FromArgb(((int)(255 * (transparency * transparency))), dropShadowStruct.Color);               
            rInner.Inflate(-1,-1);
            DrawRoundedRectangle(g2, rInner, (int)blurSize, Pens.Transparent, color);
            blurSize--;
        } while (blurSize > 0);

        g.DrawImage(img, 0, 0);
        g.Flush();

        g2.Dispose();
        img.Dispose();
    }

    void DrawShadow(IEnumerable<Control> controls, Graphics g)
    {
        foreach (var control in controls)
        {
            var dropShadowStruct = GetDropShadowStruct(control);

            if (dropShadowStruct.Inset)
            {
                continue; // must be handled by the control itself
            }

            DrawOutsetShadow(g, dropShadowStruct, control);
        }
    }

    // drawing the loop on an image because of speed
    private void DrawOutsetShadow(Graphics g, dynamic dropShadowStruct, Control control)
    {
        var rOuter = control.Bounds;
        var rInner = control.Bounds;
        rInner.Offset(dropShadowStruct.HShadow, dropShadowStruct.VShadow);
        rInner.Inflate(-dropShadowStruct.Blur, -dropShadowStruct.Blur);
        rOuter.Inflate(dropShadowStruct.Spread, dropShadowStruct.Spread);
        rOuter.Offset(dropShadowStruct.HShadow, dropShadowStruct.VShadow);
        var originalOuter = rOuter;

        var img = new Bitmap(originalOuter.Width, originalOuter.Height, g);
        var g2 = Graphics.FromImage(img);

        var currentBlur = 0;

        do
        {
            var transparency = (rOuter.Height - rInner.Height)/(double) (dropShadowStruct.Blur*2 + dropShadowStruct.Spread*2);
            var color = Color.FromArgb(((int)(255 * (transparency * transparency))), dropShadowStruct.Color);
            var rOutput = rInner;
            rOutput.Offset(-originalOuter.Left, -originalOuter.Top);
            DrawRoundedRectangle(g2, rOutput, currentBlur, Pens.Transparent, color);
            rInner.Inflate(1, 1);
            currentBlur = (int) ((double) dropShadowStruct.Blur*(1 - (transparency*transparency)));
        } while (rOuter.Contains(rInner));

        g2.Flush();
        g2.Dispose();

        g.DrawImage(img, originalOuter);

        img.Dispose();
    }

    private static dynamic GetDropShadowStruct(Control control)
    {
        if (control.Tag == null || !(control.Tag is string) || !control.Tag.ToString().StartsWith("DropShadow"))
            return null;

        string[] dropShadowParams = control.Tag.ToString().Split(':')[1].Split(',');
        var dropShadowStruct = new
                                {
                                    HShadow = Convert.ToInt32(dropShadowParams[0]),
                                    VShadow = Convert.ToInt32(dropShadowParams[1]),
                                    Blur = Convert.ToInt32(dropShadowParams[2]),
                                    Spread = Convert.ToInt32(dropShadowParams[3]),
                                    Color = ColorTranslator.FromHtml(dropShadowParams[4]),
                                    Inset = dropShadowParams[5].ToLowerInvariant() == "inset"
                                };
        return dropShadowStruct;
    }

    private void DrawRoundedRectangle(Graphics gfx, Rectangle bounds, int cornerRadius, Pen drawPen, Color fillColor)
    {
        int strokeOffset = Convert.ToInt32(Math.Ceiling(drawPen.Width));
        bounds = Rectangle.Inflate(bounds, -strokeOffset, -strokeOffset);

        var gfxPath = new GraphicsPath();
        if (cornerRadius > 0)
        {
            gfxPath.AddArc(bounds.X, bounds.Y, cornerRadius, cornerRadius, 180, 90);
            gfxPath.AddArc(bounds.X + bounds.Width - cornerRadius, bounds.Y, cornerRadius, cornerRadius, 270, 90);
            gfxPath.AddArc(bounds.X + bounds.Width - cornerRadius, bounds.Y + bounds.Height - cornerRadius, cornerRadius,
                           cornerRadius, 0, 90);
            gfxPath.AddArc(bounds.X, bounds.Y + bounds.Height - cornerRadius, cornerRadius, cornerRadius, 90, 90);
        }
        else
        {
            gfxPath.AddRectangle(bounds);
        }
        gfxPath.CloseAllFigures();

        gfx.FillPath(new SolidBrush(fillColor), gfxPath);
        if (drawPen != Pens.Transparent)
        {
            var pen = new Pen(drawPen.Color);
            pen.EndCap = pen.StartCap = LineCap.Round;
            gfx.DrawPath(pen, gfxPath);
        }
    }
    }
}