【问题标题】:Dealing with Android's texture size limit处理 Android 的纹理大小限制
【发布时间】:2013-03-17 08:22:24
【问题描述】:

我需要在 Android 应用上显示较大的图像。 现在我正在使用带有源位图的 ImageView。 我了解 openGL 有一定的设备独立限制 图像尺寸可以有多大才能对其进行处理。

无论此限制如何,是否有 ANY 方式来显示这些图像(固定宽度,不裁剪), 除了将图像拆分成多个 ImageView 元素?

谢谢。

2013 年 4 月 1 日更新 到目前为止,仍然没有运气,所有建议都是降低图像质量。有人建议可以通过使用 CPU 进行处理而不是使用 GPU 来绕过这一限制(尽管可能需要更多时间来处理)。 不明白,难道真的没有办法在不降低画质的情况下,显示固定宽度的长图吗?我敢打赌,如果有人至少能指出我正确的方向,我会很高兴的。

谢谢大家。

【问题讨论】:

  • 我不确定,但您是否尝试过使用 WebView 代替?
  • 不是真的,我有多个非常大的图像的实例随机放置在列表视图上。我必须考虑性能,这听起来是个很糟糕的主意..
  • 看看这个不错的项目:github.com/ened/Android-Tiling-ScrollView

标签: android android-layout opengl-es android-gui


【解决方案1】:

您可以使用BitmapRegionDecoder 来拆分较大的位图(需要 API 级别 10)。我编写了一个方法,该方法将利用这个类并返回一个可以放在ImageView 中的Drawable

private static final int MAX_SIZE = 1024;

private Drawable createLargeDrawable(int resId) throws IOException {

    InputStream is = getResources().openRawResource(resId);
    BitmapRegionDecoder brd = BitmapRegionDecoder.newInstance(is, true);

    try {
        if (brd.getWidth() <= MAX_SIZE && brd.getHeight() <= MAX_SIZE) {
            return new BitmapDrawable(getResources(), is);
        }

        int rowCount = (int) Math.ceil((float) brd.getHeight() / (float) MAX_SIZE);
        int colCount = (int) Math.ceil((float) brd.getWidth() / (float) MAX_SIZE);

        BitmapDrawable[] drawables = new BitmapDrawable[rowCount * colCount];

        for (int i = 0; i < rowCount; i++) {

            int top = MAX_SIZE * i;
            int bottom = i == rowCount - 1 ? brd.getHeight() : top + MAX_SIZE;

            for (int j = 0; j < colCount; j++) {

                int left = MAX_SIZE * j;
                int right = j == colCount - 1 ? brd.getWidth() : left + MAX_SIZE;

                Bitmap b = brd.decodeRegion(new Rect(left, top, right, bottom), null);
                BitmapDrawable bd = new BitmapDrawable(getResources(), b);
                bd.setGravity(Gravity.TOP | Gravity.LEFT);
                drawables[i * colCount + j] = bd;
            }
        }

        LayerDrawable ld = new LayerDrawable(drawables);
        for (int i = 0; i < rowCount; i++) {
            for (int j = 0; j < colCount; j++) {
                ld.setLayerInset(i * colCount + j, MAX_SIZE * j, MAX_SIZE * i, 0, 0);
            }
        }

        return ld;
    }
    finally {
        brd.recycle();
    }
}

该方法将检查可绘制资源是否在两个轴上都小于MAX_SIZE (1024)。如果是,它只返回可绘制对象。如果不是,它会将图像分开并解码图像块并将它们放在LayerDrawable中。

我选择 1024 是因为我相信大多数可用的手机都会支持至少这么大的图像。如果你想找到手机的实际纹理大小限制,你必须通过 OpenGL 做一些时髦的事情,这不是我想深入研究的。

我不确定你是如何访问你的图片的,所以我假设它们在你的 drawable 文件夹中。如果不是这种情况,那么重构方法以获取所需的任何参数应该相当容易。

【讨论】:

  • 需要注意的是,这个实现只是把它分成了行,而不是一个网格。如果宽度大于最大尺寸,它将通过算法,但块仍将包含大于 MAX_SIZE 的宽度。不过,添加对它的支持是一个微不足道的修复,我从来没有想过使用 LayerDrawable 来显示可绘制对象的网格。很好的答案。
  • 在修复中进行了编辑,将其拆分为方形块,而不仅仅是行。
  • 感谢您的补充@DavidLiu。我处理了您的编辑中的一些错误。请检查我的编辑并确保我没有破坏您的编辑意图。该方法抛出IOException,这就是不需要catch的原因。
  • @Jason Robinson 哎呀,是的。我复制粘贴在我的应用程序中使用的未抛出 IOException 的修改版本中。看起来不错。
  • 这确实是一个很好的解决GL贴图尺寸限制的方案。谢谢。
【解决方案2】:

你可以使用BitmapFactoryOptions来减小图片的大小。你可以使用类似的东西:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3; //reduce size 3 times

【讨论】:

  • 谢谢,但有没有什么方法可以在不降低图像质量的情况下达到预期的效果?
  • 我认为没有任何解决方案可以不降低图像质量。因为它给出了溢出错误。
【解决方案3】:

您了解您的地图是如何工作的吗?我曾经为地图制作过渲染器。您可以使用相同的技巧来显示您的图像。

将您的图片划分为方形图块(例如 128x128 像素)。创建支持从图块渲染的自定义 imageView。您的 imageView 知道它现在应该显示位图的哪个部分,并且只显示从您的 sd 卡加载它们所需的图块。使用这样的瓦片地图,您可以显示无穷无尽的图像。

【讨论】:

    【解决方案4】:

    如果您向我们提供位图的尺寸,将会有所帮助。

    请理解 OpenGL 的运行违反了自然的数学限制。

    例如,OpenGL 中的纹理必须是 2 的 x 次方,这是有充分理由的。这实际上是可以干净地完成任何缩小的数学运算而没有任何剩余的唯一方法。

    因此,如果您向我们提供给您带来麻烦的最小位图的确切尺寸,我们中的一些人可能会告诉您您遇到了什么样的实际限制。

    【讨论】:

    • 位图的尺寸是动态的,宽度可以高达480px,高度可以在1px到10000px之间。要显示的所需宽度是屏幕宽度减去一些边距。图像应缩放至所需宽度,同时保持从左上角裁剪的纵横比。
    • 那么,它不是 OpenGL 纹理。不要那样对待它。你可以在OpenGL中有背景图片,这很好,只要你不把它们当作纹理,它们就可以了。
    • 不将它们视为纹理是什么意思?我不直接使用 OpenGL,我所做的只是为 ImageView 设置一个源,然后由于设备的纹理大小限制,图像不会显示。例如:“位图太大,无法上传到 Nexus 10 上的纹理 (480x5400, max=4096x4096)”。
    • 您的图像可能会在 OpenGL 到达之前自动缩放。创建一个 drawable-nodpi 文件夹并将您的图像移动到该文件夹​​中。顺便问一下,您打算使用捏拉缩放吗?或其他一些类似缩放的功能?为了使缩放起作用,您的图像确实需要像 Leonidas 建议的那样平铺成正方形。你能告诉我们你的代码吗?我相信向我们展示您的代码应该会有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多