Browse Source

change detect img function & base64 function

main
MTing 2 weeks ago
parent
commit
e36aac4079
  1. 462
      app/src/main/java/com/ouxuan/oxface/OXFaceOnlineActivity.java
  2. 125
      financelibrary/src/main/java/com/baidu/idl/face/main/finance/utils/BitmapUtils.java

462
app/src/main/java/com/ouxuan/oxface/OXFaceOnlineActivity.java

@ -39,6 +39,8 @@ import com.baidu.idl.main.facesdk.FaceInfo;
import com.baidu.idl.main.facesdk.model.BDFaceImageInstance;
import com.ouxuan.oxface.utils.LogManager;
import java.util.List;
/**
* 简化版人脸识别界面 - 只显示视频流
*/
@ -51,6 +53,27 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
// 图片越大性能消耗越大也可以选择640*480 1280*720
private static final int PREFER_WIDTH = SingleBaseConfig.getBaseConfig().getRgbAndNirWidth();
private static final int PERFER_HEIGH = SingleBaseConfig.getBaseConfig().getRgbAndNirHeight();
// 新增控制变量
private static int PROCESS_FRAME_INTERVAL = 10; // 降低处理频率每隔10帧处理一次
private int frameCounter = 0;
private boolean needSendFaceImage = false; // 是否需要将人脸图片转为base64发送
private long lastProcessTime = 0;
private long lastBackgroundProcessTime = 0; // 应用在后台时的最后处理时间
private static long MIN_PROCESS_INTERVAL = 1000; // 增加最小处理间隔至1秒
// 智能调节处理频率的控制变量
private static final int FAST_PROCESS_FRAME_INTERVAL = 3; // 快速处理频率每3帧处理一次
private static final long FAST_MIN_PROCESS_INTERVAL = 300; // 快速处理间隔300ms
private static final int SLOW_PROCESS_FRAME_INTERVAL = 30; // 慢速处理频率每30帧处理一次
private static final long SLOW_MIN_PROCESS_INTERVAL = 3000; // 慢速处理间隔3000ms
private static final long FACE_DETECTION_TIMEOUT = 5000; // 人脸检测超时时间5秒
private long lastFaceDetectedTime = 0; // 上次检测到人脸的时间
private boolean isFaceDetected = false; // 当前是否检测到人脸
private int consecutiveNoFaceCount = 0; // 连续未检测到人脸的次数
private static final int CONSECUTIVE_NO_FACE_THRESHOLD = 20; // 连续未检测到人脸的阈值
private Context mContext;
private AutoTexturePreviewView mAutoCameraPreviewView;
private TextureView mDrawDetectFaceView;
@ -133,6 +156,11 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
mContext = this;
initView();
// 初始化人脸检测状态
lastFaceDetectedTime = System.currentTimeMillis();
isFaceDetected = false;
consecutiveNoFaceCount = 0;
// 检查并请求相机权限
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
@ -143,6 +171,9 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
LogManager.logInfo(TAG, "相机权限已授予");
}
// 启动内存优化周期性任务
startMemoryOptimizationTask();
LogManager.logInfo(TAG, "OXFaceOnlineActivity onCreate");
}
@ -320,41 +351,164 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
private void startTestOpenDebugRegisterFunction() {
LogManager.logInfo(TAG, "启动摄像头预览");
// 设置摄像头方向
if (SingleBaseConfig.getBaseConfig().getRBGCameraId() != -1){
CameraPreviewManager.getInstance().setCameraFacing(SingleBaseConfig.getBaseConfig().getRBGCameraId());
} else {
CameraPreviewManager.getInstance().setCameraFacing(CameraPreviewManager.CAMERA_FACING_FRONT);
}
CameraPreviewManager.getInstance().startPreview(mContext, mAutoCameraPreviewView,
PREFER_WIDTH, PERFER_HEIGH, new CameraDataCallback() {
@Override
public void onGetCameraData(byte[] data, Camera camera, int width, int height) {
// 摄像头预览数据进行人脸检测
if (isNeedCamera) {
FaceSDKManager.getInstance().onDetectCheck(data, null, null,
height, width, 1, new FaceDetectCallBack() {
@Override
public void onFaceDetectCallback(LivenessModel livenessModel) {
// 开发模式结果输出
checkOpenDebugResult(livenessModel);
try {
// 设置摄像头方向
if (SingleBaseConfig.getBaseConfig().getRBGCameraId() != -1){
CameraPreviewManager.getInstance().setCameraFacing(SingleBaseConfig.getBaseConfig().getRBGCameraId());
} else {
CameraPreviewManager.getInstance().setCameraFacing(CameraPreviewManager.CAMERA_FACING_FRONT);
}
CameraPreviewManager.getInstance().startPreview(mContext, mAutoCameraPreviewView,
PREFER_WIDTH, PERFER_HEIGH, new CameraDataCallback() {
@Override
public void onGetCameraData(byte[] data, Camera camera, int width, int height) {
try {
// 摄像头预览数据进行人脸检测
if (isNeedCamera) {
// 增加帧计数器和时间间隔控制
frameCounter++;
long currentTime = System.currentTimeMillis();
// 智能调节处理频率
adjustProcessFrequency(currentTime);
// 只有当满足处理条件时才进行人脸检测
if (frameCounter % PROCESS_FRAME_INTERVAL == 0 &&
(currentTime - lastProcessTime) > MIN_PROCESS_INTERVAL) {
lastProcessTime = currentTime;
// 检查应用是否处于前台
if (!isApplicationInForeground()) {
// 如果应用在后台减少处理频率每隔10秒处理一次
if ((currentTime - lastBackgroundProcessTime) < 10000) {
return;
}
lastBackgroundProcessTime = currentTime;
}
FaceSDKManager.getInstance().onDetectCheck(data, null, null,
height, width, 1, new FaceDetectCallBack() {
@Override
public void onFaceDetectCallback(LivenessModel livenessModel) {
try {
// 更新人脸检测状态
updateFaceDetectionStatus(livenessModel);
// 开发模式结果输出
checkOpenDebugResult(livenessModel);
} catch (Exception e) {
LogManager.logError(TAG, "人脸检测回调处理异常", e);
}
}
@Override
public void onTip(int code, String msg) {
LogManager.logInfo(TAG, "人脸检测提示 - 代码: " + code + ", 消息: " + msg);
}
@Override
public void onTip(int code, String msg) {
try {
if(!msg.equals("未检测到人脸")){
LogManager.logInfo(TAG, "人脸检测提示onTip - 代码: " + code + ", 消息: " + msg);
}
} catch (Exception e) {
LogManager.logError(TAG, "人脸检测提示处理异常", e);
}
}
@Override
public void onFaceDetectDarwCallback(LivenessModel livenessModel) {
// 绘制人脸框
showFrame(livenessModel);
@Override
public void onFaceDetectDarwCallback(LivenessModel livenessModel) {
try {
// 绘制人脸框
showFrame(livenessModel);
} catch (Exception e) {
LogManager.logError(TAG, "人脸框绘制回调处理异常", e);
}
}
});
} else if (frameCounter % 30 == 0) {
// 对于跳过处理的帧每30帧清空一次画布确保无人脸时画面干净
try {
LivenessModel emptyModel = new LivenessModel();
emptyModel.setTrackFaceInfo(null);
showFrame(emptyModel);
} catch (Exception e) {
LogManager.logError(TAG, "清空画布时发生异常", e);
}
});
}
}
} catch (Exception e) {
LogManager.logError(TAG, "摄像头数据处理异常", e);
}
}
});
} catch (Exception e) {
LogManager.logError(TAG, "启动摄像头预览失败", e);
// 尝试重新初始化摄像头
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (!isFinishing()) {
LogManager.logInfo(TAG, "尝试重新启动摄像头预览");
startTestOpenDebugRegisterFunction();
}
});
}
}, 5000); // 5秒后重试
}
}
/**
* 智能调节处理频率
* @param currentTime 当前时间
*/
private void adjustProcessFrequency(long currentTime) {
// 如果检测到人脸加速处理
if (isFaceDetected) {
if (PROCESS_FRAME_INTERVAL != FAST_PROCESS_FRAME_INTERVAL ||
MIN_PROCESS_INTERVAL != FAST_MIN_PROCESS_INTERVAL) {
PROCESS_FRAME_INTERVAL = FAST_PROCESS_FRAME_INTERVAL;
MIN_PROCESS_INTERVAL = FAST_MIN_PROCESS_INTERVAL;
LogManager.logInfo(TAG, "检测到人脸,加速处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
}
}
// 如果长时间未检测到人脸降低处理频率以节省资源
else if (currentTime - lastFaceDetectedTime > FACE_DETECTION_TIMEOUT) {
// 检查是否已经处于慢速处理模式
if (PROCESS_FRAME_INTERVAL != SLOW_PROCESS_FRAME_INTERVAL ||
MIN_PROCESS_INTERVAL != SLOW_MIN_PROCESS_INTERVAL) {
PROCESS_FRAME_INTERVAL = SLOW_PROCESS_FRAME_INTERVAL;
MIN_PROCESS_INTERVAL = SLOW_MIN_PROCESS_INTERVAL;
LogManager.logInfo(TAG, "长时间未检测到人脸,降低处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
}
}
}
/**
* 更新人脸检测状态
* @param livenessModel 活体检测模型
*/
private void updateFaceDetectionStatus(LivenessModel livenessModel) {
long currentTime = System.currentTimeMillis();
// 检查是否检测到人脸
boolean faceDetected = (livenessModel != null &&
livenessModel.getTrackFaceInfo() != null &&
livenessModel.getTrackFaceInfo().length > 0);
if (faceDetected) {
// 检测到人脸
isFaceDetected = true;
lastFaceDetectedTime = currentTime;
consecutiveNoFaceCount = 0; // 重置连续未检测到人脸计数器
LogManager.logDebug(TAG, "检测到人脸");
} else {
// 未检测到人脸
consecutiveNoFaceCount++;
// 如果连续多次未检测到人脸标记为未检测到人脸状态
if (consecutiveNoFaceCount >= CONSECUTIVE_NO_FACE_THRESHOLD) {
isFaceDetected = false;
LogManager.logDebug(TAG, "连续未检测到人脸,当前计数: " + consecutiveNoFaceCount);
}
}
}
/**
@ -366,26 +520,35 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
public void run() {
Canvas canvas = mDrawDetectFaceView.lockCanvas();
if (canvas == null) {
mDrawDetectFaceView.unlockCanvasAndPost(canvas);
return;
}
// 始终清空canvas
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// 如果没有模型数据直接返回清空的画布
if (model == null) {
// 清空canvas
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
mDrawDetectFaceView.unlockCanvasAndPost(canvas);
return;
}
// 获取人脸信息
FaceInfo[] faceInfos = model.getTrackFaceInfo();
// 如果没有检测到人脸直接返回清空的画布
if (faceInfos == null || faceInfos.length == 0) {
// 清空canvas
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
mDrawDetectFaceView.unlockCanvasAndPost(canvas);
return;
}
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (int i = 0 ; i < faceInfos.length;i++) {
// 只在检测到人脸时绘制人脸框
for (int i = 0; i < faceInfos.length; i++) {
FaceInfo faceInfo = faceInfos[i];
// 如果人脸置信度太低不绘制
if (faceInfo.score < 0.6) {
continue;
}
rectF.set(FaceOnDrawTexturViewUtil.getFaceRectTwo(faceInfo));
// 检测图片的坐标和显示的坐标不一样需要转换
@ -397,7 +560,8 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
FaceOnDrawTexturViewUtil.drawRect(canvas,
rectF, paint, 5f, 50f, 25f);
}
// 清空canvas
// 提交canvas
mDrawDetectFaceView.unlockCanvasAndPost(canvas);
}
});
@ -649,7 +813,61 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
@Override
protected void onDestroy() {
super.onDestroy();
LogManager.logInfo(TAG, "OXFaceOnlineActivity onDestroy");
// 停止摄像头预览
if (CameraPreviewManager.getInstance() != null) {
CameraPreviewManager.getInstance().stopPreview();
}
// 释放当前的LivenessModel资源
if (currentLivenessModel != null) {
BDFaceImageInstance image = currentLivenessModel.getBdFaceImageInstance();
if (image != null) {
image.destory();
}
// 清空引用
currentLivenessModel = null;
}
// 释放绘图资源
if (rectF != null) {
rectF = null;
}
if (paint != null) {
paint = null;
}
if (paintBg != null) {
paintBg = null;
}
// 清除其他相关资源
System.gc();
LogManager.logInfo(TAG, "OXFaceOnlineActivity onDestroy - 资源已释放");
}
@Override
protected void onStop() {
super.onStop();
LogManager.logInfo(TAG, "OXFaceOnlineActivity onStop - 应用进入后台");
// 应用进入后台时进一步降低处理频率以节省资源
PROCESS_FRAME_INTERVAL = 30; // 后台时每30帧处理一次
MIN_PROCESS_INTERVAL = 3000; // 后台时最小间隔3秒
LogManager.logInfo(TAG, "后台模式处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
}
@Override
protected void onStart() {
super.onStart();
LogManager.logInfo(TAG, "OXFaceOnlineActivity onStart - 应用回到前台");
// 应用回到前台时恢复正常的处理频率
PROCESS_FRAME_INTERVAL = FAST_PROCESS_FRAME_INTERVAL; // 前台时使用快速处理频率
MIN_PROCESS_INTERVAL = FAST_MIN_PROCESS_INTERVAL; // 前台时使用快速处理间隔
LogManager.logInfo(TAG, "前台模式处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
}
// ***************开发模式结果输出*************
@ -743,16 +961,27 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
if (livenessModel == null) {
return;
}
String base64img = getFaceImageBase64(currentLivenessModel);
if (base64img != null) {
// Log.i(TAG, "checkResultOnline: " + base64img);
Log.i(TAG, "checkResultOnline: Yes! Got a base64img!" );
} else {
Log.i(TAG, "run:checkResultOnline base64img score too low ");
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#fec133"));
textCompareStatus.setText("请重新识别");
// 减少base64转换频率只有在特定条件下才进行转换
// 例如每3秒检查一次是否需要发送人脸图像
long currentTime = System.currentTimeMillis();
if (currentTime - searshTime > 3000) {
searshTime = currentTime;
needSendFaceImage = true;
String base64img = getFaceImageBase64(currentLivenessModel);
if (base64img != null) {
// 这里可以处理base64数据如上传到服务器等
Log.i(TAG, "checkResultOnline: 获取到人脸base64数据");
// 处理完成后重置标志
needSendFaceImage = false;
} else {
Log.i(TAG, "run:checkResultOnline base64img score too low ");
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#fec133"));
textCompareStatus.setText("请重新识别");
}
}
}
});
@ -762,15 +991,134 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
if (livenessModel == null) return null;
FaceInfo faceInfo = livenessModel.getFaceInfo();
if (true) { //判定条件
// 添加判断条件减少不必要的base64转换
if (faceInfo != null && faceInfo.bestImageScore > SingleBaseConfig.getBaseConfig().getBestImageScore()) {
BDFaceImageInstance image = livenessModel.getBdFaceImageInstance();
Bitmap bitmap = BitmapUtils.getInstaceBmp(image);
String bitmap_str = BitmapUtils.bitmapToBase64(bitmap);
image.destory();
return bitmap_str; // 简化实现实际项目中需要实现 bitmap base64 的功能
} else {
return null;
if (image != null) {
Bitmap bitmap = BitmapUtils.getInstaceBmp(image);
// 仅在确实需要使用base64数据时才进行转换
if (needSendFaceImage) {
String bitmap_str = BitmapUtils.bitmapToBase64(bitmap);
image.destory();
return bitmap_str;
} else {
// 如果不需要发送则不进行base64转换直接释放资源
image.destory();
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
return "dummy_base64_placeholder";
}
}
}
return null;
}
/**
* 检查应用是否在前台
* @return 如果应用在前台则返回true否则返回false
*/
private boolean isApplicationInForeground() {
android.app.ActivityManager activityManager = (android.app.ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<android.app.ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
String packageName = getPackageName();
for (android.app.ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
&& appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
/**
* 低内存时的处理
*/
@Override
public void onLowMemory() {
super.onLowMemory();
LogManager.logInfo(TAG, "系统内存不足,触发onLowMemory");
// 清理不必要的缓存
clearMemoryCache();
// 强制GC
System.gc();
}
/**
* 清理内存缓存
*/
private void clearMemoryCache() {
// 如果当前不在人脸检测状态释放当前的LivenessModel
if (currentLivenessModel != null && !isNeedCamera) {
BDFaceImageInstance image = currentLivenessModel.getBdFaceImageInstance();
if (image != null) {
image.destory();
}
currentLivenessModel = null;
}
// 如果设备内存不足考虑调整处理频率
PROCESS_FRAME_INTERVAL = Math.min(30, PROCESS_FRAME_INTERVAL + 5);
MIN_PROCESS_INTERVAL = Math.min(3000, MIN_PROCESS_INTERVAL + 500);
LogManager.logInfo(TAG, "内存不足,调整处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
}
/**
* 优化内存的周期性任务
*/
private void startMemoryOptimizationTask() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// 获取当前应用内存使用情况
Runtime runtime = Runtime.getRuntime();
long usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024);
long totalMemory = runtime.maxMemory() / (1024 * 1024);
float memoryUsageRatio = (float) usedMemory / totalMemory;
LogManager.logInfo(TAG, "内存使用情况:" + usedMemory + "MB/" + totalMemory +
"MB,使用率:" + (int)(memoryUsageRatio * 100) + "%");
// 如果内存使用率超过70%主动清理内存
if (memoryUsageRatio > 0.7f) {
LogManager.logInfo(TAG, "内存使用率超过70%,主动清理内存");
clearMemoryCache();
System.gc();
}
// 如果内存使用率超过85%进行更积极的清理
if (memoryUsageRatio > 0.85f) {
LogManager.logWarning(TAG, "内存使用率超过85%,进行积极清理");
// 进一步降低处理频率
PROCESS_FRAME_INTERVAL = Math.min(50, PROCESS_FRAME_INTERVAL + 10);
MIN_PROCESS_INTERVAL = Math.min(5000, MIN_PROCESS_INTERVAL + 1000);
// 清理更多资源
if (currentLivenessModel != null) {
BDFaceImageInstance image = currentLivenessModel.getBdFaceImageInstance();
if (image != null) {
image.destory();
}
currentLivenessModel = null;
}
LogManager.logInfo(TAG, "积极清理后调整处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
System.gc();
}
// 每30秒执行一次
if (!isFinishing()) {
new Handler().postDelayed(this, 30000);
}
}
}, 30000);
}
}

125
financelibrary/src/main/java/com/baidu/idl/face/main/finance/utils/BitmapUtils.java

@ -529,13 +529,126 @@ public final class BitmapUtils {
* @return Base64编码的字符串
*/
public static String bitmapToBase64(Bitmap bm) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 30, baos);
byte[] byteArray = baos.toByteArray();
// 检查传入的位图是否有效
if (bm == null || bm.isRecycled()) {
Log.e(TAG, "尝试转换无效的Bitmap到Base64");
return null;
}
// 减小图像尺寸以降低内存占用
Bitmap scaledBitmap = null;
try {
// 判断是否需要缩放图片
int originalWidth = bm.getWidth();
int originalHeight = bm.getHeight();
int targetWidth = 320; // 设置合理的目标宽度
// 如果原图已经很小直接使用更小的尺寸
if (originalWidth <= 160) {
targetWidth = originalWidth;
} else if (originalWidth <= 320) {
targetWidth = 160;
}
if (originalWidth > targetWidth) {
float scaleFactor = (float) targetWidth / originalWidth;
int targetHeight = (int) (originalHeight * scaleFactor);
scaledBitmap = Bitmap.createScaledBitmap(bm, targetWidth, targetHeight, true);
} else {
// 原图尺寸已经足够小直接使用
scaledBitmap = bm;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 使用更低的压缩质量(20%)进一步减小数据体积
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 20, baos);
byte[] byteArray = baos.toByteArray();
try {
baos.close();
} catch (IOException e) {
Log.e(TAG, "关闭ByteArrayOutputStream失败: " + e.getMessage());
}
// 使用Base64进行编码
String encodedString = Base64.encodeToString(byteArray, Base64.DEFAULT);
// 使用NO_WRAP标志避免插入换行符节省内存
String encodedString = Base64.encodeToString(byteArray, Base64.NO_WRAP);
// 立即释放字节数组
byteArray = null;
// 如果创建了新的缩放位图则释放它
if (scaledBitmap != bm && scaledBitmap != null && !scaledBitmap.isRecycled()) {
scaledBitmap.recycle();
}
return encodedString;
} catch (OutOfMemoryError e) {
Log.e(TAG, "Bitmap转Base64时内存溢出: " + e.getMessage());
// 确保资源被释放
if (scaledBitmap != null && scaledBitmap != bm && !scaledBitmap.isRecycled()) {
scaledBitmap.recycle();
}
// 尝试更激进的压缩
return bitmapToBase64Aggressive(bm);
} catch (Exception e) {
Log.e(TAG, "Bitmap转Base64时发生错误: " + e.getMessage());
// 确保资源被释放
if (scaledBitmap != null && scaledBitmap != bm && !scaledBitmap.isRecycled()) {
scaledBitmap.recycle();
}
return null;
}
}
/**
* 更激进的Bitmap转Base64方法用于内存不足时的备选方案
* @param bm 要转换的Bitmap
* @return Base64编码的字符串
*/
private static String bitmapToBase64Aggressive(Bitmap bm) {
if (bm == null || bm.isRecycled()) {
return null;
}
try {
// 使用更小的尺寸和更低的质量
int originalWidth = bm.getWidth();
int originalHeight = bm.getHeight();
int targetWidth = 160; // 更小的目标宽度
Bitmap scaledBitmap;
if (originalWidth > targetWidth) {
float scaleFactor = (float) targetWidth / originalWidth;
int targetHeight = (int) (originalHeight * scaleFactor);
scaledBitmap = Bitmap.createScaledBitmap(bm, targetWidth, targetHeight, true);
} else {
scaledBitmap = bm;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 使用最低的压缩质量(10%)
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 10, baos);
byte[] byteArray = baos.toByteArray();
try {
baos.close();
} catch (IOException e) {
Log.e(TAG, "关闭ByteArrayOutputStream失败: " + e.getMessage());
}
return encodedString;
String encodedString = Base64.encodeToString(byteArray, Base64.NO_WRAP);
// 立即释放资源
byteArray = null;
if (scaledBitmap != bm && scaledBitmap != null && !scaledBitmap.isRecycled()) {
scaledBitmap.recycle();
}
return encodedString;
} catch (Exception e) {
Log.e(TAG, "激进压缩Bitmap转Base64时发生错误: " + e.getMessage());
return null;
}
}
}
Loading…
Cancel
Save