可交换图像文件格式(正式名称Exif )是一种标准,用于指定数码相机(包括智能手机)的图像和声音使用的格式和辅助标签。它包含相机参数、图像尺寸和图像方向等元数据。
大多数相机传感器的形状是宽度大于高度的长方形。即使竖着拍摄照片,原始图像数据仍按照传感器的形状进行存储。在查看照片时,我们需要知道如何正确显示它们。此时需要Exif中的方向数据。相机的方向传感器可用于提供这一信息。
以下是关于方向和用于显示所需的旋转角度的示意图(图源)。
如果图像是镜像翻转的,则方向标记如下图中的右图所示:
大多数图像查看器和网页浏览器会自动根据方向标记显示图像。一些图像编辑器,如GIMP,会提示用户是否旋转图像。
用于校正图像方向的代码
在开发移动文档扫描应用程序时,我们可能需要根据方向旋转拍摄的图像。
以下是执行此操作的代码。
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;
}
注意Bitmap不包含Exif。需要直接传递文件路径给ExifInterface
。
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
}
源代码
安卓和iOS文档扫描demo的源代码:
使用了Dynamsoft Document Normalizer SDK来执行文档检测和裁剪操作。