C# マウスによる拡大処理

 

リサイズイベントによる縮小・拡大

 今回はpictureBoxに表示する写真の縮小・拡大について検討しました。先ずは、フォームサイズを変更する時に発生するリサイズイベント毎に画像の縮尺を変更しています。
 下図①のプログラム起動時の写真に対し、②フォーム拡大時の写真は一見同じ様ですが、文字・ボタン等が相対的に小さくなっています。実際のパソコンモニター上では、②は①の2倍以上大きく表示されています。次に③ですが、フォームサイズを変更する時、縦横比が崩れますが、フォーム縦横比に依らず、元写真の縦横比を維持し全画像を表示しています。

①プログラム起動時

②フォーム拡大(ボタンサイズ等が相対的に小さい)

③全画像表示 ※縦横比を変えずに全画像表示

 

マウス範囲指定による拡大

 次にマウスで範囲指定し、選択範囲を拡大表示する方法を検討しました。次の3つの写真は、①・②・③の順に拡大されています。①の写真では判り難いのですが、②の写真では選択範囲が黒い点線で囲われていることが判ります。
 ④は参考に拡大率を高くした場合の写真を掲載しています。元の写真の解像度にも依りますが、比較的詳細部位の確認も出来る様です。

①プログラム起動時

②1回目の拡大
③2回目の拡大

④参考(拡大率を高くした例)

プログラム

 プログラムを掲載しておきます。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ListViewTest
{
    public partial class Frm_03 : Form
    {
        private Bitmap crtImg;
        private double zRatio = 1d ;
        private Rectangle drwRct;
        private Rectangle srcRct;
 
        bool draw_flag = false;
        Point[] mus_dn = new Point[2];

        public Frm_03()
        {
            InitializeComponent();
        }

        private void Frm_03_Load(object sender, EventArgs e)
        {
            crtImg = new Bitmap(@"");

            reset_drwRct();

            // pictureBox1に対し、PictureBox2を透明化する処理
            pictureBox2.Parent = pictureBox1;
            pictureBox2.BackColor = Color.Transparent;

            // 元のParent(Form)に対する座標を補正する
            pictureBox2.Location = new Point(pictureBox2.Location.X - pictureBox1.Location.X, pictureBox2.Location.Y - pictureBox1.Location.Y);
            pictureBox2.Size = pictureBox1.Size;
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            reset_drwRct();
        }


        private void Frm_03_Resize(object sender, EventArgs e)
        {
            reset_drwRct();
        }

        // 全画像を領域に最大表示する
        private void reset_drwRct() {
            srcRct = new Rectangle(0, 0, crtImg.Width, crtImg.Height);
            pic_reseize();
        }

        // マウス領域指定し、画像リサイズ(マウスアップ時呼出)
        private void update_drwRct() {
            Point tmp_mv = new Point();

            if (mus_dn[1].X - mus_dn[0].X >= 0) { tmp_mv.X = mus_dn[0].X; } else { tmp_mv.X = mus_dn[1].X; }        // 始点修正(X)
            if (mus_dn[1].Y - mus_dn[0].Y >= 0) { tmp_mv.Y = mus_dn[0].Y; } else { tmp_mv.Y = mus_dn[1].Y; }        // 始点修正(Y)

            int tmp_wdt = Math.Abs(mus_dn[1].X - mus_dn[0].X);                                                      // 幅(X)         
            int tmp_hgt = Math.Abs(mus_dn[1].Y - mus_dn[0].Y);                                                      // 幅(Y)
            
            Rectangle tmpRct = srcRct;
            Rectangle tp_Rct = drwRct;

            // 指定領域を元画像に対する領域に変換
            srcRct.X = tmpRct.X+(int)Math.Round((double)tmpRct.Width * tmp_mv.X / tp_Rct.Width);                    // 元画像始点(X)
            srcRct.Y = tmpRct.Y+(int)Math.Round((double)tmpRct.Height * tmp_mv.Y / tp_Rct.Height);                  // 元画像終点(Y)
            srcRct.Width = (int)Math.Round((double)tmpRct.Width * tmp_wdt / tp_Rct.Width);                          // 元画像幅(W)
            srcRct.Height = (int)Math.Round((double)tmpRct.Height * tmp_hgt / tp_Rct.Height);                       // 元画像高さ(H)

            pic_reseize();
        }

        // srcRct(元画像の表示領域)指定後、呼出
        private void pic_reseize() {
            int pbx_w = pictureBox1.Width;
            int pbx_h = pictureBox1.Height;

            double ratio_w = (double)pbx_w / srcRct.Width;                                      // 幅方向倍率
            double ratio_h = (double)pbx_h / srcRct.Height;                                     // 高さ方向倍率

            // 対象領域が全て収まる様に倍率を確定
            if (ratio_w > ratio_h){ zRatio = ratio_h; }
            else { zRatio = ratio_w; }

            drwRct = new Rectangle(0, 0, (int)Math.Round(srcRct.Width * zRatio), (int)Math.Round(srcRct.Height * zRatio));

            Bitmap cvs = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            Graphics g = Graphics.FromImage(cvs);

            g.DrawImage(crtImg, drwRct, srcRct, GraphicsUnit.Pixel);
            g.Dispose();

            pictureBox2.Image = null;
            pictureBox1.Image = cvs;
      
      textBox1.Text = String.Format("{0:0.#####}", zRatio);  

        }


         
        private void pictureBox2_MouseDown(object sender, MouseEventArgs e)
        {
            draw_flag = true;
            mus_dn[0].X = e.X;
            mus_dn[0].Y = e.Y;
        }

        private void pictureBox2_MouseMove(object sender, MouseEventArgs e)
        {
            if (!draw_flag) { return; };

            Bitmap tmp_cvs = new Bitmap(pictureBox2.Width, pictureBox2.Height);
            Graphics tmp_g = Graphics.FromImage(tmp_cvs);
            Point tmp_mv = new Point();
            Pen tmp_p = new Pen(Color.FromArgb(255, 0, 0, 0), 1);
            tmp_p.DashStyle = DashStyle.Dot;

            if (e.X - mus_dn[0].X >= 0) { tmp_mv.X = mus_dn[0].X; } else { tmp_mv.X = e.X; }    // 始点修正(X)
            if (e.Y - mus_dn[0].Y >= 0) { tmp_mv.Y = mus_dn[0].Y; } else { tmp_mv.Y = e.Y; }    // 始点修正(Y)

            int tmp_wdt = Math.Abs(e.X - mus_dn[0].X);                                          // 幅(X)         
            int tmp_hgt = Math.Abs(e.Y - mus_dn[0].Y);                                          // 幅(Y)

            // 指定領域枠を描画
            tmp_g.DrawRectangle(tmp_p, tmp_mv.X, tmp_mv.Y, tmp_wdt, tmp_hgt);
            pictureBox2.Image = tmp_cvs;

        }

        private void pictureBox2_MouseUp(object sender, MouseEventArgs e)
        {
            if (!draw_flag) { return; };

            mus_dn[1].X = e.X;
            mus_dn[1].Y = e.Y;

            update_drwRct();

            draw_flag = false;
        }

       

     
    }
}

 

まとめ

 出来て良かったです。次回は縮小・拡大した写真上に描画する検討を行う予定です。