如何从 Android 上的相机获取位图?

Posted

技术标签:

【中文标题】如何从 Android 上的相机获取位图?【英文标题】:How can i get bitmap from camera on android? 【发布时间】:2017-03-16 12:23:24 【问题描述】:

代码:

public void startCameraActivity()
        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (cameraIntent.resolveActivity(getActivity().getPackageManager()) != null) 
            startActivityForResult(cameraIntent, 1000);
        
    

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) 
        if(resultCode == Activity.RESULT_OK) 
            if (requestCode == 1000)
                File photo = new File(Environment.getExternalStorageDirectory(), ".camera.jpg");
                OutputStream out = null;
                String imagePath = data.getData().getPath();
                Bitmap image = BitmapFactory.decodeFile(imagePath);
                ExifInterface exif = null;

                try 
                    exif = new ExifInterface(imagePath);

                    int exifOrientation = exif.getAttributeInt(
                            ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
                    int exifDegree = exifOrientationToDegrees(exifOrientation);
                    image = rotate(image, exifDegree);
                    photo.createNewFile();
                    out = new FileOutputStream(Environment.getExternalStorageDirectory());
                    image.compress(Bitmap.CompressFormat.PNG, 100, out);
                    out.close();
                 catch (IOException e) 
                    Toast.makeText(getContext(), "hello error", Toast.LENGTH_LONG).show();
                
                returnUri = Uri.fromFile(photo);
            
            Glide.with(this)
                    .load(returnUri)
                    .into(mImageview);
        
    

用于旋转图像

public int exifOrientationToDegrees(int exifOrientation)
    
        if(exifOrientation == ExifInterface.ORIENTATION_ROTATE_90)
        return 90;
        else if(exifOrientation == ExifInterface.ORIENTATION_ROTATE_180)
        return 180;
        else if(exifOrientation == ExifInterface.ORIENTATION_ROTATE_270)
        return 270;
        return 0;
    
    public Bitmap rotate(Bitmap bitmap, int degrees)
    
        if(degrees != 0 && bitmap != null)
        
            Matrix m = new Matrix();
            m.setRotate(degrees, (float) bitmap.getWidth() / 2,
                    (float) bitmap.getHeight() / 2);

            try
            
                Bitmap converted = Bitmap.createBitmap(bitmap, 0, 0,
                        bitmap.getWidth(), bitmap.getHeight(), m, true);
                if(bitmap != converted)
                
                    bitmap.recycle();
                    bitmap = converted;
                
            
            catch(OutOfMemoryError ex)
            
            
        
        return bitmap;
     

我编写了一个从相机获取图片的代码。

但是那张来自相机的照片方向不正确。

所以我搜索旋转该​​图像。

但上面的代码不起作用。

问题出在哪里? 我该如何解决?

android 显示器说

java.lang.RuntimeException: Failure delivering result ResultInfowho=null, request=66536, result=-1, data=Intent  act=inline-data dat=content://media/external/images/media/8464 flg=0x1 (has extras)  to activity ~~!@.MainActivity: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)' on a null object reference


Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)' on a null object reference

编辑完整的logcat

11-03 11:21:42.060 16104-16104/? E/AndroidRuntime: FATAL EXCEPTION: main
                                                   Process: com.keepair.www.pinair, PID: 16104
                                                   java.lang.RuntimeException: Failure delivering result ResultInfowho=null, request=66536, result=-1, data=Intent  act=inline-data dat=content://media/external/images/media/8465 flg=0x1 (has extras)  to activity com.keepair.www.pinair/com.keepair.www.pinair.MainActivity: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)' on a null object reference
                                                       at android.app.ActivityThread.deliverResults(ActivityThread.java:4173)
                                                       at android.app.ActivityThread.handleSendResult(ActivityThread.java:4216)
                                                       at android.app.ActivityThread.access$1400(ActivityThread.java:181)
                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1523)
                                                       at android.os.Handler.dispatchMessage(Handler.java:102)
                                                       at android.os.Looper.loop(Looper.java:145)
                                                       at android.app.ActivityThread.main(ActivityThread.java:6117)
                                                       at java.lang.reflect.Method.invoke(Native Method)
                                                       at java.lang.reflect.Method.invoke(Method.java:372)
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
                                                    Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)' on a null object reference
                                                       at com.keepair.www.pinair.GreenFragment.onActivityResult(GreenFragment.java:296)
                                                       at android.support.v4.app.FragmentActivity.onActivityResult(FragmentActivity.java:165)
                                                       at android.app.Activity.dispatchActivityResult(Activity.java:6632)
                                                       at android.app.ActivityThread.deliverResults(ActivityThread.java:4169)
                                                       at android.app.ActivityThread.handleSendResult(ActivityThread.java:4216) 
                                                       at android.app.ActivityThread.access$1400(ActivityThread.java:181) 
                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1523) 
                                                       at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                       at android.os.Looper.loop(Looper.java:145) 
                                                       at android.app.ActivityThread.main(ActivityThread.java:6117) 
                                                       at java.lang.reflect.Method.invoke(Native Method) 
                                                       at java.lang.reflect.Method.invoke(Method.java:372) 
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399) 
                                                       at 

com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)

【问题讨论】:

能否显示完整的 logcat 异常? 我添加了@criket_007 image.compress 正在抛出错误。似乎您从旋转方法返回了 null 【参考方案1】:

这是我写的,你可以试试。

public static final int PICK_USER_PROFILE_IMAGE = 1000;
public void startCameraActivity()
        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (cameraIntent.resolveActivity(getActivity().getPackageManager()) != null) 
            startActivityForResult(cameraIntent, PICK_USER_PROFILE_IMAGE);
        
    

    @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode == RESULT_OK) 
        if (requestCode == Constants.PICK_USER_PROFILE_IMAGE) 
            if (resultCode == RESULT_OK) 
                Bitmap bmp = ImagePicker.getImageFromResult(this, resultCode, data);
               //your compressed rotated bitmap here

            
        
    

下面是 ImagePicker 类,它有一系列的方法来完成你的工作

public class ImagePicker 

private static final int DEFAULT_MIN_WIDTH_QUALITY = 400;        // min pixels
private static final String TAG = "ImagePicker";
private static final String TEMP_IMAGE_NAME = "tempImage";

public static int minWidthQuality = DEFAULT_MIN_WIDTH_QUALITY;

public static Bitmap getImageFromResult(Context context, int resultCode,
                                        Intent imageReturnedIntent) 
    Log.d(TAG, "getImageFromResult, resultCode: " + resultCode);
    Bitmap bm = null;
    File imageFile = getTempFile(context);
    if (resultCode == Activity.RESULT_OK) 
        Uri selectedImage;
        boolean isCamera = (imageReturnedIntent == null ||
                imageReturnedIntent.getData() == null ||
                imageReturnedIntent.getData().equals(Uri.fromFile(imageFile)));
        if (isCamera)      /** CAMERA **/
            selectedImage = Uri.fromFile(imageFile);
         else             /** ALBUM **/
            selectedImage = imageReturnedIntent.getData();
        
        Log.d(TAG, "selectedImage: " + selectedImage);

        bm = getImageResized(context, selectedImage);
        int rotation = getRotation(context, selectedImage, isCamera);
        bm = rotate(bm, rotation);
    
    return bm;



private static Bitmap decodeBitmap(Context context, Uri theUri, int sampleSize) 
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = sampleSize;

    AssetFileDescriptor fileDescriptor = null;
    try 
        fileDescriptor = context.getContentResolver().openAssetFileDescriptor(theUri, "r");
     catch (FileNotFoundException e) 
        e.printStackTrace();
    

    Bitmap actuallyUsableBitmap = BitmapFactory.decodeFileDescriptor(
            fileDescriptor.getFileDescriptor(), null, options);

    Log.d(TAG, options.inSampleSize + " sample method bitmap ... " +
            actuallyUsableBitmap.getWidth() + " " + actuallyUsableBitmap.getHeight());

    return actuallyUsableBitmap;


/**
 * Resize to avoid using too much memory loading big images (e.g.: 2560*1920)
 **/
private static Bitmap getImageResized(Context context, Uri selectedImage) 
    Bitmap bm = null;
    int[] sampleSizes = new int[]5, 3, 2, 1;
    int i = 0;
    do 
        bm = decodeBitmap(context, selectedImage, sampleSizes[i]);
        Log.d(TAG, "resizer: new bitmap width = " + bm.getWidth());
        i++;
     while (bm.getWidth() < minWidthQuality && i < sampleSizes.length);
    return bm;



private static int getRotation(Context context, Uri imageUri, boolean isCamera) 
    int rotation;
    if (isCamera) 
        rotation = getRotationFromCamera(context, imageUri);
     else 
        rotation = getRotationFromGallery(context, imageUri);
    
    Log.d(TAG, "Image rotation: " + rotation);
    return rotation;


private static int getRotationFromCamera(Context context, Uri imageFile) 
    int rotate = 0;
    try 

        context.getContentResolver().notifyChange(imageFile, null);
        ExifInterface exif = new ExifInterface(imageFile.getPath());
        int orientation = exif.getAttributeInt(
                ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_NORMAL);

        switch (orientation) 
            case ExifInterface.ORIENTATION_ROTATE_270:
                rotate = 270;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                rotate = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_90:
                rotate = 90;
                break;
        
     catch (Exception e) 
        e.printStackTrace();
    
    return rotate;


public static int getRotationFromGallery(Context context, Uri imageUri) 
    String[] columns = MediaStore.Images.Media.ORIENTATION;
    Cursor cursor = context.getContentResolver().query(imageUri, columns, null, null, null);
    if (cursor == null) return 0;

    cursor.moveToFirst();

    int orientationColumnIndex = cursor.getColumnIndex(columns[0]);
    return cursor.getInt(orientationColumnIndex);



private static Bitmap rotate(Bitmap bm, int rotation) 
    if (rotation != 0) 
        Matrix matrix = new Matrix();
        matrix.postRotate(rotation);
        Bitmap bmOut = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
        return bmOut;
    
    return bm;



 private static File getTempFile(Context context) 
        File imageFile = new File(context.getExternalCacheDir(), TEMP_IMAGE_NAME);
        imageFile.getParentFile().mkdirs();
        return imageFile;
    

ImagePicker 类具有处理图像压缩和旋转的所有方法。

希望对你有帮助

【讨论】:

感谢您的回答 rana_sadam【参考方案2】:

对于获取实际图像的预定义路径的捕获​​图像使用

Intent cameraIntent = new Intent(
                android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
this.startActivityForResult(cameraIntent, 101); 

在捕获图像之后,您可以在 cameraIntent 中设置的路径上获取捕获图像。如果您不想设置预定义路径,请检查 Intent 数据。

if (resultCode == android.app.Activity.RESULT_OK && requestCode == 101) 
                try 

                    path_mm = "Onsuccess_resultcode";
                    generateNoteOnSD("photo34.txt", path_mm);
                    Bitmap photo = null;
                    if (data == null) 
                    //get Bitmap  here.
                     
               else 
                    Uri u1 = data.getData();
                    //get uri and find actual path on that uri.
                     
                     catch(Exception ex)
                     

【讨论】:

【参考方案3】:

首先也许你应该看看这一行:

if(degrees != 0 && bitmap != null)

如果此行为假,则返回“null”,并且监视器会给出该错误。

【讨论】:

以上是关于如何从 Android 上的相机获取位图?的主要内容,如果未能解决你的问题,请参考以下文章

Android获取相机位图的方向?并向后旋转-90度

从相机/图库加载图像位图时会旋转 [Android 9]

使用 jni 将位图从 android 相机传递到 C++

刚从相机拍摄并通过从图库中挑选显示的Android裁剪图像

如何从可绘制文件夹上的图像获取路径并设置为图像视图,位图?

如何在android中结合覆盖位图和捕获的图像?