读取JPEG元数据(方向)出现问题

70
我有一张在iPhone上拍摄的JPEG图像。在我的桌面PC上(Windows Photo Viewer、Google Chrome等),方向是错误的。
我正在开发一个ASP.NET MVC 3 Web应用程序,需要上传照片(目前使用plupload)。
我有一些服务器端代码来处理图像,包括读取EXIF数据。
我尝试读取EXIF元数据中的PropertyTagOrientation字段(使用GDI - Image.PropertyItems),但该字段不存在。
所以它可能是一些特定的iPhone元数据,或者其他元数据。
我使用了另一个工具,如Aurigma Photo Uploader,它正确地读取元数据并旋转图像。它是如何做到这一点的?
有人知道哪些其他JPEG元数据可以包含所需的信息,以便知道需要旋转的信息,这是Aurigma使用的吗?
这是我用来读取EXIF数据的代码:
var image = Image.FromStream(fileStream);

foreach (var prop in image.PropertyItems)
{
   if (prop.Id == 112 || prop.Id == 5029)
   {
      // do my rotate code - e.g "RotateFlip"
      // Never get's in here - can't find these properties.
   }
}

有什么想法吗?
5个回答

151

以下是有关8个方向值的代码片段。

首先需要注意以下几点:

EXIF ID 0x0112 是用于方向的。这是一个有用的EXIF ID参考:http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html

0x0112 是十六进制等效于274。属性PropertyItem.Id的数据类型是int,因此这里有用的是274

另外,5029可能应该是0x502920521,这对应于ThumbnailOrientation,但可能不是此处所需。

调整图像方向:

注意:imgSystem.Drawing.Image或从它继承的类,如System.Drawing.Bitmap

if (Array.IndexOf(img.PropertyIdList, 274) > -1)
{
    var orientation = (int)img.GetPropertyItem(274).Value[0];
    switch (orientation)
    {
        case 1:
            // No rotation required.
            break;
        case 2:
            img.RotateFlip(RotateFlipType.RotateNoneFlipX);
            break;
        case 3:
            img.RotateFlip(RotateFlipType.Rotate180FlipNone);
            break;
        case 4:
            img.RotateFlip(RotateFlipType.Rotate180FlipX);
            break;
        case 5:
            img.RotateFlip(RotateFlipType.Rotate90FlipX);
            break;
        case 6:
            img.RotateFlip(RotateFlipType.Rotate90FlipNone);
            break;
        case 7:
            img.RotateFlip(RotateFlipType.Rotate270FlipX);
            break;
        case 8:
            img.RotateFlip(RotateFlipType.Rotate270FlipNone);
            break;
    }
    // This EXIF data is now invalid and should be removed.
    img.RemovePropertyItem(274);
}

13
更完整的答案:包括方向情况的详细描述,并注明要删除EXIF数据(以防后面进行处理)。 - thomasb
7
非常有帮助。在我看来,这应该被接受作为答案。 - Jeff Doolittle
2
在这里,您可以找到一些用于测试的方向图像示例:https://github.com/recurser/exif-orientation-examples - Krisztián Balla

17

看起来您忘记了查找的方向id值是十六进制的。 在使用112的地方,您应该使用0x112。

这篇文章解释了Windows如何处理方向错误,这篇文章似乎与您正在做的事情非常相关。


1
iPhone5S无法工作,拍摄的照片没有EXIF数据,有什么解决办法吗? - user192344
@user192344 如果你将它保存为png格式,它将不会保存EXIF信息,请将其保存为jpg格式。 - fligant

14

这篇帖子看起来,您需要检查ID 274。

foreach (PropertyItem p in properties) {
      if (p.Id == 274) {
            Orientation = (int)p.Value[0];
         if (Orientation == 6)
            oldImage.RotateFlip(RotateFlipType.Rotate90FlipNone);
         if (Orientation == 8)
            oldImage.RotateFlip(RotateFlipType.Rotate270FlipNone);
      break;
      }
}

嗯,我也试过了。它找到了一个ID为“274”的属性,但方向值是“1”。所以它没有翻转。 - RPM1984
+1 - 虽然这不是正确答案,但我的旋转方式是错误的,而你的是正确的。 - RPM1984
1
此外,“3”是倒置的,参见http://sylvana.net/jpegcrop/exif_orientation.html。我的测试结果也证实了这一点。 - DenNukem
这对我帮助很大。你可以使用这段代码以及一个针对所有方向的案例来正确定位任何图像。 - David C

14

我综合了给出的答案和评论,得出了这个结果:

    MemoryStream stream = new MemoryStream(data);
    Image image = Image.FromStream(stream);

    foreach (var prop in image.PropertyItems) {
        if ((prop.Id == 0x0112 || prop.Id == 5029 || prop.Id == 274)) {
            var value = (int)prop.Value[0];
            if (value == 6) {
                image.RotateFlip(RotateFlipType.Rotate90FlipNone);
                break;
            } else if (value == 8) {
                image.RotateFlip(RotateFlipType.Rotate270FlipNone);
                break;
            } else if (value == 3) {
                image.RotateFlip(RotateFlipType.Rotate180FlipNone);
                break;
            } 
        }
    }

2
0x112 = 274,它们相等,因此您可以在 if 语句中省略其中一个。 - Louis Somers
2
我尝试了这个方法,但在移动浏览器中仍然遇到问题。在Web浏览器中它可以正常工作。但在移动设备上,图像会向右旋转90度。请帮忙解决? - Shalin Jirawla
@ShalinJirawla 我曾经也遇到过你的问题:我刚刚添加了一个解决方案,它对我很有效。 - Darkseal
得到更多赞的答案是在不需要翻转移动图像时进行翻转(可能是情况2、4、5、7)。这对我来说效果更好! - deebs

2

在这里发布一下,以防有人遇到相同的问题。我在使用WFP和GDI读取方向时,在生产环境中遇到了问题。唯一有效的方法是使用:https://github.com/dlemstra/Magick.NET

代码非常简单:

var img = new MagickImage(inputStream);
img.AutoOrient();   // Fix orientation
img.Strip();        // remove all EXIF information
img.Write(outputPath);

这对我没有用,Android和iOS拍摄的照片仍然以横向显示,而它们都是以纵向模式拍摄的。 - Mason
检查一下你上传图片的方式,确保原始图片被上传。如果在上传之前进行了处理/压缩,可能会删除重要的元数据。那段代码从以前就一直有效。 - Diego Jancic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接