Чтение проблем 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);