Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/269.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在DrawingContext上绘制时在图像上绘制阴影_C#_.net_Wpf - Fatal编程技术网

C# 在DrawingContext上绘制时在图像上绘制阴影

C# 在DrawingContext上绘制时在图像上绘制阴影,c#,.net,wpf,C#,.net,Wpf,我在自定义FrameworkElement的OnRender方法中绘制图像。我想画一个阴影,这个形象以及。我需要在代码中这样做,我不想使用DropShadowBitmapEffect,因为它已经过时了。我怎样才能做到这一点 public class MyDrawingView : FrameworkElement { protected override void OnRender(System.Windows.Media.DrawingContext dc)

我在自定义FrameworkElement的OnRender方法中绘制图像。我想画一个阴影,这个形象以及。我需要在代码中这样做,我不想使用DropShadowBitmapEffect,因为它已经过时了。我怎样才能做到这一点

    public class MyDrawingView : FrameworkElement
    {
        protected override void OnRender(System.Windows.Media.DrawingContext dc)
        {
             drawImagesOnDrawingContext(dc);
        }

        public RenderTargetBitmap getBitmap()
        {
            DrawingVisual dv = new DrawingVisual();
            using (DrawingContext dcMine = dv.RenderOpen())
            {
                drawImagesOnDrawingContext(dcMine);
                dcMine.Close();
            }
            RenderTargetBitmap rtb = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32);
            rtb.Render(dv);
            return rtb;
        }

        private void drawImagesOnDrawingContext(System.Windows.Media.DrawingContext dc)
        {
            //how to draw shadow on bi?
            BitmapImage bi = new BitmapImage(new Uri(@"D:\mytemp\img1.jpg"));
            dc.DrawImage(bi, new Rect(50, 50, 100, 100));

            //how to draw shadow on bi1
            BitmapImage bi1 = new BitmapImage(new Uri(@"D:\mytemp\img2.jpg"));
            dc.DrawImage(bi1, new Rect(30, 30, 100, 100));
        }

    }
请注意,下面SvenG建议的解决方案,即为底层元素添加效果,对我来说并不适用,因为它为整个元素提供阴影,而不是我绘制的单个图像。例如,如果我有两个重叠的DrawImage,建议的解决方案将从整体上绘制阴影。上部图像的阴影不会绘制在下部图像上


此外,我想使用如上所示的getBitmap函数创建位图,以导出带有阴影的绘制图像。

将以下代码添加到OnRenderMethod中:

  ....

  dc.DrawImage(bi, new Rect(50, 50, 100, 100));

  // Create DropShadow
  DropShadowEffect effect = new DropShadowEffect();
  effect = new DropShadowEffect();
  effect.Color = Colors.Gray;
  effect.Direction = 45;
  this.Effect = effect;

DrawingContext
上有一个旧的
PushEffect()
调用,它可以完成您所需的操作,但与BitmapEffect一样,它已经过时

bitmappeffect
的替代品是
Effect
类。有一个名为
DropShadowEffect
的子类正是您所追求的,但不幸的是,正如SvenG所说,这不能直接应用于位图

支持应用效果的最低级别元素是
DrawingVisual
类。这并不太糟糕,因为
DrawingVisual
是一个非常轻量级的类。没有布局开销。最好是在自己的
DrawingVisual
中创建每个位图,并将visual的
Effect
属性设置为
DropShadowEffect
。显然,如果你有成千上万的位图,它可能不是一个可行的解决方案

所有这些都可以在代码中完成,但不是
OnRender()
,因为每个视觉对象都有自己的渲染上下文。但是,要正确渲染子绘图视觉效果,您需要向框架介绍它们

您需要在自定义元素中重写两个方法以查看这些视觉效果:
VisualChildrenCount
来说明您有多少子元素,以及GetVisualChild()来将它们返回到系统。因此,您需要保留一组可用的视觉资料。如果要对它们进行命中测试,还可以调用
AddVisualChild()
AddLogicalChild()

public class MyDrawingView : FrameworkElement
{
    List<DrawingVisual> _visuals = new List<DrawingVisual>();

    public MyDrawingView()
    {
        CreateVisuals();
    }

    //Gets a bitmap rendering of the visual and its children for saving as image file
    public RenderTargetBitmap GetBitmap()
    {
        var rtb = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32);
        rtb.Render(this);
        return rtb;
    }

    protected override int VisualChildrenCount
    {
        get
        {
            return _visuals.Count;
        }
    }

    protected override Visual GetVisualChild(int index)
    {
        return _visuals[index];
    }

    private void CreateVisuals()
    {
        CreateVisualForBitmap(@"D:\mytemp\img1.jpg", new Rect(50, 50, 100, 100));
        CreateVisualForBitmap(@"D:\mytemp\img2.jpg", new Rect(30, 30, 100, 100));
    }

    private void CreateVisualForBitmap(string bitmapPath, Rect bounds)
    {
        var bitmap    = new BitmapImage(new Uri(bitmapPath));
        var visual    = new DrawingVisual();
        visual.Effect = new DropShadowEffect();

        using (DrawingContext dc = visual.RenderOpen())
        {
            dc.DrawImage(bitmap, bounds);
        }

        _visuals.Add(visual);
        AddVisualChild(visual);
        AddLogicalChild(visual);
    }
}
公共类MyDrawingView:FrameworkElement { 列表_visuals=新列表(); 公共MyDrawingView() { CreateVisuals(); } //获取视觉对象及其子对象的位图呈现,以另存为图像文件 公共RenderTargetBitmap GetBitmap() { var rtb=新的RenderTargetBitmap(200、200、96、96,PixelFormats.Pbgra32); rtb.渲染(此); 返回rtb; } 受保护的重写int VisualChildrenCount { 得到 { 返回_visuals.Count; } } 受保护的重写Visual GetVisualChild(int索引) { 返回图像[索引]; } 私有void CreateVisuals() { CreateVisualOrbitMap(@“D:\mytemp\img1.jpg”,新的Rect(50,50,100,100)); CreateVisualOrbitMap(@“D:\mytemp\img2.jpg”,新的Rect(30,30100100)); } 私有void CreateVisualOrbitMap(字符串位图路径,矩形边界) { var bitmap=新的位图(新的Uri(位图路径)); var visual=新的DrawingVisual(); visual.Effect=新的DropShadowEffect(); 使用(DrawingContext dc=visual.renderropen()) { dc.DrawImage(位图、边界); } _视觉效果。添加(视觉); AddVisualChild(视觉); AddLogicalChild(可视); } }
此解决方案部分解决了我的问题。我的问题是,如果我有两个重叠的DrawImage,这个解决方案将从整体上绘制阴影。上面图像的阴影不会绘制在下面的图像上。嗨,Sven,你能建议我如何解决上面评论中描述的问题吗?Amaltas,问题是效果只能应用于UIElements,这就是我在这里所做的:你的DrawingView有一个效果,无论您使用drawingContext绘制了多少图像。从我的角度来看,使用FrameworkElement并在其上绘制多个位图图像感觉有点不对劲。为什么不创建一个用户控件或一个样式,其中包含DrawingView元素和其他图像控件以及要显示的图像?位图是否透明?ie是要对位图的各个像素进行阴影处理,还是只对每个位图进行矩形阴影处理?@GazTheDestroyer位图可以是透明的,因此每个位图的矩形阴影将不起作用。但是,现在我也不知道如何画矩形阴影!您建议我如何从该图形创建位图,并将其另存为图像文件?我使用原始代码中显示的getBitmap函数来执行此操作。我在上面添加了一个getBitmap()函数。这确实有效!我的一个问题是,尽管我的应用程序不会有数千个位图,但它可以有数百个由用户照片创建的位图。当用户在屏幕上绘制时,我可以使用重新调整大小的位图来节省内存,但在导出最终图像时,我希望使用完整的位图;因此,内存可能是一个问题,因为所有位图似乎都将一起加载。有没有一种方法可以按顺序加载位图?WPF渲染不是这样工作的。OnRender()有效地提供了有关如何渲染的说明,但实际渲染可以在后台由框架随时完成。因此,如果您想要全尺寸位图,即使您按顺序提供它们,WPF仍将存储它们。在您想要导出之前,您可能会使用较小的版本,但此时您仍然需要加载所有的全尺寸位图。