获取缩略图

本文主要讲解说明图片和apk安装文件获取缩略图的实现方式


1. 图片获取缩略图

  思想: 主要根据BitmapFactory类为基础实现;

              主要涉及到了 BitmapFactory.Options类对象及 BitmapFactory.decodeFile(String, Options)方法


Options类用到的主要成员

1.  public boolean inJustDecodeBounds;

        /**
         * If set to true, the decoder will return null (no bitmap), but
         * the out... fields will still be set, allowing the caller to query
         * the bitmap without having to allocate the memory for its pixels.
         */

    true  -- 将不会返回实际的Bitmap对象(不会分配内存空间,避免内存溢出OOM),但是,可以获取图片的原始高度opt.outHeight、原始宽度信息opt.outWidth。

    false - 将申请分配内存,获取得到Bitmap对象。


2. public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;

        /**
         * If this is non-null, the decoder will try to decode into this
         * internal configuration. If it is null, or the request cannot be met,
         * the decoder will try to pick the best matching config based on the
         * system's screen depth, and characteristics of the original image such
         * as if it has per-pixel alpha (requiring a config that also does).
         * 
         * Image are loaded with the {@link Bitmap.Config#ARGB_8888} config by
         * default.
         */

        表示图片解码时使用的颜色模式,也就是图片中每个像素颜色的表示方式。

参数inpreferredconfig的可选值有四个,分别为ALPHA_8,RGB_565,ARGB_4444,ARGB_8888。它们的含义列举如下。

参数取值 含义
ALPHA_8 图片中每个像素用一个字节(8位)存储,该字节存储的是图片8位的透明度值
RGB_565 图片中每个像素用两个字节(16位)存储,两个字节中高5位表示红色通道,中间6位表示绿色通道,低5位表示蓝色通道
ARGB_4444 图片中每个像素用两个字节(16位)存储,Alpha,R,G,B四个通道每个通道用4位表示
ARGB_8888 图片中每个像素用四个字节(32位)存储,Alpha,R,G,B四个通道每个通道用8位表示


3.  public int inSampleSize;

        /**
         * If set to a value > 1, requests the decoder to subsample the original
         * image, returning a smaller image to save memory. The sample size is
         * the number of pixels in either dimension that correspond to a single
         * pixel in the decoded bitmap. For example, inSampleSize == 4 returns
         * an image that is 1/4 the width/height of the original, and 1/16 the
         * number of pixels. Any value <= 1 is treated the same as 1. Note: the
         * decoder uses a final value based on powers of 2, any other value will
         * be rounded down to the nearest power of 2.
         */

     默认或最小值为1,一般大于1,为2的幂,若不为2的幂,解码器将会解码为最接近的2的幂。

    该参数设置图片的缩放大小(压缩比),优化可以参考:http://www.jianshu.com/p/f15cd2ed6ec0


4.  public boolean inPurgeable;

    true  -- 系统内存不足时,可以被回收

    false --  不能被回收


5. public boolean inInputShareable;

        /**
         * @deprecated As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this is
         * ignored.
         *
         * In {@link android.os.Build.VERSION_CODES#KITKAT} and below, this
         * field works in conjuction with inPurgeable. If inPurgeable is false,
         * then this field is ignored. If inPurgeable is true, then this field
         * determines whether the bitmap can share a reference to the input
         * data (inputstream, array, etc.) or if it must make a deep copy.
         */

      设置是否深拷贝,与 inPurgeable 搭配使用。

     inPurgeable - false   ,该参数没有意义,被忽略。

     inPurgeable - true    ,该参数为true,可以共享一个引用给输入数据(流、数组等);false-深拷贝


结合以上几个Options成员变量的使用,可以在获取缩略图时,避免OOM,当然,具体也可以参考:

http://blog.csdn.net/berber78/article/details/19830173

 如何处理图片来避免OOM异常:

1.在Android 2.3.3以及之前,建议使用Bitmap.recycle()方法,及时释放资源。

2.设置Options.inPreferredConfig值来降低内存消耗 //如把默认值ARGB_8888改为RGB_565,节约一半内存

3.设置Options.inSampleSize 对大图片进行压缩 

4.设置Options.inPurgeable和inInputShareable:让系统能及时回收内存。

1)inPurgeable:设置为True时,表示系统内存不足时可以被回 收,设置为False时,表示不能被回收。

2)inInputShareable:设置是否深拷贝,与inPurgeable结合使用,inPurgeable为false时,该参数无意义True:  share  a reference to the input data(inputStream, array,etc) 。 False :a deep copy。

5.使用decodeStream代替其他decodeResource,setImageResource,setImageBitmap等方法:

//decodeStream直接调用 JNI>>nativeDecodeAsset()来完成decode,无需再使用Java层的createBitmap,也不使用java空间进行分辨率适配,虽节省dalvik内存,但需要在hdpi和mdpi,ldpi中配置相应的 图片资源,否则在不同分辨率机器上都是同样大小(像素点数量)。其他方法如setImageBitmap、setImageResource、 BitmapFactory.decodeResource在完成decode后,最终都是通过java层的 createBitmap来完成的,需要消耗更多内存。

6.通过程序设定手动干涉GC处理,增强堆内存处理效率,在程序onCreate时:

private final static floatTARGET_HEAP_UTILIZATION = 0.75f;

VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);

7.自定义堆内存大小:
VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);

8.基础类型上,因为Java没有实际的指针,在敏感运算方面还是要借助NDK来完成。这点比较有意思的是Google 推出NDK可能是帮助游戏开发人员,比如OpenGL ES的支持有明显的改观,本地代码操作图形界面是很必要的;

--------------------------------------------------------------------------------------------------------------


了解了获取缩略图需要知道的一些前提信息后,下面简单说明步骤:

           

1. 创建Options对象,设置参数 

            BitmapFactory.Options opt = new BitmapFactory.Options();
            opt.inJustDecodeBounds = true;


2. 解密图片文件,获取信息

            //  定义的ImageView尺寸

            int thumbSize = context.getResources().getDimensionPixelSize(
                        R.dimen.list_item_thumbnail_size);
            Point mThumbSize = new Point(thumbSize, thumbSize);

            final int widthSample = opt.outWidth / mThumbSize.x;
            final int heightSample = opt.outHeight / mThumbSize.y;


           // 计算缩放比

           int sampleSize = Math.min(widthSample, heightSample);

          if (sampleSize<=0)  sampleSize=1;

        以上是获取 sampleSize的一种方式,可以有多种优化方式,其中,图片的宽和高可以用 sampleSize、opt.outHeight表示。


3.  赋值缩放比 

      opt.inSampleSize = sampleSize;

     上面 第 2 步只是一种获取的方式,也可以有其他优化方式。

         http://www.jianshu.com/p/f15cd2ed6ec0


4. 设置 缩略图获取所需参数

            opt.inJustDecodeBounds = false;                
            opt.inPreferredConfig = Bitmap.Config.RGB_565;
            opt.inPurgeable = true;
            opt.inInputShareable = true;


5. 重新读出缩略图

     // 读取缩放后的Bitmap

    bmp = BitmapFactory.decodeFile(filePath, opt);

   // 创建缩略图

      bmp = ThumbnailUtils.extractThumbnail(bmp, mThumbSize.x,

                                          mThumbSize.y,ThumbnailUtils.OPTIONS_RECYCLE_INPUT);


 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

了解以上步骤后,可以参考如下类似的实现:

    private static final int MAX_FILENAME_LENGTH = 50;
    private static final int MAX_IMAGE_SIZE = 20 * 1024 * 1024;
    //private static final int MAX_IMAGE_RESOLUTION = 4096 * 4096;
    private static final int MAX_IMAGE_WIDTH = 4096;
    private static final int MAX_IMAGE_HEIGTH = 4096;
    public static final int MAX_NUM_COMPRESSION = 5;


    // 获取缩略图接口

    public static Bitmap readBitMap(String filePath, boolean isImage,
            Context context) {
        if (isImage) {
            File tempFile = new File(filePath);
            if (tempFile.length() > MAX_IMAGE_SIZE){

               // 返回默认图片
                getDefaultBitmap(context);
            }
            int thumbSize = context.getResources().getDimensionPixelSize(
                        R.dimen.list_item_thumbnail_size);
            Point mThumbSize = new Point(thumbSize, thumbSize);


            BitmapFactory.Options opt = new BitmapFactory.Options();
            opt.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(filePath, opt);
            
            final int widthSample = opt.outWidth / mThumbSize.x;
            final int heightSample = opt.outHeight / mThumbSize.y;


            Log.d(TAG, "readBitMap()  widthSample = " + widthSample+ "  heightSample= "+heightSample
                  +"   x="+  mThumbSize.x+"   y="+ mThumbSize.y); 


            opt.inJustDecodeBounds = false;
            opt.inPreferredConfig = Bitmap.Config.RGB_565;
            opt.inPurgeable = true;
            opt.inInputShareable = true;
            Bitmap bmp = null;


            boolean noBitmap = true;
            boolean wbmp = filePath.endsWith(".wbmp");
            int sampleSize = computeSampleSize(opt, -1, 128*128); 

           //  多种优化计算缩放比
            //   int sampleSize = Math.min(widthSample, heightSample);


            int num_tries = 0;


            if (wbmp && (opt.outWidth > MAX_IMAGE_WIDTH || opt.outHeight > MAX_IMAGE_HEIGTH)) {
                return getDefaultBitmap(context);
            }
            while (noBitmap) {
                try {
                    Log.d(TAG, "readBitMap().try: num_tries = " + num_tries + "; filePath = " + filePath +"  sampleSize="+sampleSize);
                    opt.inSampleSize = sampleSize;
                    bmp = BitmapFactory.decodeFile(filePath, opt);
                    bmp = ThumbnailUtils.extractThumbnail(bmp, mThumbSize.x, mThumbSize.y,ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
                    noBitmap = false;
                } catch (OutOfMemoryError error) {
                    Log.e(TAG, "Happen OOM ", error);
                    if (++num_tries >= MAX_NUM_COMPRESSION) {
                        noBitmap = false;
                    }
                    if (bmp != null) {
                        bmp.recycle();
                        bmp = null;
                    }
                    System.gc();
                    sampleSize *= 2;
                    Log.d(TAG, "readBitMap().catch: num_tries = " + num_tries + "; filePath = " + filePath);
                }
            }
            
            return bmp;
        } else {
            PackageManager pm = context.getPackageManager();
            PackageInfo info = pm.getPackageArchiveInfo(filePath,
                    PackageManager.GET_ACTIVITIES);
           
            Drawable drawable;
            if (info != null) {
                ApplicationInfo appInfo = info.applicationInfo;
                appInfo.sourceDir = filePath;
                appInfo.publicSourceDir = filePath;
                drawable = appInfo.loadIcon(pm);
                
                if (drawable instanceof NinePatchDrawable) {
                    Bitmap bitmap = Bitmap.createBitmap(
                            drawable.getIntrinsicWidth(),
                            drawable.getIntrinsicHeight(),
                            Bitmap.Config.RGB_565);
                    Canvas canvas = new Canvas(bitmap);
                    drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
                            drawable.getIntrinsicHeight());
                    drawable.draw(canvas);
                    return bitmap;
                } else if (drawable instanceof BitmapDrawable) {
                    BitmapDrawable bd = (BitmapDrawable) drawable;
                    return bd.getBitmap();
                } else {
                    drawable = null;
                    return null;
                }
       
            } else {
                drawable = null;
                return null;
            }


        }
    }


    public static int computeSampleSize(BitmapFactory.Options options,
            int minSideLength, int maxNumOfPixels) {
        int initialSize = computeInitialSampleSize(options, minSideLength,maxNumOfPixels);


        int roundedSize;
        if (initialSize <= 8 ) {
            roundedSize = 1;
            while (roundedSize < initialSize) {
                roundedSize <<= 1;
            }
        } else {
            roundedSize = (initialSize + 7) / 8 * 8;
        }


        return roundedSize;
    }


    private static int computeInitialSampleSize(BitmapFactory.Options options,int minSideLength, int maxNumOfPixels) {
        double w = options.outWidth;
        double h = options.outHeight;


        int lowerBound = (maxNumOfPixels == -1) ? 1 :
                (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
        int upperBound = (minSideLength == -1) ? 128 :
                (int) Math.min(Math.floor(w / minSideLength),
                Math.floor(h / minSideLength));


        if (upperBound < lowerBound) {
            // return the larger one when there is no overlapping zone.
            return lowerBound;
        }


        if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
            return 1;
        } else if (minSideLength == -1) {
            return lowerBound;
        } else {
            return upperBound;
        }
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值