2012-01-17 5 views
2

Я рисую изображение в методе OnRender моего пользовательского элемента FrameworkElement. Я хотел бы также нарисовать тень этого изображения. Мне нужно сделать это в коде, и я бы не хотел использовать DropShadowBitmapEffect, потому что он устарел. Как я могу это достичь?Нарисуйте тень на изображении при рисовании DrawingContext

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, как показано выше, для экспорта рисованного изображения с тенями.

+0

Являются ли растровые изображения прозрачными? т.е. хотите ли вы затенять отдельные пиксели растрового изображения или просто прямоугольную тень для каждого растрового изображения? – GazTheDestroyer

+0

@GazTheDestroyer Растровые изображения могут быть прозрачными, поэтому прямоугольная тень для каждого растрового изображения не будет работать. Но сейчас я не могу понять, как рисовать прямоугольную тень! – AmaltasCoder

ответ

4

Существует старая PushEffect() вызов на DrawingContext, что сделал бы то, что вам требуется, но как BitmapEffect это является устаревшим.

BitmapEffect замена: Effect класс. Существует подкласс, называемый DropShadowEffect, что и есть то, что вам нужно, но, к сожалению, как говорит SvenG, это нельзя применить непосредственно к растровым изображениям.

Элемент самого низкого уровня, который поддерживает применяемые эффекты, - это класс DrawingVisual. Это не так уж плохо, потому что DrawingVisual - довольно легкий класс. Накладных расходов нет. Лучше всего было бы создать каждый битмап в своем собственном DrawingVisual и установить свойство визуализации Effect на DropShadowEffect. Очевидно, что если у вас есть тысячи растровых изображений, это не может быть жизнеспособным решением.

Все это можно сделать в коде, но не OnRender(), так как каждый визуал имеет свой собственный контекст визуализации. Тем не менее, для рисования DrawingVisuals для правильного отображения вам необходимо рассказать о них.

Чтобы отобразить эти изображения, вам необходимо переопределить два метода в вашем пользовательском элементе: 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); 
    } 
} 
+0

Как вы предлагаете мне создать растровое изображение из этого чертежа, которое я могу сохранить как файл изображения? Я делаю это, используя функцию getBitmap, показанную в моем исходном коде. – AmaltasCoder

+0

Добавили функцию GetBitmap() выше. – GazTheDestroyer

+0

Это работает! Одна из проблем заключается в том, что даже если мое приложение не будет иметь тысячи растровых изображений, но оно может содержать сотни растровых изображений, созданных из пользовательских фотографий. Я могу использовать перемасштабированные растровые изображения для сохранения памяти, когда пользователь рисует на экране, но при экспорте конечного изображения я хотел бы использовать полные растровые изображения; поэтому память может быть проблемой, так как кажется, что все растровые изображения будут загружены вместе. Есть ли способ, которым растровые изображения можно загружать последовательно? – AmaltasCoder

1

Добавьте следующий код в 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; 
+0

Это решение частично решает мою проблему. Проблема, с которой я сталкиваюсь, заключается в том, что если бы у меня было два дублирующих DrawImage, это решение привлечет тень, учитывая целое. Тень верхнего изображения не будет нарисована на нижнем изображении. – AmaltasCoder

+0

Привет, SvenG, можете ли вы также предложить, как я могу решить проблему, описанную в комментарии выше. – AmaltasCoder

+1

Амальтас, проблема в том, что эффекты могут применяться только к UIElements, что я и сделал здесь: ваш DrawingView имеет один Эффект, независимо от того, сколько изображений вы рисуете с помощью drawContext. С моей точки зрения, как-то неправильно иметь FrameworkElement и нарисовать на нем несколько BitmapImages. Почему бы не создать UserControl или стиль, содержащий элементы DrawingView, а также элементы управления изображением с изображениями, которые вы хотите отобразить? – SvenG

Смежные вопросы