【问题标题】:How to remove blank space around an image in Android?如何在Android中删除图像周围的空白?
【发布时间】:2015-12-24 04:16:52
【问题描述】:

给定带有 alpha 通道(透明度)的图像,我想删除图像边界和实际图像之间的任何空白空间。 这应该在后台任务或加载屏幕中完成,并具有可接受的运行时间,不会削弱用户体验。

我怎样才能达到这个结果?

【问题讨论】:

    标签: android image whitespace crop


    【解决方案1】:

    我很难找到解决问题的最佳实践甚至建议。基于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 空白空间的结束位置,它会运行以下步骤:

    1. 从顶行开始 (y=0)
    2. 检查行的所有列(x 从 0 到 imageWidth)
    3. 如果发现不透明像素,则中断循环并保存 y 坐标。否则继续。
    4. 在列的末尾,转到下一行 (y+1) 并再次开始检查列。如果已找到不透明的像素,则中断。

    其他维度使用类似的方法,只是改变扫描的方向。

    一旦获得图像的第一个有用像素的 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)等类似语句。
    • startWidthstartHeight 最初不应设置为 0,因为如果您的图像顶部和左侧没有空白空间,您的 for 循环将运行到最后.因此,您将浪费等于2 * width * height 的计算时间。我认为最好将它们设置为-1
    • 这确实很棒,但是如何在特定的可绘制对象上运行它?
    • 检查stackoverflow.com/a/10600736/4473512 的drawable > 位图转换。此外,如果这个答案在 5 年后仍然可行,您应该检查其他来源(即:常用的图形库)!
    【解决方案2】:

    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)
    }
    

    【讨论】:

      猜你喜欢
      • 2020-11-10
      • 1970-01-01
      • 2019-09-29
      • 2019-12-18
      • 2012-08-03
      • 1970-01-01
      • 1970-01-01
      • 2021-06-19
      • 2016-02-25
      相关资源
      最近更新 更多