Чтение проблем JPEG Метаданные (ориентация)

У меня есть изображение в формате JPEG, которое было снято на iphone. На моем настольном ПК (Windows Photo Viewer, Google Chrome и т.д.) Ориентация неверна.

Я работаю над веб-приложением ASP.NET MVC 3, где мне нужно загружать фотографии (в настоящее время используется plupload).

У меня есть серверный код для обработки изображений, включая чтение данных EXIF.

Я пробовал читать поле PropertyTagOrientation в метаданных EXIF ​​(используя 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 in here - can't find these properties.
   }
}

Любые идеи?

Ответ 1

Похоже, вы забыли, что значения идентификатора ориентации, которые вы искали, находятся в шестнадцатеричном формате. Если вы используете 112, вы должны использовать 0x112.

В этой статье объясняется, как переносится ориентированная на Windows ориентация, а this один кажется довольно важным для того, что вы делаете.

Ответ 2

Вот фрагмент, который обращается к 8 значениям ориентации.

Сначала несколько примечаний:

EXIF ​​id 0x0112 предназначен для ориентации. Это полезная ссылка EXIF ​​id http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html

0x0112 - это шестнадцатеричный эквивалент 274. Тип данных PropertyItem.Id - это int, что означает 274.

Кроме того, предположим, что 5029 0x5029 или 20521, что коррелирует с ThumbnailOrientation, хотя, скорее всего, это не так. /p >

Ориентное изображение:

Примечание: img является System.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);
}

Ответ 3

Я написал небольшой вспомогательный класс, чтобы суммировать все ответы. Он также обновит Exif Orientation Tag соответственно изменениям, внесенным в изображение, что может быть полезно, если вы просмотрите изображение в приложении просмотра exif-aware после его вращения. Это также должно решить проблему, поднятую @ShalinJirawla выше.

using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;

public static class ImageHelper
{
    /// <summary>
    /// Rotate the given image file according to Exif Orientation data
    /// </summary>
    /// <param name="sourceFilePath">path of source file</param>
    /// <param name="targetFilePath">path of target file</param>
    /// <param name="targetFormat">target format</param>
    /// <param name="updateExifData">set it to TRUE to update image Exif data after rotation (default is TRUE)</param>
    /// <returns>The RotateFlipType value corresponding to the applied rotation. If no rotation occurred, RotateFlipType.RotateNoneFlipNone will be returned.</returns>
    public static RotateFlipType RotateImageByExifOrientationData(string sourceFilePath, string targetFilePath, ImageFormat targetFormat, bool updateExifData = true)
    {
        // Rotate the image according to EXIF data
        var bmp = new Bitmap(sourceFilePath);
        RotateFlipType fType = RotateImageByExifOrientationData(bmp, updateExifData);
        if (fType != RotateFlipType.RotateNoneFlipNone)
        {
            bmp.Save(targetFilePath, targetFormat);
        }
        return fType;
    }

    /// <summary>
    /// Rotate the given bitmap according to Exif Orientation data
    /// </summary>
    /// <param name="img">source image</param>
    /// <param name="updateExifData">set it to TRUE to update image Exif data after rotation (default is TRUE)</param>
    /// <returns>The RotateFlipType value corresponding to the applied rotation. If no rotation occurred, RotateFlipType.RotateNoneFlipNone will be returned.</returns>
    public static RotateFlipType RotateImageByExifOrientationData(Image img, bool updateExifData = true)
    {
        int orientationId = 0x0112;
        var fType = RotateFlipType.RotateNoneFlipNone;
        if (img.PropertyIdList.Contains(orientationId))
        {
            var pItem = img.GetPropertyItem(orientationId);
            fType = GetRotateFlipTypeByExifOrientationData(pItem.Value[0]);
            if (fType != RotateFlipType.RotateNoneFlipNone)
            {
                img.RotateFlip(fType);
                // Remove Exif orientation tag (if requested)
                if (updateExifData) img.RemovePropertyItem(orientationId);
            }
        }
        return fType;
    }

    /// <summary>
    /// Return the proper System.Drawing.RotateFlipType according to given orientation EXIF metadata
    /// </summary>
    /// <param name="orientation">Exif "Orientation"</param>
    /// <returns>the corresponding System.Drawing.RotateFlipType enum value</returns>
    public static RotateFlipType GetRotateFlipTypeByExifOrientationData(int orientation)
    {
        switch (orientation)
        {
            case 1:
            default:
                return RotateFlipType.RotateNoneFlipNone;
            case 2:
                return RotateFlipType.RotateNoneFlipX;
            case 3:
                return RotateFlipType.Rotate180FlipNone;
            case 4:
                return RotateFlipType.Rotate180FlipX;
            case 5:
                return RotateFlipType.Rotate90FlipX;
            case 6:
                return RotateFlipType.Rotate90FlipNone;
            case 7:
                return RotateFlipType.Rotate270FlipX;
            case 8:
                return RotateFlipType.Rotate270FlipNone;
        }
    }
}

Дополнительная информация и краткое тематическое исследование также доступны здесь:

Изменить ориентацию изображения для iPhone и/или фотографий Android в NET С#

Ответ 4

Из этот пост выглядит так, что вам нужно проверить 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;
      }
}

Ответ 5

Я объединил данные ответы и комментарии и придумал следующее:

    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;
            } 
        }
    }

Ответ 6

Проводка здесь на всякий случай, если кто-то имеет такую же проблему. У меня были проблемы с производством, которые читали ориентацию с использованием 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);