Jaa


ブログ用 画像ユーティリティ ⑤ ユーザーコントロール

以下のようにXAMLで記述できるユーザーコントロール VgaImageUC を作成します。

<local:VgaImageUC x:Name="myVgaImage" Grid.Row="1" 
MouseLeftButtonDown="UC_MouseLeftButtonDown" 
MouseMove="UC_MouseMove" />

このユーザーコントロールの役割は①要件と戦略で説明したように、以下の4つです。

  1. Vgaサイズ画像の作成と表示
  2. モザイク画像の作成と、クリップ表示
  3. 上記2つの画像の合成画像の作成
  4. jpgにエンコードして出力

ユーザーコントロールは UserContrl クラスを継承した具象クラスです(これに対し、カスタムコントロールはControlを継承した具象クラス)。Visual Studio のソリューションエクスプローラーで追加→新しい項目から、以下のダイアログで[ユーザーコントロール(WPF)]を選ぶと、XAMLとコードビハインドのテンプレートを生成してくれます。

image

2つの画像を表示するXAMLを記述します。Mosaique画像はVisibilutyをHiddenにして、ぼかしをかけないRenderOptionであるNearestNeighborにします。

<UserControl x:Class="ImageShrinker.VgaImageUC"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
>
<Border  Name="myPlaceholder" Width="640" Height="480">
  <Canvas Name="myCanvas">
   <Image Canvas.Left="0" Canvas.Top="0" Name="myImage" />
   <Image Canvas.Left="0" Canvas.Top="0" Name="myMosaique"
Visibility="Hidden"
RenderOptions.BitmapScalingMode="NearestNeighbor" />
  </Canvas>
</Border>
</UserControl>

VgaImageUCユーザーコントロールでは、ファイル名(FileName)とクリップ矩形(ClipRect)が変更されたら、自動的に画像を表示させたいので、この2つのプロパティをDependencyPropertyとして定義します。

public string FileName
{
  get { return (string)GetValue(FileNameProperty); }
  set { SetValue(FileNameProperty, value); }
}

public static DependencyProperty FileNameProperty =
  DependencyProperty.Register("FileName", typeof(string),
  typeof(VgaImageUC), new FrameworkPropertyMetadata(
    new PropertyChangedCallback(OnFileNameChanged)));

/// <summary>
/// プロパティ変更のコールバック
/// </summary>
private static void OnFileNameChanged(
  DependencyObject obj,
  DependencyPropertyChangedEventArgs args)
{
  VgaImageUC control = (VgaImageUC)obj;
  control.UpdateImage();
}

private readonly int _vgaWidth = 640;
private readonly int _scale = 20;
/// <summary>
/// 画像の更新
/// </summary>
private void UpdateImage()
{
  BitmapImage bi =
CreateSmallImage(_vgaWidth, this.FileName);
  myImage.Source = bi;
  myImage.Width = bi.PixelWidth;
  myImage.Height = bi.PixelHeight;

  myMosaique.Source =
CreateSmallImage(_vgaWidth / _scale, this.FileName);
myMosaique.Width = bi.PixelWidth;
myMosaique.Height = bi.PixelHeight;

  myPlaceholder.Width = bi.PixelWidth;
  myPlaceholder.Height = bi.PixelHeight;
}

 

public Rect ClipRect
{
  get { return (Rect)GetValue(ClipRectProperty); }
  set { SetValue(ClipRectProperty, value); }
}

public static DependencyProperty ClipRectProperty =
DependencyProperty.Register("ClipRect", typeof(Rect),
typeof(VgaImageUC), new FrameworkPropertyMetadata(
new PropertyChangedCallback(OnClipRectChanged)));

/// <summary>
/// プロパティ変更のコールバック
/// </summary>
private static void OnClipRectChanged(
DependencyObject obj,
DependencyPropertyChangedEventArgs args)
{
  VgaImageUC control = (VgaImageUC)obj;
  control.UpdateRect();
}

/// <summary>
/// モザイククリップ矩形の更新
/// </summary>
private void UpdateRect()
{
  myMosaique.Clip = new RectangleGeometry(this.ClipRect);
  myMosaique.Visibility = Visibility.Visible;
}

また、ファイル名を引数として受け取るコンストラクタも追加します。App.xaml.csから呼び出すときにこれを使います。

public VgaImageUC(string filename)
{
  InitializeComponent();
  this.FileName = filename;
}