How to Handle Image Orientation based on Exif
Exchangeable image file format (officially Exif) is a standard that specifies formats for images, sound, and ancillary tags used by digital cameras (including smartphones). It contains metadata like camera parameters, image dimensions, and image orientation.
Most camera sensors have a shape where its width is larger than the height. If a photo is taken in portrait, the raw image data is still stored in the sensor’s dimension. When viewing the photo, we need to know how to display it correctly. This is when the orientation flag in Exif is needed. The camera’s orientation sensor will provide the orientation info.
Here is a diagram of the flags of orientation and the rotation needed for display (image source).
If the image is mirrored, then the flags are like the right graph in the following image:
Most image viewers and browsers will display images based on the orientation. Some image editors like GIMP will prompt the user whether to rotate the image.
Code for Correcting the Image Orientation
When developing a mobile document scanning app, we may need to rotate the images taken based on the orientation.
Here is the code to do this.
For Android (Java):
private Bitmap rotatedImageBasedOnExif(Bitmap bitmap, String path) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
ExifInterface exif = null;
try {
exif = new ExifInterface(path);
} catch (IOException e) {
return bitmap;
}
int rotate = 0;
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
}
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
Bitmap rotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
try (FileOutputStream out = new FileOutputStream(path)) {
rotated.compress(Bitmap.CompressFormat.JPEG, 100, out);
} catch (IOException e) {
e.printStackTrace();
}
return rotated;
}
return bitmap;
}
Please note that bitmap does not contain the Exif. You need to directly pass the path for ExifInterface
.
For iOS (Swift):
static func normalizedImage(_ image:UIImage) -> UIImage {
if image.imageOrientation == UIImage.Orientation.up {
return image
}
UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
image.draw(in: CGRect(x:0,y:0,width:image.size.width,height:image.size.height))
let normalized = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext();
return normalized
}
Source Code
Check out the Android and iOS document scanner demos to have a try:
Dynamsoft Document Normalizer is used for document boundary detection and cropping.