• 保存到桌面  加入收藏  设为首页
安卓应用

安卓-代码--ImageResizer(图片采样 OOM内存溢出)

时间:2016-10-18 12:29:39   作者:   来源:胜行天下   阅读:658   评论:2

获得清晰且占用native内存很小的bitmap
 
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

/**
 * 图片采样,获得清晰且占用内存很小的bitmap(Bitmap对象由Native方法生成) 。类说明 : 图片大小修改 避免oom内存溢出;
 * 暂时使用的方法都采用 decodeSampledBitmapFromPathMoreSafe(),后期需要用到其他方法,
 * 按照decodeSampledBitmapFromPathMoreSafe重新修改,测试通过后在此记录,并更新备份此代码。 已修改代码:1、Bitmap
 * decodeSampledBitmapFromPath(String path, int reqWidth, int reqHeight);
 * 
 * @author 作者 江节胜 E-mail:jiangjsheng@qq.com
 * @version 创建时间:2016年7月14日 下午1:45:06
 * 
 */
public class ImageResizer {
    private static final String TAG = "ImageResizer";

    public ImageResizer() {
    }

    // 传入资源文件,计算合适的大小,返回一个Bitmap对象
    public Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
            int reqWidth, int reqHeight) {
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);// 或者其他方式

    }

    /**
     * 为了加载文件系统的文件避免二次decodeStream返回null而专门调整的方法decode方法 解释:
     * FileInputStream是一种有序的文件流,而两次的decodeStream调用影响了文件流的位置属性,
     * 导致了第二次decodeStream时得到的是null,为了解决这个问题,可以通过文件流来得到他所对应的文件描述符, 然后在通过
     * BitmapFactory.decodeFileDescriptor方法来加载一张缩放过的图片
     */
    public Bitmap decodeSampledBitmapFromFileDescriptor(FileDescriptor fd,
            int reqWidth, int reqHeight) {
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();

        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFileDescriptor(fd, null, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFileDescriptor(fd, null, options);
    }

    /**
     * 方法说明:可能还是解决不了内存溢出,最多捕获内存溢出。使用decodeSampledBitmapFromPathMoreSafe处理
     */
    @Deprecated
    public Bitmap decodeSampledBitmapFromPath(String path, int reqWidth,
            int reqHeight) {
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        try {
            return BitmapFactory.decodeFile(path, options);
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 20160918新增:inSampleSize 重新计算(之前的方法计算的值不够精确),并捕获异常。
     * 方法说明:http://www.cnblogs.com/zgz345/archive/2013/01/08/2851204.html 使用中要
     * if(!bmp.isRecycle() ){ bmp.recycle() //回收图片所占的内存 system.gc() //提醒系统及时回收 }
     * 从ImageView中获取
     */
    public Bitmap decodeSampledBitmapFromPathMoreSafe(String path,
            int reqWidth, int reqHeight) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inDither = false;
        options.inPurgeable = true;
        options.inTempStorage = new byte[12 * 1024];// 创建一个12kb的临时空间
        options.inJustDecodeBounds = true;

        File file = new File(path);
        FileInputStream fs = null;
        try {
            fs = new FileInputStream(file);

            BitmapFactory.decodeFileDescriptor(fs.getFD(), null, options);
        } catch (Exception e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        // Calculate inSampleSize
        // options.inSampleSize = calculateInSampleSize(options, reqWidth,
        // reqHeight);
        /**
         * 使用此方法计算inSampleSize值 20160918新增
         */
        final int minSideLength = Math.min(reqWidth, reqHeight);
        options.inSampleSize = computeSampleSize(options, minSideLength,
                reqWidth * reqHeight);
        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;

        Bitmap bmp = null;
        try {
            fs = new FileInputStream(file);
            if (fs != null)
                bmp = BitmapFactory.decodeFileDescriptor(fs.getFD(), null,
                        options);
            if (fs != null) {
                fs.close();
                fs = null;
            }
            return bmp;

        } catch (Exception e) {

            try {
                if (fs != null) {
                    fs.close();
                    fs = null;
                }
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            Log.i("test",
                    "ImageResizer(图片压缩) decodeSampledBitmapFromPathMoreSafe 出现内存溢出 并返回null对象");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 方法说明: 直接使用 BitmapFactory.decodeStream(is) 返回空
     * 
     * @author Aotu-JS ,email:jiangjsheng@qq.com
     * @version 创建时间:2016年8月16日 下午6:14:26
     * 
     * @param is
     * @param reqWidth
     * @param reqHeight
     * @return
     */
    public Bitmap decodeSampledBitmapFromInputStream(InputStream is,
            int reqWidth, int reqHeight) {
        // First decode with inJustDecodeBounds=true to check dimensions
        Log.i("test", "decodeStream is0 == null " + String.valueOf(is == null));
        byte[] data = null;
        try {
            data = readStream(is);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeByteArray(data, 0, data.length, options);
        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;

        Bitmap decodeStream = BitmapFactory.decodeByteArray(data, 0,
                data.length, options);
        Log.i("test",
                "decodeStream Bitmap == null "
                        + String.valueOf(decodeStream == null));
        Log.i("test", "decodeStream is1 == null " + String.valueOf(is == null));
        Log.i("test", "decodeStream Bitmap size " + decodeStream.getByteCount());
        Log.i("test", "decodeStream options.inSampleSize = "
                + options.inSampleSize);

        return decodeStream;

    }

    /**
     * 原始方法计算的inSampleSize值不够精确,容易导致oom
     */
    public int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {
        if (reqWidth == 0 || reqHeight == 0) {
            return 1;
        }

        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        Log.d(TAG, "origin, w= " + width + " h=" + height);
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and
            // keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }

        Log.d(TAG, "sampleSize:" + inSampleSize);
        return inSampleSize;
    }

    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;
        }
    }

    /*
     * 得到图片字节流 数组大小
     */
    public static byte[] readStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        outStream.close();
        inStream.close();
        return outStream.toByteArray();
    }
}

有任何疑问或技术合作都可联系我

微信:767000122 【推荐】

QQ:596957738


相关评论

加我微信 596957738 (QQ同号)加我微信   QQ联系:596957738   地址:江苏省南京市雨花台区

苏公网安备32011402010305号

皖ICP备16019989号

江节胜的Gitee,江节胜的Git地址