Hộp thoại để chọn hình ảnh từ thư viện hoặc từ máy ảnh


122

Có cách tiêu chuẩn nào để gọi hộp thoại với chọn để chọn hình ảnh từ máy ảnh hoặc lấy từ thư viện (như trong danh bạ điện thoại tích hợp sẵn hoặc Skype) không?

Tôi đã xem qua cái này nhưng mã mở thư viện mà không đề xuất chọn nó từ máy ảnh.

Thiết bị: Samsung Galaxy Tab
Android: 2.3.3


Hãy xem câu trả lời này với ý định hợp nhất cả hai yêu cầu (Máy ảnh và Thư viện) trong một Ý định duy nhất: stackoverflow.com/a/32475805/2232889
Mario Velasco

Câu trả lời:


192

Mã dưới đây có thể được sử dụng để chụp ảnh và chọn ảnh. Chỉ cần hiển thị một hộp thoại có hai tùy chọn và khi lựa chọn, hãy sử dụng mã thích hợp.

Để chụp ảnh từ máy ảnh:

Intent takePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePicture, 0);//zero can be replaced with any action code (called requestCode)

Để chọn ảnh từ thư viện:

Intent pickPhoto = new Intent(Intent.ACTION_PICK,
           android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhoto , 1);//one can be replaced with any action code

onActivityResult mã:

protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) { 
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent); 
    switch(requestCode) {
    case 0:
        if(resultCode == RESULT_OK){  
            Uri selectedImage = imageReturnedIntent.getData();
            imageview.setImageURI(selectedImage);
        }

    break; 
    case 1:
        if(resultCode == RESULT_OK){  
            Uri selectedImage = imageReturnedIntent.getData();
            imageview.setImageURI(selectedImage);
        }
    break;
    }
}

Cuối cùng, thêm quyền này vào tệp kê khai:

 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

20
Không cần quyền Máy ảnh vì nó mở ứng dụng mặc định.
tasomaniac

2
@Jeremy Không, sai rồi. Nếu bạn không có quyền gì cả, bạn có thể sử dụng nó. Bởi vì nó không phải là ứng dụng của bạn mở máy ảnh. Sắc thái ở đây là nếu bạn có quyền và nếu người dùng từ chối quyền, thì việc sử dụng quyền này Intentnhư một phương án dự phòng sẽ ném ra SecurityException. Thông tin thêm: plus.google.com/+AndroidDevelopers/posts/e9kyM7VXajz
tasomaniac

2
Cho phép máy ảnh hiện nay là cần thiết để máy ảnh mở @tasomaniac ý
Saad Bilal

26
với ACTION_IMAGE_CAPTURE tôi nhận được imageReturnedIntent.getData () == null tại sao?
Xan

3
Theo tài liệu chính thức developer.android.com/training/camera/photobasics, chụp ảnh không lưu hình ảnh trong Uri được trả về từ intents getData (). Bạn chỉ có thể nhận được thu nhỏ từ kết quả dự định (intent.getBundle () nhận được ( "dữ liệu).) Hình ảnh kích thước đầy đủ có thể được ghi vào tập tin chuẩn bị cho mục đích này trước startActivityForResult được gọi..
marioc64

56

Tôi đã hợp nhất một số giải pháp để tận dụng hoàn toàn việc chọn hình ảnh từ Thư viện hoặc Máy ảnh. Đây là các tính năng của ImagePicker sử dụng ý chính (cũng trong một lib Github ):

  • Ý định hợp nhất cho các yêu cầu lại Thư viện và Máy ảnh.
  • Thay đổi kích thước hình ảnh lớn đã chọn (ví dụ: 2500 x 1600)
  • Xoay hình ảnh nếu cần thiết

Ảnh chụp màn hình:

Mục đích bắt đầu của ImagePicker

Chỉnh sửa : Đây là một đoạn mã để có được Ý định hợp nhất cho ứng dụng Thư viện và Máy ảnh với nhau. Bạn có thể xem mã đầy đủ tại ImagePicker use gist (cũng trong Github lib ):

public static Intent getPickImageIntent(Context context) {
    Intent chooserIntent = null;

    List<Intent> intentList = new ArrayList<>();

    Intent pickIntent = new Intent(Intent.ACTION_PICK,
            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    takePhotoIntent.putExtra("return-data", true);
    takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getTempFile(context)));
    intentList = addIntentsToList(context, intentList, pickIntent);
    intentList = addIntentsToList(context, intentList, takePhotoIntent);

    if (intentList.size() > 0) {
        chooserIntent = Intent.createChooser(intentList.remove(intentList.size() - 1),
                context.getString(R.string.pick_image_intent_text));
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new Parcelable[]{}));
    }

    return chooserIntent;
}

private static List<Intent> addIntentsToList(Context context, List<Intent> list, Intent intent) {
    List<ResolveInfo> resInfo = context.getPackageManager().queryIntentActivities(intent, 0);
    for (ResolveInfo resolveInfo : resInfo) {
        String packageName = resolveInfo.activityInfo.packageName;
        Intent targetedIntent = new Intent(intent);
        targetedIntent.setPackage(packageName);
        list.add(targetedIntent);
    }
    return list;
}

4
Nó hoạt động hoàn hảo, Mario. Cảm ơn bạn rất nhiều! Tôi đã thử nghiệm nó trong Samsung GT-I9100, LG L7, nhưng nó không thành công khi chúng tôi cố gắng đưa hình ảnh từ máy ảnh vào Nexus 6 với Android 6. Giải pháp sẽ là thêm dòng này vào dòng 58 của bạn trong ImagePicker.java:boolean isCamera = (imageReturnedIntent == null || imageReturnedIntent.getData() == null);
Gabi Moreno

1
Cảm ơn bạn @GabrielMorenoIbarra. Bạn đã sửa nó, bây giờ nó cũng có trong mã của tôi.
Mario Velasco

là gì getTempFilevà làm thế nào để sử dụng chức năng này? vui lòng cập nhật câu trả lời
Basheer AL-MOMANI

1
Nó là một chức năng để lấy một File tạm thời. Hãy xem để liên kết và bạn sẽ tìm thấy một kịch bản chi tiết hơn
Mario Velasco

1
@Brainware, vâng, nó phụ thuộc vào phiên bản Android. Cân nhắc sử dụng FileProvidercho API> = 23 và Uriít hơn.
CoolMind

19

Thư viện này làm cho nó đơn giản.

Chỉ cần gọi:

PickImageDialog.on(MainActivity.this, new PickSetup(BuildConfig.APPLICATION_ID));

Sau đó, thực hiện Hoạt động của bạn triển khai IPickResult và ghi đè phương thức bên dưới này.

@Override
public void onPickResult(PickResult r) {
    if (r.getError() == null) {
        imageView.setImageBitmap(r.getBitmap());

        //or

        imageView.setImageURI(r.getUri());
    } else {
        //Handle possible errors
        //TODO: do what you have to do with r.getError();
    }
}

Tôi có ảnh amazon trong điện thoại s7 edge của tôi khi tôi chọn tùy chọn thư viện, nó chuyển hướng đến trang đăng nhập amazon và trong các điện thoại khác, nó tốt .. nhưng tôi đang thử nghiệm trong s7 edge
nafees ahmed 25/12/18

Đây là cách tiếp cận rất lộn xộn, có thể ảnh hưởng đến toàn bộ mã. Không hiểu sao anh chàng lại tạo repo mvn riêng.
Joy

Điều này có cho phép chụp nhiều ảnh hay nhiều ảnh không?
Adnan

12

Bạn có thể triển khai mã này để chọn hình ảnh từ thư viện hoặc máy ảnh: -

private ImageView imageview;
private Button btnSelectImage;
private Bitmap bitmap;
private File destination = null;
private InputStream inputStreamImg;
private String imgPath = null;
private final int PICK_IMAGE_CAMERA = 1, PICK_IMAGE_GALLERY = 2;

Bây giờ trên sự kiện nhấp vào nút, bạn có thể gọi phương thức chọn Hình ảnh của mình. Đây là onCreate của hoạt động bên trong.

imageview = (ImageView) findViewById(R.id.imageview);
btnSelectImage = (Button) findViewById(R.id.btnSelectImage);

//OnbtnSelectImage click event...
btnSelectImage.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            selectImage();
        }
    });

Bên ngoài hoạt động của bạn oncreate.

// Select image from camera and gallery
private void selectImage() {
    try {
        PackageManager pm = getPackageManager();
        int hasPerm = pm.checkPermission(Manifest.permission.CAMERA, getPackageName());
        if (hasPerm == PackageManager.PERMISSION_GRANTED) {
            final CharSequence[] options = {"Take Photo", "Choose From Gallery","Cancel"};
            android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app.AlertDialog.Builder(activity);
            builder.setTitle("Select Option");
            builder.setItems(options, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int item) {
                    if (options[item].equals("Take Photo")) {
                        dialog.dismiss();
                        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                        startActivityForResult(intent, PICK_IMAGE_CAMERA);
                    } else if (options[item].equals("Choose From Gallery")) {
                        dialog.dismiss();
                        Intent pickPhoto = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                        startActivityForResult(pickPhoto, PICK_IMAGE_GALLERY);
                    } else if (options[item].equals("Cancel")) {
                        dialog.dismiss();
                    }
                }
            });
            builder.show();
        } else
            Toast.makeText(this, "Camera Permission error", Toast.LENGTH_SHORT).show();
    } catch (Exception e) {
        Toast.makeText(this, "Camera Permission error", Toast.LENGTH_SHORT).show();
        e.printStackTrace();
    }
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    inputStreamImg = null;
    if (requestCode == PICK_IMAGE_CAMERA) {
        try {
            Uri selectedImage = data.getData();
            bitmap = (Bitmap) data.getExtras().get("data");
            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 50, bytes);

            Log.e("Activity", "Pick from Camera::>>> ");

            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
            destination = new File(Environment.getExternalStorageDirectory() + "/" +
                    getString(R.string.app_name), "IMG_" + timeStamp + ".jpg");
            FileOutputStream fo;
            try {
                destination.createNewFile();
                fo = new FileOutputStream(destination);
                fo.write(bytes.toByteArray());
                fo.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            imgPath = destination.getAbsolutePath();
            imageview.setImageBitmap(bitmap);

        } catch (Exception e) {
            e.printStackTrace();
        }
    } else if (requestCode == PICK_IMAGE_GALLERY) {
        Uri selectedImage = data.getData();
        try {
            bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImage);
            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 50, bytes);
            Log.e("Activity", "Pick from Gallery::>>> ");

            imgPath = getRealPathFromURI(selectedImage);
            destination = new File(imgPath.toString());
            imageview.setImageBitmap(bitmap);

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

public String getRealPathFromURI(Uri contentUri) {
    String[] proj = {MediaStore.Audio.Media.DATA};
    Cursor cursor = managedQuery(contentUri, proj, null, null, null);
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
    cursor.moveToFirst();
    return cursor.getString(column_index);
}

Atlast, cuối cùng thêm máy ảnh và ghi quyền lưu trữ bên ngoài vào AndroidManifest.xml

Nó rất hiệu quả với tôi, hy vọng nó cũng sẽ hiệu quả với bạn.


1
Tôi thêm phép camera nhưng lỗi accure và hiển thị lỗi "cho phép máy ảnh"
Hosseini roghayeh

7

Tôi nghĩ rằng đó là tùy thuộc vào bạn để hiển thị hộp thoại đó để lựa chọn. Đối với Thư viện, bạn sẽ sử dụng mã đó và đối với Máy ảnh, hãy thử điều này .


1
Nhưng hình ảnh bị lộn ngược trong mẫu này
Sunny

3

Nếu bạn muốn lấy hình ảnh từ thư viện hoặc chụp hình ảnh và đặt nó ở chế độ xem ảnh ở chế độ dọc thì mã sau sẽ giúp bạn ..

Trong onCreate ()

imageViewRound.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            selectImage();
        }
    });




    private void selectImage() {
    Constants.iscamera = true;
    final CharSequence[] items = { "Take Photo", "Choose from Library",
            "Cancel" };

     TextView title = new TextView(context);
     title.setText("Add Photo!");
        title.setBackgroundColor(Color.BLACK);
        title.setPadding(10, 15, 15, 10);
        title.setGravity(Gravity.CENTER);
        title.setTextColor(Color.WHITE);
        title.setTextSize(22);


    AlertDialog.Builder builder = new AlertDialog.Builder(
            AddContactActivity.this);



    builder.setCustomTitle(title);

    // builder.setTitle("Add Photo!");
    builder.setItems(items, new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int item) {
            if (items[item].equals("Take Photo")) {
                // Intent intent = new
                // Intent(MediaStore.ACTION_IMAGE_CAPTURE);

                Intent intent = new Intent(
                        android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                /*
                 * File photo = new
                 * File(Environment.getExternalStorageDirectory(),
                 * "Pic.jpg"); intent.putExtra(MediaStore.EXTRA_OUTPUT,
                 * Uri.fromFile(photo)); imageUri = Uri.fromFile(photo);
                 */
                // startActivityForResult(intent,TAKE_PICTURE);

                Intent intents = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

                fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);

                intents.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

                // start the image capture Intent
                startActivityForResult(intents, TAKE_PICTURE);

            } else if (items[item].equals("Choose from Library")) {
                Intent intent = new Intent(
                        Intent.ACTION_PICK,
                        android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                intent.setType("image/*");
                startActivityForResult(
                        Intent.createChooser(intent, "Select Picture"),
                        SELECT_PICTURE);
            } else if (items[item].equals("Cancel")) {
                dialog.dismiss();
            }
        }
    });
    builder.show();
}




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

    switch (requestCode) {
    case SELECT_PICTURE:
        Bitmap bitmap = null;
        if (resultCode == RESULT_OK) {
            if (data != null) {


                try {
                    Uri selectedImage = data.getData();
                    String[] filePath = { MediaStore.Images.Media.DATA };
                    Cursor c = context.getContentResolver().query(
                            selectedImage, filePath, null, null, null);
                    c.moveToFirst();
                    int columnIndex = c.getColumnIndex(filePath[0]);
                    String picturePath = c.getString(columnIndex);
                    c.close();
                    imageViewRound.setVisibility(View.VISIBLE);
                    // Bitmap thumbnail =
                    // (BitmapFactory.decodeFile(picturePath));
                    Bitmap thumbnail = decodeSampledBitmapFromResource(
                            picturePath, 500, 500);

                    // rotated
                    Bitmap thumbnail_r = imageOreintationValidator(
                            thumbnail, picturePath);
                    imageViewRound.setBackground(null);
                    imageViewRound.setImageBitmap(thumbnail_r);
                    IsImageSet = true;
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        break;
    case TAKE_PICTURE:
        if (resultCode == RESULT_OK) {

            previewCapturedImage();

        }

        break;
    }

}



 @SuppressLint("NewApi")
private void previewCapturedImage() {
    try {
        // hide video preview

        imageViewRound.setVisibility(View.VISIBLE);

        // bimatp factory
        BitmapFactory.Options options = new BitmapFactory.Options();

        // downsizing image as it throws OutOfMemory Exception for larger
        // images
        options.inSampleSize = 8;

        final Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getPath(),
                options);

        Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, 500, 500,
                false);

        // rotated
        Bitmap thumbnail_r = imageOreintationValidator(resizedBitmap,
                fileUri.getPath());

        imageViewRound.setBackground(null);
        imageViewRound.setImageBitmap(thumbnail_r);
        IsImageSet = true;
        Toast.makeText(getApplicationContext(), "done", Toast.LENGTH_LONG)
                .show();
    } catch (NullPointerException e) {
        e.printStackTrace();
    }
}






    // for roted image......
private Bitmap imageOreintationValidator(Bitmap bitmap, String path) {

    ExifInterface ei;
    try {
        ei = new ExifInterface(path);
        int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_NORMAL);
        switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            bitmap = rotateImage(bitmap, 90);
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            bitmap = rotateImage(bitmap, 180);
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
            bitmap = rotateImage(bitmap, 270);
            break;
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

    return bitmap;
}



private Bitmap rotateImage(Bitmap source, float angle) {

    Bitmap bitmap = null;
    Matrix matrix = new Matrix();
    matrix.postRotate(angle);
    try {
        bitmap = Bitmap.createBitmap(source, 0, 0, source.getWidth(),
                source.getHeight(), matrix, true);
    } catch (OutOfMemoryError err) {
        source.recycle();
        Date d = new Date();
        CharSequence s = DateFormat
                .format("MM-dd-yy-hh-mm-ss", d.getTime());
        String fullPath = Environment.getExternalStorageDirectory()
                + "/RYB_pic/" + s.toString() + ".jpg";
        if ((fullPath != null) && (new File(fullPath).exists())) {
            new File(fullPath).delete();
        }
        bitmap = null;
        err.printStackTrace();
    }
    return bitmap;
}




public static Bitmap decodeSampledBitmapFromResource(String pathToFile,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(pathToFile, options);

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

    Log.e("inSampleSize", "inSampleSize______________in storage"
            + options.inSampleSize);
    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(pathToFile, options);
}




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) {

        // Calculate ratios of height and width to requested height and
        // width
        final int heightRatio = Math.round((float) height
                / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will
        // guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;

    }

    return inSampleSize;
}




public String getPath(Uri uri) {
    String[] projection = { MediaStore.Images.Media.DATA };
    Cursor cursor = managedQuery(uri, projection, null, null, null);
    int column_index = cursor
            .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    return cursor.getString(column_index);
}






private static File getOutputMediaFile(int type) {

    // External sdcard location
    File mediaStorageDir = new File(
            Environment
                    .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            IMAGE_DIRECTORY_NAME);

    // Create the storage directory if it does not exist
    if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.d(IMAGE_DIRECTORY_NAME, "Oops! Failed create "
                    + IMAGE_DIRECTORY_NAME + " directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
            Locale.getDefault()).format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator
                + "IMG_" + timeStamp + ".jpg");
    } else {
        return null;
    }

    return mediaFile;
}






public Uri getOutputMediaFileUri(int type) {
    return Uri.fromFile(getOutputMediaFile(type));
}

Hy vọng điều này sẽ giúp bạn....!!!

Nếu targetSdkVersion cao hơn 24, thì FileProvider sẽ được sử dụng để cấp quyền truy cập.

Tạo tệp xml (Đường dẫn: res \ xml) provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

Thêm nhà cung cấp trong AndroidManifest.xml

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths"/>
</provider>

và thay thế

return Uri.fromFile(getOutputMediaFile(type));

Đến

               return FileProvider.getUriForFile(this,  BuildConfig.APPLICATION_ID + ".provider", getOutputMediaFile(type));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.