处理安卓纹理尺寸限制

14

我需要在Android应用程序上显示较大的图像。目前我正在使用带有源位图的ImageView。 我了解到openGL在处理图像大小时具有某种设备无关限制。

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

谢谢。

更新 2013年4月1日 迄今为止仍然没有成功,所有建议都是降低图像质量。有人建议可以通过使用CPU而不是GPU来处理来绕过此限制(尽管可能需要更长时间来处理)。 我不明白,难道真的没有办法在不降低图像质量的情况下显示长图像吗?我敢打赌有的,我希望有人能至少指引我正确的方向。

谢谢大家。


1
我不确定,但你是否尝试使用 WebView 代替? - Edward van Raak
1
不是真的,我有多个非常大的图像实例随机放置在列表视图上。我必须考虑性能,这听起来像一个相当糟糕的想法。 - woot
看看这个不错的项目:https://github.com/ened/Android-Tiling-ScrollView - Sherif elKhatib
4个回答

10

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


@Jason Robinson 哎呀,是的。我复制粘贴了我在应用程序中使用的修改后版本,它没有引发 IOException。看起来不错。 - David Liu
这个方法能否用于位图,如果可以,怎么做?我已经将检测最大GL纹理大小的代码放在这里:http://pastebin.com/gFTdHPbg - tim687
@tim687 这个 newInstance (http://developer.android.com/reference/android/graphics/BitmapRegionDecoder.html#newInstance(byte[], int, int, boolean)) 方法接收一个字节数组。看起来应该是可行的。使用 这个答案 将 Bitmap 转换成字节数组。 - Jason Robinson
SO 不让我链接它,否则会搞乱链接。请前往 BitmapRegionDecoder javadocs,并查找使用字节数组的工厂方法。 - Jason Robinson
@JasonRobinson 我最终使用了分块拆分的方法,但我的位图没有绘制出来。我会解决的 :-P - tim687
显示剩余4条评论

3
您可以使用BitmapFactoryOptions来减小图片的大小。您可以像这样使用:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3; //reduce size 3 times

谢谢,但是难道没有任何方法可以在不降低图像质量的情况下实现所需的结果吗? - woot
我认为没有不降低图像质量的解决方案,因为这会导致溢出错误。 - developerCoder

2

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

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


0

如果您能提供位图的尺寸,那将会很有帮助。

请理解OpenGL运行在自然数学限制下。

例如,在OpenGL中纹理必须是2的幂次方,这是因为只有这样才能保证任何缩小操作都不会产生余数。

因此,如果您能告诉我们最小位图的确切尺寸,我们中的一些人可能会告诉您实际限制的类型。


位图的尺寸是动态的,宽度可以高达480像素,高度可以在1像素至10000像素之间任意取值。所需显示的宽度是屏幕宽度减去一些边距。图像应按比例缩放到所需宽度,并从左上角进行纵横比裁剪。 - woot
那么,这不是OpenGL纹理。不要把它当作纹理来处理。你可以在OpenGL中使用背景图像,没问题,只要你不把它们当作纹理来处理,它们就没问题。 - Stephan Branczyk
你说的不把它们当作纹理处理是什么意思?我并不直接使用OpenGL,我所做的只是为ImageView设置一个源,然后由于设备的纹理大小限制,图像无法显示。例如:“在Nexus 10上,无法将位图上传到纹理中(480x5400,最大=4096x4096)”。 - woot
你的图片可能在OpenGL加载它们之前就被自动缩放了。创建一个drawable-nodpi文件夹,然后将你的图片移动到这个文件夹中。顺便问一下,你打算使用捏合缩放吗?或者其他类似的缩放功能?为了让缩放工作,你的图片确实需要像Leonidas建议的那样被分割成正方形瓷砖。能否给我们展示你的代码呢?我相信展示你的代码会有所帮助。 - Stephan Branczyk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接