Android相机能否限制拍摄图片的尺寸或文件大小?
安卓相机拍摄限制分辨率/文件大小解决方案
问题背景
开发安卓应用时,系统相机拍摄的图片可达10MB(8000x6000像素),性能过剩,需要限制最大分辨率为4032x3024或最大文件大小3MB,现有代码如下:
private void dispatchTakePictureIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // Ensure that there's a camera activity to handle the intent if (takePictureIntent.resolveActivity(getPackageManager()) != null) { // Create the File where the photo should go File photoFile = null; try { photoFile = createImageFile(); } catch (IOException ex) { // Error occurred while creating the File ... } // Continue only if the File was successfully created if (photoFile != null) { Uri photoURI = FileProvider.getUriForFile(this, "com.example.android.fileprovider", photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); } } }
一、尝试直接限制拍摄分辨率(4032x3024)
通过给相机Intent添加分辨率相关参数,可以尝试让系统相机直接输出指定尺寸的图片,但不同安卓厂商的系统相机对这些参数的支持不一致,部分厂商可能会忽略设置:
修改dispatchTakePictureIntent方法,添加分辨率参数:
private void dispatchTakePictureIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { File photoFile = null; try { photoFile = createImageFile(); } catch (IOException ex) { // 处理文件创建异常 } if (photoFile != null) { Uri photoURI = FileProvider.getUriForFile(this, "com.example.android.fileprovider", photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); // 添加分辨率限制参数 takePictureIntent.putExtra("outputX", 4032); takePictureIntent.putExtra("outputY", 3024); takePictureIntent.putExtra("aspectX", 4); takePictureIntent.putExtra("aspectY", 3); startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); } } }
如果系统相机不支持上述参数,这种方法会失效,此时需要在拍摄完成后对图片进行压缩处理。
二、拍摄后压缩图片(保证分辨率/文件大小达标)
由于系统相机的兼容性问题,更可靠的方式是拍摄完成后,对图片进行压缩处理,同时满足分辨率和文件大小要求:
1. 工具类实现压缩逻辑
public class ImageCompressor { // 按分辨率压缩图片到指定尺寸以内 public static Bitmap compressByResolution(String imagePath, int maxWidth, int maxHeight) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(imagePath, options); options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(imagePath, options); } // 计算图片采样率,避免内存溢出 private static int calculateInSampleSize(BitmapFactory.Options options, int maxWidth, int maxHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > maxHeight || width > maxWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; while ((halfHeight / inSampleSize) >= maxHeight && (halfWidth / inSampleSize) >= maxWidth) { inSampleSize *= 2; } } return inSampleSize; } // 按文件大小压缩,直到文件小于目标大小(单位:KB) public static File compressByFileSize(Bitmap bitmap, String outputPath, int targetSizeKB) { File outputFile = new File(outputPath); int quality = 100; ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos); while (baos.toByteArray().length / 1024 > targetSizeKB && quality > 0) { baos.reset(); quality -= 10; bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos); } try { FileOutputStream fos = new FileOutputStream(outputFile); fos.write(baos.toByteArray()); fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); } return outputFile; } }
2. 在拍摄完成后调用压缩
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { // 获取拍摄后图片的路径(需自行实现getImagePathFromUri方法) String imagePath = getImagePathFromUri(photoURI); // 先按分辨率压缩到4032x3024 Bitmap compressedBitmap = ImageCompressor.compressByResolution(imagePath, 4032, 3024); // 再压缩到3MB以内(3*1024=3072KB) File finalFile = ImageCompressor.compressByFileSize(compressedBitmap, getCompressedImagePath(), 3072); // 使用finalFile进行后续业务处理 } }
三、注意事项
- 系统相机的
ACTION_IMAGE_CAPTURE参数兼容性差,依赖厂商实现,拍摄后压缩是更可靠的方案 - 压缩图片时要注意读取Exif信息修正图片方向(部分相机拍摄的图片会有旋转角度)
- 处理大图片时要注意内存溢出问题,务必使用
BitmapFactory.Options进行采样加载
内容的提问来源于stack exchange,提问作者JavaSheriff
相关产品推荐
相关产品推荐

