拡大縮小・D&Dによるファイルの読み書き機能付きPictureBox

C# コンピュータ
C#
Controlをドラッグアンドドロップする方法を知ったので、PictureBoxに組み込んでみました。

ファイル名:Form1.cs

namespace MyPicbox1;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        MyPicbox picbox = new()
        {
            Dock = DockStyle.Fill,
        };
        Controls.Add(picbox);
        
        Load += (s, e) =>
        {
            var bmp = new Bitmap(@"C:\Users\karet\Pictures\20230614193457.png");
            picbox.Bitmap = bmp;
        };
    }
}

ファイル名:MyPicbox.cs

using System.Drawing.Drawing2D;
public class MyPicbox : UserControl
{
    Bitmap? _bitmap = null;

    public Bitmap? Bitmap
    {
        get
        {
            return _bitmap;
        }
        set
        {
            _bitmap = value;
            MyPicbox_Resize(null, new EventArgs());
        }
    }

    Graphics? _graphics = null;
    Matrix? _matrix = null;

    string _localPath = "";
    public string LocalPath
    {
        get
        {
            return _localPath;
        }
        set
        {
            _localPath = value;

            loadImage(_localPath);
        }
    }

    static async Task<Bitmap?> LoadFile(string LocalPath)
    {
        using var fs = new FileStream(LocalPath, FileMode.Open, FileAccess.Read);
        var result = await Task.Run(()=>(Bitmap)Bitmap.FromStream(fs));
        return result;
    }

    PictureBox _picbox = new()
    {
        Dock = DockStyle.Fill,
        AllowDrop = true,
    };
    public MyPicbox()
    {
        Controls.Add(_picbox);
        Load += MyPicbox_Load;
        Resize += MyPicbox_Resize;
        _picbox.DragEnter += _picbox_DragEnter;
        _picbox.DragDrop += _picbox_DragDrop;
        _picbox.MouseWheel += _picbox_MouseWheel;
        _picbox.MouseDown += _picbox_MouseDown;
    }
    async void loadImage(string LocalPath)
    {
        if (!File.Exists(LocalPath)) return;
        _picbox.Image?.Dispose();
        _bitmap = await LoadFile(LocalPath);
        MyPicbox_Resize(null, new EventArgs());
    }
    void saveImage(string LocalPath)
    {
        if (File.Exists(LocalPath)) return;
        if (null == _bitmap) return;

        if ("" == _localPath)
        {
            _localPath = Path.GetTempFileName() + ".png";
        }
        _bitmap.Save(_localPath, System.Drawing.Imaging.ImageFormat.Png);
    }
    void MyPicbox_Load(Object? s, EventArgs e)
    {
        var bmp = new Bitmap(this.Width, this.Height);
        using var g = Graphics.FromImage(bmp);
        g.Clear(Color.Gray);
        _picbox.Image?.Dispose();
        _picbox.Image = bmp;
    }
    void _picbox_DragEnter(Object? s, DragEventArgs e)
    {
        e.Effect = DragDropEffects.All;
    }
    void _picbox_DragDrop(Object? s, DragEventArgs e)
    {
        if (e.Data == null) return;
        Object? obj = e.Data.GetData(DataFormats.FileDrop, false);
        if (obj == null) return;
        this.LocalPath = ((string[])obj)[0];
    }
    void MyPicbox_Resize(Object? s, EventArgs e)
    {
        if (_graphics != null)
        {
            _matrix = _graphics.Transform;
            _graphics.Dispose();
            _graphics = null;
        }
        else
        {
            _matrix = new Matrix();
        }
        _picbox.Image?.Dispose();
        _picbox.Image = new Bitmap(_picbox.Width, _picbox.Height);
        _graphics = Graphics.FromImage(_picbox.Image);
        _graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
        DrawImage();
    }
    void DrawImage()
    {
        if (_bitmap == null || _graphics == null) return;
        if (_matrix != null) _graphics.Transform = _matrix;
        _graphics.Clear(_picbox.BackColor);
        _graphics.DrawImage(_bitmap, 0, 0);
        _picbox.Refresh();
    }
    void _picbox_MouseWheel(Object? s, MouseEventArgs e)
    {
        if (_bitmap == null || _matrix == null) return;
        _matrix.Translate(-e.X, -e.Y, MatrixOrder.Append);

        if (e.Delta > 0)
        {
            if (_matrix.Elements[0] < 100)
            {
                _matrix.Scale(1.5f, 1.5f, MatrixOrder.Append);
            }
        }
        else
        {
            if (_matrix.Elements[0] > 0.20)
            {
                _matrix.Scale(1.0f / 1.5f, 1.0f / 1.5f, MatrixOrder.Append);
            }
        }
        _matrix.Translate(e.X, e.Y, MatrixOrder.Append);

        DrawImage();
    }
    async void _picbox_MouseDown(Object? s, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            if ("" == _localPath)
            {
                await Task.Run(()=>saveImage(_localPath));
            }
            var effect = DragDropEffects.Copy | DragDropEffects.Move;
            string[] paths = {_localPath};
            IDataObject data = new DataObject(DataFormats.FileDrop, paths);
            var result = _picbox.DoDragDrop(data, effect);

            if ( result == DragDropEffects.None)
            {
                MessageBox.Show("D&D failed.");
            }
        }
    }
}
MyPicboxクラスの動作確認のためにForm1Loadでビットマップをセットしています。
この状態では画像はセットされていますが読み込み元のパスがセットされていないので、エクスプローラーにドラッグアンドドロップするとテンポラリファイルが作成されそちらがコピーされます。
ドラッグアンドドロップで既存の画像ファイルを開いた場合は、開いたファイルのパスがコピー元になります。
ほかの機能はマウスのホイールで画像が拡大縮小されます。

コメント