从图库或相机中选择图像的对话框

Posted

技术标签:

【中文标题】从图库或相机中选择图像的对话框【英文标题】:Dialog to pick image from gallery or from camera 【发布时间】:2012-04-27 06:17:28 【问题描述】:

是否有标准的方式来调用对话框,选择从相机中选择图像或从图库中获取图像(如在内置电话簿或 Skype 中)?

我查看了this,但代码打开了图库,但没有建议从相机中选择它。

设备:三星 Galaxy Tab 安卓:2.3.3

【问题讨论】:

看看这个答案,意图将两个请求(相机和画廊)合并到一个独特的意图中:***.com/a/32475805/2232889 【参考方案1】:

下面的代码可用于拍照和挑选照片。只需显示一个包含两个选项的对话框,并在选择后使用适当的代码。

从相机拍照:

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

从图库中挑选照片:

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代码:

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;
    

最后在清单文件中添加这个权限:

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

【讨论】:

不需要相机权限,因为它会打开默认应用程序。 @Jeremy 不,那是错误的。如果您根本没有权限,则可以使用它。因为打开相机的不是您的应用程序。细微差别是,如果您拥有权限并且用户拒绝了该权限,则使用此 Intent 作为后备将引发 SecurityException。更多信息:plus.google.com/+AndroidDevelopers/posts/e9kyM7VXajz 现在需要相机权限才能打开相机意图@tasomaniac 使用 ACTION_IMAGE_CAPTURE 我收到 imageReturnedIntent.getData() == null 为什么? 根据官方文档developer.android.com/training/camera/photobasics拍照不会将图像保存在从意图getData()返回的Uri中。您只能从结果意图 (intent.getBundle().get("data)) 中获取缩略图。在调用 startActivityForResult 之前,可以将全尺寸图像写入为此目的准备的文件。【参考方案2】:

我已经合并了一些解决方案,以制作一个完整的工具,用于从图库或相机中挑选图像。这些是ImagePicker util gist 的功能(也在Github lib 中):

图库和相机请求的合并意图。 调整所选大图像的大小(例如:2500 x 1600) 必要时旋转图像

截图:

编辑:这里有一段代码用于将图库和相机应用的 Intent 合并在一起。 你可以在ImagePicker util gist(也可以在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;

【讨论】:

完美运行,马里奥。太感谢了!我在三星 GT-I9100、LG L7 上对其进行了测试,但是当我们尝试将来自相机的图像放入装有 Android 6 的 Nexus 6 中时它失败了。解决方案是将其添加到 ImagePicker.java 中的 58 行:@ 987654328@ 谢谢@GabrielMorenoIbarra。你修复了它,现在它也在我的代码中。 getTempFile是什么以及如何使用这个功能?请更新答案 获取临时文件的函数。看一下链接,你会发现更详细的脚本 @Brainware,是的,这取决于 Android 版本。考虑对 API >= 23 使用 FileProvider 并为更少使用 Uri【参考方案3】:

This 库让它变得简单。

打电话:

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

然后让你的 Activity 实现 IPickResult 并覆盖下面的方法。

@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();
    

【讨论】:

我的手机 s7 edge 中有亚马逊照片,当我选择图库选项时,它会重定向到亚马逊登录页面,在其他手机中它很好.. 但我正在 s7 edge 中进行测试 这是一种非常混乱的方法,可能会影响整个代码。不知道为什么这家伙创建了单独的 mvn repo。 这是否允许多选或多捕获图像?【参考方案4】:

您可以实现此代码以从图库或相机中选择图像:-

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;

现在在按钮单击事件上,您可以调用选择图像的方法。这是活动的 onCreate 内部。

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();
        
    );

在您的活动的 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);

最后,最后添加摄像头并将外部存储权限写入AndroidManifest.xml

它对我很有用,希望它也对你有用。

【讨论】:

我添加了摄像头权限但出现错误并显示“摄像头权限错误”【参考方案5】:

如果您想从图库中获取图像或捕获图像并将其设置为纵向模式的图像视图,那么以下代码将为您提供帮助..

在 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));

希望对您有所帮助....!!!

如果 targetSdkVersion 高于 24,则使用 FileProvider 授予访问权限。

创建一个xml文件(路径: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>

在AndroidManifest.xml中添加一个Provider

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

替换

return Uri.fromFile(getOutputMediaFile(type));

               return FileProvider.getUriForFile(this,  BuildConfig.APPLICATION_ID + ".provider", getOutputMediaFile(type));

【讨论】:

MediaStore.Images.Media.DATA 已弃用更新答案。

以上是关于从图库或相机中选择图像的对话框的主要内容,如果未能解决你的问题,请参考以下文章

在 WebView 中从相机或图库上传图像

Android - 如何从相机捕获图像或从库中添加

Android:单击相机中的图像并在对话框中显示图像

捕获图像并动态添加到网格视图

从相机中选择图像时无法交付结果,但从图库中选择图像时没有问题

文件上传选项以从相机拍摄图像或从图库中选择不适用于 Mozilla Firefox 中的 Web 应用程序