如何删除 Android 中图像周围的空白 space?
How to remove blank space around an image in Android?
给定一张带有 alpha 通道(透明度)的图像,我想删除图像边界和实际图像之间的任何空白 space。
这应该在后台任务或加载屏幕中完成,并有一个可接受的 运行 时间,以免削弱用户体验。
我怎样才能达到这个结果?
我很难找到解决问题的最佳实践甚至建议。基于 this anwer by JannGabriel,谁通过减小图像大小裁剪了图像的右侧和底部,我设法更进一步,还删除了顶部和左侧的空白 spaces,并总体上缩短了精化时间。结果很好,我目前正在我的项目中使用它。
我是 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 循环是 运行 检查像素是否不包含透明颜色,返回第一个非透明像素有用坐标。这是通过使用与 trim 的维度相反的维度作为基础来详细说明坐标:要找到 y,为每个 y 扫描 x。
要检查垂直顶部空白 space 的结束位置,它会运行以下步骤:
- 从第一行开始 (y=0)
- 检查行的所有列(x 从 0 到 imageWidth)
- 如果发现不透明像素,则中断循环并保存y坐标。否则继续。
- 在列的末尾,转到下一行 (y+1) 并再次开始检查列。如果已找到非透明像素,则中断。
其他维度使用类似的方法,只是改变扫描方向。
得到图像第一个有用像素的4个坐标后,调用Bitmap.createBitmap
方法,以原始位图为基础图像,有用像素坐标为Top-Left和Bottom-调整大小的右限制。
Note 1: It is useful to note that the coordinates 0, 0 equals to Top-Left.
Note 2: The ending width and height in Bitmap.createBitmap are reduced by the new starting relative coordinate, otherwise the new image will have the boundaries wrongly pushed bottom-right. Figure it like this: you have an image 100x100px, so with ending coordinates 100,100. Changing the starting coordinates to 50,50 will bring the ending coordinates of your elaboration rectangle to 150,150 (100 original coordinate + 50 of modified starting point), pushing it outside the original image boundaries. To avoid this, the new ending coordinate is reduced by the new starting coordinate (100 + 50 new starting coord - 50 new starting coord adjustment)
Note 3: in the original answer, a check for all the pixels in a given direction is run using the same dimension of the coordinate to find, returning the most advanced useful pixel. Checking the opposite dimension and stopping at the first useful pixel increased performances.
用于回答@Manzotin 的 Kotlin 实现,修复了小错误。
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)
}
您可以使用单个 属性 ImageView 视图 trim 透明 space 图像周围。
您可以使用 android:adjustViewBounds="true"
属性 到 XML 布局文件以 trim 透明 space 相应图像。
给定一张带有 alpha 通道(透明度)的图像,我想删除图像边界和实际图像之间的任何空白 space。 这应该在后台任务或加载屏幕中完成,并有一个可接受的 运行 时间,以免削弱用户体验。
我怎样才能达到这个结果?
我很难找到解决问题的最佳实践甚至建议。基于 this anwer by JannGabriel,谁通过减小图像大小裁剪了图像的右侧和底部,我设法更进一步,还删除了顶部和左侧的空白 spaces,并总体上缩短了精化时间。结果很好,我目前正在我的项目中使用它。 我是 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 循环是 运行 检查像素是否不包含透明颜色,返回第一个非透明像素有用坐标。这是通过使用与 trim 的维度相反的维度作为基础来详细说明坐标:要找到 y,为每个 y 扫描 x。
要检查垂直顶部空白 space 的结束位置,它会运行以下步骤:
- 从第一行开始 (y=0)
- 检查行的所有列(x 从 0 到 imageWidth)
- 如果发现不透明像素,则中断循环并保存y坐标。否则继续。
- 在列的末尾,转到下一行 (y+1) 并再次开始检查列。如果已找到非透明像素,则中断。
其他维度使用类似的方法,只是改变扫描方向。
得到图像第一个有用像素的4个坐标后,调用Bitmap.createBitmap
方法,以原始位图为基础图像,有用像素坐标为Top-Left和Bottom-调整大小的右限制。
Note 1: It is useful to note that the coordinates 0, 0 equals to Top-Left.
Note 2: The ending width and height in Bitmap.createBitmap are reduced by the new starting relative coordinate, otherwise the new image will have the boundaries wrongly pushed bottom-right. Figure it like this: you have an image 100x100px, so with ending coordinates 100,100. Changing the starting coordinates to 50,50 will bring the ending coordinates of your elaboration rectangle to 150,150 (100 original coordinate + 50 of modified starting point), pushing it outside the original image boundaries. To avoid this, the new ending coordinate is reduced by the new starting coordinate (100 + 50 new starting coord - 50 new starting coord adjustment)
Note 3: in the original answer, a check for all the pixels in a given direction is run using the same dimension of the coordinate to find, returning the most advanced useful pixel. Checking the opposite dimension and stopping at the first useful pixel increased performances.
用于回答@Manzotin 的 Kotlin 实现,修复了小错误。
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)
}
您可以使用单个 属性 ImageView 视图 trim 透明 space 图像周围。
您可以使用 android:adjustViewBounds="true"
属性 到 XML 布局文件以 trim 透明 space 相应图像。