有关图片的压缩,整理一下.有用的COPY


工具两个类. ImageHelp 与 ImageHelp
调用方法MainActivity
直接贴代码了

ImageHelp

package com.myetc.bitmapuse;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Environment;
import android.util.Log;

/**
 * 图片压缩工具类
 * 1:指定res中的id进行压缩
 * 2:指定bitmap进行压缩
 * 3:指定path 进行压缩
 * @author lixifeng
 * 声明:要有SD卡的读存权限
 */
public class ImageHelp  {
    private static String TEMP_PATH = "sdcard/aboutimage/temp";
    private static int maxFileSize_KB =200;//图片压缩大小最终文件大小<maxFileSize_KB
    private static int imageSizeW_H =1000*2000;//图片压缩大小区间 指在x*y<imageSizeW_H 而不是边长固定

    /**
     * 压缩图片并保存到文件
     * @param context 页面
     * @param pathInput SD卡形式的图片路径 (注:要压缩的图片)
     * @param pathOutput SD形貌的图片路径 (注:压缩后图片存放的位置)
     * @param max 压缩指定最大的边(注:0:不取最大边.以 imageSizeW_H 为准)
     * 
     * imageSizeW_H 默认为:1000*2000
     * maxFileSize_KB 默认为200KB 
     * 
     */
    public  void resampleImageAndSaveToNewLocation(final Context context,
            final String pathInput, final String pathOutput,int max) {
        resampleImageAndSaveToNewLocation(context, 0, null,pathInput, pathOutput,max);
    }
    /**
     * 压位图并保存到文件
     * @param context 页面
     * @param bitmap 位图
     * @param pathOutput SD形貌的图片路径 (注:压缩后图片存放的位置)
     * @param max 压缩指定最大的边(注:0:不取最大边.以 imageSizeW_H 为准)
     * 
     * imageSizeW_H 默认为:1000*2000
     * maxFileSize_KB 默认为200KB 
     * 
     */
    public  void resampleImageAndSaveToNewLocation(final Context context,
            final Bitmap bitmap, final String pathOutput,int max) {
        resampleImageAndSaveToNewLocation(context, 0, bitmap,null, pathOutput,max);
    }
    /**
     * 压位图并保存到文件
     * @param context 页面
     * @param id res资源下的id
     * @param pathOutput SD形貌的图片路径 (注:压缩后图片存放的位置)
     * @param max 压缩指定最大的边(注:0:不取最大边.以 imageSizeW_H 为准)
     * 
     * imageSizeW_H 默认为:1000*2000
     * maxFileSize_KB 默认为200KB 
     * 
     */
    public  void resampleImageAndSaveToNewLocation(final Context context,
            final int id, final String pathOutput,int max){
        resampleImageAndSaveToNewLocation(context, id, null, null,pathOutput,max);

    }
    /**
     * 压缩进度的监听 注:子线程.不可操作UI,如要主线程,自行结耦
     * @param imageHelpListen
     */
    public void setImageHelpListen(ImageHelpListen imageHelpListen) {
        ImageHelpListen = imageHelpListen;
    }

    /**
     * 把资源文件,保存到sd卡中
     * 
     * @param context
     * @param id
     * @param pathOutput
     * @param max 指定最大边 注:max!=0 imageSizeW_H刚失效 0:无效
     * @throws Throwable
     */
    private  void resampleImageAndSaveToNewLocation(final Context context,
            final int id, final Bitmap bitmap,final String pathInput,final String pathOutput,final int max)  {

        //创建一个线程,去执行当前的任务
        new Thread(new ImageHelpRun(){
            @Override
            public void run() {
                super.run();

                String temp_ =  TEMP_PATH+"/"+System.currentTimeMillis()+".jpg";
                setState(State.START,null);

                //第一步,把资源保存到文件中去
                try {
                    setState(State.ING,null);
                    resampleImageAndSaveToNewLocation(context, id, bitmap, pathInput,temp_);
                } catch (Throwable e) {
                    setState(State.ERROR,e);

                }


                //第二步,以当前的路径 ,压缩图片
                try {
                    resampleImageAndSave(maxFileSize_KB, temp_, pathOutput, imageSizeW_H,max);
                    setState(State.SUCCESS,null);
                    //删除缓存
                    try {
                        new File(temp_).delete();
                    } catch (Throwable e) {
                        System.err.println("删除缓存失败");
                    }
                } catch (Throwable e) {
                    setState(State.ERROR,e);
                }
            }
        }).start();


    }


    private void setState(State state,Throwable e){
        if(ImageHelpListen!=null){
            ImageHelpListen.getState(state ,e);;
        }
    }
    ImageHelpListen ImageHelpListen;

    public interface ImageHelpListen{
        public void getState(State state, Throwable e);
    }



    public static String getTEMP_PATH() {
        return TEMP_PATH;
    }
    public static void setTEMP_PATH(String tEMP_PATH) {
        TEMP_PATH = tEMP_PATH;
    }
    public static int getMaxFileSize_KB() {
        return maxFileSize_KB;
    }
    public static void setMaxFileSize_KB(int maxFileSize_KB) {
        ImageHelp.maxFileSize_KB = maxFileSize_KB;
    }
    public static int getImageSizeW_H() {
        return imageSizeW_H;
    }
    public static void setImageSizeW_H(int imageSizeW_H) {
        ImageHelp.imageSizeW_H = imageSizeW_H;
    }



    public enum State{ START, ING, SUCCESS, ERROR };

}

ImageHelpRun

package com.myetc.bitmapuse;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.os.Build;
import android.util.Log;

public class ImageHelpRun implements Runnable{


    //文件流,所执行的步长
    private static final int moveSize = 2048;



    /**
     * 把资源文件,或者位图 保存到sd卡中
     * @param context
     * @param id 资源ID
     * @param bitmap 位置
     * @param pathOutput 输出位置
     * @throws Throwable 
     */
    public  void resampleImageAndSaveToNewLocation(Context context,int id,Bitmap bitmap,String pathInput,
            String pathOutput) throws Throwable {

        if(context==null) throw new NullPointerException("context is null");
        if(pathOutput==null) throw new NullPointerException("pathOutput is null");

        File file = new File(pathOutput);//创建文件

        //如果文件不存在就创建文件,写入图片
        if (!file.exists()) {
            //注:如果没有权限,不会被提示
            file.getParentFile().mkdirs();
        }else{
            file.delete();
        }


        if(id!=0){
        //读取程序中的图片 保存到 pathOutput 的文件中去
        copyIO(context.getResources().openRawResource(id), new FileOutputStream(file));
        }else if(bitmap!=null){
            //把bitmap 转为is , 保存到 pathOutput 的文件中去
            copyIO(Bitmap2IS(bitmap), new FileOutputStream(file));
        }else if(pathInput!=null){
               copyIO(new FileInputStream(pathInput), new FileOutputStream(file));
        }else{
            throw new NullPointerException("no file??????????");
        }

    }



    @Override
    public void run() {

    }
    /**
     * 
     * @param maxFileSize_KB 指定保存图片的大小 
     * @param pathInput 图片所有的位置 
     * @param pathOutput 图片要保存的位置
     * @param imageSizeW_H 图片的w*h的积
     * @return
     * @throws Exception
     */
    public  Bitmap resampleImageAndSave(int maxFileSize_KB,String pathInput,
            String pathOutput,double imageSizeW_H,int maxDim) throws Throwable{

        //计算当前文件,是否达标
        if(verFile(new File(pathInput), maxFileSize_KB)<=0){
            //如果文件达标,不用压缩,直接COPY走
            copyFile(pathInput, pathOutput);

            return null;
        }else{
            //图片超出指定kb


            System.out.println(" ");
            System.out.println(" ");
            System.out.println("*****读取缩放比例*****");

            BitmapFactory.Options opts = new BitmapFactory.Options();
            //只取图片的尺寸
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(pathInput, opts);

            //w*h小于imageSizeW_H 例:100*200<2000*80 不进行缩放
            if(opts.outWidth*opts.outHeight<=imageSizeW_H){

                //设置不缩放
                opts.inSampleSize = 1;
            }else{
                //假设 图片等比例压缩,大小为1080*1920 开方结果为 1440
                //得到以1440为最大边的图片压缩图
                int max = (int) Math.sqrt(imageSizeW_H);
                //计算出图片的等比缩放等级1-x
                opts.inSampleSize = getClosestResampleSize(opts.outWidth,
                        opts.outHeight, max);

            }

            //进行取图,包含内容
            opts.inJustDecodeBounds = false;
            //取得图片.这里可能会内存OOM ,做处理


            System.out.println(" ");
            System.out.println(" ");
            System.out.println("*****加载图片*****");


            Bitmap bit = null;
            boolean loadImage = true;//开关...你懂的..
            //在这里,进行循环压缩
            do {
                try {
                    //取到图片
                    bit = BitmapFactory.decodeFile(pathInput, opts);
                    loadImage = false;
                } catch (OutOfMemoryError e) {
                    //如果缩放(或缩放为1)情况下,也oom,进行缩放递增
                    loadImage = true;
                    //缩放图片,进行加载
                    opts.inSampleSize = opts.inSampleSize+1;
                }
            } while (loadImage);


            /*
             * 注:::::::::这里确定取到了bitmap.而没有异常
             * 
             */

            System.out.println(" ");
            System.out.println(" ");
            System.out.println("*****旋转图片*****");
            //判断图片是否被旋转了,如果旋转,进行反转图片


            bit = resampleImage(bit, maxDim, pathInput);



            System.out.println(" ");
            System.out.println(" ");
            System.out.println("*****保存缩放后的图片*****");



            int quality = 100;
            if(opts.inSampleSize==1){
                //如果没有改变大小,改变质量,质量以输入的10% 降
                //保存完之后,验证是否符合标准
                quality  = 90;
            }else{
                //用来重原图开始
                //因为用了do while,所在进行添加一次上限的值,进行保存原图
                quality  = 100;
            }

            int dif = 20;//每次在原图的基本上读取的等级 100 80 60 40 20 0
        //如何快速计算出质量比
            double difKB = 0;
            do {

                //保存图片的方法,要进行升级
                File file = new File(pathOutput);
                if (!file.exists()) {
                    //注:如果没有权限,不会被提示
                    file.getParentFile().mkdirs();
                }else{
                    file.delete();
                }

                OutputStream out = new FileOutputStream(file);
                //压缩图片质量,在原图上
                bit.compress(Bitmap.CompressFormat.JPEG, quality, out);
                //保存到图片达标
                difKB = verFile(file, maxFileSize_KB);
                quality-=dif;

            } while (difKB>0);


            System.out.println(" ");
            System.out.println(" ");
            System.out.println("*****完成*****");
            return bit;

        }


    }
    /**
     *  图片压缩,旋转
     * @param bmpt 指定的bit 
     * @param maxDim 指定压缩大小 0:只压缩只旋转
     * @param pathInput 图片所在的位置
     * @return
     * @throws Exception
     */
    public  Bitmap resampleImage(Bitmap bmpt, int maxDim,String pathInput)
            throws Exception {


        Matrix m = new Matrix();
        int sdk = new Integer(Build.VERSION.SDK).intValue();
        if (sdk > 4) {
            //图片旋转
            int rotation = readPictureDegree(pathInput);
            if (rotation != 0) {
                //进行旋转
                m.postRotate(rotation);

            }
        }

        if(maxDim!=0){

        BitmapFactory.Options optsScale = getResampling(bmpt.getWidth(),
                bmpt.getHeight(), maxDim);
        m.postScale((float) optsScale.outWidth / (float) bmpt.getWidth(),
                (float) optsScale.outHeight / (float) bmpt.getHeight());
        }

        return Bitmap.createBitmap(bmpt, 0, 0, bmpt.getWidth(),
                bmpt.getHeight(), m, true);
    }

    /**
     * 计算由指定最大边,应改变的大小
     * @param cx 宽
     * @param cy 高
     * @param max 最大的一个边
     * @return
     */
    private  BitmapFactory.Options getResampling(int cx, int cy, int max) {
        float scaleVal = 1.0f;
        BitmapFactory.Options bfo = new BitmapFactory.Options();
        if (cx > cy) {
            scaleVal = (float) max / (float) cx;
        } else if (cy > cx) {
            scaleVal = (float) max / (float) cy;
        } else {
            scaleVal = (float) max / (float) cx;
        }
        bfo.outWidth = (int) (cx * scaleVal + 0.5f);
        bfo.outHeight = (int) (cy * scaleVal + 0.5f);
        return bfo;
    }
    /**
     * 把bitmap 转换为 is
     * @param bm
     * @return
     */
    public InputStream Bitmap2IS(Bitmap bm) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        InputStream sbs = new ByteArrayInputStream(baos.toByteArray());
        return sbs;
    }

    /**
     * 读取图片的旋转角度(注:不会30度45度)
     * @param path 图片所在的路径 (注:用路径,是最高性能的读取,用bitmap什么的,内存会疯掉的)
     * @return 返回:角度
     */
    public  int readPictureDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(
                    ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                degree = 90;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                degree = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                degree = 270;
                break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }
    /**
     * 计算图片在指定边的情况下,缩放等级
     * @param cx 宽
     * @param cy 高
     * @param maxDim 指定大小
     * @return 返回:缩放等级  2,缩小2倍 3,3倍
     */
    private  int getClosestResampleSize(int cx, int cy, int maxDim) {
        int max = Math.max(cx, cy);

        int resample = 1;
        for (resample = 1; resample < Integer.MAX_VALUE; resample++) {
            if (resample * maxDim > max) {
                resample--;
                break;
            }
        }

        if (resample > 0) {
            return resample;
        }
        return 1;
    }

    /**  
     * 复制单个文件  
     * @param oldPath String 原文件路径 如:c:/fqf.txt  
     * @param newPath String 复制后路径 如:f:/fqf.txt  
     * @return   注:会oom
     */   
   private   void copyFile(String oldPath, String newPath) throws Throwable {   

       File oldfile = new File(oldPath);   
       if (oldfile.exists()) { //文件存在时   
           //进行copy
           copyIO(new FileInputStream(oldPath), new FileOutputStream(newPath));  
       }else{
            throw new NotFoundException("no foud oldPath");
       }
   }  
   /**
    * 流文件的copy
    * @param is 输入流
    * @param os 输出流
    */
   private  void copyIO(InputStream is,FileOutputStream os ) throws Throwable{
        //移动步长
          byte[] buffer = new byte[moveSize]; 
          int count = 0; 
          //以 buffer 进行写入
          while((count=is.read(buffer)) > 0) 
          { 
              os.write(buffer, 0, count); 
          }
        //关闭流
          os.flush();
          os.close();
          is.close();
   }

    /**
     * 
     * @param file 指定的文件大小
     * @param maxFileSize_KB 要对比的值
     * @return 返回:指定文件与要对比值的差值 .单位KM
     * @throws Exception
     */
    private  double verFile(File file,int maxFileSize_KB) throws Exception{
        long fileS = getFileSize(file);
        double fileSize = 1;
        return ((double) fileS / 1024) - maxFileSize_KB;
    }

    /**
     *  获取指定文件大小 
     * @param file 指定文件
     * @return 返回:字节单位的大小
     * @throws Exception
     */
    private long getFileSize(File file) throws Exception {
        long size = 0;
        if (file.exists()) {
            FileInputStream fis = null;
            fis = new FileInputStream(file);
            size = fis.available();
        } else {
            size = 0;
        }
        return size;
    }

}

MainActivity

package com.myetc.bitmapuse;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;

import com.myetc.bitmapuse.ImageHelp.State;

public class MainActivity extends Activity {

    private Button a;
    private Context context = this;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        a = new Button(context);
        a.setText("压缩");
        setContentView(a);
        initAction();
    }

    Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            super.handleMessage(msg);;
            a.setText(""+msg.obj);
        };
    };
    private void initAction(){
        a.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                String path = Environment.getExternalStorageDirectory().getPath();//获取手机本地存//储路径,这个位置可以根据需要自己改。
                ImageHelp m_ImageHelp = new ImageHelp();
                m_ImageHelp.setImageHelpListen(new ImageHelp.ImageHelpListen() {

                    @Override
                    public void getState(State state, Throwable e) {
                        Message msg =   handler.obtainMessage();
                        switch (state) {
                        case START:
                            System.out.println("保存开始");
                            msg.obj = "保存开始";
                            break;
                        case ING:
                            System.out.println("保存中");
                            msg.obj = "保存中";
                            break;
                        case SUCCESS:
                            msg.obj = "保存成功";
                            break;
                        case ERROR:
                            msg.obj = "保存错误";
                            e.printStackTrace();
                            break;
                        default:
                            msg.obj = "其它";
                            break;
                        }

                        handler.sendMessage(msg);
                    }
                });
                m_ImageHelp.resampleImageAndSaveToNewLocation(context, "/mnt/sdcard/aaa/p1.jpg", "sdcard/aaa/test/p000.jpg",0);
            }
        });
    }

}