【发布时间】:2015-12-24 04:16:52
【问题描述】:
【问题讨论】:
标签: android image whitespace crop
【问题讨论】:
标签: android image whitespace crop
我很难找到解决问题的最佳实践甚至建议。基于this anwer by JannGabriel,他通过减小图像大小来裁剪图像的右侧和底部,我设法更进一步,还删除了顶部和左侧的空白区域,并总体上缩短了精化时间。结果很好,我目前正在我的项目中使用它。 我对 Android 编程相当陌生,欢迎对这种方法提出任何建议。
public static Bitmap TrimBitmap(Bitmap bmp) {
int imgHeight = bmp.getHeight();
int imgWidth = bmp.getWidth();
//TRIM WIDTH - LEFT
int startWidth = 0;
for(int x = 0; x < imgWidth; x++) {
if (startWidth == 0) {
for (int y = 0; y < imgHeight; y++) {
if (bmp.getPixel(x, y) != Color.TRANSPARENT) {
startWidth = x;
break;
}
}
} else break;
}
//TRIM WIDTH - RIGHT
int endWidth = 0;
for(int x = imgWidth - 1; x >= 0; x--) {
if (endWidth == 0) {
for (int y = 0; y < imgHeight; y++) {
if (bmp.getPixel(x, y) != Color.TRANSPARENT) {
endWidth = x;
break;
}
}
} else break;
}
//TRIM HEIGHT - TOP
int startHeight = 0;
for(int y = 0; y < imgHeight; y++) {
if (startHeight == 0) {
for (int x = 0; x < imgWidth; x++) {
if (bmp.getPixel(x, y) != Color.TRANSPARENT) {
startHeight = y;
break;
}
}
} else break;
}
//TRIM HEIGHT - BOTTOM
int endHeight = 0;
for(int y = imgHeight - 1; y >= 0; y--) {
if (endHeight == 0 ) {
for (int x = 0; x < imgWidth; x++) {
if (bmp.getPixel(x, y) != Color.TRANSPARENT) {
endHeight = y;
break;
}
}
} else break;
}
return Bitmap.createBitmap(
bmp,
startWidth,
startHeight,
endWidth - startWidth,
endHeight - startHeight
);
}
说明: 对于图像的每一侧,运行一个 FOR 循环来检查像素是否不包含透明颜色,返回第一个不透明像素的有用坐标。这是通过使用与要修剪的维度相反的维度作为基础来细化坐标来完成的:要找到 y,扫描 x 以查找每个 y。
要检查 Vertical-Top 空白空间的结束位置,它会运行以下步骤:
其他维度使用类似的方法,只是改变扫描的方向。
一旦获得图像的第一个有用像素的 4 个坐标,就会调用 Bitmap.createBitmap 方法,将原始位图作为基础图像,有用像素坐标作为左上角和右下角的限制调整大小。
注意 1:注意坐标 0, 0 等于 Top-Left。
注意 2:Bitmap.createBitmap 中的结束宽度和高度会减少新的起始相对坐标,否则新图像的边界会被错误地推到右下角。像这样想象:你有一个 100x100 像素的图像,所以结束坐标为 100,100。将起始坐标更改为 50,50 将使您的细化矩形的结束坐标变为 150,150(100 原始坐标 + 50 修改的起点),将其推到原始图像边界之外。为了避免这种情况,新的结束坐标会减少新的起始坐标(100 + 50 新起始坐标 - 50 新起始坐标调整)
注意 3:在原始答案中,使用坐标的相同维度对给定方向上的所有像素进行检查以查找,返回最先进的有用像素。检查相反的维度并在第一个有用的像素处停止会提高性能。
【讨论】:
http://stackoverflow.com/a/886979/1043882中描述的方式,而不是if (startWidth == 0)等类似语句。
startWidth 和 startHeight 最初不应设置为 0,因为如果您的图像顶部和左侧没有空白空间,您的 for 循环将运行到最后.因此,您将浪费等于2 * width * height 的计算时间。我认为最好将它们设置为-1。
Kotlin 实现回答 @Manzotin 并修复小错误。
fun Bitmap.trimBorders(color: Int): Bitmap {
var startX = 0
loop@ for (x in 0 until width) {
for (y in 0 until height) {
if (getPixel(x, y) != color) {
startX = x
break@loop
}
}
}
var startY = 0
loop@ for (y in 0 until height) {
for (x in 0 until width) {
if (getPixel(x, y) != color) {
startY = y
break@loop
}
}
}
var endX = width - 1
loop@ for (x in endX downTo 0) {
for (y in 0 until height) {
if (getPixel(x, y) != color) {
endX = x
break@loop
}
}
}
var endY = height - 1
loop@ for (y in endY downTo 0) {
for (x in 0 until width) {
if (getPixel(x, y) != color) {
endY = y
break@loop
}
}
}
val newWidth = endX - startX + 1
val newHeight = endY - startY + 1
return Bitmap.createBitmap(this, startX, startY, newWidth, newHeight)
}
【讨论】: