C#のWinFormsで画像加工アプリ1「ドラックアンドドロップで画像を表示しCtrl+Cでクリップボードへコピー」

コンピュータ

画像加工アプリケーションを作成します。
今回はメインとなるフォームにドラックアンドドロップで画像表示、Ctrl+Cでクリップボードへコピー、メニューで画像の拡大機能を作成してみました。

プロジェクトの作成

mkdir GazouKakou01
cd GazouKakou01
dotnet new winforms

ソースコード

ファイル名:Form1.cs

using System.Drawing.Drawing2D;

namespace GazouKakou01;

public partial class Form1 : Form
{
    Bitmap? _buffBmp;
    Bitmap? _viewBmp;
    int _scale = 1;

    public void ScaleChange()
    {
        if (_buffBmp is null) return;

        int w = _buffBmp.Width * _scale;
        int h = _buffBmp.Height * _scale;
        _viewBmp?.Dispose();
        _viewBmp = new (w, h);
        using var g = Graphics.FromImage(_viewBmp);
        g.InterpolationMode = InterpolationMode.NearestNeighbor;
        g.DrawImage(_buffBmp, 0, 0, w, h);
    }
    public Bitmap? Bmp
    {
        get
        {
            return _viewBmp;
        }
        set
        {
            _buffBmp?.Dispose();
            _buffBmp = value;
            ScaleChange();
        }
    }
    // メインメニュー
    readonly MenuStrip menubar = new();
    readonly ToolStripMenuItem viewMenuItem = new()
    {
        Text = "表示",
    };
    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,
    };
    // ステータスバー
    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.Add(viewMenuItem);
        viewMenuItem.DropDownItems.AddRange(new ToolStripItem[] {
            expandX1MenuItem,
            expandX2MenuItem,
            expandX4MenuItem,
            expandX8MenuItem,});
        // ステータスバーを登録
        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;
            });
            mainPicbox.Image = this._viewBmp;
        };
        // キーボードイベント
        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 = "";
            }
        };
        // 拡大項目を選択
        Action<Object?> scaleExec = new((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;
                }
            }
            ScaleChange();
            mainPicbox.Image = this.Bmp;
        });
        // メニューアイテムのクリックイベント
        expandX1MenuItem.Click += (s, e) => scaleExec(s);
        expandX2MenuItem.Click += (s, e) => scaleExec(s);
        expandX4MenuItem.Click += (s, e) => scaleExec(s);
        expandX8MenuItem.Click += (s, e) => scaleExec(s);
    }
    ~Form1()
    {
        _viewBmp?.Dispose();
        _buffBmp?.Dispose();    
    }
}

実行


フォームに画像ファイルをドラックアンドドロップ

画像が表示されます。

メニューで拡大率を選択できます。
このほかにキーボードでCtrl+Cでクリップボードへ画像がコピーされます。

今後

画像の編集は基本的にGIMPで行っているのですが、GIMPに無いOpenCVのフィルターなどをアプリケーションに実装し、フィルターの結果をコピーしGIMPで貼り付けて連携するような使い方を想定しています。
過去の記事で試したOpenCVのフィルター類を一個のアプリケーションで呼び出せるような形になりますが、ソースコードが膨大になりそうですので、フィルターごとに一つのソースファイル(=記事)としてプロジェクトに追加していく予定です。

コメント