Android像素编辑器极端宽高比下Bitmap像素矩形化问题
问题:极端宽高比Bitmap绘制时像素矩形化
我正在开发一款Android像素艺术编辑器,发现创建宽高比极端的Bitmap(例如3x300、5x90或反向比例)时,像素会呈现轻微矩形。但宽高比相近的Bitmap(如50x40、90x80)不会出现此问题。
相关代码
边界Rect计算代码
private fun setBoundingRect() { val ratio = if (bitmapWidth > bitmapHeight) { bitmapHeight.toDouble() / bitmapWidth.toDouble() } else { bitmapWidth.toDouble() / bitmapHeight.toDouble() } val rectW: Int = if (bitmapWidth > bitmapHeight) { width } else if (bitmapHeight > bitmapWidth) { (height * ratio).toInt() } else { width } val rectH: Int = if (bitmapWidth > bitmapHeight) { (width * ratio).toInt() } else if (bitmapHeight > bitmapWidth) { height } else { width } val canvasCenter = Point(width / 2, height / 2) val left = canvasCenter.x - rectW / 2 val top = canvasCenter.y - rectH / 2 val right = canvasCenter.x + rectW / 2 val bottom = canvasCenter.y + rectH / 2 boundingRect = Rect(left, top, right, bottom) }
逻辑说明:通过计算宽高比作为缩放因子,对容器尺寸进行缩放以匹配Bitmap比例,多数情况有效,但极端比例时出问题。
onDraw方法代码
override fun onDraw(canvas: Canvas) { if (::drawingViewBitmap.isInitialized) { canvas.drawRect(boundingRect, PaintData.rectPaint) canvas.drawBitmap(drawingViewBitmap, null, boundingRect, null) drawGrid(canvas) } }
问题分析与解决方案
问题核心在于整数取整导致的比例偏差:计算rectW和rectH时直接用toInt()截断小数,极端宽高比下,这种截断会让boundingRect的宽高比与原始Bitmap产生细微差异,最终导致像素拉伸变形。另外,默认的Bitmap缩放滤镜也会加剧这个问题。
修复步骤:
修正宽高比计算,消除比例偏差
不要单独计算宽和高,应基于容器尺寸和Bitmap原始比例算出统一缩放因子,再同步计算宽高,确保boundingRect比例与Bitmap完全一致:private fun setBoundingRect() { val bitmapRatio = bitmapWidth.toDouble() / bitmapHeight.toDouble() val containerRatio = width.toDouble() / height.toDouble() val scaleFactor: Double = if (bitmapRatio > containerRatio) { // Bitmap更宽,以容器宽度为基准缩放 width.toDouble() / bitmapWidth.toDouble() } else { // Bitmap更高,以容器高度为基准缩放 height.toDouble() / bitmapHeight.toDouble() } val rectW = (bitmapWidth * scaleFactor).toInt() val rectH = (bitmapHeight * scaleFactor).toInt() val canvasCenter = Point(width / 2, height / 2) val left = canvasCenter.x - rectW / 2 val top = canvasCenter.y - rectH / 2 val right = canvasCenter.x + rectW / 2 val bottom = canvasCenter.y + rectH / 2 boundingRect = Rect(left, top, right, bottom) }禁用缩放滤镜,保持像素锐利
绘制Bitmap时使用关闭过滤的Paint,避免双线性过滤导致的像素模糊与拉伸:// 提前初始化绘制Bitmap的Paint private val bitmapPaint = Paint().apply { isFilterBitmap = false isAntiAlias = false } override fun onDraw(canvas: Canvas) { if (::drawingViewBitmap.isInitialized) { canvas.drawRect(boundingRect, PaintData.rectPaint) canvas.drawBitmap(drawingViewBitmap, null, boundingRect, bitmapPaint) drawGrid(canvas) } }额外校验:匹配Bitmap密度
确保drawingViewBitmap的密度与当前View的屏幕密度一致,避免系统自动密度缩放导致变形:Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888).apply { density = resources.displayMetrics.densityDpi }
内容的提问来源于stack exchange,提问作者thebluepandabear
相关产品推荐
相关产品推荐

