在Android中使用相机:为什么当相机拍摄照片而不是从照片库中选择时,Cursor为空?

时间:2014-12-15 11:45:48

标签: android image camera android-cursor

在我的应用中,用户可以从相机或图库添加许多图像。 用户点击有一个addPhoto按钮,她可以选择相机或图库,选择或拍照,照片会添加到页面中。这可以继续下去。

除了一件事,每件事都很好: 一些图像是纵向的,我需要旋转它们(因为Android旋转它们并使它们成为风景,我必须将它们旋转回来)。但我无法使用相机图片,因为光标对于它们是空的。

图像保存在设备上。 Uri不是没有。我还应该检查什么? 我究竟做错了什么?奇怪的是,当从画廊中选择图像时,每件事情都很完美!

以下是使用图片的活动的代码:

public class CreatePropertyActivity5 extends ActionBarActivity {
    protected static final int SELECT_PICTURE = 1;
    private static final int ACTIVITY_REQUEST_CODE_IMAGE = 100;
    private static final int IMAGE_DESCRIPTION = 200;

    private static List<File> cameraImageFiles;
    private static Bitmap selectedImageBitmap;
    private static LinearLayout ll; 
    private static int id = 0;
    private static int password = 0;

    private static JSONRequestForCreatePropertyListing propertyListing;
    private static ImageView imageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_create_property_5);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        //if not null, means Android has killed the process while the user has been working with camera or gallery to add images, and the onCreate is called AGAIN. And we don't want to initialize the layout again cause we will loose our previously added photos.
        if (propertyListing==null) {
            propertyListing = (JSONRequestForCreatePropertyListing) getIntent().getSerializableExtra("JSONRequestForCreatePropertyListing");
            CreatePropertListingAsync cplp = new CreatePropertListingAsync(this, propertyListing);
            cplp.execute();
            ll = (LinearLayout) findViewById(R.id.llCreatePropertyImages);

        }
        else {
        //If Android has killed the activity once and this is the second time we are in onCreate(), the static ll which has the previously added images in it won't be attached to the xml page and so we have to add it manually.
            LinearLayout ll2 = (LinearLayout) findViewById(R.id.ll_activity_create_property);
            ((ViewGroup)ll.getParent()).removeView(ll);
            ll2.addView(ll);
        }

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    }
    public void onClickTakePicture(View v) throws IOException {
        // Camera.
        final List<Intent> cameraIntents = new ArrayList<Intent>();
        final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);     
        final PackageManager packageManager = getPackageManager();
        final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);

        cameraImageFiles = new ArrayList<File>();

        int i=0;
        for(ResolveInfo res : listCam) {
            final String packageName = res.activityInfo.packageName;
            final Intent intent = new Intent(captureIntent);
            intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
            intent.setPackage(packageName);
            intent.putExtra(MediaStore.MEDIA_IGNORE_FILENAME, ".nomedia");

            //** below 4 lines put the uri of the camera taken picture to the EXTRA_OUTPUT 
            File cameraImageOutputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "myFileName.jpg");
            cameraImageFiles.add(cameraImageOutputFile);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cameraImageFiles.get(i)));
            i++;

            cameraIntents.add(intent);
        }

        // Filesystem.
        final Intent galleryIntent = new Intent();
        galleryIntent.setType("image/*");
        galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

        // Chooser of filesystem options.
        final Intent chooserIntent = Intent.createChooser(galleryIntent, "add new");

        // Add the camera options.
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
        startActivityForResult(chooserIntent, ACTIVITY_REQUEST_CODE_IMAGE);

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent)
    {

        switch(requestCode) { 

        // For sending photos to server. We come here from activity51 when user clicks on send photo. This "case" happens second. 
        case IMAGE_DESCRIPTION:
            if(resultCode == RESULT_OK){
                //add the image to the activity5 page.
                imageView = new ImageView(this);
                imageView.setPadding(0, 10, 0, 0);
                ll.setVisibility(View.VISIBLE);
                if (findViewById(R.id.ll_create_property_successful)!= null)
                    findViewById(R.id.ll_create_property_successful).setVisibility(View.VISIBLE);
                imageView.setImageBitmap(selectedImageBitmap);
                ll.addView(imageView);

                if ((TextView) findViewById(R.id.txt_property_listing_code)!= null)
                    ((TextView) findViewById(R.id.txt_property_listing_code)).setText(""+id);
                if ((TextView)findViewById(R.id.txt_property_listing_password)!= null)
                    ((TextView) findViewById(R.id.txt_property_listing_password)).setText(""+password);

                String s = imageReturnedIntent.getStringExtra("key");
                //user entered description is in "key"
                imageView.setTag(s);
                Bitmap bitmap1 = ((BitmapDrawable)imageView.getDrawable()).getBitmap();
                ByteArrayOutputStream stream=new ByteArrayOutputStream();
                bitmap1.compress(Bitmap.CompressFormat.PNG, 90, stream);
                byte[] image=stream.toByteArray();
                String img_str = Base64.encodeToString(image, 0);

                //This part sends the picture to the server
                ArrayList<Photos> photos = new ArrayList<Photos>();
                photos.add(new Photos(new Ax(img_str)));


                //if not null, means Android has killed the process while the user has been working with camera or gallery to add images, and the onCreate is called AGAIN. And we don't want to initialize the layout again cause we will loose our previously added photos.
                JSONRequestForAddPhoto jr = new JSONRequestForAddPhoto(id, password, photos);

                new AddPhotoAsync(this, jr).execute();
            }

            //If user has pressed the cancel button and not the send photo button (in activity51) we come here and do nothing.
            break;
        //After the user has selected a photo (or taken one with camera) we come here :). This "case" happens first for a photo.
        case ACTIVITY_REQUEST_CODE_IMAGE:
            if(resultCode == RESULT_OK){

                Uri uri = null;
                if(imageReturnedIntent == null){   //since we used EXTRA_OUTPUT for camera, so it will be null

                    if (cameraImageFiles!=null && cameraImageFiles.get(0)!=null)    
                        for(int i=0;i<cameraImageFiles.size();i++){
                            if(cameraImageFiles.get(i).exists()){
                                uri = Uri.fromFile(cameraImageFiles.get(i));
                                break;
                            }
                        }
                    else
                        Toast.makeText(this, "Sorry :( A problem occured whille trying to add this photo", Toast.LENGTH_LONG);
                }
                else {  // from gallery
                    uri = imageReturnedIntent.getData();
                }

                if(uri != null){
                    try {

                        selectedImageBitmap = decodeSampledBitmapFromResource(uri, 500, 500);

                        Matrix matrix = new Matrix();
                        matrix.postRotate(getOrientation(this, uri));

                        selectedImageBitmap = Bitmap.createBitmap(selectedImageBitmap, 0, 0, selectedImageBitmap.getWidth(), selectedImageBitmap.getHeight(), matrix, true);


                        Intent i= new Intent(this, CreatePropertyActivity51.class);
                        i.putExtra("photoUri", uri);
                        startActivityForResult(i,IMAGE_DESCRIPTION);

                        //*** show activity51

                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public Bitmap decodeSampledBitmapFromResource(Uri uri, int reqWidth, int reqHeight) throws IOException {

        ContentResolver cr = getContentResolver();
        InputStream inStream = cr.openInputStream(uri);
        // First decode with inJustDecodeBounds=true to check dimensions
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(inStream, null, options);

        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        inStream.close();
        inStream = cr.openInputStream(uri);


        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        Bitmap result = BitmapFactory.decodeStream(inStream, null , options);
        inStream.close();
        return result;
    }
    public int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        int height = options.outHeight;
        int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            int halfHeight = height / 2;
            int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2.
            while ((halfHeight / inSampleSize) > reqHeight     ||     (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

    public static int getOrientation(Context context, Uri photoUri) {
        /* it's on the external media. */
        Cursor cursor = context.getContentResolver().query(photoUri, new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);

        if (cursor == null)
            return 0;
        if (cursor.getCount() != 1) {
            return -1;
        }

        cursor.moveToFirst();
        return cursor.getInt(0);
    }


}

1 个答案:

答案 0 :(得分:1)

当用户从图库中选择图像时,它会返回投影的URI ,而在相机的情况下,URI返回的是直接图像路径URI。

因此,如果是图库,则执行此操作,

/**
 * Get from library
 */
private void getPhoto() {
    Intent i = new Intent(Intent.ACTION_PICK,
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(i, GET_PICTURE_REQUEST_CODE);
}

如果是相机,则执行此操作,

/**
 * Take Photo
 */
private void takePhoto() {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    //cameraImageUri is the Uri where camera app should save the clicked photo
    cameraImageUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraImageUri);
    startActivityForResult(intent, TAKE_PICTURE_REQUEST_CODE);
}

onActivityResult()中,如果是图库,则需要获取imageUri并获取光标,

String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(imageUri,
              filePathColumn, null, null, null);

但在相机中,您可以直接使用cameraImageUri.toString()来获取图片路径。

您不必将direct URI转换为projected URI(在图库选择的情况下获得)。

要详细说明direct URIprojected URI之间的区别,直接URI可能看起来像content://...,而投影的URI看起来像file://...,因为它是通过内容获得的解析器。