65.9K
CodeProject 正在变化。 阅读更多。
Home

Photo Selector 是一个 C# 程序,用于从您的相机或存储卡中选择“保留”的照片

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (2投票s)

2016年1月20日

CPOL

6分钟阅读

viewsIcon

9225

downloadIcon

437

在本文中,我将展示简单的程序如何帮助改进您的摄影工作流程。它简化了选择存储卡或相机上哪些图像值得处理的第一步。它使用一个替代PictureBox控件来显示照片并允许它们被放大

引言

照片选择器是一个简单的图像处理程序,旨在简化从外部媒体中选择和复制JPG和RAW照片到硬盘驱动器上的工作文件夹的过程。您需要拍摄JPG或JPG + RAW才能使用此程序。

背景

我用数码相机拍了很多照片。每次外出拍摄回来,我可能需要整理500张照片。我过去常常将所有照片复制到我当月的图片文件夹中。问题是我从不删除那些不合格的照片。为了解决这个问题,我开始使用Windows照片查看器浏览存储卡上的照片。我会记下值得处理的照片编号,然后将选定的几张照片移动到我的硬盘上。“记下编号”?没有人应该被迫记下编号。所以,我设计了一个相当简单的软件解决方案。我的解决方案让您可以查看存储卡(或类似设备)上的照片,进行缩放和平移,以检查焦点和清晰度,然后将“保留”的照片复制到硬盘上的指定文件夹。虽然我的程序仅限于显示JPG图像,但它知道如何将RAW图像传输到指定的T作文件夹。

我感谢Code Project的贡献者Lev Danielyan提供的EXIF元数据提取库,以及Bob Powell提供的ZoomPicBox控件。

显示图像

该程序使用Bob Powell的ZoomPicBox控件来显示图像。该控件提供流畅的平移和缩放功能。我添加了代码来Dispose Image,以确保图像删除正常工作。这是显示图像的方法。

      private void ShowImage()
      {
         this.Text = "Photo Selector - " + _SourceImageFile;
         LoadExifInto(_SourceImagePath);
         Bitmap image = new Bitmap(_SourceImagePath, true);
         zoomPic.Image = RotateImage(image);
         this.trkZoom.Value = 20;
         this.zoomPic.Zoom = 0.01f * this.trkZoom.Value;
      }

EXIF标签中的“方向”标签用于确定照片的方向。RotateImage在需要时使用标准的.Net方法旋转图像。请注意,图像文件的方向不会改变。旋转是为了确保照片以正确的方向显示。

缩放通过一行事件处理程序完成。

        private void trkZoom_ValueChanged_1(object sender, EventArgs e)
        {
            this.zoomPic.Zoom = 0.01f * this.trkZoom.Value;
        }

平移通过ZoomPicBox上的MouseDownMouseMoveMouseUp事件处理。

      private void zoomPic_MouseDown(object sender, MouseEventArgs e)
      {
         if (e.Button == System.Windows.Forms.MouseButtons.Left)
         {
            _MouseDown = true;
            clickPosition.X = e.X;
            clickPosition.Y = e.Y;
         }
      }
      private void zoomPic_MouseMove(object sender, MouseEventArgs e)
      {
         if (_MouseDown)
         {
            Cursor = Cursors.Hand;
            scrollPosition.X = clickPosition.X - e.X - lastPosition.X;
            scrollPosition.Y = clickPosition.Y - e.Y - lastPosition.Y;
            zoomPic.AutoScrollPosition = scrollPosition;
         }
      }
      private void zoomPic_MouseUp(object sender, MouseEventArgs e)
      {
         Cursor = Cursors.Default;
         lastPosition.X = zoomPic.AutoScrollPosition.X;
         lastPosition.Y = zoomPic.AutoScrollPosition.Y;
         _MouseDown = false;
      }

EXIF数据

用户可以在简单的DataGrid中查看EXIF数据。为了避免显示过多信息,我排除了一些标签。

菜单选项

文件/选择初始图像

此菜单项显示一个对话框,允许您选择要处理的JPG文件集中的第一个JPG文件。它仅限于JPG文件。您可以选择任何文件,也许是特定拍摄会话中的第一个文件。一旦您选择了一个JPG文件,它将被显示。您可以使用缩放滑块进行缩放,并通过用鼠标拖动图像或使用图像缩放时出现的滚动条进行平移。

选择原始图像文件夹(如果与JPG源设备文件夹不同)

有些相机允许您使用两张不同的存储卡,并可以选择将其中一张分配给JPG图像,另一张分配给RAW。其他相机可能会将文件存储在同一存储卡上的不同文件夹中。当您选择初始(JPG)文件时,照片选择器会检查同一文件夹中是否存在匹配的RAW文件。如果存在,它假定该文件夹中的每个JPG文件都将有一个匹配的RAW文件。如果它没有找到该RAW文件,那么它会启用菜单选项“选择原始图像文件夹(如果与JPG源设备文件夹不同)”。这让您可以选择存储匹配RAW文件的文件夹。

如果您的电脑只有一个存储卡插槽或读卡器,而您的相机使用两张卡,就会出现问题。在这种情况下,您将JPG文件复制到硬盘上的临时文件夹,并选择其中的一个文件作为您的初始图像。我建议复制JPG文件而不是RAW文件,因为它们更小。两种方法都有效。

文件/选择原始图像文件夹

此菜单项显示一个对话框,允许您选择要存储RAW图像副本的文件夹。通常,这将是您硬盘上的一个文件夹。

如果您不选择这样的文件夹,那么照片选择器将不会保存RAW文件。

文件/选择JPG图像文件夹

此菜单项显示一个对话框,允许您选择要存储JPG图像副本的文件夹。通常,这将是您硬盘上的一个文件夹。

设置/设置原始文件扩展名

此菜单项显示一个对话框,允许您设置相机用于RAW文件的扩展名。默认值为.ARW

工具栏

如果您点击“后退”按钮,将显示当前图像文件之前的图像文件。如果您在第一张图像处,则会显示最后一张图像。

如果您点击“前进”按钮,将显示当前图像文件之后的图像文件。如果您在最后一张图像处,则会显示第一张图像。

如果您点击“删除”按钮,当前图像文件将被删除,并会弹出确认对话框。RAW和JPG图像都将被删除。然后将显示下一个图像文件。

如果您点击“复制”按钮,当前图像将被复制到选定的目标图像文件夹。然后将显示下一个图像文件。

如果您点击EXIF按钮,将显示当前图像文件的主要EXIF标签。

移动滑块将放大和缩小图像。您可能会使用它来检查清晰度。如果单击图像并按住鼠标左键,同时移动鼠标,您还可以平移图像。

保存图片

当您将图像文件从源文件夹复制到目标文件夹时,程序会检查是否存在同名文件。可能会发生冲突,因为您已经复制了文件,或者您将文件从不同的存储卡复制到同一个目标文件夹,或者您的相机循环使用了其编号集。

如果程序发现冲突,它会检查文件是否长度相同。如果相同,它会将两个文件读入内存并逐字节比较。如果文件确实完全相同,它会告诉您。否则,它会像Windows一样在文件名后面加上括号中的数字。这是用于读取和比较文件的代码。

      private bool FilesIdentical(string X, string Y)
      {
         byte[] bX;
         byte[] bY;
         try {
            bX = ReadAll(new FileStream(X, FileMode.Open, FileAccess.Read));
            bY = ReadAll(new FileStream(Y, FileMode.Open, FileAccess.Read));
         }
         catch (Exception ex) {
            throw ex;
         }
         for (int i = 0; i < bX.Length; i++) {
            if (bX[i] != bY[i]) {
               return false;
            }
         }
         bX = null;
         bY = null;
         return true;
      }
      public static byte[] ReadAll(FileStream fileStream)
      {
         MemoryStream m = new MemoryStream();
         fileStream.CopyTo(m);
         fileStream.Close();
         fileStream.Dispose();
         return m.ToArray();
      }

其他文件比较方法会从每个文件中一次读取一个字节,直到它们找到不匹配的地方。如果您预计文件不匹配,这种方法会比读取整个文件更快。然而,当两个文件大小相同且名称相同时,它们极有可能完全相同。在这种情况下,我使用的技术可能同样快速。

帮助

我使用Microsoft Word创建了一个帮助文件并将其保存为PDF文件。当点击帮助按钮时,会显示该帮助文件。

使用代码

此代码使用了中级C#编码技术。它可以作为处理照片的应用程序的起点,因为它允许显示、缩放和平移图像。它还演示了如何获取EXIF数据以及如何将照片旋转到正确的方向。

作为一名摄影师,我发现这个程序改进了我的工作流程,并阻止我将不需要的照片保存到硬盘上。

关注点

该程序演示了如何使用Bob Powell的 ZoomPicBox控件来显示、缩放和平移图像。它还演示了如何使用Lev Danielyan的 EXIF元数据提取库。逐字节的文件比较方法是可重用的。该程序帮助我整理存储卡上的照片,并决定哪些是“值得保留的”。

历史

Code-Project 的第一个版本

© . All rights reserved.