【问题标题】:Images are rotated in PictureBox图片在 PictureBox 中旋转
【发布时间】:2016-08-21 21:16:17
【问题描述】:

正如问题所暗示的,当我将图像加载到图片框(使用对话框)时,它不会显示为原始外观。在这个屏幕截图中,左边的图片是我加载到图片框(右边)中的图片。

想知道是什么原因导致我使用 Paint 应用程序绘制图像并使用 Windows 照片查看器对其进行旋转,旋转后的图像按原样加载(旋转),也就是说,有些图片加载正常,而其他图片旋转!我不知道为什么?!

【问题讨论】:

  • Photo-viewer 通过调整 EXIF 数据来旋转 JPG - 它实际上并没有改变像素数据。我猜图片框不会检查 JPG 的 EXIF 方向。 BMP 和 PNG 等其他格式没有 EXIF,因此照片查看器在旋转它们时实际上会修改像素数据。

标签: c# winforms picturebox


【解决方案1】:

当您在 Windows 照片查看器中查看图像时,如果图像具有 Exif 方向数据,它会自动更正图像方向。 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); }
    }
}

【讨论】:

  • 如果您使用MyPictureBox 而不是PictureBox,旋转将自动修复。您也可以在图像上手动使用CorrectExifOrientation 方法并将图像放入PictureBox。如果您对答案有任何疑问,请告诉我:)
【解决方案2】:

如果没有原始图像数据,就无法确定发生了什么。但很明显,在某些时候,一些涉及图像处理的软件已经使用 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 对象传递给它,它就会返回存储在文件中的 EXIF 方向(如果有)。

有了它,您可以根据需要旋转图像。

【讨论】:

    【解决方案3】:

    我将图像从文件资源管理器加载到图片框,如下所示:

    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
    }
    

    这些是我的参考资料:

    代码参考(我修改了接受的答案):https://stackoverflow.com/a/42972969/11565087

    Visual 参考(在 cmets 中找到[我不知道如何在此处链接评论]):http://csharphelper.com/blog/2016/07/read-an-image-files-exif-orientation-data-in-c/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-10
      • 1970-01-01
      • 2011-05-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多