I'm reading the Exif information of a JPEG to rotate an image. The JPEG gets uploaded in ASP.NET and I read the upload stream, rotate it and save it. It's working perfectly on my dev machine (Windows 10, IIS 10), but when I try on the server (Windows Server 2012 R2, IIS 8.5), it doesn't work, it doesn't load any Exif information.
Here's the code:
void SavePhoto()
{
// PHOTO is the Html
HttpPostedFile photo = Request.Files["ProfilePhoto_File"];
using (var image = Image.FromStream(photo.InputStream, true, true))
{
SaveConvertingFormat(image, "output_path.jpg");
}
}
public static void SaveConvertingFormat(Image image, string outputPath)
{
int imageWidth = image.Width;
int imageHeight = image.Height;
using (var result = new Bitmap(imageWidth, imageHeight))
{
using (var g = Graphics.FromImage(result))
{
g.DrawImage(image, 0, 0, imageWidth, imageHeight);
}
var rotation = GetExifRotate(image, outputPath);
// IN THE SERVER, rotation IS ALWAYS RotateNoneFlipNone
if (rotation != RotateFlipType.RotateNoneFlipNone)
result.RotateFlip(rotation);
SaveJpeg(result, outputPath, 85);
}
}
private static void SaveJpeg(this Image img, string filename, int quality)
{
EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, (long)quality);
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save(filename, jpegCodec, encoderParams);
}
public static RotateFlipType GetExifRotate(Image img, string outputPath)
{
// Source: https://stackoverflow.com/a/48347653/72350
// ERROR:
// IN THE PRODUCTION SERVER, PropertyIdList IS EMPTY!
const int ExifOrientationId = 0x112;
if (!img.PropertyIdList.Contains(ExifOrientationId))
return RotateFlipType.RotateNoneFlipNone;
var prop = img.GetPropertyItem(ExifOrientationId);
int val = BitConverter.ToUInt16(prop.Value, 0);
var rot = RotateFlipType.RotateNoneFlipNone;
if (val == 3 || val == 4)
rot = RotateFlipType.Rotate180FlipNone;
else if (val == 5 || val == 6)
rot = RotateFlipType.Rotate90FlipNone;
else if (val == 7 || val == 8)
rot = RotateFlipType.Rotate270FlipNone;
if (val == 2 || val == 4 || val == 5 || val == 7)
rot |= RotateFlipType.RotateNoneFlipX;
return rot;
}
Again, the code above:
Any suggestions?
Just in case someone has the same issue. I had problems in production reading the orientation using WFP and GDI.
When using WPF, the error was:
System.Runtime.InteropServices.COMException (0x88982F8A): The component registration is invalid.
(Exception from HRESULT: 0x88982F8A)
at System.Windows.Media.Imaging.BitmapMetadata.GetQuery(String query)
SOLUTION:
The only thing that worked was using: https://github.com/dlemstra/Magick.NET
The code is fairly simple:
var img = new MagickImage(inputStream);
img.AutoOrient(); // Fix orientation
img.Strip(); // remove all EXIF information
img.Write(outputPath);
It also helped me remove 10s of lines.
It isn't necessary to strip the EXIF data. AutoOrient() automatically sets the EXIF orientation to TopLeft.
You'll also want to use the using clause, as MagickImage implements IDisposable.
using (var img = new MagickImage(inputStream))
{
img.AutoOrient(); // Fix orientation
img.Write(outputPath);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With