2013-03-27 110 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卡上加載它們所需的圖塊。使用這種瓷磚地圖可以顯示無盡的圖像。