CropBox
轻松地为您的桌面应用程序添加图像裁剪功能
引言
因此,这次我正在编写一个桌面应用程序,用户应该能够选择图像的一部分并保存裁剪后的图像。
通常,在开始自己编写代码之前,我会花费大量时间和精力在网上搜索和尝试现有的控件,但这次我没有,因为从一开始我就有99%的把握,我找不到任何能达到我期望的控件。
于是我立即开始自己开发控件。我想要一个类似PictureBox
的东西,它可以显示图像,并且有一个可调整的选择框等等。
没什么可说的了。这个控件最终比我预期的要好,而且非常易于使用。所以,就是这样。如果你需要它,就去用吧——否则就不用了……
控件功能概览
1) 基本控件信息
我从标准的Panel控件派生了这个控件。这样,它就具备了Panel
的所有属性和行为,使得设计和布局你的窗体变得容易。
你会问,为什么不从PictureBox
派生呢?好问题!说实话,我也不知道。我想让控件尽可能轻量级和简单,而且我认为Panel
比PictureBox
更适合作为基础。
2) 你需要了解的属性
正如你稍后会看到的,这个控件使用起来极其简单。有几个属性是需要了解的。其中大部分都与控件的外观有关。
Image
-Image
属性是指定你需要裁剪的图像的地方。OverlayColor
- 图像中未被选中的部分会显示一个半透明的覆盖层,以便更容易看清选区本身。你可以在这里设置覆盖层的颜色。OverlayAlpha
- 覆盖层是半透明的,OverlayAlpha
属性决定了它的透明度。该值应在0
(不可见)和255
(完全不透明)之间。SelectionInitialMode
决定了加载图像时自动显示的选区。如果你不喜欢默认模式并选择Custom
,你应该在代码中处理SetInitialSelection
事件。否则,将使用FullImage
模式。SelectionResizeMode
决定了如何调整选区的大小。它还决定了是否显示角部的调整柄。SelectionBorderColor
、SelectionBorderDashStyle
、SelectionBorderDashPattern
和SelectionBorderWidth
都决定了选中区域周围的边框如何绘制。SelectionBorderDashPattern
在设计器中不可见,但如果你将SelectionBorderDashStyle
设置为Custom
,则应在代码中设置它。否则,你可以忽略它。SelectionResizeHandleBorderColor
、SelectionResizeHandleBorderWidth
和SelectionResizeHandleColor
决定了角落的调整柄如何绘制(如果需要绘制的话)。ThumbnailScalingPercentage
- 如果你需要,该控件可以为你裁剪后的图像生成缩略图。此属性以完整图像大小的百分比确定其大小。
1.2版本新增
StartEditingMode
- 决定何时可以编辑图像。
3) 你需要了解的方法
GetCroppedImage
- 返回控件中裁剪到选中区域的图像。GetCroppedImageThumbnail
- 返回控件中裁剪到选中区域的图像的缩略图。另请参阅ThumbnailScalingPercentage
属性。
1.2版本新增
StartEdit
和EndEdit
- 调用这些方法开始或结束编辑模式。SaveCroppedImage
- 将裁剪后的图像直接保存到文件。SaveCroppedImageThumbnail
- 将裁剪后的图像缩略图直接保存到文件。ResetSelection
- 将选区重置为初始选区。
用法
如前所述,使用该控件非常简单直接。只需将其拖放到窗体上,然后根据需要调整大小和外观。然后将图像分配给Image
属性,例如:
cropBox1.Image = Image.FromFile(fileName);
之后,你可以编辑选区,当你准备好裁剪图像时,可以像这样获取裁剪后的图像:
Image croppedImage = cropBox1.GetCroppedImage();
之后,就可以用简单的.NET编程将其保存为Jpeg文件了。
croppedImage.Save(fileName, ImageFormat.Jpeg);
提示
该控件使用整个客户端区域来绘制图像,但如果你觉得这样不好看,可以简单地设置Padding
属性,在图像周围添加边框。
我学到的有趣的事情
从文件加载图像的标准.NET功能(见上面的代码)根本不关心EXIF方向标签。这意味着,如果你用智能手机等拍摄了照片,在将其加载到Image
类时,它可能会显示得完全错误。
幸运的是,这个问题很容易解决,当然,我在控件中也包含了解决方案。
if (Array.IndexOf(_image.PropertyIdList, 274) > -1)
{
var orientation = (int)_image.GetPropertyItem(274).Value[0];
switch (orientation)
{
case 1:
// No rotation required.
break;
case 2:
_image.RotateFlip(RotateFlipType.RotateNoneFlipX);
break;
case 3:
_image.RotateFlip(RotateFlipType.Rotate180FlipNone);
break;
case 4:
_image.RotateFlip(RotateFlipType.Rotate180FlipX);
break;
case 5:
_image.RotateFlip(RotateFlipType.Rotate90FlipX);
break;
case 6:
_image.RotateFlip(RotateFlipType.Rotate90FlipNone);
break;
case 7:
_image.RotateFlip(RotateFlipType.Rotate270FlipX);
break;
case 8:
_image.RotateFlip(RotateFlipType.Rotate270FlipNone);
break;
}
// This EXIF data is now invalid and should be removed.
_image.RemovePropertyItem(274);
}
(上面的代码片段为了简洁起见,是直接“借鉴”自StackOverflow上用户ReenignE
的代码——其余部分都是我完成的!要赞美就赞美该赞美的人……)
历史
版本 1.2 (2019-08-26)
- 新功能:添加了StartEditing属性,用于确定编辑何时开始。
- 新功能:添加了StartEdit和EndEdit方法调用。
- 新功能:添加了直接保存到文件的方法,SaveCroppedImage(2个重载)。
- 新功能:添加了直接保存缩略图到文件的方法,SaveCroppedImageThumbnail(2个重载)。
- 新功能:添加了ResetSelection方法。
- 错误修复:MaintainAspectRatio模式未能正常工作。
版本 1.1 (2019-08-22)
- 错误修复 - 图像未随控件缩放。
- 错误修复 - 修复了“负数”选区。
- 错误修复 - 修复了方形图像选区的舍入误差。
- 改进 - 一些细微的界面代码更改。
版本 1.0 (2019-08-21)
- 首次发布