複数の画像を連結するだけであれば簡単にできます。しかし隣の画像の縦や横の長さとそろえたい、縦横の比を変えずに拡大縮小してから並べたい、そのまま並べるのではなく必要な部分だけトリミングしたものを並べたいということもあるのではないでしょうか?

簡単な動作でお気に入りの画像を自分でひとつの画像に編集したい、そんなかたのためにアプリを作成してみることにしました。

これまでスクロールバー付きのピクチャーボックスを自作してきましたが、これをつかって「ドラッグ&ドラッグでトリミングした画像を連結するアプリ」を作成します。

まずデータを管理するためのクラスを作成します。

Bitmapをファイルとして保存するときにBase64エンコードをします。そこでコンストラクタ内でそのための処理をおこなっています。WidthプロパティとHeightプロパティは描画するときの幅と高さです。

コンストラクタ内でSourceBitmapプロパティにBitmapがセットされるのですが、ファイルを読みだしたときはnullになっています。そこでSourceBitmap == nullのときはSourceBitmapBase64からBitmapを生成してそれを返します。

BitmapForShowプロパティはトリミングされて実際に描画されるBitmapです。X、YプロパティはどこにトリミングされたBitmapが表示されるかを示すもので、Width、Heightプロパティはそのときのサイズです。MarginLeft、MarginTop、MarginRight、MarginBottomプロパティは上下左右の切り捨てられた部分です。

拡大縮小するときに幅、高さのどちらかのみを指定して縦横比そのままで他方を求めるということもできます。EnableWidthのみがtrueのときは幅から高さを求めます。逆にEnableHeightプロパティのみがtrueのときは高さから幅を求めます。両方trueの場合は縦横比に縛られず両方をそれぞれ指定することができます。両方がfalseの場合はBitmapForShowの幅と高さをそのまま使います。

ではDataクラスを示します。

次にデザイナで以下のようなものを作ります。

TreeViewにファイルをドラッグ&ドロップするとアイテムとして追加されるとともに右側のScrollPictureBoxにBitmapが表示されます。複数同時にドラッグ&ドロップすると同じ位置に重なってしまいますが、これらはドラッグ&ドロップすることで移動させることができます。

重なり合っているとどれがどれなのかわからなくなります。そこで現在選択されているTeeNodeに対応するBitmapがどれなのかがわかるように左側下部のPictureBoxにも表示させます。

まずアップダウンコントロールで表示倍率を変更できるようにします。

TreeViewの上にファイルをドラッグドロップするとTreeNodeが追加されるとともに、追加されたBitmapがSchoolPictureBoxに表示されるようにします。

TreeNodeが追加されるときにBitmapをDataクラスのコンストラクタに渡して、Dataオブジェクトを生成します。そしてこれをTreeNode.Tagにセットします。これで追加された画像とTreeNodeを関連付けることができます。

上記が終わったら自作メソッド ShowBitmaps()でSchoolPictureBoxに描画させます。

GetDatas()メソッド内でTreeNodeに関連付けられたDataオブジェクトのリストを返してしますが、Reverse()メソッドで順番を逆にしています。これはTreeNodeの上にあるものを上側(手前)に描画したいからです。先に描画したものはあとから描画されたものに隠されてしまいます。上にあるものを手前に描画するために順番を逆にしているのです。

次に選択されているTreeNodeに対応するBitmapを左側下部のPictureBoxに描画します。左側がファイルから取得されたBitmap、右側がトリミングされたBitmapです。

次にBitmapをドラッグ&ドロップで移動できるようにします。ドラッグ&ドロップで移動できるのは現在選択されているTreeNodeに対応するBitmapがクリックされたときです。

ScrollPictureBox内でクリックされるとPictureBoxMouseDown1イベントが発生します。自作メソッド IsInRectangle(Rectangle rect, Point pt)でクリックされた点が現在選択されているTreeNodeに対応するBitmapが表示されている矩形内部かどうかを判定し、矩形内部であればそのBitmapの位置と対応するDataオブジェクトを保存します。そしてPictureBoxMouseMove1イベントが発生したらイベントハンドラに渡される引数から移動量を知ることができるのでそのぶんだけ移動させます。

実際の移動の処理はMovingData.XとMovingData.Yを書き換えてShowBitmaps()メソッドを呼ぶだけです。このとき後述するダイアログ(トリミング処理をするためのもの。後述)が存在する場合はその値も変更させます。

マウスボタンが離されたら MovingData に nullを代入してそれ以降のマウス移動にともなう処理がおきないようにします。

TreeNodeをドラッグ&ドロップすると位置を入れ替えることができるようにします。TreeNodeの位置を入れ替えたらShowBitmaps()メソッドを実行して再描画します。

メニューで[削除]を選択するとTreeNodeを削除できるようにします。TreeNodeを削除したらShowBitmaps()メソッドを実行して再描画します。

ファイルとして保存したり読み出すことができるようにします。

最後に合成された画像をPngファイルとして保存するメソッドを示します。