国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android中超大圖片無法顯示的問題解決

2019-12-12 03:59:49
字體:
來源:轉載
供稿:網友

發現問題

最近在做圖片瀏覽功能時遇到了一個很蛋疼的問題,在開啟硬件加速情況下,超大圖無法正常顯示(圖的長寬有一個大于9000),而且程序不會crash,只是圖片加載不出來,View顯示為黑色。通過查看日志,發現系統打印出了下面的內容:

W OpenGLRenderer( 4014): Bitmap too large to be uploaded into a texture (600x9518, max=8192x8192) 

從日志內容可以看出,這是由OpenGL打印出來的日志,是由于圖片的尺寸太大導致的。而且我們可以發現,由于這個問題系統日志是以Warning級別打印出來的,并沒有拋出異常,程序并不會報錯,只是圖片顯示不出來,很難發現問題。當我們把頁面的硬件加速關掉后,圖片就可以顯示出來了。

問題分析

從日志最后的內容可以看出,OpenGL對圖片尺寸的限制是8192,這個尺寸是怎么得到的呢?是否所有的設備都是這個值呢?

要解釋這個問題,需要先來看一下GLES10中的一個常量GL_MAX_TEXTURE_SIZE,從字面上看,它表示Texture的最大值。 查看文檔:

https://www.khronos.org/opengles/sdk/1.1/docs/man/glGet.xml

這里給出的解釋是: The value gives a rough estimate of the largest texture that the GL can handle。也就是OpenGL可以處理的最大尺寸的粗略估計值。既然是粗略估計值,那肯定是有一個準確值的。

網上搜索了一下,基本上都是說通過執行下面的代碼,可以得到這個準確值。

int[] maxTextureSize = new int[1]; GLES10.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxTextureSize, 0); 

然而,這段代碼在我的設備上運行的結果始終是0。這是由于在Android 5.0之后,在進行OpenGL方法的調用時,需要手動創建OpenGL的Context。而這個工作在5.0之前是由framework來完成的。我們這里就是因為沒有創建這個Context導致調用結果為0。

那么有效的代碼就是下面這樣子的:

private void getGLESTextureLimitBelowLollipop() {  int[] maxSize = new int[1];  GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0);  Toast.makeText(this," " + maxSize[0],Toast.LENGTH_LONG).show(); }  private void getGLESTextureLimitEqualAboveLollipop() {  EGL10 egl = (EGL10) EGLContext.getEGL();  EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);  int[] vers = new int[2];  egl.eglInitialize(dpy, vers);  int[] configAttr = {   EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RGB_BUFFER,   EGL10.EGL_LEVEL, 0,   EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT,   EGL10.EGL_NONE  };  EGLConfig[] configs = new EGLConfig[1];  int[] numConfig = new int[1];  egl.eglChooseConfig(dpy, configAttr, configs, 1, numConfig);  if (numConfig[0] == 0) {// TROUBLE! No config found.  }  EGLConfig config = configs[0];  int[] surfAttr = {   EGL10.EGL_WIDTH, 64,   EGL10.EGL_HEIGHT, 64,   EGL10.EGL_NONE  };  EGLSurface surf = egl.eglCreatePbufferSurface(dpy, config, surfAttr);  final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; // missing in EGL10  int[] ctxAttrib = {   EGL_CONTEXT_CLIENT_VERSION, 1,   EGL10.EGL_NONE  };  EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, ctxAttrib);  egl.eglMakeCurrent(dpy, surf, surf, ctx);  int[] maxSize = new int[1];  GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0);  egl.eglMakeCurrent(dpy, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE,   EGL10.EGL_NO_CONTEXT);  egl.eglDestroySurface(dpy, surf);  egl.eglDestroyContext(dpy, ctx);  egl.eglTerminate(dpy);   Toast.makeText(this," " + maxSize[0],Toast.LENGTH_LONG).show(); } 
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {  getGLESTextureLimitEqualAboveLollipop(); } else {  getGLESTextureLimitBelowLollipop(); } 

在我的5.0的手機上,執行上面的代碼,得到這個最大值maxSize是16384,也就是說,當圖片的長和寬有一個超過這個值得時候,在開啟硬件加速的情況下,圖片就顯示不出來了。在不同的手機上運行上述代碼,運行結果不盡相同,說明這個值是設備相關的。

問題解決

既然知道了問題所在,下面就是想辦法來解決這個問題了。

首先,前面既然提到了是硬件加速導致的這個問題,最簡單的方法當然是關閉硬件加速,可以在Activity級別,也可以在View級別關閉硬件加速。這種是屬于簡單粗暴型的。
Activity級別:

android:hardwareAccelerated="false"

View級別:

view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

另外一種方法是通過縮小Bitmap的方式,保證圖片的尺寸不會超過OpenGL的限制,但是,對于查看高清圖的情況,不允許對圖片進行縮放,這個方法是無效的。

最后也是最合理的方式,就是通過Android提供的BitmapRegionDecoder類來處理大圖加載。它的原理是每次只根據需要加載圖片的一部分,然后根據當前用戶的操作去截取圖片不同部分進行更新。具體的用法可以參考官方文檔。

總結

以上就是這篇文章的全部內容了,希望本文的內容對各位Android開發者們能有一定的幫助,如果有疑問大家可以留言交流。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 泾川县| 忻州市| 云林县| 清徐县| 涿鹿县| 北海市| 安远县| 彭水| 广平县| 如皋市| 高唐县| 山阳县| 西贡区| 甘肃省| 江安县| 兴化市| 台南县| 罗江县| 巴林左旗| 彭水| 瑞丽市| 睢宁县| 剑河县| 玉屏| 巴林右旗| 石狮市| 道孚县| 肥乡县| 丰台区| 长治市| 进贤县| 星子县| 若羌县| 黔西县| 神农架林区| 崇阳县| 武定县| 巴马| 通州市| 固阳县| 马鞍山市|