SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

WPFで強めのブラーを高速にかける

普通にぼかしを強めにかけてみる

背景画像として、ぼやけた画像を使いたいことって、結構あると思います。
で、普通にこれをやると、こんな感じだと思います。

<Window x:Class="WpfBaseTemplate1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1"
        Width="1024"
        Height="768">
    <Grid>
        <Image x:Name="imgBlur"
               HorizontalAlignment="Center"
               VerticalAlignment="Center"
               Source="Image/sample.jpg"
               Stretch="UniformToFill">
            <Image.Effect>
                <BlurEffect Radius="300" />
            </Image.Effect>
        </Image>
    </Grid>
</Window>

結果画像はこんな感じ。
f:id:minami_SC:20140221214924j:plain:w400


でも、コレってでっかい画像領域に強烈にぼかしエフェクトをかけてるので、
当然ですが、とても重いです。

ぼかし対象の画像を切り替えたり、画面をリサイズしてエフェクトをかけなおしたりすると、
そのたびにもっさりとした動作をします。

そこで、BitmapCacheを使ってこの処理を高速化してみました。

BitmapCacheを使った、BlurEffectの高速化

  1. ContentControlの中にImageControlを入れます。
  2. ContentControlにBitmapCacheを設定
    1. このContentControlを画面上に描画する時、RenderAtScaleプロパティで設定した倍率で縮小された解像度で描画されます。
  3. ImageコントロールにBlurEffectをかける
    1. 親のContentControlで、縮小スケーリングがかかっているので、BlurEffectをかける対象の画像も小さくなっている。


やってることは、↓こんなイメージですね。
f:id:minami_SC:20140221214933p:plain


普通にぼかしをかけるのと、ここで紹介した高速化した方法の違いは、こんなイメージ
f:id:minami_SC:20140221214944p:plain

結果

BitmapCacheと併用した結果は以下の通り。
縮小した解像度の画像に対してBlurEffectをかけているので、普通にぼかしをかけるよりBlurRadiusプロパティを小さい値にしても十分なぼかしが得られます。
最初に書いた普通の実装ではBlurRadius=300としていましたが、BitmapCacheを使ったこちらの方法では、BlurRadius=170くらいで同等くらいなぼかしができています。
これにより、一層高速な処理ができています。
f:id:minami_SC:20140221215901j:plain:w400

コード
<Window x:Class="WpfBaseTemplate1.Window2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window2"
        Width="1024"
        Height="768">
    <Window.Resources>
        <Style x:Key="ZuruiWhiteTextBlockStyle2" TargetType="{x:Type TextBlock}">
            <Setter Property="Foreground" Value="#FFFFFFFF" />
            <Setter Property="Effect">
                <Setter.Value>
                    <DropShadowEffect BlurRadius="0"
                                      Direction="135"
                                      ShadowDepth="1"
                                      Color="#80000000" />
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <ContentControl>
            <ContentControl.CacheMode>
                <BitmapCache RenderAtScale="0.05" />
            </ContentControl.CacheMode>
            <Image HorizontalAlignment="Center"
                   VerticalAlignment="Center"
                   Source="Image/sample.jpg"
                   Stretch="UniformToFill">
                <Image.Effect>
                    <BlurEffect Radius="170" />
                </Image.Effect>
            </Image>
        </ContentControl>
        <TextBlock Margin="50"
                   HorizontalAlignment="Right"
                   VerticalAlignment="Bottom"
                   FontSize="50"
                   Style="{StaticResource ZuruiWhiteTextBlockStyle2}"
                   Text="ぼかした画像のサンプル"
                   TextWrapping="Wrap" />
    </Grid>
</Window>


この方法を使えば、最近のiOS風の極端にぼかした背景とかも、軽い計算負荷で実現できそうですね。
画像だけでは、あまり効果は伝わらないですが、、、
実際にプログラムを動かしてウィンドウのリサイズとかをしてみると、高速化の効果が感じられると思います。