Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Exif information not working on production server

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:

  • Works: Windows 10, IIS 10
  • Doesn't work: Windows Server 2012 R2, IIS 8.5

Any suggestions?

like image 558
Diego Jancic Avatar asked Oct 19 '25 01:10

Diego Jancic


2 Answers

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.

like image 128
Diego Jancic Avatar answered Oct 20 '25 16:10

Diego Jancic


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);
}
like image 36
James Avatar answered Oct 20 '25 14:10

James