Windows Phoneアプリは分かりやすいデザインと直感的な操作感が重要です。この2つを両立させるにはWindows Phone用コントロールの組み合わせやXAMLによる修飾が不可欠です。ComponentOne Studio for Windows Phoneを使うときも同様で複数のコントロールを組み合わせることでコンポーネントを使う効果が高まるときがあります。
そこでDockPanel for Windows Phone(C1DockPanel)、Imaging for Windows Phone(C1Bitmap)、ProgressBar for Windows Phone(C1ProgressBar)およびC1GestureListenerを使って画像をトリミングするサンプルを作成してみたいと思います。
なお、サンプルとしてはVB版とC#版の両方を用意し、XAML定義を始めとしてそれぞれのコードが対応づけられるようにプロシージャ順やロジックにも配慮してあるので、ご活用ください(CZ1206ImageVB、CZ1206ImageCS)。
コンポーネントの登録
ComponentOne Studio for Windows PhoneのコントロールをVisual Studioで利用するには、関連する26個のコントロールをツールボックスへ登録が必要です。[ツールボックスアイテムの選択]ダイアログで名前空間でソートし、C1.Phoneで始まるコントロールをすべてチェックしてください。
初期準備
アプリ用プロジェクトの準備
まずは、PictureHubにある写真を画面に表示する部分を作成してみましょう。
[ファイル]-[新規作成]-[プロジェクト]-[Silverlight for Windows Phone]-[Windows Phoneアプリケーション]の順で選択して、新規にWindows Phoneアプリ用のプロジェクトを作成します。
プロジェクトが生成されたら、アプリに必要なXAML定義とロジックコードを記述するためのファイルを作成しましょう。クラスを作成する前にファイルを格納する場所として、ソリューションエクスプローラでプロジェクトに[Models]フォルダ、[Viwes]フォルダ、[ViewModels]フォルダ、[Images]フォルダを作成します。そして、MainPage.xamlを[View]フォルダにコピーします。
このまま実行するとエラーが発生するので、スタートアップ画面であるMainPage.xamlの位置を「MainPage.xaml」から「Views/MainPage.xaml」に変更します。
: <DefaultTask Name ="_default" NavigationPage="Views/MainPage.xaml"/> :
C1Bitmapの利用方法
C1BitmapクラスはWindows Phoneのページに直接貼り付けて利用するものではありません。C1BitmapクラスはWritebleBitmapクラスと同じように、ImageコントロールのSourceに指定して利用します。
つまり、XAML定義を変更しなくてもSourceに指定している部分をC1Bitmapに切り替えれば、既存アプリにC1Bitmapクラスの豊富な機能が追加できる足がかりを簡単に作ることができます。
画像表示部分の作成
では、PictureHubから画像を選択して表示する部分を作成しましょう。MainPage.xamlのXAML定義は次のようになります。
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Height="535" Width="456"> <Image x:Name="C1Sample_Image" Stretch="None" Tap="C1Sample_Image_Tap" /> <my:C1ProgressBar x:Name="Now_ProgressBar" IsIndeterminate="True" /> </Grid>
ContentPanel部分にImageコントロールとC1ProgressBarを設置し、ApplicationBarMenuItemに画像選択用のメニューを追加しています(上記リスト2では、見やすさを考慮し一部コードを省略しています。詳細はサンプルコードを確認ください)。これでWindows Phone全体に画像表示エリアを確保することになります。
注目すべきプロパティとしては、StretchをNoneにしている点です。なぜこのようなプロパティ値をとるかというと、画像の拡大縮小をImageコントロールまかせにせず、コード内で画面に納まらないときだけ縦横比を維持しつつ、縮小表示のみ(拡大表示は抑止)対応するようにしたいからです。
画面表示関連のコード
Partial Public Class MainPage Inherits PhoneApplicationPage Private IsNewPageInstance As Boolean = False ' コンストラクター Public Sub New() InitializeComponent() Me.IsNewPageInstance = True Me.ApplicationBar.IsMenuEnabled = True Me.Now_ProgressBar.IsIndeterminate = False End Sub ''' <summary> ''' 画像選択 ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub Choose_Click(sender As System.Object, e As System.EventArgs) Me.Now_ProgressBar.IsIndeterminate = True Me.ApplicationBar.IsMenuEnabled = False App.ViewModel.PictureShow().Execute(New Size(CType(Me.C1Sample_Image.Parent, Grid).ActualWidth, _ CType(Me.C1Sample_Image.Parent, Grid).ActualHeight)) End Sub ''' <summary> ''' 写真取得 ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub PropertyChanged(sender As Object, e As PropertyChangedEventArgs) If e.PropertyName = "Item" Then Me.C1Sample_Image.Source = App.ViewModel.PictureItem.ImageSource Me.ApplicationBar.IsMenuEnabled = True Me.Now_ProgressBar.IsIndeterminate = False End If End Sub ''' <summary> ''' ページ遷移時に情報を復元する ''' </summary> ''' <param name="e"></param> ''' <remarks></remarks> Protected Overrides Sub OnNavigatedTo(e As System.Windows.Navigation.NavigationEventArgs) MyBase.OnNavigatedTo(e) If IsNewPageInstance Then AddHandler App.ViewModel.PropertyChanged, AddressOf PropertyChanged End If End Sub End Class
using System; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using Microsoft.Phone.Controls; namespace CZ1206ImageCS { public partial class MainPage : PhoneApplicationPage { private Boolean IsNewPageInstance = false; // コンストラクター public MainPage() { InitializeComponent(); this.IsNewPageInstance = true; this.ApplicationBar.IsMenuEnabled = true; this.Now_ProgressBar.IsIndeterminate = false; } /// <summary> /// 画像選択 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Choose_Click(System.Object sender, System.EventArgs e) { this.Now_ProgressBar.IsIndeterminate = true; this.ApplicationBar.IsMenuEnabled = false; App.ViewModel.PictureShow.Execute(new Size(((Grid)this.C1Sample_Image.Parent).ActualWidth, ((Grid)this.C1Sample_Image.Parent).ActualHeight)); } /// <summary> /// 写真取得 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void PropertyChanged(System.Object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName == "Item") { this.C1Sample_Image.Source = App.ViewModel.PictureItem.ImageSource; this.ApplicationBar.IsMenuEnabled = true; this.Now_ProgressBar.IsIndeterminate = false; } } /// <summary> /// ページ遷移時に情報を復元する /// </summary> /// <param name="e"></param> protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); if (IsNewPageInstance) { App.ViewModel.PropertyChanged += new PropertyChangedEventHandler(PropertyChanged); } } } }
画面上で[画像の選択]メニューをクリックして、Choose_Clickイベントプロシージャを呼び出します。この中では画面上の縦横のサイズをパラメータにして、ViewModelのPictureShow.Executeメソッドを呼び出しています。
PictureShow.Executeメソッドは、画像選択用の画面を開くだけで実行が終わります。
画面表示時に自動実行する「OnNavigatedTo」の中でイベントの登録を行っているため、画像を選択した時にはPropertyChangedプロシージャが実行されます。
AddHandler App.ViewModel.PropertyChanged, AddressOf PropertyChanged
App.ViewModel.PropertyChanged += new PropertyChangedEventHandler(PropertyChanged);
今回のサンプルではApp.ViewModelを経由してPictureModelクラスを使用しています。PictureModelクラスの中ではPictureHubから画像を取得したり、トリミングや色調変換などのロジックも記述したりなどができます。
PictureHubから画像を取得するコード
PictureModelクラスにPictureHubから画像を取得するコードを記述しましょう。PictureModelクラスを読み解くには、コードの後ろの方にあるShowメソッドの内容から見ていくのが良いでしょう。
Public Class PictureModel Implements INotifyPropertyChanged Private PhotoTask As New Microsoft.Phone.Tasks.PhotoChooserTask ''' <summary> ''' PictureHubから画像を選択する ''' </summary> ''' <param name="parameter">画像描画領域の最大</param> ''' <remarks></remarks> Public Sub Show(ByVal parameter As Size) Me.ActureSize = parameter AddHandler Me.PhotoTask.Completed, (Sub(d_Sender, d_e) If d_e.TaskResult = Microsoft.Phone.Tasks.TaskResult.OK Then Dim photo As New Imaging.BitmapImage photo.SetSource(d_e.ChosenPhoto) photo.CreateOptions = BitmapCreateOptions.IgnoreImageCache Me.Original_Bitmap = New C1.Phone.Imaging.C1Bitmap(New Imaging.WriteableBitmap(photo)) End If End Sub) Me.PhotoTask.Show() End Sub End Class
using System; using System.ComponentModel; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; namespace CZ1206ImageCS { public class PictureModel : INotifyPropertyChanged { private Microsoft.Phone.Tasks.PhotoChooserTask PhotoTask = new Microsoft.Phone.Tasks.PhotoChooserTask(); /// <summary> /// PictureHubから画像を選択する /// </summary> /// <param name="size"></param> internal void Show(Size parameter) { this.ActureSize = parameter; this.PhotoTask.Completed += (d_sender, d_e) => { if (d_e.TaskResult == Microsoft.Phone.Tasks.TaskResult.OK) { BitmapImage photo = new BitmapImage(); photo.SetSource(d_e.ChosenPhoto); photo.CreateOptions = BitmapCreateOptions.IgnoreImageCache; this.Original_Bitmap = new C1.Phone.Imaging.C1Bitmap(new WriteableBitmap(photo)); } }; this.PhotoTask.Show(); } } }
STEP1:
Showメソッドは画面表示サイズをparameterパラメタで受け取り、内部変数のActureSizeに保存します。
STEP2:
PhotoChooserTaskのComplatedイベントのイベントプロシージャを、ラムダ式で次のように定義します。
AddHandler Me.PhotoTask.Completed, (Sub(d_Sender, d_e) …………End Sub)
this.PhotoTask.Completed += (d_sender, d_e) => { …………}
この定義部分は、すぐには実行されません。
STEP3:
PhotoChooserTaskのShowメソッドを実行してPictureHubの画像選択画面が表示されたら、本プロシージャの実行が完了し、呼び出し元に復帰します。
STEP4:
写真が選択された時に初めてCompletedイベントが発生してCompletedイベントプロシージャが呼び出されます。このプロシージャの中では、指定された画像をC1Bitmap型のOriginal_Bitmapプロパティに代入します。Original_Bitmapプロパティは設定した画像を画面のサイズに合わせて縮小表示してくれるプロパティです。
Private Property Original_Bitmap As C1.Phone.Imaging.C1Bitmap Get Return _OriginalBitmap End Get Set(value As C1.Phone.Imaging.C1Bitmap) _OriginalBitmap = value If Me.ActureSize.Width < value.Width Then Me.Scale = Math.Ceiling((Me.ActureSize.Width / value.Width) * 100) / 100 End If If Me.ActureSize.Height < value.Height Then Dim heightScale As Double = Math.Ceiling((Me.ActureSize.Height / value.Height) * 100) / 100 If Me.Scale > heightScale Then Me.Scale = heightScale End If End If If Me.Scale > 1.0 Then Me.Scale = 1.0 End If Me._Item = New C1.Phone.Imaging.C1Bitmap(CType(value.Width * Me.Scale, Integer), _ CType(value.Height * Me.Scale, Integer)) Me._Item.Copy(value, True) Call NotifyPropertyChanged("Item") End Set End Property Private Property _OriginalBitmap As C1.Phone.Imaging.C1Bitmap = Nothing Public Property Item As C1.Phone.Imaging.C1Bitmap Get Return _Item End Get Set(value As C1.Phone.Imaging.C1Bitmap) _Item = value Call NotifyPropertyChanged("Item") End Set End Property Private Property _Item As C1.Phone.Imaging.C1Bitmap = Nothing
private C1.Phone.Imaging.C1Bitmap Original_Bitmap { get { return _OriginalBitmap; } set { _OriginalBitmap = value; if (this.ActureSize.Width < value.Width) { this.Scale = Math.Ceiling((this.ActureSize.Width / value.Width) * 100) / 100; } if (this.ActureSize.Height < value.Height) { double heightScale = Math.Ceiling((this.ActureSize.Height / value.Height) * 100) / 100; if (this.Scale > heightScale) { this.Scale = heightScale; } } if (this.Scale > 1.0) { this.Scale = 1.0; } this._Item = new C1.Phone.Imaging.C1Bitmap((int)(value.Width * this.Scale), (int)(value.Height * this.Scale)); this._Item.Copy(value, true); NotifyPropertyChanged("Item"); } } private C1.Phone.Imaging.C1Bitmap _OriginalBitmap = null; public C1.Phone.Imaging.C1Bitmap Item { get { return _Item; } set { _Item = value; NotifyPropertyChanged("Item"); } } private C1.Phone.Imaging.C1Bitmap _Item = null;
STEP5:
Original_Bitmapプロパティに値を設定すると、set部にvalue値として設定値が渡されます。set部では画面表示部の縦サイズと画像の縦サイズ、画面表示部の横サイズと画像の横サイズを比較して縦横比を崩さずに画面に収めるための縮小比Scaleを計算します。
今回のサンプルでは画面表示部よりも画像サイズが小さいときには拡大は行わないので、Scale > 1.0の場合は等倍になるように1.0の値をScale値に採用しています。
STEP6:
Scale値が決まれば、あとは、C1Bitmapの機能を使って画面の縮小を行い、その結果をItemプロパティに設定してNotifyPropertyChangedイベントを発生させます。
このイベントはViewModelを経由してMainPage.xaml.vb(MainPage.xaml.cs)のPropertyChangedイベントプロシージャを起動し、MainPage.xamlに画像を表示します。
表示部分にC1Bitmapを使う利点について
ImageクラスやBitmapImageクラス、WritebleBitmapクラスを使わず、C1Bitmapを使う利点はどこにあるのでしょうか。それは、C1BitmapにあるCopyメソッドという強力なメソッドの存在にあります。
今回のサンプルでは、_Itemを生成する際、表示サイズに合わせるよう縦横を指定してnewしていますが、このようにしてサイズを指定したC1BitmapでCopyメソッドを使えば、そのサイズに合わせてコピー元の画像を縮小拡大してくれます。そのため、たった1行の記述だけで画像ファイルを画面サイズに合わせることができます。
範囲選択部分の作成
前ページまでで、画像表示部分が完成しました。次は、トリミング領域を指定するための定義を行います。トリミングは画面上をタップしてからパンすると、その領域の外側がグレー表示されるようにします。
範囲表示にはComponentOne Studio for Windows PhoneのC1DockPanelを使います。
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Height="535" Width="456"> <Image x:Name="C1Sample_Image" Stretch="None" Tap="C1Sample_Image_Tap" /> <my:C1DockPanel x:Name="Selection_Panel"> <Border my:C1DockPanel.Dock="Top" Height="{Binding Top}" VerticalAlignment="Top" Background="{StaticResource MaskBrush}" /> <Border my:C1DockPanel.Dock="Bottom" Height="{Binding Bottom}" VerticalAlignment="Bottom" Background="{StaticResource MaskBrush}" /> <Border my:C1DockPanel.Dock="Left" Width="{Binding Left}" HorizontalAlignment="Left" Background="{StaticResource MaskBrush}" /> <Border my:C1DockPanel.Dock="Right" Width="{Binding Right}" HorizontalAlignment="Right" Background="{StaticResource MaskBrush}" /> </my:C1DockPanel> <my:C1ProgressBar x:Name="Now_ProgressBar" IsIndeterminate="True" /> </Grid>
C1DockPanelは画面の上下左右の辺にドッキングしたパネルコントロールです。XAML定義では、上下のパネルではHeightプロパティを、左右のパネルではWidthプロパティをBindingしてこのBinding値を画面上の操作(ジェスチャ)に応じて変化させ、範囲指定ができるようにしています。
範囲指定を行うコード
Private Selection As SelectionSize Private ActureSize As Rect Private PointStart As New Point Private PointEnd As New Point Private WithEvents GestureListener As C1.Phone.C1GestureListener ' コンストラクター Public Sub New() InitializeComponent() Me.IsNewPageInstance = True Me.ApplicationBar.IsMenuEnabled = True Me.Now_ProgressBar.IsIndeterminate = False Me.GestureListener = C1.Phone.C1GestureService.GetGestureListener(Me.C1Sample_Image) End Sub ''' <summary> ''' 選択範囲の指定を開始する ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub GestureListener_DragStarted(sender As Object, e As C1.Phone.C1DragStartedGestureEventArgs) _ Handles GestureListener.DragStarted Me.ActureSize = New Rect((CType(Me.C1Sample_Image.Parent, Grid).ActualWidth - Me.C1Sample_Image.ActualWidth) / 2, _ (CType(Me.C1Sample_Image.Parent, Grid).Height - Me.C1Sample_Image.ActualHeight) / 2, _ Me.C1Sample_Image.ActualWidth, _ Me.C1Sample_Image.ActualHeight) Me.PointStart = e.GetPosition(Me.C1Sample_Image) Me.PointEnd = e.GetPosition(Me.C1Sample_Image) Call UpdateSelection(Me.PointStart, Me.PointEnd) End Sub ''' <summary> ''' 選択範囲指定中の描画を行う ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub GestureListener_DragDelta(sender As Object, e As C1.Phone.C1DragDeltaGestureEventArgs) _ Handles GestureListener.DragDelta Me.PointEnd = e.GetPosition(Me.C1Sample_Image) Call UpdateSelection(Me.PointStart, Me.PointEnd) End Sub ''' <summary> ''' 選択範囲の終わりを検出する ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub GestureListener_DragCompleted(sender As Object, e As C1.Phone.C1DragCompletedGestureEventArgs) _ Handles GestureListener.DragCompleted Me.PointEnd = e.GetPosition(Me.C1Sample_Image) Call UpdateSelection(Me.PointStart, Me.PointEnd) End Sub ''' <summary> ''' 選択範囲を更新する ''' </summary> ''' <param name="selectStart"></param> ''' <param name="selectEnd"></param> ''' <remarks></remarks> Private Sub UpdateSelection(ByVal selectStart As Point, ByVal selectEnd As Point) selectStart.X = Math.Min(Math.Max(selectStart.X, 0), Me.ActureSize.Width) selectEnd.X = Math.Min(Math.Max(selectEnd.X, 0), Me.ActureSize.Width) selectStart.Y = Math.Min(Math.Max(selectStart.Y, 0), Me.ActureSize.Height) selectEnd.Y = Math.Min(Math.Max(selectEnd.Y, 0), Me.ActureSize.Height) Me.Selection = New SelectionSize(Me.ActureSize, _ New Point(Math.Round(Math.Min(selectStart.X, selectEnd.X)), _ Math.Round(Math.Min(selectStart.Y, selectEnd.Y))), _ New Point(Math.Round(Math.Max(selectStart.X, selectEnd.X)), _ Math.Round(Math.Max(selectStart.Y, selectEnd.Y)))) Call UpdateMask() End Sub ''' <summary> ''' トリミングエリアを描画する ''' </summary> ''' <remarks></remarks> Private Sub UpdateMask() Me.Selection_Panel.DataContext = Me.Selection End Sub
private SelectionSize Selection; private Rect ActureSize; private Point PointStart = new Point(); private Point PointEnd = new Point(); private C1.Phone.C1GestureListener GestureListener; // コンストラクター public MainPage() { InitializeComponent(); this.IsNewPageInstance = true; this.ApplicationBar.IsMenuEnabled = true; this.Now_ProgressBar.IsIndeterminate = false; this.GestureListener = C1.Phone.C1GestureService.GetGestureListener(this.C1Sample_Image); } /// <summary> /// 選択範囲の指定を開始する /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void GestureListener_DragStarted(System.Object sender, C1.Phone.C1DragStartedGestureEventArgs e) { this.PointStart = e.GetPosition(this.C1Sample_Image); this.PointEnd = e.GetPosition(this.C1Sample_Image); UpdateSelection(this.PointStart, this.PointEnd); } /// <summary> /// 選択範囲指定中の描画を行う /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void GestureListener_DragDelta(System.Object sender, C1.Phone.C1DragDeltaGestureEventArgs e) { this.PointEnd = e.GetPosition(this.C1Sample_Image); UpdateSelection(this.PointStart, this.PointEnd); } /// <summary> /// 選択範囲の終わりを検出する /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void GestureListener_DragCompleted(System.Object sender, C1.Phone.C1DragCompletedGestureEventArgs e) { this.PointEnd = e.GetPosition(this.C1Sample_Image); UpdateSelection(this.PointStart, this.PointEnd); } /// <summary> /// 選択範囲を更新する /// </summary> /// <param name="selectStart"></param> /// <param name="selectEnd"></param> private void UpdateSelection(Point selectStart, Point selectEnd) { selectStart.X = Math.Min(Math.Max(selectStart.X, 0), this.ActureSize.Width); selectEnd.X = Math.Min(Math.Max(selectEnd.X, 0), this.ActureSize.Width); selectStart.Y = Math.Min(Math.Max(selectStart.Y, 0), this.ActureSize.Height); selectEnd.Y = Math.Min(Math.Max(selectEnd.Y, 0), this.ActureSize.Height); this.Selection = new SelectionSize(this.ActureSize, new Point(Math.Round(Math.Min(selectStart.X, selectEnd.X)), Math.Round(Math.Min(selectStart.Y, selectEnd.Y))), new Point(Math.Round(Math.Max(selectStart.X, selectEnd.X)), Math.Round(Math.Max(selectStart.Y, selectEnd.Y)))); UpdateMask(); } /// <summary> /// トリミングエリアを描画する /// </summary> private void UpdateMask() { this.Selection_Panel.DataContext = this.Selection; }
描画範囲の指定にはC1.Phone.C1GestureListenerを使用します。DragStartedイベントで範囲指定の開始検知を行いDragCompletedイベントで範囲指定の終了を検知します。もちろん範囲を指定中もDragDeltaイベントにより常時UpdateSelectionプロシージャを呼び出すようになってます。
UpdateSelectionプロシージャの中ではマスク範囲を掲載してその結果をC1DockPanelのDataContextに設定してXAML上のBindingに値を供給してます。
トリミング機能の実装
範囲指定ができたらいよいよ次はトリミングの実装です。MainPage.xaml.vb(MainPage.xaml.cs)ではボタンがクリックされたらViewModelを経由してPictureModelのTrimメソッドを呼び出すようにコーディングされています。すべての処理はPictureModelクラスにあるので、PictureModelクラスの内容を見てみましょう。
Public Sub Trim(rect As SelectionSize) Dim sizeX As Integer = (Me.ActureSize.Width - (rect.Right + rect.Left)) Dim sizeY As Integer = (Me.ActureSize.Height - (rect.Bottom + rect.Top)) Dim crop As New C1.Phone.Imaging.C1Bitmap(sizeX, sizeY) Dim posX As Integer = (rect.Left - rect.ActureSize.Left) Dim posY As Integer = (rect.Top - rect.ActureSize.Top) crop.BeginUpdate() For row As Integer = 0 To sizeY - 1 For col As Integer = 0 To sizeX - 1 crop.SetPixel(col, row, Me.Item.GetPixel(col + posX, row + posY)) Next Next crop.EndUpdate() Me.Item = crop End Sub
public void Trim(SelectionSize rect) { int sizeX = (int)(this.ActureSize.Width - (rect.Right + rect.Left)); int sizeY = (int)(this.ActureSize.Height - (rect.Bottom + rect.Top)); C1.Phone.Imaging.C1Bitmap crop = new C1.Phone.Imaging.C1Bitmap(sizeX, sizeY); int posX = (int)(rect.Left - rect.ActureSize.Left); int posY = (int)(rect.Top - rect.ActureSize.Top); crop.BeginUpdate(); for (int row = 0; row <= sizeY - 1; row++) { for (int col = 0; col <= sizeX - 1; col++) { crop.SetPixel(col, row, this.Item.GetPixel(col + posX, row + posY)); } } crop.EndUpdate(); this.Item = crop; }
残念ながらCopyコマンドのようにトリミング専用のコマンドは存在しませんが、ピクセル単位に取得と設定ができるGetPixelとSetPixelがあるので、この2つを使って必要なピクセルを1つずつ転記します。
後はトリミング後のデータをSNSに投稿したりSkyDriveにアップしたりする機能をつければ、十分実用的なアプリに仕上がるでしょう。
まとめ
今回は、C1DockPanel、C1Bitmap、C1ProgressBar、C1GestureListenerの4つを組み合わせて画像処理アプリを作成してみました。1つ1つ使うのも良いですが、このような形で組み合わせて使うことでさらに作りやすくなります。ぜひ、単独で利用するだけなく、複数のコントロールを組み合わせ、効率的な開発を実現してみてください。