From 19e6e276bde9f872fad12998a781e2ebf603b13a Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Thu, 4 Dec 2025 13:42:30 +0800 Subject: [PATCH] 20251204_134218_045 --- powerbell/build.properties | 4 +- .../BackgroundSettingsActivity.java | 159 +++++++++---- .../utils/BackgroundSourceUtils.java | 20 +- .../studio/powerbell/utils/FileUtils.java | 18 +- .../powerbell/utils/ImageCropUtils.java | 218 ++++++++---------- 5 files changed, 240 insertions(+), 179 deletions(-) diff --git a/powerbell/build.properties b/powerbell/build.properties index 9b296b37..bbd31512 100644 --- a/powerbell/build.properties +++ b/powerbell/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Wed Dec 03 22:57:30 GMT 2025 +#Thu Dec 04 05:39:23 GMT 2025 stageCount=13 libraryProject= baseVersion=15.11 publishVersion=15.11.12 -buildCount=195 +buildCount=205 baseBetaVersion=15.11.13 diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/activities/BackgroundSettingsActivity.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/activities/BackgroundSettingsActivity.java index 6ec882c7..f626498e 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/activities/BackgroundSettingsActivity.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/activities/BackgroundSettingsActivity.java @@ -6,7 +6,6 @@ import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; -import android.graphics.Matrix; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -14,10 +13,10 @@ import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.provider.MediaStore; -import android.util.Log; import android.view.View; import android.widget.Toast; import androidx.appcompat.app.AlertDialog; +import androidx.core.content.FileProvider; import cc.winboll.studio.libaes.views.AToolbar; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.ToastUtils; @@ -236,9 +235,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg public void onClick(View v) { LogUtils.d(TAG, "【按钮点击】固定比例裁剪"); // 调用裁剪工具类:传入上下文、预览图、固定比例(按视图宽高)、请求码 - ImageCropUtils.startSystemCrop( - BackgroundSettingsActivity.this, - new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath()), + startSystemCrop( + mBgSourceUtils.getPreviewBackgroundBean(), mBackgroundView.getWidth(), mBackgroundView.getHeight(), false, @@ -252,9 +250,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg public void onClick(View v) { LogUtils.d(TAG, "【按钮点击】自由裁剪"); // 调用裁剪工具类:传入上下文、预览图、自由裁剪(比例参数传0)、请求码 - ImageCropUtils.startSystemCrop( - BackgroundSettingsActivity.this, - new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath()), + startSystemCrop( + mBgSourceUtils.getPreviewBackgroundBean(), 0, 0, true, @@ -288,7 +285,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg LogUtils.d(TAG, "【拍照权限】已获取"); Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); try { - Uri photoUri = ImageCropUtils.getFileProviderUri(BackgroundSettingsActivity.this, mfTakePhoto); + Uri photoUri = getFileProviderUri(mfTakePhoto); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); LogUtils.d(TAG, "【拍照启动】Uri:" + photoUri.toString()); @@ -412,9 +409,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg doubleRefreshPreview(); // 拍照后启动固定比例裁剪(调用工具类) - ImageCropUtils.startSystemCrop( - this, - mfTakePhoto, + startSystemCrop( + mBgSourceUtils.getPreviewBackgroundBean(), mBackgroundView.getWidth(), mBackgroundView.getHeight(), false, @@ -460,7 +456,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg } private void handleCropImageResult(int requestCode, int resultCode, Intent data) { - Log.d(TAG, "handleCropImageResult: 处理裁剪结果"); + LogUtils.d(TAG, "handleCropImageResult: 处理裁剪结果"); File cropTempFile = new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundScaledCompressFilePath()); boolean isFileExist = cropTempFile.exists(); boolean isFileReadable = isFileExist ? cropTempFile.canRead() : false; @@ -468,7 +464,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg boolean isCropSuccess = (resultCode == RESULT_OK) && isFileExist && isFileReadable && fileSize > 100; if (isCropSuccess) { - Log.d(TAG, "handleCropImageResult: 裁剪成功"); + LogUtils.d(TAG, "handleCropImageResult: 裁剪成功"); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); previewBean.setIsUseBackgroundFile(true); previewBean.setIsUseBackgroundScaledCompressFile(true); @@ -495,7 +491,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg public void run() { if (mBackgroundView != null && !isFinishing()) { mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean()); - Log.d(TAG, "handleCropImageResult: 裁剪图片加载完成"); + LogUtils.d(TAG, "handleCropImageResult: 裁剪图片加载完成"); } } }, 50); @@ -505,9 +501,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg } private float getRatioFromSystemCropFile(File systemCropFile) { - Log.d(TAG, "getRatioFromSystemCropFile: 读取比例"); + LogUtils.d(TAG, "getRatioFromSystemCropFile: 读取比例"); if (systemCropFile == null || !systemCropFile.exists() || !systemCropFile.isFile()) { - Log.e(TAG, "getRatioFromSystemCropFile: 文件无效"); + LogUtils.e(TAG, "getRatioFromSystemCropFile: 文件无效"); return -1; } @@ -518,19 +514,19 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg int cropWidth = options.outWidth; int cropHeight = options.outHeight; if (cropWidth <= 0 || cropHeight <= 0) { - Log.e(TAG, "getRatioFromSystemCropFile: 尺寸无效"); + LogUtils.e(TAG, "getRatioFromSystemCropFile: 尺寸无效"); return -1; } float systemRatio = (float) cropWidth / cropHeight; - Log.d(TAG, "getRatioFromSystemCropFile: 比例:" + systemRatio); + LogUtils.d(TAG, "getRatioFromSystemCropFile: 比例:" + systemRatio); return systemRatio; } private Bitmap adjustBitmapToFinalRatio(Bitmap originalBitmap, float finalCropRatio) { - Log.d(TAG, "adjustBitmapToFinalRatio: 调整比例"); + LogUtils.d(TAG, "adjustBitmapToFinalRatio: 调整比例"); if (originalBitmap == null || originalBitmap.isRecycled() || finalCropRatio <= 0) { - Log.e(TAG, "adjustBitmapToFinalRatio: 参数无效"); + LogUtils.e(TAG, "adjustBitmapToFinalRatio: 参数无效"); return originalBitmap; } @@ -539,7 +535,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg float originalRatio = (float) originalWidth / originalHeight; if (Math.abs(originalRatio - finalCropRatio) < 0.001f) { - Log.d(TAG, "adjustBitmapToFinalRatio: 比例一致"); + LogUtils.d(TAG, "adjustBitmapToFinalRatio: 比例一致"); return originalBitmap; } @@ -552,7 +548,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg } targetWidth = Math.round(targetHeight * finalCropRatio); - Log.d(TAG, "adjustBitmapToFinalRatio: 调整前:" + originalWidth + "x" + originalHeight + ",调整后:" + targetWidth + "x" + targetHeight); + LogUtils.d(TAG, "adjustBitmapToFinalRatio: 调整前:" + originalWidth + "x" + originalHeight + ",调整后:" + targetWidth + "x" + targetHeight); Bitmap adjustedBitmap = Bitmap.createBitmap( originalBitmap, @@ -566,15 +562,15 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg } private void saveScaledBitmapToFile(Bitmap bitmap, File targetFile) { - Log.d(TAG, "saveScaledBitmapToFile: 保存图片"); + LogUtils.d(TAG, "saveScaledBitmapToFile: 保存图片"); if (bitmap == null || bitmap.isRecycled() || targetFile == null) { - Log.e(TAG, "saveScaledBitmapToFile: 参数无效"); + LogUtils.e(TAG, "saveScaledBitmapToFile: 参数无效"); return; } if (targetFile.exists()) { boolean deleteSuccess = targetFile.delete(); - Log.d(TAG, "saveScaledBitmapToFile: 删除原文件:" + (deleteSuccess ? "成功" : "失败")); + LogUtils.d(TAG, "saveScaledBitmapToFile: 删除原文件:" + (deleteSuccess ? "成功" : "失败")); } OutputStream outputStream = null; @@ -582,24 +578,24 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg outputStream = new BufferedOutputStream(new FileOutputStream(targetFile)); bitmap.compress(CompressFormat.JPEG, 100, outputStream); outputStream.flush(); - Log.d(TAG, "saveScaledBitmapToFile: 保存成功"); + LogUtils.d(TAG, "saveScaledBitmapToFile: 保存成功"); } catch (IOException e) { - Log.e(TAG, "saveScaledBitmapToFile: 异常:" + e.getMessage()); + LogUtils.e(TAG, "saveScaledBitmapToFile: 异常:" + e.getMessage()); } finally { if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { - Log.e(TAG, "saveScaledBitmapToFile: 关闭流异常"); + LogUtils.e(TAG, "saveScaledBitmapToFile: 关闭流异常"); } } } } private Bitmap parseCropTempFileToBitmap(File cropTempFile) { - Log.d(TAG, "parseCropTempFileToBitmap: 解析文件"); + LogUtils.d(TAG, "parseCropTempFileToBitmap: 解析文件"); if (cropTempFile == null || !cropTempFile.exists() || !cropTempFile.isFile() || cropTempFile.length() <= 100) { - Log.e(TAG, "parseCropTempFileToBitmap: 文件无效"); + LogUtils.e(TAG, "parseCropTempFileToBitmap: 文件无效"); return null; } @@ -613,7 +609,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg sampleSize *= 2; } sampleSize = Math.min(sampleSize, 16); - Log.d(TAG, "parseCropTempFileToBitmap: 采样率:" + sampleSize); + LogUtils.d(TAG, "parseCropTempFileToBitmap: 采样率:" + sampleSize); options.inJustDecodeBounds = false; options.inSampleSize = sampleSize; @@ -625,16 +621,16 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg try { cropBitmap = BitmapFactory.decodeFile(cropTempFile.getAbsolutePath(), options); if (cropBitmap == null || cropBitmap.isRecycled()) { - Log.e(TAG, "parseCropTempFileToBitmap: 解析失败"); + LogUtils.e(TAG, "parseCropTempFileToBitmap: 解析失败"); return null; } - Log.d(TAG, "parseCropTempFileToBitmap: 解析成功"); + LogUtils.d(TAG, "parseCropTempFileToBitmap: 解析成功"); } catch (OutOfMemoryError e) { - Log.e(TAG, "parseCropTempFileToBitmap: OOM"); + LogUtils.e(TAG, "parseCropTempFileToBitmap: OOM"); Toast.makeText(this, "图片解析失败", Toast.LENGTH_SHORT).show(); return null; } catch (Exception e) { - Log.e(TAG, "parseCropTempFileToBitmap: 异常:" + e.getMessage()); + LogUtils.e(TAG, "parseCropTempFileToBitmap: 异常:" + e.getMessage()); return null; } @@ -683,14 +679,12 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg LogUtils.d(TAG, "【选图权限】已添加持久化权限"); } - mBgSourceUtils.createCropFileProviderPath(selectedImage); - String targetCompressPath = mBgSourceUtils.getPreviewBackgroundBean().getBackgroundScaledCompressFilePath(); - + BackgroundBean cropBean = mBgSourceUtils.createCropFileProviderBackgroundBean(selectedImage); + LogUtils.d(TAG, "【选图同步】路径绑定完成"); // 选图后启动固定比例裁剪(调用工具类) - ImageCropUtils.startSystemCrop( - this, - new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath()), + startSystemCrop( + cropBean, mBackgroundView.getWidth(), mBackgroundView.getHeight(), false, @@ -703,6 +697,87 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg LogUtils.d(TAG, "【操作回调】取消或失败"); ToastUtils.show("操作已取消"); } + + + /** + * 启动系统裁剪工具 + * @param activity 上下文 + * @param srcFile 裁剪原图 + * @param aspectX 裁剪宽比例(自由裁剪传0) + * @param aspectY 裁剪高比例(自由裁剪传0) + * @param isFreeCrop 是否自由裁剪 + * @param requestCode 裁剪请求码 + */ + public void startSystemCrop(BackgroundBean cropBean, int aspectX, int aspectY, boolean isFreeCrop, int requestCode) { + + LogUtils.d(TAG, "startSystemCrop: 启动系统裁剪,自由裁剪:" + isFreeCrop); + File srcFile = new File(cropBean.getBackgroundFilePath()); + + // 校验原图 + if (srcFile == null || !srcFile.exists() || srcFile.length() <= 100) { + Toast.makeText(this, "无有效图片可裁剪", Toast.LENGTH_SHORT).show(); + LogUtils.e(TAG, "startSystemCrop: 原图无效"); + return; + } + + // 生成输入Uri + Uri inputUri = getFileProviderUri(srcFile); + if (inputUri == null) { + Toast.makeText(this, "获取图片Uri失败", Toast.LENGTH_SHORT).show(); + LogUtils.e(TAG, "startSystemCrop: 输入Uri生成失败"); + return; + } + + // 生成输出文件(使用BackgroundSourceUtils的压缩路径) + BackgroundSourceUtils bgSourceUtils = BackgroundSourceUtils.getInstance(this); + File outputFile = new File(bgSourceUtils.getPreviewBackgroundBean().getBackgroundScaledCompressFilePath()); + if (outputFile == null) { + Toast.makeText(this, "裁剪输出路径无效", Toast.LENGTH_SHORT).show(); + LogUtils.e(TAG, "startSystemCrop: 输出文件为空"); + return; + } + Uri outputUri = getFileProviderUri(outputFile); + + + Uri cropOutPutUri = outputUri; + + Intent intent = new Intent("com.android.camera.action.CROP"); + intent.setDataAndType(inputUri, "image/*"); + //intent.setDataAndType(inputUri, activity.getContentResolver().getType(inputUri)); + intent.putExtra("crop", "true"); + intent.putExtra("noFaceDetection", true); + + if (!isFreeCrop) { + intent.putExtra("aspectX", aspectX); + intent.putExtra("aspectY", aspectY); + } + + intent.putExtra("return-data", true); + intent.putExtra(MediaStore.EXTRA_OUTPUT, cropOutPutUri); + intent.putExtra("scale", true); + intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + startActivityForResult(intent, requestCode); + LogUtils.d(TAG, "startSystemCrop: 启动裁剪成功,输出路径:" + outputFile.getAbsolutePath()); + } + + /** + * 获取FileProvider Uri(复用方法,避免重复代码) + */ + public Uri getFileProviderUri(File file) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + String FILE_PROVIDER_AUTHORITY = getPackageName() + ".fileprovider"; + + return FileProvider.getUriForFile(this, FILE_PROVIDER_AUTHORITY, file); + } else { + return Uri.fromFile(file); + } + } catch (Exception e) { + LogUtils.e(TAG, "getFileProviderUri: 生成Uri失败:" + e.getMessage()); + return null; + } + } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/BackgroundSourceUtils.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/BackgroundSourceUtils.java index aa1b0868..5979571b 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/BackgroundSourceUtils.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/BackgroundSourceUtils.java @@ -245,23 +245,15 @@ public class BackgroundSourceUtils { return contentUri; } - public boolean createCropFileProviderPath(Uri uri) { + public BackgroundBean createCropFileProviderBackgroundBean(Uri uri) { InputStream is = null; FileOutputStream fos = null; try { clearCropTempFiles(); - String szType = mContext.getContentResolver().getType(uri); + //String szType = mContext.getContentResolver().getType(uri); // 2. 截取MIME类型后缀(如从image/jpeg中提取jpeg)【核心新增逻辑】 - String fileSuffix = ""; - if (szType != null && szType.contains("/")) { - // 分割字符串,取"/"后面的部分(如"image/jpeg" → 分割后取索引1的"jpeg") - fileSuffix = szType.split("/")[1]; - // 调试日志:打印截取后的文件后缀 - } else { - // 异常处理:若类型为空或格式错误,默认后缀设为jpeg(保留原逻辑兼容性) - fileSuffix = "jpeg"; - } + String fileSuffix = FileUtils.getFileSuffix(mContext, uri); String newCropFileName = UUID.randomUUID().toString() + System.currentTimeMillis(); mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix); mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix); @@ -273,7 +265,7 @@ public class BackgroundSourceUtils { is = mContext.getContentResolver().openInputStream(uri); if (is == null) { LogUtils.e(TAG, "【选图解析】ContentResolver打开Uri失败,Uri:" + uri.toString()); - return false; + return null; } // 2. 初始化选图临时文件输出流(Java7 手动创建流,不依赖try-with-resources) @@ -310,14 +302,14 @@ public class BackgroundSourceUtils { LogUtils.d(TAG, "→ 目标临时文件大小:" + mCropSourceFile.length() + " bytes"); LogUtils.d(TAG, "→ 目标剪裁临时文件:" + mCropResultFile.getAbsolutePath()); LogUtils.d(TAG, "→ 目标剪裁临时文件大小:" + mCropResultFile.length() + " bytes"); - return true; + return previewBackgroundBean; } catch (Exception e) { // 捕获所有异常(IO异常/空指针等),避免崩溃 LogUtils.e(TAG, "【选图解析】流复制异常:" + e.getMessage(), e); // 异常时清理无效文件,防止残留 clearCropTempFiles(); - return false; + return null; } finally { // 7. 手动关闭流资源(Java7 标准写法,避免内存泄漏) diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/FileUtils.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/FileUtils.java index 0aad1cee..ed832d0a 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/FileUtils.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/FileUtils.java @@ -11,6 +11,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.UUID; +import android.content.Context; +import android.net.Uri; /** * 文件操作工具类 @@ -260,6 +262,20 @@ public class FileUtils { } } } - + + public static String getFileSuffix(Context context, Uri uri){ + String szType = context.getContentResolver().getType(uri); + // 2. 截取MIME类型后缀(如从image/jpeg中提取jpeg)【核心新增逻辑】 + String fileSuffix = ""; + if (szType != null && szType.contains("/")) { + // 分割字符串,取"/"后面的部分(如"image/jpeg" → 分割后取索引1的"jpeg") + fileSuffix = szType.split("/")[1]; + // 调试日志:打印截取后的文件后缀 + } else { + // 异常处理:若类型为空或格式错误,默认后缀设为jpeg(保留原逻辑兼容性) + fileSuffix = "jpeg"; + } + return fileSuffix; + } } diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/ImageCropUtils.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/ImageCropUtils.java index c56dfa2d..1f28a8c9 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/ImageCropUtils.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/ImageCropUtils.java @@ -12,9 +12,14 @@ import android.provider.MediaStore; import android.util.Log; import android.widget.Toast; import androidx.core.content.FileProvider; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.ToastUtils; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; import java.util.List; -import cc.winboll.studio.powerbell.App; +import cc.winboll.studio.powerbell.model.BackgroundBean; /** * @Author ZhanGSKen&豆包大模型 @@ -22,127 +27,100 @@ import cc.winboll.studio.powerbell.App; * @Describe 图片裁剪工具类(仅调用系统裁剪,传入比例/自由裁剪参数) */ public class ImageCropUtils { - private static final String TAG = "ImageCropUtils"; + public static final String TAG = "ImageCropUtils"; // FileProvider授权(与清单文件一致) - /** - * 启动系统裁剪工具 - * @param activity 上下文 - * @param srcFile 裁剪原图 - * @param aspectX 裁剪宽比例(自由裁剪传0) - * @param aspectY 裁剪高比例(自由裁剪传0) - * @param isFreeCrop 是否自由裁剪 - * @param requestCode 裁剪请求码 - */ - public static void startSystemCrop(Activity activity, File srcFile, int aspectX, int aspectY, boolean isFreeCrop, int requestCode) { - - Log.d(TAG, "startSystemCrop: 启动系统裁剪,自由裁剪:" + isFreeCrop); - // 校验原图 - if (srcFile == null || !srcFile.exists() || srcFile.length() <= 100) { - Toast.makeText(activity, "无有效图片可裁剪", Toast.LENGTH_SHORT).show(); - Log.e(TAG, "startSystemCrop: 原图无效"); - return; - } + + - // 生成输入Uri - Uri inputUri = getFileProviderUri(activity, srcFile); - if (inputUri == null) { - Toast.makeText(activity, "获取图片Uri失败", Toast.LENGTH_SHORT).show(); - Log.e(TAG, "startSystemCrop: 输入Uri生成失败"); - return; - } - - // 生成输出文件(使用BackgroundSourceUtils的压缩路径) - BackgroundSourceUtils bgSourceUtils = BackgroundSourceUtils.getInstance(activity); - File outputFile = new File(bgSourceUtils.getPreviewBackgroundBean().getBackgroundScaledCompressFilePath()); - if (outputFile == null) { - Toast.makeText(activity, "裁剪输出路径无效", Toast.LENGTH_SHORT).show(); - Log.e(TAG, "startSystemCrop: 输出文件为空"); - return; - } - Uri outputUri = getFileProviderUri(activity, outputFile); - - // 构建裁剪意图 - Intent intent = new Intent("com.android.camera.action.CROP"); - intent.setDataAndType(inputUri, "image/*"); - intent.putExtra("crop", "true"); - intent.putExtra("noFaceDetection", true); - - // 设置裁剪比例(自由裁剪则不设置) - if (!isFreeCrop && aspectX > 0 && aspectY > 0) { - intent.putExtra("aspectX", aspectX); - intent.putExtra("aspectY", aspectY); - Log.d(TAG, "startSystemCrop: 裁剪比例:" + aspectX + ":" + aspectY); - } - - // 输出配置 - intent.putExtra("outputX", 2048); - intent.putExtra("outputY", 2048); - intent.putExtra("scale", true); - intent.putExtra("scaleUpIfNeeded", true); - intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); - intent.putExtra("quality", 100); - intent.putExtra("return-data", false); - intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri); - - // 权限设置 - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); - } - - // 适配系统裁剪工具 - try { - List resolveInfos = activity.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); - if (!resolveInfos.isEmpty()) { - ResolveInfo resolveInfo = resolveInfos.get(0); - String cropPackageName = resolveInfo.activityInfo.packageName; - String cropActivityName = resolveInfo.activityInfo.name; - - // 授予MIUI裁剪权限 - if (cropPackageName.equals("com.miui.gallery")) { - activity.grantUriPermission(cropPackageName, inputUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - activity.grantUriPermission(cropPackageName, outputUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - } - - // 显式启动裁剪 - Intent cropIntent = new Intent(intent); - cropIntent.setComponent(new ComponentName(cropPackageName, cropActivityName)); - activity.startActivityForResult(cropIntent, requestCode); - Log.d(TAG, "startSystemCrop: 启动裁剪成功,输出路径:" + outputFile.getAbsolutePath()); - } else { - // 兜底启动 - Intent chooser = Intent.createChooser(intent, "选择裁剪工具"); - chooser.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - if (chooser.resolveActivity(activity.getPackageManager()) != null) { - activity.startActivityForResult(chooser, requestCode); - } else { - Toast.makeText(activity, "无可用裁剪工具", Toast.LENGTH_SHORT).show(); - } - } - } catch (Exception e) { - Log.e(TAG, "startSystemCrop: 启动裁剪失败:" + e.getMessage()); - Toast.makeText(activity, "裁剪工具启动失败", Toast.LENGTH_SHORT).show(); - } - } - - /** - * 获取FileProvider Uri(复用方法,避免重复代码) - */ - public static Uri getFileProviderUri(Activity activity, File file) { - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - String FILE_PROVIDER_AUTHORITY = activity.getPackageName() + ".fileprovider"; - - return FileProvider.getUriForFile(activity, FILE_PROVIDER_AUTHORITY, file); - } else { - return Uri.fromFile(file); - } - } catch (Exception e) { - Log.e(TAG, "getFileProviderUri: 生成Uri失败:" + e.getMessage()); - return null; - } - } +// +// /** +// * 保存剪裁后的Bitmap(优化版) +// */ +// private void saveCropBitmap(Bitmap bitmap) { +// if (bitmap == null) { +// ToastUtils.show("剪裁图片为空"); +// return; +// } +// +// // 内存优化:大图片自动缩放 +// Bitmap scaledBitmap = bitmap; +// if (bitmap.getByteCount() > 10 * 1024 * 1024) { // 超过10MB +// float scale = 1.0f; +// while (scaledBitmap.getByteCount() > 5 * 1024 * 1024) { +// scale -= 0.2f; // 每次缩小20% +// if (scale < 0.2f) break; // 最小缩放到20% +// scaledBitmap = scaleBitmap(scaledBitmap, scale); +// } +// if (scaledBitmap != bitmap) { +// bitmap.recycle(); // 回收原Bitmap +// } +// } +// +// // 优化:创建保存目录 +// File backgroundDir = new File(mBackgroundPictureUtils.getBackgroundDir()); +// if (!backgroundDir.exists()) { +// if (!backgroundDir.mkdirs()) { +// ToastUtils.show("无法创建保存目录"); +// if (scaledBitmap != bitmap) scaledBitmap.recycle(); +// return; +// } +// } +// +// File saveFile = new File(backgroundDir, getBackgroundFileName()); +// +// // 优化:检查文件是否可写 +// if (saveFile.exists() && !saveFile.canWrite()) { +// if (!saveFile.delete()) { +// ToastUtils.show("无法删除旧文件"); +// if (scaledBitmap != bitmap) scaledBitmap.recycle(); +// return; +// } +// } +// +// FileOutputStream fos = null; +// try { +// fos = new FileOutputStream(saveFile); +// boolean success = scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos); +// fos.flush(); +// if (success) { +// ToastUtils.show("保存成功"); +// // 更新数据 +// mBackgroundPictureUtils.getBackgroundPictureBean().setIsUseBackgroundFile(true); +// updatePreviewBackground(); +// } else { +// ToastUtils.show("图片压缩保存失败"); +// } +// } catch (FileNotFoundException e) { +// LogUtils.e(TAG, "文件未找到" + e); +// ToastUtils.show("保存失败:文件路径错误"); +// } catch (IOException e) { +// LogUtils.e(TAG, "写入异常" + e); +// ToastUtils.show("保存失败:磁盘可能已满或路径错误"); +// } finally { +// if (fos != null) { +// try { +// fos.close(); +// } catch (IOException e) { +// LogUtils.e(TAG, "流关闭异常" + e); +// } +// } +// if (scaledBitmap != null && !scaledBitmap.isRecycled()) { +// scaledBitmap.recycle(); +// } +// } +// } +// +// /** +// * 缩放Bitmap +// */ +// private Bitmap scaleBitmap(Bitmap original, float scale) { +// if (original == null) { +// return null; +// } +// int width = (int) (original.getWidth() * scale); +// int height = (int) (original.getHeight() * scale); +// return Bitmap.createScaledBitmap(original, width, height, true); +// } }