import java.io.FileOutputStream;
import java.io.IOException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.media.ThumbnailUtils;
import com.idtechinfo.common.CoderHelper;
/**
* 图片处理工具类
*
*/
public class ImageUtil {
public static final int UNCONSTRAINED = -1;
/**
* 从字节数组中解析Bitmap
*
* 参数定义参见:@{link #decodeFile}
*/
public static Bitmap decodeByteArray(byte[] data, int minSideLength) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);
if (options.outWidth < 0 || options.outHeight < 0)
return null;
// Calculate inSampleSize
options.inSampleSize = computeSampleSize(options, minSideLength);
options.inDither = false;
options.inJustDecodeBounds = false;
return BitmapFactory.decodeByteArray(data, 0, data.length, options);
}
/**
* 从文件中解析Bitmap
*
* @param minSideLength
* 最小边界的大小(宽、高中最小的一边值,例如需要1280*720的图,则传720)
* 传{@link #UNCONSTRAINED}则不限制大小
* @return null则解码失败
*/
public static Bitmap decodeFile(String pathName, int minSideLength) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
if (options.outWidth < 0 || options.outHeight < 0)
return null;
// Calculate inSampleSize
options.inSampleSize = computeSampleSize(options, minSideLength);
// Decode bitmap with inSampleSize set
options.inDither = false;
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(pathName, options);
}
/**
* 保存图像到文件
* @author 老吴
*/
public static boolean saveBitmapToFile(Bitmap bitmap, String outFileName, int jpegQuality, boolean isRecycleBitmap) {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(outFileName, false);
return bitmap.compress(CompressFormat.JPEG, jpegQuality, outStream);
} catch (Throwable e) {
e.printStackTrace();
return false;
} finally {
CoderHelper.close(outStream);
if (isRecycleBitmap) {
if (bitmap != null && !bitmap.isRecycled())
bitmap.recycle();
}
}
}
/**
* 压缩图像
*
* @param imgPath
* 待压缩的图片路径
* @param outImgPath
* 压缩后输出路径
* @param jpegQuality
* 压缩质量 0-100
* @param minSideLength
* 取值参见{@link #decodeFile(String, int)}的同名参数
* @param considerRotate
* 是否考虑图片旋转
*/
public static boolean compresImage(String imgPath, String outImgPath, int jpegQuality, int minSideLength, boolean considerRotate) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imgPath, options);
options.inSampleSize = computeSampleSize(options, minSideLength);
options.inJustDecodeBounds = false;
try {
Bitmap bmp = BitmapFactory.decodeFile(imgPath, options);
int dstWidth = 0, dstHeight = 0;
if (options.outWidth > options.outHeight) {
dstWidth = (int) ((double) minSideLength / (double) options.outHeight * (double) options.outWidth);
dstHeight = minSideLength;
} else {
dstWidth = minSideLength;
dstHeight = (int) ((double) minSideLength / (double) options.outWidth * (double) options.outHeight);
}
bmp = ThumbnailUtils.extractThumbnail(bmp, dstWidth, dstHeight, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
int degreeRotate = 0;
if (considerRotate && (degreeRotate = getExifOrientation(imgPath)) != 0) {
Bitmap bmp2 = rotateBitmap(bmp, degreeRotate);
if (!bmp.isRecycled())
bmp.recycle();
bmp = bmp2;
}
return saveBitmapToFile(bmp, outImgPath, jpegQuality, true);
} catch (Throwable ex) {
ex.printStackTrace();
}
return false;
}
/**
* 获取图片文件扩展信息(方向)
*
*
* @param filepath
* 文件路径
* @return int 图片的旋转角度
*
* @author 老吴
*/
public static int getExifOrientation(String filepath) {
int degree = 0;
ExifInterface exif = null;
try {
exif = new ExifInterface(filepath);
} catch (IOException ex) {
ex.printStackTrace();
}
if (exif != null) {
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
if (orientation != -1) {
// We only recognize a subset of orientation tag values.
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;
}
}
}
return degree;
}
/**
* 将Bitmpa纠正到正确方向
*
* @param degree
* : 图片被系统旋转的角度
* @param bitmap
* : 需纠正方向的图片
* @return 纠向后的图片
*
* @author 老吴
*/
public static Bitmap rotateBitmap(Bitmap bitmap, int degree) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
try {
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
} catch (Throwable ex) {
ex.printStackTrace();
return null;
}
}
private static int computeSampleSize(BitmapFactory.Options options, int minSideLength) {
return computeSampleSize(options, minSideLength, UNCONSTRAINED);
}
private 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 == UNCONSTRAINED) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
int upperBound = (minSideLength == UNCONSTRAINED) ? 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 == UNCONSTRAINED) && (minSideLength == UNCONSTRAINED)) {
return 1;
} else if (minSideLength == UNCONSTRAINED) {
return lowerBound;
} else {
return upperBound;
}
}
}
import java.io.IOException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.media.ThumbnailUtils;
import com.idtechinfo.common.CoderHelper;
/**
* 图片处理工具类
*
*/
public class ImageUtil {
public static final int UNCONSTRAINED = -1;
/**
* 从字节数组中解析Bitmap
*
* 参数定义参见:@{link #decodeFile}
*/
public static Bitmap decodeByteArray(byte[] data, int minSideLength) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);
if (options.outWidth < 0 || options.outHeight < 0)
return null;
// Calculate inSampleSize
options.inSampleSize = computeSampleSize(options, minSideLength);
options.inDither = false;
options.inJustDecodeBounds = false;
return BitmapFactory.decodeByteArray(data, 0, data.length, options);
}
/**
* 从文件中解析Bitmap
*
* @param minSideLength
* 最小边界的大小(宽、高中最小的一边值,例如需要1280*720的图,则传720)
* 传{@link #UNCONSTRAINED}则不限制大小
* @return null则解码失败
*/
public static Bitmap decodeFile(String pathName, int minSideLength) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
if (options.outWidth < 0 || options.outHeight < 0)
return null;
// Calculate inSampleSize
options.inSampleSize = computeSampleSize(options, minSideLength);
// Decode bitmap with inSampleSize set
options.inDither = false;
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(pathName, options);
}
/**
* 保存图像到文件
* @author 老吴
*/
public static boolean saveBitmapToFile(Bitmap bitmap, String outFileName, int jpegQuality, boolean isRecycleBitmap) {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(outFileName, false);
return bitmap.compress(CompressFormat.JPEG, jpegQuality, outStream);
} catch (Throwable e) {
e.printStackTrace();
return false;
} finally {
CoderHelper.close(outStream);
if (isRecycleBitmap) {
if (bitmap != null && !bitmap.isRecycled())
bitmap.recycle();
}
}
}
/**
* 压缩图像
*
* @param imgPath
* 待压缩的图片路径
* @param outImgPath
* 压缩后输出路径
* @param jpegQuality
* 压缩质量 0-100
* @param minSideLength
* 取值参见{@link #decodeFile(String, int)}的同名参数
* @param considerRotate
* 是否考虑图片旋转
*/
public static boolean compresImage(String imgPath, String outImgPath, int jpegQuality, int minSideLength, boolean considerRotate) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imgPath, options);
options.inSampleSize = computeSampleSize(options, minSideLength);
options.inJustDecodeBounds = false;
try {
Bitmap bmp = BitmapFactory.decodeFile(imgPath, options);
int dstWidth = 0, dstHeight = 0;
if (options.outWidth > options.outHeight) {
dstWidth = (int) ((double) minSideLength / (double) options.outHeight * (double) options.outWidth);
dstHeight = minSideLength;
} else {
dstWidth = minSideLength;
dstHeight = (int) ((double) minSideLength / (double) options.outWidth * (double) options.outHeight);
}
bmp = ThumbnailUtils.extractThumbnail(bmp, dstWidth, dstHeight, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
int degreeRotate = 0;
if (considerRotate && (degreeRotate = getExifOrientation(imgPath)) != 0) {
Bitmap bmp2 = rotateBitmap(bmp, degreeRotate);
if (!bmp.isRecycled())
bmp.recycle();
bmp = bmp2;
}
return saveBitmapToFile(bmp, outImgPath, jpegQuality, true);
} catch (Throwable ex) {
ex.printStackTrace();
}
return false;
}
/**
* 获取图片文件扩展信息(方向)
*
*
* @param filepath
* 文件路径
* @return int 图片的旋转角度
*
* @author 老吴
*/
public static int getExifOrientation(String filepath) {
int degree = 0;
ExifInterface exif = null;
try {
exif = new ExifInterface(filepath);
} catch (IOException ex) {
ex.printStackTrace();
}
if (exif != null) {
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
if (orientation != -1) {
// We only recognize a subset of orientation tag values.
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;
}
}
}
return degree;
}
/**
* 将Bitmpa纠正到正确方向
*
* @param degree
* : 图片被系统旋转的角度
* @param bitmap
* : 需纠正方向的图片
* @return 纠向后的图片
*
* @author 老吴
*/
public static Bitmap rotateBitmap(Bitmap bitmap, int degree) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
try {
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
} catch (Throwable ex) {
ex.printStackTrace();
return null;
}
}
private static int computeSampleSize(BitmapFactory.Options options, int minSideLength) {
return computeSampleSize(options, minSideLength, UNCONSTRAINED);
}
private 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 == UNCONSTRAINED) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
int upperBound = (minSideLength == UNCONSTRAINED) ? 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 == UNCONSTRAINED) && (minSideLength == UNCONSTRAINED)) {
return 1;
} else if (minSideLength == UNCONSTRAINED) {
return lowerBound;
} else {
return upperBound;
}
}
}