#wp7dev_jp

さて、これまで写真をぼかすことをやってきましたが、今回から別のネタで進めてみます。

今回からトライするのは、レイヤー機能です。Photoshop に搭載しているフォトレタッチの重要な機能で、1つの画像に2つ目の画面をいろいろな効果を付けて合成します。

今回は、まず乗算を実装してみます。

ファイルの追加

プロジェクトに、「Images:フォルダを追加して、そこに以下のファイルをコピーします。

  • フォルダ: C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Icons\dark
    • ファイル1:appbar.folder.rest.png
    • ファイル2:appbar.favs.rest.png

コピーしたらファイルのプロパティを以下のように設定。

  • ビルドアクション: コンテンツ
  • 出力ディレクトリにコピー:新しい場合はコピーする

それから480X480の元画像とマスク用画像を用意しておきます(Source.jpg, Mask.png)
こちらも、Images フォルダにコピーしておきましょう。

image image

XAML

さて、UI を作ります。こんなUIになります。

image

<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel は、アプリケーション名とページ タイトルを格納します-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
    <TextBlock x:Name="ApplicationTitle" Text="Photo Effect Sample " 
                Style="{StaticResource PhoneTextNormalStyle}" 
                FontFamily="Segoe WP Bold" />
    <TextBlock x:Name="PageTitle" Text="Layer Effect" 
                Margin="9,-7,0,0" 
                Style="{StaticResource PhoneTextTitle1Style}" 
                FontFamily="Segoe WP Light" />
</StackPanel>
<!--ContentPanel - 追加コンテンツをここに入力します-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" 
        Height="480">
    <Image Name="sourceimg2" Stretch="UniformToFill" Height="480" 
            Source="/Layer;component/Images/Mask.png" />
    <Image Name="sourceimg1" Stretch="UniformToFill" Height="480"
            Source="/Layer;component/Images/Source.jpg"/>
    <Image Name="resultimg" Stretch="UniformToFill" Height="480" />
</Grid>
</Grid>
 
<!--ApplicationBar の使用法を示すサンプル コード-->
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
    <shell:ApplicationBarIconButton 
        IconUri="/Images/appbar.folder.rest.png" Text="画像"
        x:Name="btnOpenPict" Click="btnOpenPict_Click" />
    <shell:ApplicationBarIconButton 
        IconUri="/Images/appbar.favs.rest.png" Text="エフェクト" 
        x:Name="btnEffect" Click="btnEffect_Click" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

C#

さて、コード側です。といってもぼかし処理と変わりません。

乗算はその名の通り、ピクセル同士の掛け算をします。
式は 結果=元画像xマスク画像 / 255 これを各ポイントのRGBそれぞれに配置します。
元画像に対してマスク画像を掛け算して、結果としてちょっと暗くなります。

private void btnOpenPict_Click(object sender, EventArgs e)
{
    PhotoChooserTask task = new PhotoChooserTask();
    task.Completed += new EventHandler<PhotoResult>(task_Completed);
    task.Show();
}
void task_Completed(object sender, PhotoResult e)
{
    if (e.TaskResult == TaskResult.OK)
    {
        BitmapImage bmp = new BitmapImage();
        bmp.SetSource(e.ChosenPhoto);
        sourceimg1.Source = bmp;
    }
}
private void btnEffect_Click(object sender, EventArgs e)
{
    WriteableBitmap sourcewp1 = new WriteableBitmap(sourceimg1, null); //元画像用
    WriteableBitmap sourcewp2 = new WriteableBitmap(sourceimg2, null); //元画像用
    int wpw = sourcewp1.PixelWidth;
    int wph = sourcewp2.PixelHeight;
    WriteableBitmap finalwp = new WriteableBitmap(wpw, wph); //最終結果保存用
    //デバッグ用:時間計開始時間設定
    DateTime start = DateTime.Now;
    for (int pixel = 0; pixel < sourcewp1.Pixels.Length; pixel++)
    {
        uint color1 = (uint)sourcewp1.Pixels[pixel];
        uint color2 = (uint)sourcewp2.Pixels[pixel];
        uint A1 = (color1 >> 24);
        uint R1 = ((color1 >> 16) & 0xFF);
        uint G1 = ((color1 >> 8) & 0xFF);
        uint B1 = ((color1) & 0xFF);
        uint A2 = (color2 >> 24);
        uint R2 = ((color2 >> 16) & 0xFF);
        uint G2 = ((color2 >> 8) & 0xFF);
        uint B2 = ((color2) & 0xFF);
        uint A = A1;
        uint R = 0;
        uint G = 0;
        uint B = 0;
        // 乗算
        R = R1 * R2 / 255;
        G = G1 * G2 / 255;
        B = B1 * B2 / 255;
        finalwp.Pixels[pixel] =
            ((int)A << 24) | ((int)R << 16) | ((int)G << 8) | (int)B;
    }
    //作成された画像を元画像として表示
    resultimg.Source = finalwp;
    ApplicationTitle.Text = "Photo Effect Sample : " +
        (DateTime.Now - start).TotalSeconds.ToString() + " sec";
    //処理時間表示
}

さて、実行してみます。 元の画像にマスク画像を乗算した結果です。マスク画像を変えると別の効果も楽しめます。

image image

処理時間も0.1秒かからないのでかなりいいですね。あとは、このフィルタの処理部分を変えていけばいろいろ出来そうです。

関連リンク