-
Notifications
You must be signed in to change notification settings - Fork 414
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c7ccfe3
commit b090895
Showing
6 changed files
with
324 additions
and
309 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
303 changes: 187 additions & 116 deletions
303
compresshelper/src/main/java/com/nanchen/compresshelper/BitmapUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,159 +1,230 @@ | ||
package com.nanchen.compresshelper; | ||
|
||
import android.content.res.Resources; | ||
import android.content.Context; | ||
import android.graphics.Bitmap; | ||
import android.graphics.BitmapFactory; | ||
import android.graphics.Canvas; | ||
import android.graphics.Matrix; | ||
import android.graphics.Paint; | ||
import android.media.ExifInterface; | ||
import android.net.Uri; | ||
import android.text.TextUtils; | ||
|
||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.io.FileNotFoundException; | ||
import java.io.FileOutputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
||
/** | ||
* Bitmap 压缩相关操作工具类 | ||
* | ||
* | ||
* | ||
* 原理不明白请查看我博客:http://www.cnblogs.com/liushilin/p/6116759.html | ||
* 图片处理工具类 | ||
* | ||
* Author: nanchen | ||
* Email: [email protected] | ||
* Date: 2017-02-13 15:43 | ||
* Date: 2017-03-08 9:03 | ||
*/ | ||
|
||
public class BitmapUtil { | ||
/** | ||
* 计算图片的压缩比率 | ||
* | ||
* @param options 参数 | ||
* @param reqWidth 目标的宽度 | ||
* @param reqHeight 目标的高度 | ||
* @param pathName 路径 | ||
* @return 计算的SampleSize | ||
*/ | ||
private static int calculateInSampleSize(BitmapFactory.Options options,String pathName, int reqWidth, int reqHeight) { | ||
// 源图片的高度和宽度 | ||
int height = options.outHeight; | ||
int width = options.outWidth; | ||
if (height == -1 || width == -1) { | ||
|
||
private BitmapUtil() { | ||
throw new UnsupportedOperationException("u can't instantiate me..."); | ||
} | ||
|
||
static Bitmap getScaledBitmap(Context context, Uri imageUri, float maxWidth, float maxHeight, Bitmap.Config bitmapConfig) { | ||
String filePath = FileUtil.getRealPathFromURI(context, imageUri); | ||
Bitmap scaledBitmap = null; | ||
|
||
BitmapFactory.Options options = new BitmapFactory.Options(); | ||
|
||
//by setting this field as true, the actual bitmap pixels are not loaded in the memory. Just the bounds are loaded. If | ||
//you try the use the bitmap here, you will get null. | ||
options.inJustDecodeBounds = true; | ||
Bitmap bmp = BitmapFactory.decodeFile(filePath, options); | ||
if (bmp == null) { | ||
InputStream inputStream = null; | ||
try { | ||
inputStream = new FileInputStream(filePath); | ||
BitmapFactory.decodeStream(inputStream, null, options); | ||
inputStream.close(); | ||
} catch (FileNotFoundException exception) { | ||
exception.printStackTrace(); | ||
} catch (IOException exception) { | ||
exception.printStackTrace(); | ||
} | ||
} | ||
|
||
int actualHeight = options.outHeight; | ||
int actualWidth = options.outWidth; | ||
|
||
if (actualHeight == -1 || actualWidth == -1){ | ||
try { | ||
ExifInterface exifInterface = new ExifInterface(pathName); | ||
height = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的高度 | ||
width = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的宽度 | ||
ExifInterface exifInterface = new ExifInterface(filePath); | ||
actualHeight = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的高度 | ||
actualWidth = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的宽度 | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
int inSampleSize = 1; | ||
if (height > reqHeight || width > reqWidth) { | ||
final int halfHeight = height / 2; | ||
final int halfWidth = width / 2; | ||
// Calculate the largest inSampleSize value that is a power of 2 and keeps both | ||
// height and width larger than the requested height and width. | ||
while ((halfHeight / inSampleSize) > reqHeight | ||
&& (halfWidth / inSampleSize) > reqWidth) { | ||
inSampleSize *= 2; | ||
|
||
if (actualWidth <= 0 || actualHeight <= 0) { | ||
Bitmap bitmap2 = BitmapFactory.decodeFile(filePath); | ||
if (bitmap2 != null){ | ||
actualWidth = bitmap2.getWidth(); | ||
actualHeight = bitmap2.getHeight(); | ||
}else{ | ||
return null; | ||
} | ||
} | ||
return inSampleSize; | ||
} | ||
|
||
float imgRatio = (float) actualWidth / actualHeight; | ||
float maxRatio = maxWidth / maxHeight; | ||
|
||
/** | ||
* 计算图片的压缩比率 | ||
* | ||
* @param options 参数 | ||
* @param reqWidth 目标的宽度 | ||
* @param reqHeight 目标的高度 | ||
* @return 计算的SampleSize | ||
*/ | ||
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { | ||
// 源图片的高度和宽度 | ||
int height = options.outHeight; | ||
int width = options.outWidth; | ||
int inSampleSize = 1; | ||
if (height > reqHeight || width > reqWidth) { | ||
final int halfHeight = height / 2; | ||
final int halfWidth = width / 2; | ||
// Calculate the largest inSampleSize value that is a power of 2 and keeps both | ||
// height and width larger than the requested height and width. | ||
while ((halfHeight / inSampleSize) > reqHeight | ||
&& (halfWidth / inSampleSize) > reqWidth) { | ||
inSampleSize *= 2; | ||
//width and height values are set maintaining the aspect ratio of the image | ||
if (actualHeight > maxHeight || actualWidth > maxWidth) { | ||
if (imgRatio < maxRatio) { | ||
imgRatio = maxHeight / actualHeight; | ||
actualWidth = (int) (imgRatio * actualWidth); | ||
actualHeight = (int) maxHeight; | ||
} else if (imgRatio > maxRatio) { | ||
imgRatio = maxWidth / actualWidth; | ||
actualHeight = (int) (imgRatio * actualHeight); | ||
actualWidth = (int) maxWidth; | ||
} else { | ||
actualHeight = (int) maxHeight; | ||
actualWidth = (int) maxWidth; | ||
} | ||
} | ||
return inSampleSize; | ||
} | ||
|
||
/** | ||
* 从Resources中加载图片 | ||
* | ||
* @param res Resource | ||
* @param resId 资源id | ||
* @param reqWidth 请求宽度 | ||
* @param reqHeight 请求高度 | ||
* @return Bitmap | ||
*/ | ||
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { | ||
final BitmapFactory.Options options = new BitmapFactory.Options(); | ||
options.inJustDecodeBounds = true; // 设置成了true,不占用内存,只获取bitmap宽高 | ||
BitmapFactory.decodeResource(res, resId, options); // 读取图片长款 | ||
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 调用上面定义的方法计算inSampleSize值 | ||
// 使用获取到的inSampleSize值再次解析图片 | ||
//setting inSampleSize value allows to load a scaled down version of the original image | ||
options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight); | ||
|
||
//inJustDecodeBounds set to false to load the actual bitmap | ||
options.inJustDecodeBounds = false; | ||
Bitmap src = BitmapFactory.decodeResource(res, resId, options); // 载入一个稍大的缩略图 | ||
return createScaleBitmap(src, reqWidth, reqHeight, options.inSampleSize); // 进一步得到目标大小的缩略图 | ||
} | ||
|
||
/** | ||
* 通过传入的bitmap,进行压缩,得到符合标准的bitmap | ||
* | ||
* @param src Bitmap源图 | ||
* @param dstWidth 宽度 | ||
* @param dstHeight 高度 | ||
* @return 新的Bitmap | ||
*/ | ||
private static Bitmap createScaleBitmap(Bitmap src, int dstWidth, int dstHeight, int inSampleSize) { | ||
//如果inSampleSize是2的倍数,也就说这个src已经是我们想要的缩略图了,直接返回即可。 | ||
if (inSampleSize % 2 == 0) { | ||
return src; | ||
//this options allow android to claim the bitmap memory if it runs low on memory | ||
options.inPurgeable = true; | ||
options.inInputShareable = true; | ||
options.inTempStorage = new byte[16 * 1024]; | ||
|
||
try { | ||
// load the bitmap getTempFile its path | ||
bmp = BitmapFactory.decodeFile(filePath, options); | ||
if (bmp == null) { | ||
InputStream inputStream = null; | ||
try { | ||
inputStream = new FileInputStream(filePath); | ||
BitmapFactory.decodeStream(inputStream, null, options); | ||
inputStream.close(); | ||
} catch (IOException exception) { | ||
exception.printStackTrace(); | ||
} | ||
} | ||
} catch (OutOfMemoryError exception) { | ||
exception.printStackTrace(); | ||
} | ||
if (src == null){ | ||
if (actualHeight <= 0 || actualWidth <= 0){ | ||
return null; | ||
} | ||
// 如果是放大图片,filter决定是否平滑,如果是缩小图片,filter无影响,我们这里是缩小图片,所以直接设置为false | ||
Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false); | ||
if (src != dst) { // 如果没有缩放,那么不回收 | ||
src.recycle(); // 释放Bitmap的native像素数组 | ||
|
||
try { | ||
scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, bitmapConfig); | ||
} catch (OutOfMemoryError exception) { | ||
exception.printStackTrace(); | ||
} | ||
return dst; | ||
|
||
float ratioX = actualWidth / (float) options.outWidth; | ||
float ratioY = actualHeight / (float) options.outHeight; | ||
|
||
Matrix scaleMatrix = new Matrix(); | ||
scaleMatrix.setScale(ratioX, ratioY, 0, 0); | ||
|
||
Canvas canvas = new Canvas(scaledBitmap); | ||
canvas.setMatrix(scaleMatrix); | ||
canvas.drawBitmap(bmp, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG)); | ||
|
||
//check the rotation of the image and display it properly | ||
ExifInterface exif; | ||
try { | ||
exif = new ExifInterface(filePath); | ||
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0); | ||
Matrix matrix = new Matrix(); | ||
if (orientation == 6) { | ||
matrix.postRotate(90); | ||
} else if (orientation == 3) { | ||
matrix.postRotate(180); | ||
} else if (orientation == 8) { | ||
matrix.postRotate(270); | ||
} | ||
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, | ||
scaledBitmap.getWidth(), scaledBitmap.getHeight(), | ||
matrix, true); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
|
||
return scaledBitmap; | ||
} | ||
|
||
/** | ||
* 从SD卡上加载图片 | ||
* | ||
* @param pathName 路径 | ||
* @param reqWidth 请求宽度 | ||
* @param reqHeight 请求高度 | ||
* @return Bitmap | ||
*/ | ||
public static Bitmap decodeSampledBitmapFromFile(String pathName, int reqWidth, int reqHeight) { | ||
final BitmapFactory.Options options = new BitmapFactory.Options(); | ||
options.inJustDecodeBounds = true; | ||
BitmapFactory.decodeFile(pathName, options); | ||
options.inSampleSize = calculateInSampleSize(options, pathName,reqWidth, reqHeight); | ||
options.inJustDecodeBounds = false; | ||
Bitmap src = BitmapFactory.decodeFile(pathName, options); | ||
return createScaleBitmap(src, reqWidth, reqHeight, options.inSampleSize); | ||
static File compressImage(Context context, Uri imageUri, float maxWidth, float maxHeight, | ||
Bitmap.CompressFormat compressFormat, Bitmap.Config bitmapConfig, | ||
int quality, String parentPath, String prefix, String fileName) { | ||
FileOutputStream out = null; | ||
String filename = generateFilePath(context, parentPath, imageUri, compressFormat.name().toLowerCase(), prefix, fileName); | ||
try { | ||
out = new FileOutputStream(filename); | ||
//write the compressed bitmap at the destination specified by filename. | ||
BitmapUtil.getScaledBitmap(context, imageUri, maxWidth, maxHeight, bitmapConfig).compress(compressFormat, quality, out); | ||
|
||
} catch (FileNotFoundException e) { | ||
e.printStackTrace(); | ||
} finally { | ||
try { | ||
if (out != null) { | ||
out.close(); | ||
} | ||
} catch (IOException ignored) { | ||
} | ||
} | ||
|
||
return new File(filename); | ||
} | ||
|
||
private static String generateFilePath(Context context, String parentPath, Uri uri, | ||
String extension, String prefix, String fileName) { | ||
File file = new File(parentPath); | ||
if (!file.exists()) { | ||
file.mkdirs(); | ||
} | ||
/** if prefix is null, set prefix "" */ | ||
prefix = TextUtils.isEmpty(prefix) ? "" : prefix; | ||
/** reset fileName by prefix and custom file name */ | ||
fileName = TextUtils.isEmpty(fileName) ? prefix + FileUtil.splitFileName(FileUtil.getFileName(context, uri))[0] : fileName; | ||
return file.getAbsolutePath() + File.separator + fileName + "." + extension; | ||
} | ||
|
||
|
||
/** | ||
* 删除临时图片 | ||
* @param path 图片路径 | ||
* 计算inSampleSize | ||
*/ | ||
public static void deleteTempFile(String path){ | ||
File file = new File(path); | ||
if (file.exists()){ | ||
file.delete(); | ||
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { | ||
final int height = options.outHeight; | ||
final int width = options.outWidth; | ||
int inSampleSize = 1; | ||
|
||
if (height > reqHeight || width > reqWidth) { | ||
final int heightRatio = Math.round((float) height / (float) reqHeight); | ||
final int widthRatio = Math.round((float) width / (float) reqWidth); | ||
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; | ||
} | ||
|
||
final float totalPixels = width * height; | ||
final float totalReqPixelsCap = reqWidth * reqHeight * 2; | ||
|
||
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { | ||
inSampleSize++; | ||
} | ||
|
||
return inSampleSize; | ||
} | ||
} |
Oops, something went wrong.