package com.example.utils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
public class BitmapUtils {
public final static int getDegress(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;
}
public static Bitmap rotateBitmap(Bitmap bitmap, int degress) {
if (bitmap != null) {
Matrix m = new Matrix();
m.postRotate(degress);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
return bitmap;
}
return bitmap;
}
public final static int caculateInSampleSize(BitmapFactory.Options options, int rqsW, int rqsH) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (rqsW == 0 || rqsH == 0) return 1;
if (height > rqsH || width > rqsW) {
final int heightRatio = Math.round((float) height/ (float) rqsH);
final int widthRatio = Math.round((float) width / (float) rqsW);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
/**
* 压缩指定路径的图片,并得到图片对象
* @param context
* @param path bitmap source path
* @return Bitmap {@link android.graphics.Bitmap}
*/
public final static Bitmap compressBitmap(String path, int rqsW, int rqsH) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = caculateInSampleSize(options, rqsW, rqsH);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
/**
* 压缩指定路径图片,并将其保存在缓存目录中,通过isDelSrc判定是否删除源文件,并获取到缓存后的图片路径
* @param context
* @param srcPath
* @param rqsW
* @param rqsH
* @param isDelSrc
* @return
*/
public final static String compressBitmap(Context context, String srcPath,String desPath, int rqsW, int rqsH, boolean isDelSrc) {
Bitmap bitmap = compressBitmap(srcPath, rqsW, rqsH);
File srcFile = new File(srcPath);
int degree = getDegress(srcPath);
try {
if (degree != 0) bitmap = rotateBitmap(bitmap, degree);
File file = new File(desPath);
if(srcFile.getAbsolutePath() != file.getAbsolutePath()){
FileOutputStream fos = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 40, fos);
fos.close();
}
if (isDelSrc) srcFile.deleteOnExit();
} catch (Exception e) {
e.printStackTrace();
}
return desPath;
}
/**
* 刷新相册
* @param context
* @param imgFileName
*/
private static void scanPhoto(Context context, String imgFileName)
{
Intent mediaScanIntent = new Intent("android.intent.action.MEDIA_SCANNER_SCAN_FILE");
File file = new File(imgFileName);
Uri contentUri = Uri.fromFile(file);
mediaScanIntent.setData(contentUri);
context.sendBroadcast(mediaScanIntent);
}
/**
* 压缩某个输入流中的图片,可以解决网络输入流压缩问题,并得到图片对象
* @param context
* @param path bitmap source path
* @return Bitmap {@link android.graphics.Bitmap}
*/
public final static Bitmap compressBitmap(InputStream is, int reqsW, int reqsH) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ReadableByteChannel channel = Channels.newChannel(is);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (channel.read(buffer) != -1) {
buffer.flip();
while (buffer.hasRemaining()) baos.write(buffer.get());
buffer.clear();
}
byte[] bts = baos.toByteArray();
Bitmap bitmap = compressBitmap(bts, reqsW, reqsH);
is.close();
channel.close();
baos.close();
return bitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 压缩指定byte[]图片,并得到压缩后的图像
* @param bts
* @param reqsW
* @param reqsH
* @return
*/
public final static Bitmap compressBitmap(byte[] bts, int reqsW, int reqsH) {
final Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(bts, 0, bts.length, options);
options.inSampleSize = caculateInSampleSize(options, reqsW, reqsH);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeByteArray(bts, 0, bts.length, options);
}
/**
* 压缩已存在的图片对象,并返回压缩后的图片
* @param bitmap
* @param reqsW
* @param reqsH
* @return
*/
public final static Bitmap compressBitmap(Bitmap bitmap, int reqsW, int reqsH) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.PNG, 100, baos);
byte[] bts = baos.toByteArray();
Bitmap res = compressBitmap(bts, reqsW, reqsH);
baos.close();
return res;
} catch (IOException e) {
e.printStackTrace();
return bitmap;
}
}
/**
* 压缩资源图片,并返回图片对象
* @param res {@link android.content.res.Resources}
* @param resID
* @param reqsW
* @param reqsH
* @return
*/
public final static Bitmap compressBitmap(Resources res, int resID, int reqsW, int reqsH) {
final Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resID, options);
options.inSampleSize = caculateInSampleSize(options, reqsW, reqsH);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resID, options);
}
/**
* 基于质量的压缩算法, 此方法未 解决压缩后图像失真问题
* <br> 可先调用比例压缩适当压缩图片后,再调用此方法可解决上述问题
* @param bts
* @param maxBytes 压缩后的图像最大大小 单位为byte
* @return
*/
public final static Bitmap compressBitmap(Bitmap bitmap, long maxBytes) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.PNG, 100, baos);
int options = 90;
while (baos.toByteArray().length > maxBytes) {
baos.reset();
bitmap.compress(CompressFormat.PNG, options, baos);
options -= 10;
}
byte[] bts = baos.toByteArray();
Bitmap bmp = BitmapFactory.decodeByteArray(bts, 0, bts.length);
baos.close();
return bmp;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 得到指定路径图片的options
* @param srcPath
* @return Options {@link android.graphics.BitmapFactory.Options}
*/
public final static Options getBitmapOptions(String srcPath) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(srcPath, options);
return options;
}
/**
* 获取本地图片byte[]
* @param bmp
* @param needRecycle
* @return
*/
public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
bmp.compress(CompressFormat.PNG, 100, output);
if (needRecycle) {
bmp.recycle();
}
byte[] result = output.toByteArray();
try {
output.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static void closeStream(OutputStream os){
if(os != null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void closeStream(InputStream os){
if(os != null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@SuppressLint("NewApi")
public static int getBitmapsize(Bitmap bp){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
return bp.getByteCount() / 1024;
}
return bp.getRowBytes() * bp.getHeight() / 1024;
}
/**
* 初步处理大图片 :大小压缩
* @param imgFilePath
* @param smartSpace
* @return
*/
public static Bitmap scaleCompressBp(String imgFilePath,long smartSpace){
File file = new File(imgFilePath);
if(!file.exists() || !file.isFile()){
throw new IllegalArgumentException("file not exists or file is not a image file");
}
long scalebefore = (file.length()/1024)/smartSpace;
double sqrt = Math.sqrt(scalebefore);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
if((int)sqrt <= 1) sqrt = 1;
options.inSampleSize = (int) sqrt;
return BitmapFactory.decodeFile(imgFilePath,options);
}
/**
* 进一步处理图片 : 进行质量压缩
* desSize 不能太小失真很严重
* @param bitmap
* @param desSize
* @return
*/
private static byte[] qualityCompressBp(Bitmap bitmap,int desSize) {
byte[] desBytes = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int options = 100;
int length = baos.toByteArray().length;
while (length / 1024 > desSize) {
baos.reset();
bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);
options -= 3;
if(options <= 10) break;
}
desBytes = baos.toByteArray();
closeStream(baos);
return desBytes;
}
/**
* 对图片进行压缩处理
* 在 华为4x 1300万摄像头下进行测试的结果 原始图片 2.49M 压缩后在300kb左右 其中smartSpace 50 desSize 300
* 根据处理文件大小的不同 来设置相应的smartSpace因子 和 desSize;
* @param imgFilePath 原始图片文件路径
* @param smartSpace
* @return
*/
public static Bitmap smartCompressBp(String imgFilePath,long smartSpace,int desSize){
Bitmap scaleCompressBp = scaleCompressBp(imgFilePath,smartSpace);
byte[] qualityCompressBp = qualityCompressBp(scaleCompressBp,desSize);
return BitmapFactory.decodeByteArray(qualityCompressBp, 0, qualityCompressBp.length);
}
public static Bitmap scaleCompressBp(Bitmap bp,long smartSpace){
long scalebefore = getBitmapsize(bp)/smartSpace;
double sqrt = Math.sqrt(scalebefore);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
if((int)sqrt <= 1) sqrt = 1;
options.inSampleSize = (int) sqrt;
ByteArrayOutputStream aos = new ByteArrayOutputStream();
bp.compress(Bitmap.CompressFormat.JPEG, 100, aos);
return BitmapFactory.decodeByteArray(aos.toByteArray(), 0, aos.toByteArray().length);
}
public static Bitmap smartCompressBp(Bitmap srcBitmap,long smartSpace,int desSize){
Bitmap scaleCompressBp = scaleCompressBp(srcBitmap,smartSpace);
byte[] qualityCompressBp = qualityCompressBp(scaleCompressBp,desSize);
return BitmapFactory.decodeByteArray(qualityCompressBp, 0, qualityCompressBp.length);
}
}