2012-10-16 96 views
4

我要尋找或試圖實現的算法得出盒陰影(如CSS 3 specifiction),它接受下列參數:CSS3樣箱陰影執行/算法

  • 水平偏移
  • 垂直偏移
  • 插圖
  • 傳播
  • 模糊
  • 顏色
  • (可選:不透明度)。

從哪裏開始。

我特地爲Firefox/Chrome的源代碼,看看我是否可以從那裏拉的實現,沒有這樣的運氣!

我已經看過成線性漸變的算法,一個盒子,它留下何種作品,除與圓角矩形的陰影空像素,這可能是由於邊緣的半徑畫他們。

我在.NET中使用GDI +這樣做。我的目標不是爲圖像創建陰影。我已經看到有關這方面的文章。我想爲使用GDI +繪製的形狀創建陰影。

任何幫助表示讚賞!

+0

*「...我的目的不是爲圖像創建陰影,我已經看到了有關這個的文章...」我也在尋找那些,並且發現很少,其中很不好,你能告訴我你在這個主題上找到了哪些文章嗎? –

+1

@UweKeim,我沒有在文章或實現方面找到太多東西,但是我修改了下面選擇的答案以適合我的需要。工作也很好。 – series0ne

回答

11

我編碼你來處理在其內部的控制,並增加了所要求的控制的Tag的陰影(外或內)一個DropShadowPanel。

正如您可以在圖像控件看得到他們的身影定義爲:

標籤:

文本框:陰影效果:5,5,5,10,#000000,noinset

日曆:陰影效果:10,10,80,30,#0000FF,noinset

PictureBox的左上角:陰影效果:-50,20,50,10,#888888,noinset

圖片框左下:陰影效果:10,10,20,20,#442200,插圖

PictureBox的右下:陰影效果:0,0,50,50,#442200,noinset

enter image description here

下面是面板的代碼: (它使用中間附圖成的圖像繪製到控制GDI對象之前,不使所述形式爬行 - 這實際工作相當快)

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); 
     } 
    } 
    } 
} 

代碼寫得很快,沒有太多的回顧,所以可能會有錯誤,尤其是如果你在控件上設置wring標籤)。

PS。您可能會注意到內部陰影對某些控件不起作用。這是因爲它們是Windows系統控件的包裝。面板本身無法克服這一點,但你可以這樣做:http://www.codeproject.com/Articles/4548/Generating-missing-Paint-event-for-TreeView-and-Li

+2

謝謝!這對我有很大的幫助! :-) – series0ne

+0

剛創建[一個代碼的Pastebin](http://pastebin.com/25ATLXGj),以便更容易複製。 –

+0

偉大的工作,它可以適用於Winforms以外的解決方案,只需最小的調整。 – Dested