Android拍照后如何自动将图片居中裁剪至指定尺寸
Android拍照后自动居中裁剪并覆盖原文件的实现方案
核心思路
通过Bitmap原生API实现居中裁剪逻辑:
- 计算原图的中心裁剪区域(以短边为基准取正方形)
- 将裁剪区域缩放至指定目标尺寸
- 覆盖保存到原文件路径
- 通知媒体库更新文件信息
步骤1:添加图片裁剪工具类
新建ImageCropper.java文件,封装裁剪与保存逻辑:
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.util.Log; import java.io.FileOutputStream; import java.io.IOException; public class ImageCropper { // 居中裁剪并缩放至指定尺寸,覆盖原文件 public static boolean cropAndSaveCenter(String imagePath, int targetWidth, int targetHeight) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(imagePath, options); int originalWidth = options.outWidth; int originalHeight = options.outHeight; // 计算中心裁剪区域:取短边长度作为裁剪尺寸 int cropSize = Math.min(originalWidth, originalHeight); int cropX = (originalWidth - cropSize) / 2; int cropY = (originalHeight - cropSize) / 2; // 计算采样率,避免加载超大图导致OOM options.inJustDecodeBounds = false; options.inSampleSize = calculateInSampleSize(options, cropSize, cropSize); Bitmap originalBitmap = BitmapFactory.decodeFile(imagePath, options); if (originalBitmap == null) { Log.e("ImageCropper", "解码原图失败"); return false; } // 裁剪中心区域 Bitmap croppedBitmap = Bitmap.createBitmap( originalBitmap, cropX / options.inSampleSize, cropY / options.inSampleSize, cropSize / options.inSampleSize, cropSize / options.inSampleSize ); originalBitmap.recycle(); // 释放原图内存 // 缩放至目标尺寸 Matrix matrix = new Matrix(); float scaleX = (float) targetWidth / croppedBitmap.getWidth(); float scaleY = (float) targetHeight / croppedBitmap.getHeight(); matrix.postScale(scaleX, scaleY); Bitmap scaledBitmap = Bitmap.createBitmap(croppedBitmap, 0, 0, croppedBitmap.getWidth(), croppedBitmap.getHeight(), matrix, true); croppedBitmap.recycle(); // 释放裁剪图内存 // 覆盖保存原文件 try (FileOutputStream fos = new FileOutputStream(imagePath)) { scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); scaledBitmap.recycle(); return true; } catch (IOException e) { Log.e("ImageCropper", "保存裁剪图失败", e); scaledBitmap.recycle(); return false; } } // 计算图片采样率,降低内存占用 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 halfHeight = height / 2; final int halfWidth = width / 2; while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; } }
步骤2:修改MainActivity的拍照回调
在onActivityResult中调用裁剪工具类,处理完成后更新UI与媒体库:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode == CAMERA_REQUEST_CODE){ if(resultCode == Activity.RESULT_OK){ File f = new File(currentPhotoPath); // 执行居中裁剪,目标尺寸456x456 boolean cropSuccess = ImageCropper.cropAndSaveCenter(currentPhotoPath, 456, 456); if (cropSuccess) { selectedImage.setImageURI(Uri.fromFile(f)); Log.d("tag", "裁剪完成,文件路径:" + Uri.fromFile(f)); // 通知媒体库更新文件索引 Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); Uri contentUri = Uri.fromFile(f); mediaScanIntent.setData(contentUri); this.sendBroadcast(mediaScanIntent); } else { Toast.makeText(this, "图片裁剪失败", Toast.LENGTH_SHORT).show(); // 裁剪失败时显示原图 selectedImage.setImageURI(Uri.fromFile(f)); } } } }
关键注意事项
- 内存优化:通过
inSampleSize采样率避免加载高分辨率原图导致内存溢出 - 权限兼容:Android 10及以上使用公共目录需保持
WRITE_EXTERNAL_STORAGE权限申请 - 文件备份:若需保留原图,可在裁剪前将原文件复制到其他路径
- 异常处理:代码包含基础错误捕获,实际开发可根据需求补充重试或提示逻辑
内容的提问来源于stack exchange,提问作者cherry blossom
相关产品推荐
相关产品推荐

