本文作者
链接:
https://juejin.im/post/5bc3fbcc5188255c672ed754
这篇文章是经作者授权发表的。
以前做相机的时候,我就知道有些设备拍出来之后预览的图片会需要旋转,旋转的信息保存在EXIF。网上也有一些比较成熟的旋转处理代码,经常粘贴使用,原理还不清楚。直到这篇文章,我才彻底想通了一般如何处理旋转!
一个
问题
不知道你有没有遇到过这样的问题。安卓手机拍照预览图片很正常,但是你看了照片返回的图片,发现图片的方向不对。我碰巧遇到这样一个问题,图片如下:
看,图片逆时针旋转90度。这其实是一个叫Exif的东西。我们来看看这个Exif是谁。
2
背景
首先要先了解Exif是什么,搬出百度百科
可交换图像文件格式(Exif)是专门为数码相机的照片设置的,可以记录数码照片的属性信息和拍摄数据。
毕竟Exif是一种存储图片一些信息的格式,和我们日常的拍摄设备、拍摄地点、图片大小等有关。,但是今天的主角是另外一个——就是画面取向。这个图片方向不是指我们平时用图片编辑器旋转的方向,而是拍照时手机的方向。
总共有八个方向:
下图是图片方向对应的JPEG ORIENTATION的校正算法。这里,它用三个二进制数表示八个方向,然后通过对应于每个二进制数的不同操作来校正图像,如下所示:
https://magnushoff.com/jpeg-orientation.html
最高阶二进制数表示对角翻转操作,二阶二进制数表示180度旋转操作,最低阶位表示水平翻转操作。比如001是水平翻转的,那么可以看出001的图形和原图形是关于水平轴对称的。通过将八个方向的图形与三个二进制数即三次运算相结合,方便了图形的转换。编码伪码如下:
if(价值和100b!= 0)图像。对角翻转
if(价值和010b!= 0)图像。旋转-180°
if(价值和001b!= 0)图像。水平翻转
那么有些人会很迷茫。他们平时怎么没看到这种画面?这是因为我们使用的图片查看器或浏览器与方向兼容,并将转换显示的图片。
以下是windows文件夹的演示文稿:
以下是Android Studio的图片展示
所以我们可以看到windows默认处理图像方向,而Android的ImageView没有,所以我们看到的是图像的原始方向。
这是八个F的图片链接
https://magnushoff.com/assets/test-exiforientation.
三
app应用
在Android中,三星手机的照片是一个奇妙的存在。我上面用的手机是三星手机。三星手机exif旋转90度,其他手机EXIF为0度,需要对三星手机照片进行处理。这是一张三星手机照片。exif信息:
三星手机的方向是Rotate 90CW,也就是说需要顺时针旋转90度。颅骨旋转快的同学可以参考上面的F图,相信很快就会看到101了。
然后我们取出图片的方位值进行验证:
尝试{
valesifinterface = Exifinterface(resources . OpenRawReSource(id))
valorientation = Exifinterface . GetAttribute int(Exifinterface。TAG_ORIENTATION,ExifInterface。方向_正常)
Log.e( "orientation ",orientation.toString())
} catch(e: IOException) {
e.printStackTrace()
}
打印结果为6,不符合上述101。实际上Android中的方位需要减1,也就是说6实际对应的是101的状态。
此外,需要注意的是,如果打印结果为0,那么图片没有方向信息。
那么我们来编码,这是第一种方式:
valoptions = BitmapFactory。选项()
var bitmap = BitMapFactory . DecodeReSource(参考资料,R.mipmap.error_orientation,选项)
valmatrix =矩阵()
matrix . post rotate(GetOrientation(r . MIP map . error _ orientation)。toFloat())
位图=位图。创建位图(位图,0,0,位图。宽度,位图。高度,矩阵,真)
imageview.setImageBitmap(位图)
privatefungetOrientation(id:Int):Int {
vardegree = 0
尝试{
valesifinterface = Exifinterface(resources . OpenRawReSource(id))
valorientation = Exifinterface . GetAttribute int(Exifinterface。TAG_ORIENTATION,ExifInterface。方向_正常)
何时(方位){
ExifInterface。方位_旋转_ 90->;度数= 90度
ExifInterface。方位_旋转_ 180->;度数= 180度
ExifInterface。方位_旋转_ 270->;度数= 270度
}
} catch(e: IOException) {
e.printStackTrace()
}
返回度
}
一般来说我们只需要处理这三个角度,上面三个角度对应的方位是6 ^ 3 ^ 8,也就是101,010,111。为什么一般只需要处理这三种状态?自己拿主意拿相机,无非四种情况。除了正常情况,你只需要处理三种情况?
嘿嘿我真是个智能卡。
当然,要想严格,还是需要遵循JPEG的操作模式,如下:
valoptions = BitmapFactory。选项()
var bitmap = BitMapFactory . DecodeReSource(参考资料,R.mipmap.f7t,选项)
val matrix = GenorientStatusMatrix(r . MIP map . f7t)
位图=位图。创建位图(位图,0,0,位图。宽度,位图。高度,矩阵,真)
imageview.setImageBitmap(位图)
privatefungenorationmatrix(id:Int):Matrix {
valmatrix =矩阵()
尝试{
valesifinterface = Exifinterface(resources . OpenRawReSource(id))
var orientation = Exifinterface . GetAttribute int(Exifinterface。TAG_ORIENTATION,ExifInterface。方向_正常)
if(方向>;0) {
方向-
if(方向和0b100!= 0) {//对角翻转
matrix.postScale( -1.0f,1.0f)
matrix.postRotate( -90f)
}
if(方向和0b010!= 0) {//旋转180度
matrix.postRotate( 180f)
}
if(方向和0b001!= 0) {//水平翻转
matrix.postScale( -1.0f,1.0f)
}
}
返回矩阵
} catch(e: IOException) {
e.printStackTrace()
}
返回矩阵
}
其实JPEG到方位的转换是通过代码实现的,矩阵也是相应的转换。
四
总结
Exif是一种存储照片一些信息的格式。通常我们开发Android的时候,通常需要考虑方向。然而在日常生活中,这也是暴露我们隐私的入口。所以拍照时最好关闭保存地点的选项,以免泄露我们的隐私。
这篇文章让我们明白,当我们需要预览一张照片时,我们不知道需要选择多少个角度,所以我们有一个通用的方法:
读取方向值,减去1,转换成3位二进制值,例如101,可以根据二进制值进行转换。如果每个位为1,则需要固定的转换。代码和转换规则如上。
1.《exif 分享一个困惑了我很久的知识点 | Exif》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《exif 分享一个困惑了我很久的知识点 | Exif》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/tiyu/1210136.html