14

我需要在 Android 应用程序上显示一些大图像。现在我正在使用带有源位图的 ImageView。我知道openGL对于图像尺寸可以有多大以便处理它有一定的设备独立限制。

除了将图像拆分为多个 ImageView 元素之外,是否有任何方法可以显示这些图像(具有固定宽度,不裁剪)而不管这个限制?

谢谢你。

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

感谢大家。

4

4 回答 4

10

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

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 文件夹中。如果不是这种情况,那么重构该方法以获取您需要的任何参数应该是相当容易的。

于 2013-04-07T12:25:22.543 回答
3

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

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3; //reduce size 3 times
于 2013-03-27T09:47:55.147 回答
2

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

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

于 2013-04-02T12:59:31.567 回答
0

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

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

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

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

于 2013-04-02T08:53:48.137 回答