C# WPFで画像を分割して表示する
1. はじめに
今回は、C# WPFを使用し、読み込んだ画像を縦32px、横32pxに分割して表示する方法をまとめる(図1)。
図1は、今回の完成イメージである。任意の画像ファイルを入力すると、サイズを32px * 32pxに分割し、左側のエリアに表示する。なお、読み込む画像ファイルは、32px * 32pxの1枚の絵にしたものを対象としている。
上記を実現するためのステップを下記に示す。
(1) png画像を入力する。
(2) 入力した画像を32px * 32pxに分割する。
(3) 分割した画像をリストに登録し、左側のエリアに表示する。
2. GUIの作成
まず、完成イメージと同じGUIを作成する。
(1) メニューバーを作成する
GUIにメニューバーを付け、「ファイル」→「開く」を表示する。
(2) 画面を縦列に2分割する
(3) スクロールバーを付ける
上記をXAMLで記述すると、下記のコードとなる。
<Window x:Class="MapEditor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MapEditor"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Menu Grid.ColumnSpan="2">
<MenuItem Header="ファイル">
<MenuItem Header="開く"></MenuItem>
</MenuItem>
</Menu>
<StackPanel Grid.Column="0" Margin="0,15,0,0">
<Label Content="左側のエリア"></Label>
</StackPanel>
<StackPanel Grid.Column="1" Margin="0,15,0,0">
<Label Content="右側のエリア"></Label>
</StackPanel>
</Grid>
</Window>
実行すると、下記の画面となる(図2)。
これで、GUIの作成が完了である。
3. png画像を入力する
png画像の入力処理を作成する。
3.1 クリックイベントを追加する
このGUIは、「ファイル」→「開く」ボタンを選択すると、pngファイルを読み込むこととする。追加するクリックイベントは、<MenuItem>に設定する。
・追加する箇所
<MenuItem Header="開く" Click="MenuItem_Click"></MenuItem>
<MenuItem>にクリックイベントを設定した。これによって、ボタンをクリックしたときのイベントに合わせて処理が動作する。なお、この時点では処理の中身を記述していないため、何も動作しない。
<Window x:Class="MapEditor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MapEditor"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Menu Grid.ColumnSpan="2">
<MenuItem Header="ファイル">
<MenuItem Header="開く" Click="MenuItem_Click"></MenuItem>
</MenuItem>
</Menu>
<StackPanel Grid.Column="0" Margin="0,15,0,0">
<Label Content="左側のエリア"></Label>
</StackPanel>
<StackPanel Grid.Column="1" Margin="0,15,0,0">
<Label Content="右側のエリア"></Label>
</StackPanel>
</Grid>
</Window>
次に、.cs側にクリックイベント時の処理を記述する。追加する場所は、先ほど作成した"MenuItem_Click"である。
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MapEditor
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
}
}
}
クリックイベントは、<MenuItem>に記述した名称と同じものをメソッド名として記述する。試しに、クリックイベント内に、メッセージボックスを表示する。
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("開くボタンをクリックした。");
}
実行結果を図3、図4に示す。
開くボタンを選択すると、メッセージが表示されることがわかる。
3.2 pngファイルを入力する
pngファイルを読み込むためには、BitmapImageクラスを使用する。
//pngファイルを読み込む
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(openFileDialog.FileName);
bitmap.EndInit();
まず、BitmapImageをインスタンス化し、UriSourceにファイルダイアログから開いたUriを設定する。下記が実装したコードである。
using Microsoft.Win32;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MapEditor
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
//ファイルダイアログをオープンする
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "PNG files (*.png)|*.png";
if (openFileDialog.ShowDialog() == true)
{
//pngファイルを読み込む
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(openFileDialog.FileName);
bitmap.EndInit();
}
}
}
}
これで、ファイル→開くを押したときに、ファイルダイアログが現れ、選択した画像を読み込むことができる。
3.3 画面に読み込んだ画像を貼り付ける
画面に読み込んだ画像を貼り付ける。
<Window x:Class="MapEditor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MapEditor"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Menu Grid.ColumnSpan="2">
<MenuItem Header="ファイル">
<MenuItem Header="開く" Click="MenuItem_Click"></MenuItem>
</MenuItem>
</Menu>
<StackPanel Grid.Column="0" Margin="0,15,0,0">
<Label Content="左側のエリア"></Label>
<Image Name="LeftImage"></Image>
</StackPanel>
<StackPanel Grid.Column="1" Margin="0,15,0,0">
<Label Content="右側のエリア"></Label>
</StackPanel>
</Grid>
</Window>
Xamlの左側のエリアに、Imageタグを追加した。ここに先ほどの読み込んだ画像ファイルを設定すればよい。
using Microsoft.Win32;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MapEditor
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
//ファイルダイアログをオープンする
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "PNG files (*.png)|*.png";
if (openFileDialog.ShowDialog() == true)
{
//pngファイルを読み込む
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(openFileDialog.FileName);
bitmap.EndInit();
LeftImage.Source = bitmap;
}
}
}
}
実行結果は、図5となる。
画像が非常に大きくなっているが、pngファイルを入力し、左側のエリアに表示できた。
3.3 32px * 32pxに分割して読み込む
次は、入力した画像を32px * 32pxに分割して表示する。そのためには、Xaml側は、下記のように修正する。
(1) <ItemsControl>を追加し、複数の画像を表示できるようにする。
(2) <WrapPanel>を追加し、分割画像を横に折り返して表示する。
<ItemsControl>は、リストを並べて表示するために使用する。今回は、画像ファイルを複数並べるため、リストに追加して表示する。
<WrapPanel>は、コントロールを横方向に並べるために使用する。分割した画像は、横向きに並べて表示する。下記に一部抜粋したコードを示す。
<StackPanel Grid.Column="0" Margin="0,15,0,0">
<Label Content="左側のエリア"></Label>
<ItemsControl Name="ImageListControl">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Name="LeftImage" Source="{Binding}" Width="32" Height="32"></Image>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<ItemsControl>の中に、WrapPanelを記述することで実現することができる。完成したコードを下記に示す。
<Window x:Class="MapEditor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MapEditor"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Menu Grid.ColumnSpan="2">
<MenuItem Header="ファイル">
<MenuItem Header="開く" Click="MenuItem_Click"></MenuItem>
</MenuItem>
</Menu>
<StackPanel Grid.Column="0" Margin="0,15,0,0">
<Label Content="左側のエリア"></Label>
<ItemsControl Name="ImageListControl">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Name="LeftImage" Source="{Binding}" Width="32" Height="32"></Image>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<StackPanel Grid.Column="1" Margin="0,15,0,0">
<Label Content="右側のエリア"></Label>
</StackPanel>
</Grid>
</Window>
次に、コード側は、下記のように修正する。
(1) 分割画像用のリストを定義する。
(2) 読み込んだ画像を32px * 32pxに分割する。
(3) 分割画像用のリストに設定し、画面に表示する。
//タイルのサイズを割ってインデックスを算出
int numTilesPerRow = bitmap.PixelWidth / 32;
int numTilesPerColumn = bitmap.PixelHeight / 32;
for (int y = 0; y < numTilesPerColumn; y++)
{
for (int x = 0; x < numTilesPerRow; x++)
{
//32px * 32pxに分割する
CroppedBitmap cb = new CroppedBitmap(bitmap, new Int32Rect(x * 32, y * 32, 32, 32));
//リストに追加する
tiles.Add(cb);
}
}
//画像を表示
ImageListControl.ItemsSource = tiles;
上記は、読み込んだ画像を32px * 32pxに分割し、<ItemsControl>に表示するプログラムである。読み込んだpngファイルのサイズを32pxで分割し、配列のループ数を決定する。
分割するためには、CroppedBitmapクラスを使用する。画像を分割後、リストに追加し、コントロールに貼り付ける。完成したコードを下記に示す。
using Microsoft.Win32;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MapEditor
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
//ファイルダイアログをオープンする
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "PNG files (*.png)|*.png";
if (openFileDialog.ShowDialog() == true)
{
//PNGファイルを読み込む
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(openFileDialog.FileName);
bitmap.EndInit();
//分割画像のリスト
List<ImageSource> tiles = new List<ImageSource>();
//タイルのサイズを割ってインデックスを算出
int numTilesPerRow = bitmap.PixelWidth / 32;
int numTilesPerColumn = bitmap.PixelHeight / 32;
for (int y = 0; y < numTilesPerColumn; y++)
{
for (int x = 0; x < numTilesPerRow; x++)
{
//32px * 32pxに分割する
CroppedBitmap cb = new CroppedBitmap(bitmap, new Int32Rect(x * 32, y * 32, 32, 32));
//リストに追加する
tiles.Add(cb);
}
}
//画像を表示
ImageListControl.ItemsSource = tiles;
}
}
}
}
上記を実行し、画像を入力すると、下記のように表示できる(図6)。
左側のエリアにキャラクター画像が32px*32pxに分割して表示されている。これで完成である。
この記事が気に入ったらサポートをしてみませんか?