android 超长图显示的几种方法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zuo_er_lyf/article/details/84950297

问题:用ImageView控件加载长图的时候会遇到这样的一个问题,同一张长图在有些机型可以正常显示,但是在部分机型确显示不了。

原因:当APP开启硬件加速的时候,GPU对于openglRender 渲染有一个限制值,超过了这个限制值,就无法渲染,不同的手机会有不同的限制值;

j针对这一问题,统计了一下几种解决方法

1.关闭硬件加速:

在清单文件AndroidManifest.xml中设置:

<application  android:hardwareAccelerated="false" >

或者在对应的View中设置:

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

:这样的确解决了图片加载问题,但你会在app运行的时候,发现app变得十分卡顿,影响体验,不推荐使用。

2.通过获取手机openglRender 的限制值,判断超过这个限制的话,对图片进行压缩:

<1.获取限制值

/**
     * 获取手机显示最长图片的限制值
     * @return
     */
    public static int getOpenglRenderLimitValue() {
        int maxsize;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            maxsize = getOpenglRenderLimitEqualAboveLollipop();
        } else {
            maxsize = getOpenglRenderLimitBelowLollipop();
        }
        return maxsize == 0 ? 4096 : maxsize;
    }

    private static int getOpenglRenderLimitBelowLollipop() {
        int[] maxSize = new int[1];
        GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0);
        return maxSize[0];
    }

    private static int getOpenglRenderLimitEqualAboveLollipop() {
        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);
        return maxSize[0];
    }

<2.通过Glide加载:

Glide.with(context).load(path).into(new SimpleTarget<GlideDrawable>() {
                                @Override
                                public void onLoadStarted(Drawable placeholder) {
                                    super.onLoadStarted(placeholder);
                                  
                                }

                                @Override
                                public void onLoadFailed(Exception e, Drawable errorDrawable) {
                                    super.onLoadFailed(e, errorDrawable);
                                  
                                }

                                @Override
                                public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
                                    dismissLoading();
                                    //获取图片的宽高
                                    int height = resource.getIntrinsicHeight();
                                    int width = resource.getIntrinsicWidth();
                                    //与限制值进行判断,重新设置宽高
                                    if (height > getOpenglRenderLimitValue()) {
                                        width = width * getOpenglRenderLimitValue() / height;
                                        height = getOpenglRenderLimitValue();
                                       //图片转bitmap
                                        Bitmap bitmap = ImageUtil.drawable2Bitmap(resource);
                                        //根据新的宽高比进行图片压缩
                                        Bitmap result = ImageUtil.mixCompress(context,bitmap, null,height,width);
                                        if (result != null) {
                                            view.setImageBitmap(result);

                                        }
                                    }else {
                                        //小于限制值,则直接显示
                                        view.setImageDrawable(resource);
                                        
                                    }


                                }
                            });

<3.Drawable转Bitmao

  // Drawable转换成Bitmap
    public static Bitmap drawable2Bitmap(Drawable drawable) {
        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
                drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
        drawable.draw(canvas);
        return bitmap;
    }

<4.图片压缩

 /**
     * 混合终极方法(尺寸、质量、JNI压缩)
     *
     * @param image    bitmap对象
     * @param filePath 要保存的指定目录
     * @Description: 通过JNI图片压缩把Bitmap保存到指定目录
     */
    public static Bitmap mixCompress(Context context,Bitmap image, String filePath,int Height,int Width ) {
        // 最大图片大小 1000KB
        int maxSize = 1000;
        // 获取尺寸压缩倍数
        int ratio = getRatioSize(context,Width, Height);
        // 压缩Bitmap到对应尺寸
        Bitmap result = Bitmap.createBitmap(Width / ratio,  Height / ratio, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(result);
        Rect rect = new Rect(0, 0, Width/ ratio,  Height / ratio);
        canvas.drawBitmap(image, null, rect, null);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        int quality = 100;
        result.compress(Bitmap.CompressFormat.JPEG, quality, baos);
        // 循环判断如果压缩后图片是否大于最大值,大于继续压缩
        while (baos.toByteArray().length / 1024 > maxSize) {
            // 重置baos即清空baos
            baos.reset();
            // 每次都减少10
            quality -= 10;
            // 这里压缩options%,把压缩后的数据存放到baos中
            result.compress(Bitmap.CompressFormat.JPEG, quality, baos);
        }
        return result;
    }
 /**
     * 计算缩放比
     *
     * @param bitWidth  当前图片宽度
     * @param bitHeight 当前图片高度
     * @return
     * @Description:函数描述
     */
    public static int getRatioSize(Context context,int bitWidth, int bitHeight) {
        // 图片最大分辨率
        int imageHeight =ImageViewerUtil.getOpenglRenderLimitValue();
        // 缩放比
        int ratio = 1;
        // 缩放比,由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        if (bitWidth > bitHeight && bitWidth > imageHeight) {
            // 如果图片宽度比高度大,以宽度为基准
            ratio = bitWidth / imageHeight;
        } else if (bitWidth < bitHeight && bitHeight > imageHeight) {
            // 如果图片高度比宽度大,以高度为基准
            ratio = bitHeight / imageHeight;
        }
        // 最小比率为1
        if (ratio <= 0)
            ratio = 1;
        return ratio;
    }

通过以上步骤,就可以正常显示了;

3.通过自定义View:

参考鸿洋大神的Android 高清加载巨图方案 拒绝压缩图片

4.引用第三方库:

工具类SubsamplingScaleImageView

总结:

2方法在imageview的基础上进行显示,可应用于显示的控件必须为ImageView的场景;
3,4的方法原理都是一样的,都是继承View,作用于直接显示图片,非常方便;

猜你喜欢

转载自blog.csdn.net/zuo_er_lyf/article/details/84950297