【Android - 进阶】之图片压缩

        很多时候,如果APP需要下载和加载很多图片(尤其是大图片)的时候,就往往会报如下图所示的错误:

        如上图所示,OOM(OutOfMemoryError)表示内存溢出,这是因为网络或内存中的图片被加载成Bitmap时耗费的内存超出了系统内存而造成内存溢出。解决这个问题有很多方法,这里主要介绍其中的一种方法:图片压缩。

 

        这里贴出一个工具类:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;

/**
 * 图片压缩工具类
 */
public class ImageUtil {
    /**
     * 从指定路径获取Bitmap图片
     *
     * @param imgPath 原始图片的路径
     */
    public static Bitmap getBitmap(String imgPath) {
        // Get bitmap through image path  
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = false;
        newOpts.inPurgeable = true;
        newOpts.inInputShareable = true;
        // Do not compress  
        newOpts.inSampleSize = 1;
        newOpts.inPreferredConfig = Config.RGB_565;
        return BitmapFactory.decodeFile(imgPath, newOpts);
    }

    /**
     * 将图片存储到指定路径的文件中
     *
     * @param bitmap  原始图片Bitmap
     * @param outPath 目标图片路径
     */
    public static void storeImage(Bitmap bitmap, String outPath) throws FileNotFoundException {
        FileOutputStream os = new FileOutputStream(outPath);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
    }

    /**
     * 尺寸压缩(改变图片的宽高),适合用于加载缩略图
     *
     * @param imgPath 图片路径
     * @param pixelW  想要将图片压缩到的宽度
     * @param pixelH  想要将图片压缩到的高度
     */
    public Bitmap ratio(String imgPath, float pixelW, float pixelH) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        // 开始读入图片,此时把options.inJustDecodeBounds 设回true,即只读边不读内容  
        newOpts.inJustDecodeBounds = true;
        newOpts.inPreferredConfig = Config.RGB_565;
        // Get bitmap info, but notice that bitmap is null now    
        Bitmap bitmap = BitmapFactory.decodeFile(imgPath, newOpts);

        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        // 想要缩放的目标尺寸  
        float hh = pixelH;// 设置高度为240f时,可以明显看到图片缩小了  
        float ww = pixelW;// 设置宽度为120f,可以明显看到图片缩小了  
        // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可    
        int be = 1;//be=1表示不缩放    
        if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放    
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放    
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0) be = 1;
        newOpts.inSampleSize = be;//设置缩放比例  
        // 开始压缩图片,注意此时已经把options.inJustDecodeBounds 设回false了  
        bitmap = BitmapFactory.decodeFile(imgPath, newOpts);
        return bitmap;
    }

    /**
     * 尺寸压缩(改变图片的宽高),适合用于加载缩略图
     *
     * @param image  图片的Bitmap
     * @param pixelW 想要将图片压缩到的宽度
     * @param pixelH 想要将图片压缩到的高度
     */
    public Bitmap ratio(Bitmap image, float pixelW, float pixelH) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, os);
        if (os.toByteArray().length / 1024 > 1024) {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
            os.reset();//重置baos即清空baos    
            image.compress(Bitmap.CompressFormat.JPEG, 50, os);//这里压缩50%,把压缩后的数据存放到baos中    
        }
        ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        //开始读入图片,此时把options.inJustDecodeBounds 设回true了    
        newOpts.inJustDecodeBounds = true;
        newOpts.inPreferredConfig = Config.RGB_565;
        Bitmap bitmap = BitmapFactory.decodeStream(is, null, newOpts);
        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        float hh = pixelH;// 设置高度为240f时,可以明显看到图片缩小了  
        float ww = pixelW;// 设置宽度为120f,可以明显看到图片缩小了  
        //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可    
        int be = 1;//be=1表示不缩放    
        if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放    
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放    
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0) be = 1;
        newOpts.inSampleSize = be;//设置缩放比例    
        //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了    
        is = new ByteArrayInputStream(os.toByteArray());
        bitmap = BitmapFactory.decodeStream(is, null, newOpts);
        return bitmap;
    }

    /**
     * 质量压缩,然后存储到指定路径
     *
     * @param image   原始图片Bitmap
     * @param outPath 目标图片路径
     * @param maxSize 图片将被压缩成这么多KB
     */
    public void compressAndGenImage(Bitmap image, String outPath, int maxSize) throws IOException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        // scale  
        int options = 100;
        // Store the bitmap into output stream(no compress)  
        image.compress(Bitmap.CompressFormat.JPEG, options, os);
        // Compress by loop  
        while (os.toByteArray().length / 1024 > maxSize) {
            // Clean up os  
            os.reset();
            // interval 10  
            options -= 10;
            image.compress(Bitmap.CompressFormat.JPEG, options, os);
        }
        // Generate compressed image file  
        FileOutputStream fos = new FileOutputStream(outPath);
        fos.write(os.toByteArray());
        fos.flush();
        fos.close();
    }

    /**
     * 质量压缩并存储到指定路径
     *
     * @param imgPath     想要压缩的图片路径
     * @param outPath     目标图片路径
     * @param maxSize     图片将被压缩成这么多KB
     * @param needsDelete 压缩后是否删除原始图片
     */
    public void compressAndGenImage(String imgPath, String outPath, int maxSize, boolean needsDelete) throws IOException {
        compressAndGenImage(getBitmap(imgPath), outPath, maxSize);
        if (needsDelete) {
            File file = new File(imgPath);
            if (file.exists()) {
                file.delete();
            }
        }
    }

    /**
     * 尺寸压缩后保存图片
     *
     * @param image   原始图片Bitmap
     * @param outPath 目标图片路径
     * @param pixelW  想要将图片压缩到的宽度
     * @param pixelH  想要将图片压缩到的高度
     */
    public void ratioAndGenThumb(Bitmap image, String outPath, float pixelW, float pixelH) throws FileNotFoundException {
        Bitmap bitmap = ratio(image, pixelW, pixelH);
        storeImage(bitmap, outPath);
    }

    /**
     * 尺寸压缩后保存图片,并决定是否删除原始图片
     *
     * @param imgPath     想要压缩的图片路径
     * @param outPath     目标图片路径
     * @param pixelW      想要将图片压缩到的宽度
     * @param pixelH      想要将图片压缩到的高度
     * @param needsDelete 是否删除原始图片
     */
    public void ratioAndGenThumb(String imgPath, String outPath, float pixelW, float pixelH, boolean needsDelete) throws FileNotFoundException {
        Bitmap bitmap = ratio(imgPath, pixelW, pixelH);
        storeImage(bitmap, outPath);
        if (needsDelete) {
            File file = new File(imgPath);
            if (file.exists()) {
                file.delete();
            }
        }
    }
}

 

posted on 2016-12-22 14:09  ITGungnir  阅读(284)  评论(0编辑  收藏  举报

导航