Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get EXIF Orientation Tag,Rotate to Proper Orientation, Process Image and Save the Image with proper Orientation

My program processes some images in batch.I currently need to read the exif orientation tag of the image,rotate it to proper orientation,do some processing and save the image without any EXIF Orientation Tag,but with proper Rotation.(or with EXIF tag with Proper Orientation)

I am reading EXIF and Rotating using this library:

  var bmp = new Bitmap(pathToImageFile);
    var exif = new EXIFextractor(ref bmp, "n"); // get source from http://www.codeproject.com/KB/graphics/exifextractor.aspx?fid=207371

    if (exif["Orientation"] != null)
    {
    RotateFlipType flip = OrientationToFlipType(exif["Orientation"].ToString());

    if (flip != RotateFlipType.RotateNoneFlipNone) // don't flip of orientation is correct
    {
    bmp.RotateFlip(flip);
    bmp.Save(pathToImageFile, ImageFormat.Jpeg);
    }

    // Match the orientation code to the correct rotation:

    private static RotateFlipType OrientationToFlipType(string orientation)
    {
    switch (int.Parse(orientation))
    {
    case 1:
    return RotateFlipType.RotateNoneFlipNone;

    case 2:
    return RotateFlipType.RotateNoneFlipX;

    case 3:
    return RotateFlipType.Rotate180FlipNone;
    case 4:
    return RotateFlipType.Rotate180FlipX;
    break;
    case 5:
    return RotateFlipType.Rotate90FlipX;
    break;
    case 6:
    return RotateFlipType.Rotate90FlipNone;
    case 7:
    return RotateFlipType.Rotate270FlipX;
    case 8:
    return RotateFlipType.Rotate270FlipNone;
    default:
    return 
}
}

This works. but when saving this image, the exif rotation tag still exists which makes the image to be in wrong orientation. What i can do is

       var bmp = new Bitmap(OS.FileName);       
       var exif = new EXIFextractor(ref bmp, "n");
       exif.setTag(0x112, "1");
       bmp.save("strippedexifimage");

But this code when used in a loop slows down my program by around 50%.Is there a alternative way? May be code to counter rotate the image after applying the rotation,will that work?

Update:

@Hans Passant Your answer works, but the result it produce is same as the ones produced by the library. When i use bitmap.save(),both library and your code works.But when i use the following code to save my image depending on the format selected by the user. Imgformat can be imgformat = "image/png";,imgformat = "image/jpeg"; etc some images still get saved with wrong exif orientation tag. ie: i see the wrong image preview in windows explorer,When i open the image with MS Paint,the image is having correct orientation.What im i doing wrong? Please help.

private void saveJpeg(string path, Bitmap img, long quality)
        {


            EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);


            ImageCodecInfo Codec = this.getEncoderInfo(imgformat);
             if (Codec == null)
              return;

            EncoderParameters encoderParams = new EncoderParameters(1);
            encoderParams.Param[0] = qualityParam;    
            img.Save(path + ext, Codec, encoderParams);
        }



 private ImageCodecInfo getEncoderInfo(string mimeType)
        {
            // Get image codecs for all image formats
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();

            // Find the correct image codec
            for (int i = 0; i < codecs.Length; i++)
                if (codecs[i].MimeType == mimeType)
                    return codecs[i];
            return null;
        }
like image 907
techno Avatar asked Jan 12 '16 10:01

techno


1 Answers

  var exif = new EXIFextractor(ref bmp, "n")

Using a library to implement a feature can save you a lot of time. Or you'll get stuck for days when the library is poorly designed or difficult to use. ref bmp is the first loud alert, you fell it the pit of despair by trying to specify the value as a string. Which was attractive because you did not have to consider what "type" might mean in the correct setTag() overload. It is type 3 and requires a byte[] with two elements. This is not discoverable at all, you can only use the library correctly when you don't need it.

Ditch the library, it is not helpful. The EXIF tag that stores the orientation has id 0x112 and is encoded as a 16-bit value. Just use System.Drawing directly to read the value and force it back to 1. Like this:

static void FixImageOrientation(Image srce) {
    const int ExifOrientationId = 0x112;
    // Read orientation tag
    if (!srce.PropertyIdList.Contains(ExifOrientationId)) return;
    var prop = srce.GetPropertyItem(ExifOrientationId);
    var orient = BitConverter.ToInt16(prop.Value, 0);
    // Force value to 1
    prop.Value = BitConverter.GetBytes((short)1);
    srce.SetPropertyItem(prop);

    // Rotate/flip image according to <orient>
    switch (orient) {
        // etc...
    }
}
like image 119
Hans Passant Avatar answered Sep 22 '22 20:09

Hans Passant