Android中如何将RectF边界框映射到旋转/未旋转的bitmap上
Android 旋转/非旋转场景下Bitmap的RectF坐标映射方法
RectF坐标映射的核心是对齐源、目标图像的坐标系,无旋转场景可直接按比例换算边值,带旋转场景必须通过顶点映射计算包围盒,禁止直接换算边值否则会出现坐标偏移。
无旋转场景映射(仅含缩放、位移)
这个场景逻辑最简单,先计算两个图像坐标系的缩放比例和起始偏移量,直接换算四个边值即可:
- 计算X轴缩放比:
scaleX = 目标图像渲染宽度 / 源Bitmap原始宽度 - 计算Y轴缩放比:
scaleY = 目标图像渲染高度 / 源Bitmap原始高度 - 记录目标图像相对容器原点的X/Y偏移量
offsetX/offsetY(如果目标图从容器原点开始绘制,偏移量为0) - 直接生成映射后的RectF:
val mappedRect = RectF( sourceRect.left * scaleX + offsetX, sourceRect.top * scaleY + offsetY, sourceRect.right * scaleX + offsetX, sourceRect.bottom * scaleY + offsetY )
带旋转场景映射(任意旋转角度)
只要Bitmap存在旋转操作,绝对不能直接对left/top/right/bottom四个边值做比例换算,旋转后原矩形的边不再和坐标轴平行,直接换算得到的边界框会完全错位,正确实现步骤如下:
- 复用绘制Bitmap时使用的完整Matrix(包含所有旋转、缩放、位移参数,不要单独重新拼接矩阵参数,避免和实际绘制效果不一致)
- 提取源RectF的四个顶点坐标,存入长度为8的Float数组,顺序依次为左上、右上、右下、左下四个点的X/Y坐标
- 调用Matrix的
mapPoints()方法,把源顶点数组转换为目标坐标系下的坐标 - 遍历转换后的四个顶点,取出X坐标的最小值作为新的left、最大值作为新的right,Y坐标的最小值作为新的top、最大值作为新的bottom,组成的新RectF就是正确映射后的边界框
代码实现:
fun mapRotatedBitmapRect(sourceRect: RectF, drawMatrix: Matrix): RectF { // 写入源矩形四个顶点坐标 val vertexPoints = floatArrayOf( sourceRect.left, sourceRect.top, // 左上 sourceRect.right, sourceRect.top, // 右上 sourceRect.right, sourceRect.bottom, // 右下 sourceRect.left, sourceRect.bottom // 左下 ) // 用绘制Bitmap的同源矩阵做坐标映射 drawMatrix.mapPoints(vertexPoints) // 计算映射后点的最小包围盒 val result = RectF() result.left = minOf(vertexPoints[0], vertexPoints[2], vertexPoints[4], vertexPoints[6]) result.top = minOf(vertexPoints[1], vertexPoints[3], vertexPoints[5], vertexPoints[7]) result.right = maxOf(vertexPoints[0], vertexPoints[2], vertexPoints[4], vertexPoints[6]) result.bottom = maxOf(vertexPoints[1], vertexPoints[3], vertexPoints[5], vertexPoints[7]) return result }
踩坑提示:如果你的Bitmap旋转是基于EXIF方向信息做的校正,必须保证映射用的Matrix和实际绘制到Canvas上的Matrix完全一致,不要单独给映射逻辑加旋转参数,否则会出现缩放、偏移不对齐的问题。
固定角度旋转快速计算(无缩放、无位移场景)
如果是90/180/270度这类固定角度旋转,且旋转中心为Bitmap中心、无额外缩放位移,可以用快速公式计算,不需要走Matrix逻辑:
- 顺时针旋转90度:
left = 源top值top = 源Bitmap宽度 - 源right值right = 源bottom值bottom = 源Bitmap宽度 - 源left值 - 旋转180度:
left = 源Bitmap宽度 - 源right值top = 源Bitmap高度 - 源bottom值right = 源Bitmap宽度 - 源left值bottom = 源Bitmap高度 - 源top值 - 顺时针旋转270度:
left = 源Bitmap高度 - 源bottom值top = 源left值right = 源Bitmap高度 - 源top值bottom = 源right值
注意:快速计算仅适配上述理想场景,只要存在缩放、位移、旋转中心偏移、任意角度旋转的情况,优先使用Matrix映射四点的方案,适配性更强,不会出现坐标偏差
内容的提问来源于stack exchange,提问作者Marcos Douglas
相关产品推荐
相关产品推荐

