图像在 PictureBox 中旋转
Images are rotated in PictureBox
正如问题所暗示的,当我将图像加载到 pictureBox 中(使用对话框)时,它不会显示为原始外观。在这个屏幕截图中,左边的图像是我加载到 pictureBox(右边)中的图像。
试图知道是什么原因造成的,我使用画图应用程序绘制图像并使用 Windows 照片查看器旋转它,旋转后的图像按原样加载(旋转),就是这样,有些图片很好装了,其他的都轮换了!我不知道为什么?!
没有原始图像数据,无法确定发生了什么。但很明显,在某些时候,一些涉及图像处理的软件使用了 EXIF 方向 属性 来旋转图像,而不是实际修改图像数据本身。这可能是照片查看器或在某些时候处理过照片的其他工具。
以下代码可用于检测图像的方向,正如拍摄照片的相机记录在 EXIF 数据中的那样:
static ImageOrientation GetOrientation(this Image image)
{
PropertyItem pi = SafeGetPropertyItem(image, 0x112);
if (pi == null || pi.Type != 3)
{
return ImageOrientation.Original;
}
return (ImageOrientation)BitConverter.ToInt16(pi.Value, 0);
}
// A file without the desired EXIF property record will throw ArgumentException.
static PropertyItem SafeGetPropertyItem(Image image, int propid)
{
try
{
return image.GetPropertyItem(propid);
}
catch (ArgumentException)
{
return null;
}
}
其中:
/// <summary>
/// Possible EXIF orientation values describing clockwise
/// rotation of the captured image due to camera orientation.
/// </summary>
/// <remarks>Reverse/undo these transformations to display an image correctly</remarks>
public enum ImageOrientation
{
/// <summary>
/// Image is correctly oriented
/// </summary>
Original = 1,
/// <summary>
/// Image has been mirrored horizontally
/// </summary>
MirrorOriginal = 2,
/// <summary>
/// Image has been rotated 180 degrees
/// </summary>
Half = 3,
/// <summary>
/// Image has been mirrored horizontally and rotated 180 degrees
/// </summary>
MirrorHalf = 4,
/// <summary>
/// Image has been mirrored horizontally and rotated 270 degrees clockwise
/// </summary>
MirrorThreeQuarter = 5,
/// <summary>
/// Image has been rotated 270 degrees clockwise
/// </summary>
ThreeQuarter = 6,
/// <summary>
/// Image has been mirrored horizontally and rotated 90 degrees clockwise.
/// </summary>
MirrorOneQuarter = 7,
/// <summary>
/// Image has been rotated 90 degrees clockwise.
/// </summary>
OneQuarter = 8
}
上面的GetOrientation()
方法写成一个扩展方法,当然你也可以把它当成一个普通的静态方法来调用。无论哪种方式,只需将您刚刚从文件中打开的 Bitmap
对象传递给它,它就会 return 存储在文件中的 EXIF 方向(如果有的话)。
有了它,您可以根据需要旋转图像。
当您在 Windows 照片查看器中查看图像时,如果 Exif orientation data. PictureBox
没有内置支持此类功能,它会自动更正图像方向。您可以创建一个自定义 PictureBox
,即使它们有方向数据也能正确显示图像:
using System.Linq;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
public class MyPictureBox : PictureBox
{
private void CorrectExifOrientation(Image image)
{
if (image == null) return;
int orientationId = 0x0112;
if (image.PropertyIdList.Contains(orientationId))
{
var orientation = (int)image.GetPropertyItem(orientationId).Value[0];
var rotateFlip = RotateFlipType.RotateNoneFlipNone;
switch (orientation)
{
case 1: rotateFlip = RotateFlipType.RotateNoneFlipNone; break;
case 2: rotateFlip = RotateFlipType.RotateNoneFlipX; break;
case 3: rotateFlip = RotateFlipType.Rotate180FlipNone; break;
case 4: rotateFlip = RotateFlipType.Rotate180FlipX; break;
case 5: rotateFlip = RotateFlipType.Rotate90FlipX; break;
case 6: rotateFlip = RotateFlipType.Rotate90FlipNone; break;
case 7: rotateFlip = RotateFlipType.Rotate270FlipX; break;
case 8: rotateFlip = RotateFlipType.Rotate270FlipNone; break;
default: rotateFlip = RotateFlipType.RotateNoneFlipNone; break;
}
if (rotateFlip != RotateFlipType.RotateNoneFlipNone)
{
image.RotateFlip(rotateFlip);
image.RemovePropertyItem(orientationId);
}
}
}
[Localizable(true)]
[Bindable(true)]
public new Image Image
{
get { return base.Image; }
set { base.Image = value; CorrectExifOrientation(value); }
}
}
我将我的图像从文件资源管理器加载到 pictureBox,如下所示:
private void btnBrowse_Click ( object sender, EventArgs e ) {
using( OpenFileDialog openFile = new OpenFileDialog() ) {
openFile.Title = "Select image for [user]";
openFile.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png)|*.jpg; *.jpeg; *.jpe; *.jfif; *.png|All files (*.*)|*.*";
if( openFile.ShowDialog() == DialogResult.OK ) {
//image validation
try {
Bitmap bmp = new Bitmap( openFile.FileName );//to validate the image
if( bmp != null ) {//if image is valid
pictureBox1.Load( openFile.FileName );//display selected image file
pictureBox1.Image.RotateFlip( Rotate( bmp ) );//display image in proper orientation
bmp.Dispose();
}
} catch( ArgumentException ) {
MessageBox.Show( "The specified image file is invalid." );
} catch( FileNotFoundException ) {
MessageBox.Show( "The path to image is invalid." );
}
}
}
}
这是正确显示图像方向的方法:
//Change Image to Correct Orientation When displaying to PictureBox
public static RotateFlipType Rotate ( Image bmp ) {
const int OrientationId = 0x0112;
PropertyItem pi = bmp.PropertyItems.Select( x => x )
.FirstOrDefault( x => x.Id == OrientationId );
if( pi == null )
return RotateFlipType.RotateNoneFlipNone;
byte o = pi.Value[ 0 ];
//Orientations
if( o == 2 ) //TopRight
return RotateFlipType.RotateNoneFlipX;
if( o == 3 ) //BottomRight
return RotateFlipType.RotateNoneFlipXY;
if( o == 4 ) //BottomLeft
return RotateFlipType.RotateNoneFlipY;
if( o == 5 ) //LeftTop
return RotateFlipType.Rotate90FlipX;
if( o == 6 ) //RightTop
return RotateFlipType.Rotate90FlipNone;
if( o == 7 ) //RightBottom
return RotateFlipType.Rotate90FlipY;
if( o == 8 ) //LeftBottom
return RotateFlipType.Rotate90FlipXY;
return RotateFlipType.RotateNoneFlipNone; //TopLeft (what the image looks by default) [or] Unknown
}
这些是我的参考资料:
代码参考(我修改了接受的答案):
Visual参考(在评论中找到[我不知道如何link在这里评论]):http://csharphelper.com/blog/2016/07/read-an-image-files-exif-orientation-data-in-c/
正如问题所暗示的,当我将图像加载到 pictureBox 中(使用对话框)时,它不会显示为原始外观。在这个屏幕截图中,左边的图像是我加载到 pictureBox(右边)中的图像。
试图知道是什么原因造成的,我使用画图应用程序绘制图像并使用 Windows 照片查看器旋转它,旋转后的图像按原样加载(旋转),就是这样,有些图片很好装了,其他的都轮换了!我不知道为什么?!
没有原始图像数据,无法确定发生了什么。但很明显,在某些时候,一些涉及图像处理的软件使用了 EXIF 方向 属性 来旋转图像,而不是实际修改图像数据本身。这可能是照片查看器或在某些时候处理过照片的其他工具。
以下代码可用于检测图像的方向,正如拍摄照片的相机记录在 EXIF 数据中的那样:
static ImageOrientation GetOrientation(this Image image)
{
PropertyItem pi = SafeGetPropertyItem(image, 0x112);
if (pi == null || pi.Type != 3)
{
return ImageOrientation.Original;
}
return (ImageOrientation)BitConverter.ToInt16(pi.Value, 0);
}
// A file without the desired EXIF property record will throw ArgumentException.
static PropertyItem SafeGetPropertyItem(Image image, int propid)
{
try
{
return image.GetPropertyItem(propid);
}
catch (ArgumentException)
{
return null;
}
}
其中:
/// <summary>
/// Possible EXIF orientation values describing clockwise
/// rotation of the captured image due to camera orientation.
/// </summary>
/// <remarks>Reverse/undo these transformations to display an image correctly</remarks>
public enum ImageOrientation
{
/// <summary>
/// Image is correctly oriented
/// </summary>
Original = 1,
/// <summary>
/// Image has been mirrored horizontally
/// </summary>
MirrorOriginal = 2,
/// <summary>
/// Image has been rotated 180 degrees
/// </summary>
Half = 3,
/// <summary>
/// Image has been mirrored horizontally and rotated 180 degrees
/// </summary>
MirrorHalf = 4,
/// <summary>
/// Image has been mirrored horizontally and rotated 270 degrees clockwise
/// </summary>
MirrorThreeQuarter = 5,
/// <summary>
/// Image has been rotated 270 degrees clockwise
/// </summary>
ThreeQuarter = 6,
/// <summary>
/// Image has been mirrored horizontally and rotated 90 degrees clockwise.
/// </summary>
MirrorOneQuarter = 7,
/// <summary>
/// Image has been rotated 90 degrees clockwise.
/// </summary>
OneQuarter = 8
}
上面的GetOrientation()
方法写成一个扩展方法,当然你也可以把它当成一个普通的静态方法来调用。无论哪种方式,只需将您刚刚从文件中打开的 Bitmap
对象传递给它,它就会 return 存储在文件中的 EXIF 方向(如果有的话)。
有了它,您可以根据需要旋转图像。
当您在 Windows 照片查看器中查看图像时,如果 Exif orientation data. PictureBox
没有内置支持此类功能,它会自动更正图像方向。您可以创建一个自定义 PictureBox
,即使它们有方向数据也能正确显示图像:
using System.Linq;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
public class MyPictureBox : PictureBox
{
private void CorrectExifOrientation(Image image)
{
if (image == null) return;
int orientationId = 0x0112;
if (image.PropertyIdList.Contains(orientationId))
{
var orientation = (int)image.GetPropertyItem(orientationId).Value[0];
var rotateFlip = RotateFlipType.RotateNoneFlipNone;
switch (orientation)
{
case 1: rotateFlip = RotateFlipType.RotateNoneFlipNone; break;
case 2: rotateFlip = RotateFlipType.RotateNoneFlipX; break;
case 3: rotateFlip = RotateFlipType.Rotate180FlipNone; break;
case 4: rotateFlip = RotateFlipType.Rotate180FlipX; break;
case 5: rotateFlip = RotateFlipType.Rotate90FlipX; break;
case 6: rotateFlip = RotateFlipType.Rotate90FlipNone; break;
case 7: rotateFlip = RotateFlipType.Rotate270FlipX; break;
case 8: rotateFlip = RotateFlipType.Rotate270FlipNone; break;
default: rotateFlip = RotateFlipType.RotateNoneFlipNone; break;
}
if (rotateFlip != RotateFlipType.RotateNoneFlipNone)
{
image.RotateFlip(rotateFlip);
image.RemovePropertyItem(orientationId);
}
}
}
[Localizable(true)]
[Bindable(true)]
public new Image Image
{
get { return base.Image; }
set { base.Image = value; CorrectExifOrientation(value); }
}
}
我将我的图像从文件资源管理器加载到 pictureBox,如下所示:
private void btnBrowse_Click ( object sender, EventArgs e ) {
using( OpenFileDialog openFile = new OpenFileDialog() ) {
openFile.Title = "Select image for [user]";
openFile.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png)|*.jpg; *.jpeg; *.jpe; *.jfif; *.png|All files (*.*)|*.*";
if( openFile.ShowDialog() == DialogResult.OK ) {
//image validation
try {
Bitmap bmp = new Bitmap( openFile.FileName );//to validate the image
if( bmp != null ) {//if image is valid
pictureBox1.Load( openFile.FileName );//display selected image file
pictureBox1.Image.RotateFlip( Rotate( bmp ) );//display image in proper orientation
bmp.Dispose();
}
} catch( ArgumentException ) {
MessageBox.Show( "The specified image file is invalid." );
} catch( FileNotFoundException ) {
MessageBox.Show( "The path to image is invalid." );
}
}
}
}
这是正确显示图像方向的方法:
//Change Image to Correct Orientation When displaying to PictureBox
public static RotateFlipType Rotate ( Image bmp ) {
const int OrientationId = 0x0112;
PropertyItem pi = bmp.PropertyItems.Select( x => x )
.FirstOrDefault( x => x.Id == OrientationId );
if( pi == null )
return RotateFlipType.RotateNoneFlipNone;
byte o = pi.Value[ 0 ];
//Orientations
if( o == 2 ) //TopRight
return RotateFlipType.RotateNoneFlipX;
if( o == 3 ) //BottomRight
return RotateFlipType.RotateNoneFlipXY;
if( o == 4 ) //BottomLeft
return RotateFlipType.RotateNoneFlipY;
if( o == 5 ) //LeftTop
return RotateFlipType.Rotate90FlipX;
if( o == 6 ) //RightTop
return RotateFlipType.Rotate90FlipNone;
if( o == 7 ) //RightBottom
return RotateFlipType.Rotate90FlipY;
if( o == 8 ) //LeftBottom
return RotateFlipType.Rotate90FlipXY;
return RotateFlipType.RotateNoneFlipNone; //TopLeft (what the image looks by default) [or] Unknown
}
这些是我的参考资料:
代码参考(我修改了接受的答案):
Visual参考(在评论中找到[我不知道如何link在这里评论]):http://csharphelper.com/blog/2016/07/read-an-image-files-exif-orientation-data-in-c/