有关图片的压缩,整理一下.有用的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);
}
});
}
}