C# Winform 相册功能,图片缩放,拖拽,预览图分页

效果

1.图片放大,缩小,拖拽功能

2.添加图片,分页功能

一、前言

在一些项目中也会用到预览图片的功能,至于为什么有一个添加图片的按钮,是因为有些项目,比如视觉相关的项目,摄像头拍摄图片,然后显示在界面上,拍一次显示一张。另一个,就是分页功能,当预览图位置不够用时就会用到。

当前软件的功能

1.添加图片

如果8个预览图都满了,会自动分页,就可以点击上一页,或者下一页了。

2.点击预览图显示大图

点击预览图,之前的拖拽和放大会自动复位

3.大图可以拖拽,放大,缩小

如果图片比较小,有这个功能就看到图片的更多细节了。

4.图片倒序排列

最后拍摄的图片,始终显示在前面,方便用户更好的观察到最新的图片

二、实现功能

新建一个winform项目,界面如下:

界面中大图和预览图都是 PictureBox 控件 ,至于控件的名字,在下面的代码中可以看到,在文章的最后面,我会附上这个Demo源码,Visual Studio 版本为2019

下面代码有很多地方写法不合理,仅供参考,请自己优化

代码:

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

namespace 相册功能
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //本地的相册列表
        private string AlbumPath = Application.StartupPath + "\\Album";
        //相册列表
        private List<PictureBox> PictureBoxList = new List<PictureBox>();
        //图片路径列表
        private List<string> FilesinfoList = new List<string>();
        //相册显示的图片列表
        private List<Bitmap> BitmapList = new List<Bitmap>();
        //pictureBox1的初始位置
        private Point PicStartPos;
        //pictureBox1的初始大小
        private Size PicSize;

        //测试用
        int index = -1;
        //当前页数
        private int NowPage = 1;
        //总页数
        private int TotalPage = 1;
        //鼠标滚轮缩放图片的增量值
        private int ZoomStep = 20;
        //鼠标是否在拖拽中
        private bool IsMove = false;
        //鼠标点击的位置
        private Point MouseDownPoint;

        private void Form1_Load(object sender, EventArgs e)
        {
            PicStartPos = pictureBox1.Location;
            PicSize = pictureBox1.Size;
            this.pictureBox1.MouseWheel += new MouseEventHandler(this.pictureBox1_MouseWheel);

            PictureBoxList.Add(PictureBox_ImgList1);
            PictureBoxList.Add(PictureBox_ImgList2);
            PictureBoxList.Add(PictureBox_ImgList3);
            PictureBoxList.Add(PictureBox_ImgList4);
            PictureBoxList.Add(PictureBox_ImgList5);
            PictureBoxList.Add(PictureBox_ImgList6);
            PictureBoxList.Add(PictureBox_ImgList7);
            PictureBoxList.Add(PictureBox_ImgList8);

            //添加图片的点击事件
            for (int i = 0; i < PictureBoxList.Count; i++)
            {
                PictureBoxList[i].Click += new System.EventHandler(PictureBoxClick);
            }

            DirectoryInfo directory = new DirectoryInfo(AlbumPath);
            FileSystemInfo[] filesArray = directory.GetFileSystemInfos();
            foreach (var item in filesArray)
            {
                if (item.Attributes != FileAttributes.Directory)
                {
                    FilesinfoList.Add(item.FullName);
                }
            }
        }

        /// <summary>
        /// 上一页
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Back_Click(object sender, EventArgs e)
        {
            if (NowPage <= 1) return;

            NowPage--;
            for (int i = 0; i < PictureBoxList.Count; i++)
            {
                PictureBoxList[i].Image = null;
            }

            List<Bitmap> list = GetPagesBitmap(NowPage);
            for (int i = 0; i < list.Count; i++)
            {
                PictureBoxList[i].Image = list[i];
            }

            pictureBox1.Image = list[0];
            //设置坐标
            pictureBox1.Location = PicStartPos;
            //设置控件宽高
            pictureBox1.Size = PicSize;

            Label_NumberOfPages.Text = string.Format("{0} / {1}", NowPage, TotalPage);
            BackNextButtonType();
        }

        /// <summary>
        /// 下一页
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Next_Click(object sender, EventArgs e)
        {
            if (NowPage >= TotalPage) return;

            NowPage++;
            for (int i = 0; i < PictureBoxList.Count; i++)
            {
                PictureBoxList[i].Image = null;
            }

            List<Bitmap> list = GetPagesBitmap(NowPage);
            for (int i = 0; i < list.Count; i++)
            {
                PictureBoxList[i].Image = list[i];
            }

            pictureBox1.Image = list[0];
            //设置坐标
            pictureBox1.Location = PicStartPos;
            //设置控件宽高
            pictureBox1.Size = PicSize;

            Label_NumberOfPages.Text = string.Format("{0} / {1}", NowPage, TotalPage);
            BackNextButtonType();
        }

        /// <summary>
        /// 添加图片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Add_Click(object sender, EventArgs e)
        {
            index++;
            AddPicture(new Bitmap(FilesinfoList[index]));
            if (index >= FilesinfoList.Count - 1)
                index = -1;
        }

        /// <summary>
        /// 添加图片
        /// </summary>
        /// <param name="bitmap"></param>
        private void AddPicture(Bitmap bitmap)
        {
            if (bitmap == null) return;

            //添加到图片列表
            BitmapList.Add(bitmap);
            //界面预留图中显示
            pictureBox1.Image = bitmap;
            //设置坐标
            pictureBox1.Location = PicStartPos;
            //设置控件宽高
            pictureBox1.Size = PicSize;

            //计算当前总页数
            int page = BitmapList.Count / PictureBoxList.Count;
            int remainder = BitmapList.Count % PictureBoxList.Count;
            TotalPage = remainder > 0 ? page + 1 : page;
            Label_NumberOfPages.Text = string.Format("{0} / {1}", NowPage, TotalPage);

            BackNextButtonType();

            //让图片按逆向顺序显示
            List<Bitmap> reverseSort = new List<Bitmap>();
            for (int i = BitmapList.Count - 1; i >= 0; i--)
            {
                reverseSort.Add(BitmapList[i]);
            }
            for (int i = 0; i < reverseSort.Count; i++)
            {
                if (i <= 7)
                    PictureBoxList[i].Image = reverseSort[i];
            }
        }

        /// <summary>
        /// 8张预览图片的点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PictureBoxClick(Object sender, System.EventArgs e)
        {
            PictureBox pictureBox = (PictureBox)sender;
            if (pictureBox != null && pictureBox.Image != null)
            {
                pictureBox1.Image = pictureBox.Image;
                //设置坐标
                pictureBox1.Location = PicStartPos;
            }
        }

        /// <summary>
        /// 获取索引对应的图片
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private List<Bitmap> GetPagesBitmap(int index)
        {
            if (BitmapList.Count <= 0) return null;

            //页数
            int page = BitmapList.Count / PictureBoxList.Count;
            //余数
            int remainder = BitmapList.Count % PictureBoxList.Count;
            //总页数
            int allPage = remainder > 0 ? page + 1 : page;

            if (index > allPage) return null;

            //索引起点
            int start = (index * PictureBoxList.Count) - PictureBoxList.Count;
            //索引结束点
            int end = (index * PictureBoxList.Count) - 1;
            if (end > BitmapList.Count) end = BitmapList.Count - 1;

            List<Bitmap> reverseSort = new List<Bitmap>();
            for (int i = BitmapList.Count - 1; i >= 0; i--)
            {
                reverseSort.Add(BitmapList[i]);
            }

            List<Bitmap> list = new List<Bitmap>();
            for (int i = start; i <= end; i++)
            {
                list.Add(reverseSort[i]);
            }

            if (list.Count > 0)
                return list;
            return null;
        }

        /// <summary>
        /// 上一页,下一页按钮状态
        /// </summary>
        private void BackNextButtonType()
        {
            Button_Next.Enabled = true;
            Button_Back.Enabled = true;

            //现在页 = 总页数
            if (NowPage == TotalPage)
                Button_Next.Enabled = false;
            //现在页 小于等于 1
            if (NowPage <= 1)
                Button_Back.Enabled = false;
        }


        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (pictureBox1.Image == null) return;

            if (e.Button == MouseButtons.Left)
            {
                MouseDownPoint.X = Cursor.Position.X; //记录鼠标左键按下时位置
                MouseDownPoint.Y = Cursor.Position.Y;
                IsMove = true;
                pictureBox1.Focus(); //鼠标滚轮事件(缩放时)需要picturebox有焦点
            }
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                IsMove = false;
            }
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (pictureBox1.Image == null) return;
            pictureBox1.Focus(); //鼠标在picturebox上时才有焦点,此时可以缩放
            if (IsMove)
            {
                int x, y;   //新的pictureBox1.Location(x,y)
                int moveX, moveY; //X方向,Y方向移动大小。
                moveX = Cursor.Position.X - MouseDownPoint.X;
                moveY = Cursor.Position.Y - MouseDownPoint.Y;
                x = pictureBox1.Location.X + moveX;
                y = pictureBox1.Location.Y + moveY;
                pictureBox1.Location = new Point(x, y);
                MouseDownPoint.X = Cursor.Position.X;
                MouseDownPoint.Y = Cursor.Position.Y;
            }
        }

        private void pictureBox1_MouseWheel(object sender, MouseEventArgs e)
        {
            if (pictureBox1.Image == null) return;

            PictureBox pbox = pictureBox1;
            int x = e.Location.X;
            int y = e.Location.Y;
            int ow = pbox.Width;
            int oh = pbox.Height;
            int VX, VY;  //因缩放产生的位移矢量
            if (e.Delta > 0) //放大
            {
                //第1步
                pbox.Width += ZoomStep;
                pbox.Height += ZoomStep;
                //第2步
                PropertyInfo pInfo = pbox.GetType().GetProperty("ImageRectangle", BindingFlags.Instance | BindingFlags.NonPublic);
                Rectangle rect = (Rectangle)pInfo.GetValue(pbox, null);
                //第3步
                pbox.Width = rect.Width;
                pbox.Height = rect.Height;

                //Console.WriteLine(string.Format("宽:{0},高:{1}",pbox.Width,pbox.Height));
            }
            if (e.Delta < 0) //缩小
            {
                //防止一直缩成负值
                if (pbox.Width < 300)
                    return;

                pbox.Width -= ZoomStep;
                pbox.Height -= ZoomStep;
                PropertyInfo pInfo = pbox.GetType().GetProperty("ImageRectangle", BindingFlags.Instance |
                 BindingFlags.NonPublic);
                Rectangle rect = (Rectangle)pInfo.GetValue(pbox, null);
                pbox.Width = rect.Width;
                pbox.Height = rect.Height;
            }

            //第4步,求因缩放产生的位移,进行补偿,实现锚点缩放的效果
            VX = (int)((double)x * (ow - pbox.Width) / ow);
            VY = (int)((double)y * (oh - pbox.Height) / oh);
            pbox.Location = new Point(pbox.Location.X + VX, pbox.Location.Y + VY);
        }


    }
}

代码中,鼠标缩放,拖拽功能,需要在控件里选择对应的方法,否则运行就没有效果

运行后,效果就如文章开头的 Gif 图片

源码:点击下载

结束

如果这个帖子对你有用,欢迎 关注 + 点赞 + 留言,谢谢

end

  • 18
    点赞
  • 100
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
要实现两张图片的直方对比,你需要执行以下步骤: 1. 读取两张图片并将它们转换为灰度像。 2. 将两张像的灰度值分别统计到两个直方中。 3. 对两个直方进行归一化处理,使得它们的和为1。 4. 计算两个直方之间的距离,可以使用欧几里得距离或者其他的距离度量方法。 5. 根据计算出的距离值,可以判断两张像的相似度。 下面是一个示例代码,演示如何实现两张图片的直方对比: ```csharp private void CompareHistograms(string imagePath1, string imagePath2) { // 读取两张图片并将它们转换为灰度像 Bitmap bmp1 = new Bitmap(imagePath1); Bitmap bmp2 = new Bitmap(imagePath2); Bitmap gray1 = Grayscale(bmp1); Bitmap gray2 = Grayscale(bmp2); // 将两张像的灰度值分别统计到两个直方中 int[] hist1 = Histogram(gray1); int[] hist2 = Histogram(gray2); // 对两个直方进行归一化处理 Normalize(hist1); Normalize(hist2); // 计算两个直方之间的距离 double distance = Distance(hist1, hist2); // 输出结果 Console.WriteLine("Distance: " + distance); } // 将图片转换为灰度像 private Bitmap Grayscale(Bitmap bmp) { Bitmap gray = new Bitmap(bmp.Width, bmp.Height); for (int x = 0; x < bmp.Width; x++) { for (int y = 0; y < bmp.Height; y++) { Color color = bmp.GetPixel(x, y); int grayValue = (int)(color.R * 0.299 + color.G * 0.587 + color.B * 0.114); gray.SetPixel(x, y, Color.FromArgb(grayValue, grayValue, grayValue)); } } return gray; } // 计算直方 private int[] Histogram(Bitmap bmp) { int[] hist = new int[256]; for (int x = 0; x < bmp.Width; x++) { for (int y = 0; y < bmp.Height; y++) { Color color = bmp.GetPixel(x, y); int grayValue = color.R; hist[grayValue]++; } } return hist; } // 归一化直方 private void Normalize(int[] hist) { int sum = 0; for (int i = 0; i < hist.Length; i++) { sum += hist[i]; } for (int i = 0; i < hist.Length; i++) { hist[i] = (int)(hist[i] * 1.0 / sum * 100); } } // 计算直方距离 private double Distance(int[] hist1, int[] hist2) { double distance = 0; for (int i = 0; i < hist1.Length; i++) { distance += Math.Pow(hist1[i] - hist2[i], 2); } distance = Math.Sqrt(distance); return distance; } ``` 在上面的示例代码中,Grayscale方法将一张彩色像转换为灰度像,Histogram方法计算灰度直方,Normalize方法对直方进行归一化处理,Distance方法计算两个直方之间的距离。最后,你可以调用CompareHistograms方法,传入两张图片的路径,即可计算它们的直方距离并输出结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熊思宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值