画像加工アプリケーションを作成します。
今回はメインとなるフォームにドラックアンドドロップで画像表示、Ctrl+Cでクリップボードへコピー、メニューで画像の拡大機能を作成してみました。
プロジェクトの作成
mkdir GazouKakou02
cd GazouKakou02
dotnet new winforms
ソースコード
ファイル名:Form1.cs
using System.Text.RegularExpressions;
namespace GazouKakou02;
public partial class Form1 : Form
{
Bitmap? _buffBmp;
Bitmap? _viewBmp;
public Bitmap? Bmp
{
get
{
return _viewBmp;
}
set
{
_buffBmp?.Dispose();
_buffBmp = value;
if (_buffBmp is null) return;
_viewBmp?.Dispose();
_viewBmp = Scaleup(this._buffBmp, this._scale);
mainPicbox.Image = _viewBmp;
}
}
// メインメニュー
readonly MenuStrip menubar = new();
readonly ToolStripMenuItem viewMenuItem = new()
{
Text = "表示",
};
readonly ToolStripMenuItem filterMenuItem = new()
{
Text = "フィルター",
};
// ステータスバー
readonly StatusStrip statusbar = new();
readonly ToolStripStatusLabel statusLabel1 = new();
// パネル
readonly Panel mainPanel = new()
{
Dock = DockStyle.Fill,
AllowDrop = true,
AutoScroll = true,
};
// ピクチャボックス
readonly PictureBox mainPicbox = new()
{
SizeMode = PictureBoxSizeMode.AutoSize,
};
public Form1()
{
InitializeComponent();
// キーボードイベントをFormで受け取る
this.KeyPreview = true;
// コントロールの登録
this.Controls.AddRange([
mainPanel,
menubar,
statusbar,]);
// メインメニューの登録
menubar.Items.AddRange(new ToolStripItem[]{
viewMenuItem,
filterMenuItem,});
// ステータスバーを登録
statusbar.Items.Add(statusLabel1);
// ピクチャボックスを登録
mainPanel.Controls.Add(mainPicbox);
// ドラックアンドドロップ
mainPanel.DragEnter += (s, e) =>
{
e.Effect = DragDropEffects.Copy;
};
mainPanel.DragDrop += async (s, e) =>
{
if (e.Data is null) return;
var data = e.Data.GetData(DataFormats.FileDrop, false);
if (data is not string[] files) return;
this.Bmp = await Task.Run(()=>{
using var fs = new FileStream(files[0], FileMode.Open, FileAccess.Read);
var bmp = new Bitmap(fs);
return bmp;
});
};
// キーボードイベント
this.KeyDown += async (s, e) =>
{
if (_buffBmp is null) return;
// Ctrl+C
if ((e.Modifiers & Keys.Control) == Keys.Control && e.KeyCode == Keys.C)
{
// クリップボードへ画像をコピー
var ms = new MemoryStream();
_buffBmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
Clipboard.SetData("PNG", ms);
statusLabel1.Text = "クリップボードへコピーしました。";
await Task.Delay(1000);
statusLabel1.Text = "";
}
};
// 各種機能の初期化処理
Type type = this.GetType(); // 自分自身のクラスの情報を取得
// メソッドの一覧を取得
foreach(var mi in type.GetMethods())
{
// Initで始まるメソッド以外を排除
if (Regex.IsMatch(mi.Name, "^Init_.+$") == false) continue;
// メソッドの呼び出し
mi.Invoke(this, null);
}
// クローズ
this.FormClosed += (s, e) =>
{
_viewBmp?.Dispose();
_buffBmp?.Dispose();
};
}
}
ファイル名:FilterDialog.cs
namespace GazouKakou02;
public class FilterDialog : Form
{
readonly public PictureBox Picbox = new()
{
Location = new (10, 10),
Size = new (600, 240),
};
readonly public Button OkBtn = new()
{
Location = new (10, 260),
Size = new (80, 40),
Text = "OK",
DialogResult = DialogResult.OK,
};
readonly public Button CancelBtn = new()
{
Location = new (100, 260),
Size = new (80,40),
Text = "Cancel",
DialogResult = DialogResult.Cancel,
};
readonly public Label Track1Label = new()
{
Location = new(10, 310),
Size = new(90, 40),
};
readonly public TrackBar Track1 = new()
{
Location = new Point(110, 310),
Size = new Size(200, 40),
};
// コンストラクタ
public FilterDialog(string filterName="")
{
this.ClientSize = new Size(640, 480);
this.Text = filterName;
this.AcceptButton = OkBtn;
this.CancelButton = CancelBtn;
this.Controls.AddRange(
[
Picbox,
OkBtn,
CancelBtn,
Track1Label,
Track1,
]);
}
}
ファイル名:Form1.Scaleup.cs
/// <summary>
/// プレビューの拡大表示
/// </summary>
using System.Drawing.Drawing2D;
namespace GazouKakou02;
public partial class Form1 : Form
{
// メニュー項目
readonly ToolStripMenuItem expandX1MenuItem = new()
{
Text = "等倍",
Checked = true, // チェック
Tag = 1,
};
readonly ToolStripMenuItem expandX2MenuItem = new()
{
Text = "拡大2倍",
Checked = false, // 未チェック
Tag = 2,
};
readonly ToolStripMenuItem expandX4MenuItem = new()
{
Text = "拡大x4",
Checked = false, // 未チェック
Tag = 4,
};
readonly ToolStripMenuItem expandX8MenuItem = new()
{
Text = "拡大x8",
Checked = false, // 未チェック
Tag = 8,
};
int _scale = 1; // 拡大倍率
/// <summary>
/// 拡大処理
/// </summary>
static public Bitmap Scaleup(Bitmap src, int scale)
{
int w = src.Width * scale;
int h = src.Height * scale;
Bitmap dst = new (w, h);
using var g = Graphics.FromImage(dst);
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(src, 0, 0, w, h);
return dst;
}
/// <summary>
/// 拡大処理メニュー項目を選択
/// </summary>
public void ScaleupMenuItemSelect(Object? obj)
{
if (obj is null) return;
if (obj is not ToolStripMenuItem menu) return;
foreach(ToolStripMenuItem m in viewMenuItem.DropDownItems)
{
if (m.Tag == menu.Tag)
{
m.Checked = true;
this._scale = (menu.Tag is null) ? 1 : (int)menu.Tag;
} else {
m.Checked = false;
}
}
if (_buffBmp is null) return;
this._viewBmp?.Dispose();
this._viewBmp = Scaleup(this._buffBmp, this._scale);
mainPicbox.Image = _viewBmp;
}
/// <summary>
/// 拡大処理の初期化
/// </summary>
public void Init_Scaleup()
{
// メニューの登録
viewMenuItem.DropDownItems.AddRange(
new ToolStripItem[] {
expandX1MenuItem,
expandX2MenuItem,
expandX4MenuItem,
expandX8MenuItem,
});
// メニューアイテムのクリックイベント
expandX1MenuItem.Click += (s, e) => ScaleupMenuItemSelect(s);
expandX2MenuItem.Click += (s, e) => ScaleupMenuItemSelect(s);
expandX4MenuItem.Click += (s, e) => ScaleupMenuItemSelect(s);
expandX8MenuItem.Click += (s, e) => ScaleupMenuItemSelect(s);
}
}
実行
フォームに画像ファイルをドラックアンドドロップ
画像が表示されます。
メニューで拡大率を選択できます。
このほかにキーボードでCtrl+Cでクリップボードへ画像がコピーされます。
今後
画像の編集は基本的にGIMPで行っているのですが、GIMPに無いOpenCVのフィルターなどをアプリケーションに実装し、フィルターの結果をコピーしGIMPで貼り付けて連携するような使い方を想定しています。
過去の記事で試したOpenCVのフィルター類を一個のアプリケーションで呼び出せるような形になりますが、ソースコードが膨大になりそうですので、フィルターごとに一つのソースファイル(=記事)としてプロジェクトに追加していく予定です。
コメント