I took what others have created here, and I think this one solves the end-cases that weren't handled, such as all pixels are of the same given color, and not needing to create a new array of same values either:
/**removes rows/columns of the same color from the edges
* @return a Bitmap after the removal, or null if completely of the same color*/
fun cropToRemoveSameColoredEdges(bitmap: Bitmap, @ColorInt color: Int = Color.TRANSPARENT): Bitmap? {
val height = bitmap.height
val width = bitmap.width
//this is to handle colors that have various values, but are still just same 100% transparent, so it's the same color
val checkFullTransparency = Color.alpha(color) == 0
//handle top&bottom
//top
var top = 0
var buffer = IntArray(width)
while (top < height) {
bitmap.getPixels(buffer, 0, width, 0, top, width, 1)
val firstIndexOfDifferentlyColoredPixel: Int = buffer.indexOfFirst { pixel ->
if (checkFullTransparency)
Color.alpha(pixel) != 0
else
pixel != color
}
if (firstIndexOfDifferentlyColoredPixel >= 0)
break
++top
}
//this is to handle case that entire bitmap is of the same color
if (top == height)
return null
var bottom = height - 1
while (bottom > top) {
bitmap.getPixels(buffer, 0, width, 0, bottom, width, 1)
val firstIndexOfDifferentlyColoredPixel: Int = buffer.indexOfFirst { pixel ->
if (checkFullTransparency)
Color.alpha(pixel) != 0
else
pixel != color
}
if (firstIndexOfDifferentlyColoredPixel >= 0)
break
--bottom
}
//handle left&right
val heightRemaining = bottom - top + 1
if (heightRemaining != buffer.size)
buffer = IntArray(heightRemaining)
//left
var left = 0
while (left < width) {
bitmap.getPixels(buffer, 0, 1, left, top, 1, heightRemaining)
val firstIndexOfDifferentlyColoredPixel: Int = buffer.indexOfFirst { pixel ->
if (checkFullTransparency)
Color.alpha(pixel) != 0
else
pixel != color
}
if (firstIndexOfDifferentlyColoredPixel >= 0)
break
++left
}
//right
var right = width-1
while (right >= left + 1) {
bitmap.getPixels(buffer, 0, 1, right, top, 1, heightRemaining)
val firstIndexOfDifferentlyColoredPixel: Int = buffer.indexOfFirst { pixel ->
if (checkFullTransparency)
Color.alpha(pixel) != 0
else
pixel != color
}
if (firstIndexOfDifferentlyColoredPixel >= 0)
break
--right
}
return Bitmap.createBitmap(bitmap, left, top, right - left+1, bottom - top+1)
}
Alternative, which is more elegant but always goes over all the pixels of the bitmap:
/**removes rows/columns of the same color from the edges
* @return a Bitmap after the removal, or null if completely of the same color*/
fun cropToRemoveSameColoredEdges2(bitmap: Bitmap, @ColorInt color: Int = Color.TRANSPARENT): Bitmap? {
val height = bitmap.height
val width = bitmap.width
//this is to handle colors that have various values, but are still just same 100% transparent, so it's the same color
val checkFullTransparency = Color.alpha(color) == 0
var top = height
var bottom = -1
var left = width
var right = -1
val buffer = IntArray(width)
//go over each pixel of each row
for (y in 0 until height) {
bitmap.getPixels(buffer, 0, width, 0, y, width, 1)
for (x in 0 until width) {
val pixel = buffer[x]
val isPixelDifferentFromGivenColor = if (checkFullTransparency)
Color.alpha(pixel) != 0
else
pixel != color
if (isPixelDifferentFromGivenColor) {
if (left > x)
left = x
if (right < x)
right = x
if (top > y)
top = y
if (bottom < y)
bottom = y
}
}
}
//not found any pixel that's different from the given color. technically can test all other variables too, but no need
if(top==height)
return null
return Bitmap.createBitmap(bitmap, left, top, right - left + 1, bottom - top + 1)
}