You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android图库选图旋转异常与图片质量下降问题修复咨询

解决相机拍照/图库选图的质量下降与旋转问题

一、图片质量下降的解决方法

问题根源

  1. 相机拍照时,data.getExtras().get("data")返回的是系统压缩后的缩略图,分辨率极低,直接使用必然导致画质模糊。
  2. 代码中多次对Bitmap进行缩放(ThumbnailUtils.extractThumbnail + createScaledBitmap),反复压缩会让图片细节大量丢失。
  3. 图库选图用的MediaStore.Images.Media.getBitmap是过时API,解码原图时没有做优化,也会间接影响画质。

修复步骤

1. 相机拍照改为获取原图

首先在启动相机前,先创建一个临时文件用来保存原图:

// 成员变量
private Uri cameraImageUri;

// 启动相机的方法
private void startCamera() {
    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) {
            cameraImageUri = FileProvider.getUriForFile(this,
                    "你的应用包名.fileprovider",
                    photoFile);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraImageUri);
            startActivityForResult(takePictureIntent, 2);
        }
    }
}

// 创建临时图片文件
private File createImageFile() throws IOException {
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    return File.createTempFile(imageFileName, ".jpg", storageDir);
}

然后在onActivityResult的相机分支,读取这个文件获取原图:

// 相机分支修改后
if (requestCode == 2) {
    Bitmap imgCam = null;
    try {
        imgCam = BitmapFactory.decodeStream(getContentResolver().openInputStream(cameraImageUri));
    } catch (IOException e) {
        e.printStackTrace();
    }

    if (imgCam == null) return;

    // 修正图片方向
    imgCam = rotateBitmapByExif(imgCam, cameraImageUri.getPath());
    // 仅做一次目标尺寸缩放
    imgCam = Bitmap.createScaledBitmap(imgCam, imgSize, imgSize, true);
    
    cropBitmap = Utils.processBitmap(imgCam, TF_OD_API_INPUT_SIZE);
    imgHinh.setImageBitmap(imgCam);

    loading = new ProgressDialog(this);
    loading.show();
    initBox();

    Bitmap finalImgCam = imgCam;
    new CountDownTimer(2000,1000) {
        public void onFinish() {
            classifyImage(finalImgCam);
            loading.dismiss();
        }
        public void onTick(long millisUntilFinished) {}
    }.start();
}

2. 图库选图优化解码逻辑

替换过时API,用BitmapFactory.Options优化解码,避免不必要的内存占用和画质损失:

// 图库分支修改后
else if (requestCode == 3) {
    Uri dat = data.getData();
    Bitmap imgChoose = null;
    try {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        options.inSampleSize = calculateInSampleSize(options, imgSize, imgSize);
        
        InputStream inputStream = getContentResolver().openInputStream(dat);
        imgChoose = BitmapFactory.decodeStream(inputStream, null, options);
        
        // 修正图片方向
        imgChoose = rotateBitmapByExif(imgChoose, getRealPathFromUri(dat));
    } catch (IOException e) {
        e.printStackTrace();
    }

    if (imgChoose == null) return;

    imgChoose = Bitmap.createScaledBitmap(imgChoose, imgSize, imgSize, true);
    
    cropBitmap = Utils.processBitmap(imgChoose, TF_OD_API_INPUT_SIZE);
    imgHinh.setImageBitmap(imgChoose);

    loading = new ProgressDialog(this);
    loading.show();
    initBox();

    Bitmap finalImgChoose = imgChoose;
    new CountDownTimer(2000,1000) {
        public void onFinish() {
            classifyImage(finalImgChoose);
            loading.dismiss();
        }
        public void onTick(long millisUntilFinished) {}
    }.start();
}

// 计算采样率,避免内存溢出
private 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;
}

// 获取Uri对应的真实文件路径
private String getRealPathFromUri(Uri uri) {
    String[] projection = {MediaStore.Images.Media.DATA};
    Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
    if (cursor == null) return null;
    int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    String path = cursor.getString(columnIndex);
    cursor.close();
    return path;
}

二、三星手机图片旋转的解决方法

问题根源

图片拍摄时会在Exif信息中记录方向(比如竖屏拍照时标记为旋转90度),部分品牌手机系统会自动修正这个方向,但三星部分机型需要手动读取Exif信息并旋转图片。

修复步骤

编写工具方法读取Exif方向并旋转Bitmap:

// 读取Exif方向并修正图片角度
private Bitmap rotateBitmapByExif(Bitmap bitmap, String imagePath) {
    ExifInterface exif = null;
    try {
        exif = new ExifInterface(imagePath);
    } catch (IOException e) {
        e.printStackTrace();
        return bitmap;
    }

    int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
    Matrix matrix = new Matrix();
    switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            matrix.postRotate(90);
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            matrix.postRotate(180);
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
            matrix.postRotate(270);
            break;
        default:
            return bitmap;
    }
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}

内容的提问来源于stack exchange,提问作者James Black

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 17:25:23