2010-05-07 3 views
73

Я пытаюсь получить изображение из галереи.android получить реальный путь Uri.getPath()

Intent intent = new Intent(); 
intent.setType("image/*"); 
intent.setAction(Intent.ACTION_GET_CONTENT); 
startActivityForResult(Intent.createChooser(intent, "Select picture"), resultCode); 

После того, как я вернулся из этой деятельности, у меня есть данные, которые содержат Uri. Это выглядит следующим образом:

content://media/external/images/1 

Как я могу преобразовать этот путь к реальному (так же, как «/sdcard/image.png»)?

Thanks

+1

Это, очевидно, очень поздно комментарий, но я просто хотел бы отметить, что метод startActivityForResultCode принимает код запроса в качестве аргумента, а не код результата. –

+0

сделал 'uri.getPath()' не дал вам реальный путь? – Darpan

ответ

47

Действительно ли вам необходимо получить физический путь?
Например, ImageView.setImageURI() и ContentResolver.openInputStream() позволяют получить доступ к содержимому файла, не зная его реального пути.

+0

Это именно то, что я искал, но не смог найти. Благодарю. – davs

+3

Извините, и если я хочу, чтобы преобразовать это изображение в файл, не получая реальный путь, как это сделать? – Chlebta

+3

Физический путь предоставляет доступ к имени файла и расширению. В случае загрузки файлов. – Clocker

165

Это то, что я делаю:

Uri selectedImageURI = data.getData(); 
imageFile = new File(getRealPathFromURI(selectedImageURI)); 

и:

private String getRealPathFromURI(Uri contentURI) { 
    String result; 
    Cursor cursor = getContentResolver().query(contentURI, null, null, null, null); 
    if (cursor == null) { // Source is Dropbox or other similar local file path 
     result = contentURI.getPath(); 
    } else { 
     cursor.moveToFirst(); 
     int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); 
     result = cursor.getString(idx); 
     cursor.close(); 
    } 
    return result; 
} 

Примечание: managedQuery() метод устарел, поэтому я его не использую.

Последнее изменение: Улучшение. Мы должны закрыть курсор!

+0

Большое спасибо за это - я сделал небольшое обновление в своем ответе ниже. Если вы отредактируете свое, я удалю свою. –

+0

@ChrisR сделано! И тебе спасибо! – cesards

+1

http://stackoverflow.com/a/7265235/375093 Это еще один вариант, но предлагается как лучше, чем выше. Проверьте это тоже – Sundeep

14

@Rene Juuse - выше в комментариях ... Спасибо за эту ссылку!

. код для получения реального пути немного отличается от одного SDK к другому, поэтому ниже у нас есть три метода, которые касаются разных SDK.

getRealPathFromURI_API19(): возвращает реальный путь для API 19 (или выше, но не тестировалось) getRealPathFromURI_API11to18(): возвращает реальный путь для API 11 к API 18 getRealPathFromURI_below11(): возвращает реальный путь для API ниже 11

public class RealPathUtil { 

@SuppressLint("NewApi") 
public static String getRealPathFromURI_API19(Context context, Uri uri){ 
    String filePath = ""; 
    String wholeID = DocumentsContract.getDocumentId(uri); 

    // Split at colon, use second item in the array 
    String id = wholeID.split(":")[1]; 

    String[] column = { MediaStore.Images.Media.DATA };  

    // where id is equal to    
    String sel = MediaStore.Images.Media._ID + "=?"; 

    Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
           column, sel, new String[]{ id }, null); 

    int columnIndex = cursor.getColumnIndex(column[0]); 

    if (cursor.moveToFirst()) { 
     filePath = cursor.getString(columnIndex); 
    } 
    cursor.close(); 
    return filePath; 
} 


@SuppressLint("NewApi") 
public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) { 
     String[] proj = { MediaStore.Images.Media.DATA }; 
     String result = null; 

     CursorLoader cursorLoader = new CursorLoader(
       context, 
     contentUri, proj, null, null, null);   
     Cursor cursor = cursorLoader.loadInBackground(); 

     if(cursor != null){ 
     int column_index = 
     cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 
     cursor.moveToFirst(); 
     result = cursor.getString(column_index); 
     } 
     return result; 
} 

public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri){ 
      String[] proj = { MediaStore.Images.Media.DATA }; 
      Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null); 
      int column_index 
     = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 
      cursor.moveToFirst(); 
      return cursor.getString(column_index); 
} 

шрифта: http://hmkcode.com/android-display-selected-image-and-its-real-path/


ОБНОВЛЕНИЕ 201 6 марта

Чтобы устранить все проблемы с путями изображений, я попробую создать собственную галерею как facebook и другие приложения. Это связано с тем, что вы можете использовать только локальные файлы (реальные файлы, а не виртуальные или временные), я решаю все проблемы с этой библиотекой.

https://github.com/nohana/Laevatein (эта библиотека должны взять фото с камеры или выбрать из галереи, если вы выбираете из галереи он есть ящик с альбомами и просто показать локальные файлы)

+1

API> = 19 не работает на LG G3 работает 5.1 – Clocker

+0

@Clocker на Samsung S4 ни – Ricardo

+0

Им действительно сложно управлять всеми типами исходных изображений в Android.Если вы загружаете или выбираете галерею, лучшее решение создается в виде галереи из facebook. Его обычная галерея с реальными изображениями на устройстве, без виртуальных или временных. Я исправляю все проблемы в своем приложении, используя эту библиотеку. https://github.com/nohana/Laevatein Его действительно хорошая библиотека. Настройка не простая, но вы можете открыть код и внести свои изменения. Я надеюсь это тебе поможет. – luizfelipetx

10

Примечания Этого улучшения в @user3516549 answer и Я проверил его на Moto G3 с Android 6.0.1
У меня есть эта проблема, поэтому я попытался ответить на вопрос @ user3516549, но в некоторых случаях он работал неправильно. Я нашел это в Android 6.0 (или выше), когда мы начинаем галерею изображения выбрать умысел, то экран откроется, который показывает последние изображения, если пользователь выбрал изображение из этого списка мы получим URI, как

content://com.android.providers.media.documents/document/image%3A52530 

а если пользователь выбрал галерею из выдвижного ящика вместо последнее время, то мы получим, как

URI
content://media/external/images/media/52530 

так я справиться с этим в getRealPathFromURI_API19()

public static String getRealPathFromURI_API19(Context context, Uri uri) { 
     String filePath = ""; 
     if (uri.getHost().contains("com.android.providers.media")) { 
      // Image pick from recent 
      String wholeID = DocumentsContract.getDocumentId(uri); 

      // Split at colon, use second item in the array 
      String id = wholeID.split(":")[1]; 

      String[] column = {MediaStore.Images.Media.DATA}; 

      // where id is equal to 
      String sel = MediaStore.Images.Media._ID + "=?"; 

      Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
        column, sel, new String[]{id}, null); 

      int columnIndex = cursor.getColumnIndex(column[0]); 

      if (cursor.moveToFirst()) { 
       filePath = cursor.getString(columnIndex); 
      } 
      cursor.close(); 
      return filePath; 
     } else { 
      // image pick from gallery 
      return getRealPathFromURI_BelowAPI11(context,uri) 
     } 

    } 

EDIT: если вы пытаетесь получить путь к изображению файла во внешнем SDCard в более высокой версии, то проверьте my question

+0

Привет, друг, это правда. но это происходит, потому что теперь у Google есть формат по умолчанию для загрузки всех фотографий с вашего телефона в документы Google. И просто сохраните значок в телефоне. Если вы получите этот uri из документов Google, вам необходимо загрузить фотографию, прежде чем использовать ее. Это не хорошо в целом. Итак, чтобы исправить все проблемы здесь, теперь я использую эту библиотеку. (эта библиотека просто использует локальные файлы, и с этим решением ваши проблемы будут решены), или вы можете извлечь код из библиотеки и улучшить себя, чтобы принять участие в вашей проблеме. https://github.com/nohana/Laevatein Надеюсь, это может вам помочь. – luizfelipetx

+0

1+, Его работа идеально подходит для меня. Поскольку @JaiprakasSoni сказал в своем ответе, что я столкнулся с такой же проблемой, когда я запускаю свое приложение в Moto G4, но когда я использую код выше, он отлично работает для меня. Спасибо вам. Вы сохраняете мое время – Shailesh

+0

Эта работа для меня на зефире 6.0 – androidXP

1

Hii здесь мой полный код для съемки изображения с камеры или galeery

// Моя переменная декларация

protected static final int CAMERA_REQUEST = 0; 
    protected static final int GALLERY_REQUEST = 1; 
    Bitmap bitmap; 
    Uri uri; 
    Intent picIntent = null; 

// OnClick

if (v.getId()==R.id.image_id){ 
      startDilog(); 
     } 

// тело метода

private void startDilog() { 
    AlertDialog.Builder myAlertDilog = new AlertDialog.Builder(yourActivity.this); 
    myAlertDilog.setTitle("Upload picture option.."); 
    myAlertDilog.setMessage("Where to upload picture????"); 
    myAlertDilog.setPositiveButton("Gallery", new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      picIntent = new Intent(Intent.ACTION_GET_CONTENT,null); 
      picIntent.setType("image/*"); 
      picIntent.putExtra("return_data",true); 
      startActivityForResult(picIntent,GALLERY_REQUEST); 
     } 
    }); 
    myAlertDilog.setNegativeButton("Camera", new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      picIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
      startActivityForResult(picIntent,CAMERA_REQUEST); 
     } 
    }); 
    myAlertDilog.show(); 
} 

// А остальные вещи

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 
    if (requestCode==GALLERY_REQUEST){ 
     if (resultCode==RESULT_OK){ 
      if (data!=null) { 
       uri = data.getData(); 
       BitmapFactory.Options options = new BitmapFactory.Options(); 
       options.inJustDecodeBounds = true; 
       try { 
        BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options); 
        options.inSampleSize = calculateInSampleSize(options, 100, 100); 
        options.inJustDecodeBounds = false; 
        Bitmap image = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options); 
        imageofpic.setImageBitmap(image); 
       } catch (FileNotFoundException e) { 
        e.printStackTrace(); 
       } 
      }else { 
       Toast.makeText(getApplicationContext(), "Cancelled", 
         Toast.LENGTH_SHORT).show(); 
      } 
     }else if (resultCode == RESULT_CANCELED) { 
      Toast.makeText(getApplicationContext(), "Cancelled", 
        Toast.LENGTH_SHORT).show(); 
     } 
    }else if (requestCode == CAMERA_REQUEST) { 
     if (resultCode == RESULT_OK) { 
      if (data.hasExtra("data")) { 
       bitmap = (Bitmap) data.getExtras().get("data"); 
       uri = getImageUri(YourActivity.this,bitmap); 
       File finalFile = new File(getRealPathFromUri(uri)); 
       imageofpic.setImageBitmap(bitmap); 
      } else if (data.getExtras() == null) { 

       Toast.makeText(getApplicationContext(), 
         "No extras to retrieve!", Toast.LENGTH_SHORT) 
         .show(); 

       BitmapDrawable thumbnail = new BitmapDrawable(
         getResources(), data.getData().getPath()); 
       pet_pic.setImageDrawable(thumbnail); 

      } 

     } else if (resultCode == RESULT_CANCELED) { 
      Toast.makeText(getApplicationContext(), "Cancelled", 
        Toast.LENGTH_SHORT).show(); 
     } 
    } 
} 

private String getRealPathFromUri(Uri tempUri) { 
    Cursor cursor = null; 
    try { 
     String[] proj = { MediaStore.Images.Media.DATA }; 
     cursor = this.getContentResolver().query(tempUri, proj, null, null, null); 
     int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 
     cursor.moveToFirst(); 
     return cursor.getString(column_index); 
    } finally { 
     if (cursor != null) { 
      cursor.close(); 
     } 
    } 
} 
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 Uri getImageUri(YourActivity youractivity, Bitmap bitmap) { 
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream); 
    String path = MediaStore.Images.Media.insertImage(youractivity.getContentResolver(), bitmap, "Title", null); 
    return Uri.parse(path); 
} 
+0

Как вы знаете, это 100 в этой строке 'options.inSampleSize = calculateInSampleSize (опции, 100, 100);' –

5

EDIT: Используйте это решение здесь: https://stackoverflow.com/a/20559175/2033223 Работает отлично!

Прежде, спасибо за ваше решение @luizfelipetx

Я изменил ваше решение немного. Это работает для меня:

public static String getRealPathFromDocumentUri(Context context, Uri uri){ 
    String filePath = ""; 

    Pattern p = Pattern.compile("(\\d+)$"); 
    Matcher m = p.matcher(uri.toString()); 
    if (!m.find()) { 
     Log.e(ImageConverter.class.getSimpleName(), "ID for requested image not found: " + uri.toString()); 
     return filePath; 
    } 
    String imgId = m.group(); 

    String[] column = { MediaStore.Images.Media.DATA }; 
    String sel = MediaStore.Images.Media._ID + "=?"; 

    Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
      column, sel, new String[]{ imgId }, null); 

    int columnIndex = cursor.getColumnIndex(column[0]); 

    if (cursor.moveToFirst()) { 
     filePath = cursor.getString(columnIndex); 
    } 
    cursor.close(); 

    return filePath; 
} 

Примечание: Таким образом, мы получили документы и изображения, в зависимости, если изображение получается из «списка недавних», «галерея» или каких-либо. Поэтому сначала я извлекаю идентификатор изображения, прежде чем искать его.

4

Как известно реальным программистам, нет реального пути.

A Uri с кодом content - непрозрачная ручка для некоторого контента. Если это Uri представляет открываемый контент, вы можете использовать ContentResolver и openInputStream(), чтобы получить InputStream. Аналогичным образом, Uri с схемой http или https не представляет собой локальный файл, и для его доступа вам потребуется использовать API-интерфейс HTTP-клиента.

Только Uri с кодом file идентифицирует файл (запрещающие случаи, когда файл был перемещен или удален после создания Uri).

Какие глупые люди пытаются попытаться получить путь к файловой системе, пытаясь декодировать содержимое Uri, возможно, в сочетании с заклинаниями заклинания для вызова $EVIL_DEITY.В лучшем случае, это будет ненадежным, по трем причинам:

  1. правила для декодирования Uri значения может изменяться с течением времени, например, с Android версии выпусков, в структуре Uri представляет деталь реализации, не интерфейс

  2. Даже если вы получите путь в файловой системе, вы не можете иметь права на доступ к файлу

  3. не все Uri значения могут быть расшифрованы с помощью фиксированных алгоритмов, так как многие приложения имеют свои собственные поставщики, и те, может пои нт все, от активов BLOB столбцов в данных, которые должны быть переданы потоком из Интернета

Нет проявитель с здравым смыслом не идет по этому пути.

Если у вас есть ограниченный API, для которого требуется файл, используйте InputStream от openInputStream(), чтобы сделать копию этого контента. Независимо от того, является ли это временной копией (например, используется для операции загрузки файла, затем удаляется) или долговечной копией (например, для функции «импорта» вашего приложения) зависит от вас.

Смежные вопросы