2013-03-27 89 views
14

我有要求在Android应用程序上显示有点大的图像。 现在,我正在使用带有源位图的ImageView。 我知道openGL对于 有一定的设备无关限制,图片尺寸可以有多大才能处理它。处理Android的纹理尺寸限制

ANY显示这些图像的方式(具有固定宽度,而不会裁剪)不管此限制, 比分割图像分成多个ImageView的元件之外?

谢谢。

UPDATE 01 Apr 2013 到目前为止还没有运气,所有的建议都是为了降低图像质量。有人建议可以绕过这个限制,通过使用CPU来完成处理而不是使用GPU(尽管可能需要更多时间来处理)。 我不明白,是否真的没有办法显示固定宽度的长图像而不降低图像质量?我敢打赌,如果有人会至少将我指向正确的方向,我会喜欢它。

谢谢大家。

+1

我不确定这个,但你有没有尝试过使用WebView? – 2013-03-27 09:52:52

+1

不是,我有多个非常大的图像在列表视图上随机定位的实例。我必须考虑到性能,这听起来像一个非常糟糕的主意.. – woot 2013-03-27 12:12:31

+0

看看这个不错的项目:https://github.com/ened/Android-Tiling-ScrollView – 2013-04-05 14:53:30

回答

9

您可以使用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)小轴。如果是,它只是返回drawable。如果不是,它会将图像分开并对图像块进行解码并将它们放在LayerDrawable中。

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

我不确定你是如何访问你的图片,所以我认为他们在你的可绘制文件夹。如果情况并非如此,那么重构该方法以获取所需的任何参数应该相当容易。

+0

应该指出的是,这个实现只将它分割成行而不是网格。如果宽度大于最大大小,它将通过算法,但块仍将包含大于MAX_SIZE的宽度。尽管增加对它的支持是一个微不足道的修复,但我从未想过使用LayerDrawable来显示可绘制的网格。很好的答案。 – 2013-06-04 00:52:40

+0

在修复中进行编辑,将其拆分为方块而不是仅行。 – 2013-06-04 00:58:50

+0

感谢您的加入@DavidLiu。我的照片编辑出现了一些错误。请检阅我的编辑内容,并确保我没有违反编辑的意图。该方法抛出'IOException',这就是为什么不需要捕获。 – 2013-06-04 07:29:15

3

您可以使用BitmapFactoryOptions减少picture.You的大小可以用财产以后这样的:

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

谢谢,但没有任何我可以在不降低图像质量的情况下达到预期的效果吗? – woot 2013-03-27 12:13:13

+0

我不认为有没有减少图像质量的解决方案。因为它会导致溢出错误。 – developerCoder 2013-03-28 08:23:44

0

,如果你给我们您的位图的尺寸这将有助于。

请注意,OpenGL的运行违背了自然数学极限。

例如,有一个非常好的理由,OpenGL中的纹理必须是2的幂。这实际上是任何缩减的数学运算都可以毫无余量地完成的唯一方法。

所以,如果你给我们提供给你麻烦的最小位图的确切尺寸,我们中的一些人可能会告诉你你遇到什么样的实际限制。

+0

位图的尺寸是动态的,宽度可以高达480px,高度可以是1px到10000px之间的任何值。所需要显示的宽度是屏幕宽度减去一些边距。应该将图像缩放到所需的宽度,同时从左上角保持纵横比。 – woot 2013-04-02 09:04:38

+0

然后,它不是OpenGL纹理。不要那样对待它。你可以在OpenGL中有背景图片,这很好,只要你不把它们当作纹理,它们就会好的。 – 2013-04-02 09:09:35

+0

你是什么意思不把他们当作纹理?我不直接使用OpenGL,我所做的只是为ImageView设置源,然后由于设备的纹理大小限制而不显示图像。例如:“位图太大,无法上传到Nexus 10上的纹理(480x5400,最大= 4096x4096)”。 – woot 2013-04-02 11:34:32

2

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

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