您如何在Android上处理疯狂的高MP相机(和图像)?-“画布:试图绘制太大的位图"; [英] How do you deal with insanely high MP cameras (and images) on Android? - "Canvas: trying to draw too large bitmap"

查看:52
本文介绍了您如何在Android上处理疯狂的高MP相机(和图像)?-“画布:试图绘制太大的位图";的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个活动,用户可以像这样打开相机

I have an activity where the user can open the camera like so

getPictureUri(createImageFromFile = true)?.let {
        photoUri = it
        openCameraActivity(REQUEST_IMAGE_CAPTURE, it)
    } ?: photoViewModel.onRequestUriError()

openCamera是一个如下所示的活动扩展

openCamera is an Activity Extension that looks like this

fun Activity.openCameraActivity(requestCode: Int, pictureUri: Uri) {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
    takePictureIntent.resolveActivity(packageManager)?.also {
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri)
        takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
        startActivityForResult(takePictureIntent, requestCode)
    }
}

}

当我们取回图像时,将其写入文件,并将photoUri存储在应用程序中的某个位置.效果很好!问题是某些用户拥有超高像素的摄像头,例如64mp,当他们拍照时会尝试在UI中显示并崩溃.

We write the image to a file when we get it back, and store the photoUri in the app somewhere. It works great! The issue is that some users have super high megapixel cameras, like 64mp, and when they take a picture it tries to display in the UI and it crashes.

FATAL EXCEPTION: main
Process: co.app.staging, PID: 27859
java.lang.RuntimeException: Canvas: trying to draw too large(256576512bytes) bitmap.

有什么办法可以限制相机的分辨率吗?我可以降低质量,但这充其量似乎只是一个创可贴.有什么合适的解决方案?

Is there a way I can limit the camera resolution on this? I could turn the quality down but that seems like a bandaid at best. What are some decent solutions for this?

推荐答案

我尝试过这种方法,可以从 URI 在画布上绘制位图,请尝试以下操作:

I tried this way to draw bitmap on canvas from URI, try this:

(下面的代码给出了解释)

(Explanation given below code)

private void drawBitmapUriOnCanvas(Uri selectedImage) {
    if (selectedImage != null) {
        BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
        bmpFactoryOptions.inJustDecodeBounds = true;

        try {
            BitmapFactory.decodeStream(getContentResolver().openInputStream(
                    selectedImage), null, bmpFactoryOptions);

            bmpFactoryOptions.inSampleSize = 2;
            bmpFactoryOptions.inJustDecodeBounds = false;
            Bitmap bmp = BitmapFactory
                    .decodeStream(getContentResolver().openInputStream(
                            selectedImage), null, bmpFactoryOptions);

            Bitmap alteredBitmap;
            if (bmp != null) {
                if (getDeviceRam(this) <= 1024) {
                    bmp = getResizedBitmap(bmp, displayWidth);
                }
                bmp = checkAndRotateBitmap(bmp);
                alteredBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp
                        .getHeight(), bmp.getConfig());

                Canvas canvas = new Canvas(alteredBitmap);
                Paint paint = new Paint();
                paint.setColor(Color.WHITE);
                paint.setStrokeWidth(5);
                paint.setAntiAlias(true);
                Matrix matrix = new Matrix();
                canvas.drawBitmap(bmp, matrix, paint);

                (now alteredBitmap is processed bitmap and you can use it)
            }
        } catch (FileNotFoundException e) {
            Toast.makeText(this, "Error reading Image Metadata", Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }
}

其他包含的方法:

public static long getDeviceRam(Context context) {
    ActivityManager actManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
    actManager.getMemoryInfo(memInfo);
    long totalMemory = memInfo.totalMem;
    long fileSizeInKB = totalMemory / 1024;
    // Convert the KB to MegaBytes (1 MB = 1024 KBytes)
    return fileSizeInKB / 1024;
}

public static Bitmap getResizedBitmap(Bitmap image, int maxSize) {
    int width = image.getWidth();
    int height = image.getHeight();

    float bitmapRatio = (float) width / (float) height;
    if (bitmapRatio > 1) {
        width = maxSize;
        height = (int) (width / bitmapRatio);
    } else {
        height = maxSize;
        width = (int) (height * bitmapRatio);
    }
    return Bitmap.createScaledBitmap(image, width, height, true);
}

在这里,首先,我使用 BitmapFactory 解码了图像uri,然后检查了设备ram,它的大小为1GB,然后我重新调整了位图的大小,否则下一步可以使用原始位图,

Here, first of all i decoded image uri using BitmapFactory, then i checked device ram and it it was of 1GB then i resize the bitmap other wise original bitmap will be ok for next step,

接下来只是在画布上绘制位图,您将得到 alteredBitmap 将被处理的位图,并且易于使用.

And next was simply drawing bitmap on canvas and you will get alteredBitmap will is processed bitmap and it will be easy to use.

如果这不起作用,那么还有另一种方法可以满足您的要求,如下所示:

If this will not work then there is another option for completing your requirement and it was given below:

Bitmap bitmap = getBitmapFromGallery(selectedImage.getPath(), 800, 800);

private Bitmap getBitmapFromGallery(String path, int width, int height) {

    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, width, height);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    Bitmap bitmap = BitmapFactory.decodeFile(path, options);

    // if you use image from camera then in some cases it will rotated automatically like it was captured landscape but displays portrait then you have to use method `checkAndRotateBitmap()` which was also given below
    //    bitmap = checkAndRotateBitmap(bitmap);
    return bitmap;
}

public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    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;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) >= reqHeight
                && (halfWidth / inSampleSize) >= reqWidth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

private Bitmap checkAndRotateBitmap(Bitmap bmp) {
    try {
        ExifInterface ei = new ExifInterface(imgPath);
        int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_UNDEFINED);

        Bitmap rotatedBitmap;

        switch (orientation) {

            case ExifInterface.ORIENTATION_ROTATE_90:
                rotatedBitmap = Helper.rotateImage(bmp, 90);
                break;

            case ExifInterface.ORIENTATION_ROTATE_180:
                rotatedBitmap = Helper.rotateImage(bmp, 180);
                break;

            case ExifInterface.ORIENTATION_ROTATE_270:
                rotatedBitmap = Helper.rotateImage(bmp, 270);
                break;

            case ExifInterface.ORIENTATION_NORMAL:
            default:
                rotatedBitmap = bmp;
        }
        return rotatedBitmap;

    } catch (IOException e) {
        e.printStackTrace();
        return bmp;
    }
}

编辑

有关 getBitmapFromGallery()方法的工作方式的更多信息,您应该有效地查看

EDIT

for more information on how getBitmapFromGallery() method works, you should have look at https://medium.com/android-news/loading-large-bitmaps-efficiently-in-android-66826cd4ad53

这就是我的全部朋友,现在尝试一种满足您要求的方法,让我知道是否可以使用,如果有任何问题,也可以帮助我改善答案.谢谢!!

That's all my friend, now try one of the methods for your requirement and let me know if this will work or not, also help me improve my answer if anything was wrong..Thank you!!

这篇关于您如何在Android上处理疯狂的高MP相机(和图像)?-“画布:试图绘制太大的位图";的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆