내 응용 프로그램 내부의 갤러리 내장 앱에서 이미지 / 사진을 열려고합니다.
사진 URI가 있습니다 (사진은 SD 카드에 있습니다).
의견 있으십니까?
답변
이것은 완벽한 솔루션입니다. 나는이 예제 코드를 @mad의 아래 답변에 제공된 정보로 업데이트했습니다. 또한 picasa 이미지를 처리하는 방법을 설명하는 @Khobaib의 아래 솔루션을 확인하십시오.
최신 정보
방금 원래 답변을 검토하고 github에서 체크 아웃하고 시스템에서 직접 가져올 수있는 간단한 Android Studio 프로젝트를 만들었습니다.
https://github.com/hanscappelle/SO-2169649
(여러 파일 선택 작업이 여전히 필요함)
단일 사진 선택
사용자 mad 덕분에 파일 탐색기의 이미지를 지원합니다.
public class BrowsePictureActivity extends Activity {
// this is the action code we use in our intent,
// this way we know we're looking at the response from our own action
private static final int SELECT_PICTURE = 1;
private String selectedImagePath;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.Button01)
.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// in onCreate or any event where your want the user to
// select a file
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
}
}
}
/**
* helper to retrieve the path of an image URI
*/
public String getPath(Uri uri) {
// just some safety built in
if( uri == null ) {
// TODO perform some logging or show user feedback
return null;
}
// try to retrieve the image from the media store first
// this will only work for images selected from gallery
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if( cursor != null ){
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path = cursor.getString(column_index);
cursor.close();
return path;
}
// this is our fallback here
return uri.getPath();
}
}
여러 사진 선택
누군가가 의견에 해당 정보를 요청했기 때문에 정보를 수집하는 것이 좋습니다.
EXTRA_ALLOW_MULTIPLE
의도에 추가 매개 변수 를 설정하십시오 .
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
그리고 해당 매개 변수에 대한 결과 처리 확인에서 :
if (Intent.ACTION_SEND_MULTIPLE.equals(data.getAction()))
&& Intent.hasExtra(Intent.EXTRA_STREAM)) {
// retrieve a collection of selected images
ArrayList<Parcelable> list = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
// iterate over these images
if( list != null ) {
for (Parcelable parcel : list) {
Uri uri = (Uri) parcel;
// TODO handle the images one by one here
}
}
}
이것은 API 레벨 18+에서만 지원됩니다.
답변
다음은 hcpl이 게시 한 고급 코드에 대한 업데이트입니다. 그러나 이것은 OI 파일 관리자, 천체 파일 관리자 및 미디어 갤러리에서도 작동합니다 (테스트). 그래서 나는 그것이 모든 파일 관리자와 함께 작동 할 것이라고 생각합니다 (언급 된 것보다 많은 다른 것들이 있습니까?). 그가 작성한 코드를 약간 수정했습니다.
public class BrowsePicture extends Activity {
//YOU CAN EDIT THIS TO WHATEVER YOU WANT
private static final int SELECT_PICTURE = 1;
private String selectedImagePath;
//ADDED
private String filemanagerstring;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((Button) findViewById(R.id.Button01))
.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// in onCreate or any event where your want the user to
// select a file
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
}
});
}
//UPDATED
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
//OI FILE Manager
filemanagerstring = selectedImageUri.getPath();
//MEDIA GALLERY
selectedImagePath = getPath(selectedImageUri);
//DEBUG PURPOSE - you can delete this if you want
if(selectedImagePath!=null)
System.out.println(selectedImagePath);
else System.out.println("selectedImagePath is null");
if(filemanagerstring!=null)
System.out.println(filemanagerstring);
else System.out.println("filemanagerstring is null");
//NOW WE HAVE OUR WANTED STRING
if(selectedImagePath!=null)
System.out.println("selectedImagePath is the right one for you!");
else
System.out.println("filemanagerstring is the right one for you!");
}
}
}
//UPDATED!
public String getPath(Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if(cursor!=null)
{
//HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL
//THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
else return null;
}
답변
hcpl의 메소드는 KitKat 이전에는 완벽하게 작동하지만 DocumentsProvider API에서는 작동하지 않습니다. 그건 그냥 단순히 documentproviders의 공식 안드로이드 튜토리얼을 따라 들어 : https://developer.android.com/guide/topics/providers/document-provider.html를 -> 문서, 비트 맵 섹션을 엽니 다.
간단히 hcpl의 코드를 사용하여 확장했습니다. 이미지에 대한 검색 경로가있는 파일에서 예외가 발생하면이 함수를 호출합니다.
private Bitmap getBitmapFromUri(Uri uri) throws IOException {
ParcelFileDescriptor parcelFileDescriptor =
getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return image;
}
Nexus 5에서 테스트되었습니다.
답변
위의 코드를 기준으로 아래 코드를 반영하면 더 적합 할 수 있습니다.
public String getPath(Uri uri) {
String selectedImagePath;
//1:MEDIA GALLERY --- query from MediaStore.Images.Media.DATA
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if(cursor != null){
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
selectedImagePath = cursor.getString(column_index);
}else{
selectedImagePath = null;
}
if(selectedImagePath == null){
//2:OI FILE Manager --- call method: uri.getPath()
selectedImagePath = uri.getPath();
}
return selectedImagePath;
}
답변
@hcpl & @mad의 솔루션을 살펴 보았습니다. hcpl의 솔루션은 갤러리에서 로컬 이미지를 잘 지원하고 mad는 더 나은 솔루션을 제공합니다 .OI / Astro / Dropbox 이미지도로드하는 데 도움이됩니다. 하지만 내 앱에서 작업하는 동안 picasa 라이브러리 에서 이제 Android 갤러리에 통합 된 두 솔루션이 모두 실패합니다.
나는 조금 검색하고 분석했으며 결국이 한계를 극복하는 더 좋고 우아한 솔루션을 제공했습니다. 이 경우에 도움 이 된 Dimitar Darazhanski 의 블로그 덕분에 이해하기 쉽게 약간 수정했습니다. 내 해결책은 다음과 같습니다.
public class BrowsePicture extends Activity {
//YOU CAN EDIT THIS TO WHATEVER YOU WANT
private static final int SELECT_PICTURE = 1;
private String selectedImagePath;
//ADDED
private String filemanagerstring;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((Button) findViewById(R.id.Button01))
.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// in onCreate or any event where your want the user to
// select a file
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
Log.d("URI VAL", "selectedImageUri = " + selectedImageUri.toString());
selectedImagePath = getPath(selectedImageUri);
if(selectedImagePath!=null){
// IF LOCAL IMAGE, NO MATTER IF ITS DIRECTLY FROM GALLERY (EXCEPT PICASSA ALBUM),
// OR OI/ASTRO FILE MANAGER. EVEN DROPBOX IS SUPPORTED BY THIS BECAUSE DROPBOX DOWNLOAD THE IMAGE
// IN THIS FORM - file:///storage/emulated/0/Android/data/com.dropbox.android/...
System.out.println("local image");
}
else{
System.out.println("picasa image!");
loadPicasaImageFromGallery(selectedImageUri);
}
}
}
}
// NEW METHOD FOR PICASA IMAGE LOAD
private void loadPicasaImageFromGallery(final Uri uri) {
String[] projection = { MediaColumns.DATA, MediaColumns.DISPLAY_NAME };
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if(cursor != null) {
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME);
if (columnIndex != -1) {
new Thread(new Runnable() {
// NEW THREAD BECAUSE NETWORK REQUEST WILL BE MADE THAT WILL BE A LONG PROCESS & BLOCK UI
// IF CALLED IN UI THREAD
public void run() {
try {
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
// THIS IS THE BITMAP IMAGE WE ARE LOOKING FOR.
} catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
}
}
cursor.close();
}
public String getPath(Uri uri) {
String[] projection = { MediaColumns.DATA};
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if(cursor != null) {
//HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL
//THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndexOrThrow(MediaColumns.DATA);
String filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
}
else
return uri.getPath(); // FOR OI/ASTRO/Dropbox etc
}
문제를 확인하고 알려주십시오. 나는 그것을 테스트했으며 모든 경우에 잘 작동합니다.
이것이 모두에게 도움이되기를 바랍니다.
답변
SD 카드 디렉토리에 이미지 전용 이미지 폴더 가 있다고 가정 하십시오.
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// tells your intent to get the contents
// opens the URI for your image directory on your sdcard
intent.setType("file:///sdcard/image/*");
startActivityForResult(intent, 1);
그런 다음 활동에서 다시 컨텐츠로 수행 할 작업을 결정할 수 있습니다.
이것은 이미지의 경로 이름을 검색하고 코드로 테스트하여 결과가 다시 나타날 수 있는지 확인하는 예제입니다. 필요에 따라 코드를 변경할 수 있습니다.
protected final void onActivityResult(final int requestCode, final int
resultCode, final Intent i) {
super.onActivityResult(requestCode, resultCode, i);
// this matches the request code in the above call
if (requestCode == 1) {
Uri _uri = i.getData();
// this will be null if no image was selected...
if (_uri != null) {
// now we get the path to the image file
cursor = getContentResolver().query(_uri, null,
null, null, null);
cursor.moveToFirst();
String imageFilePath = cursor.getString(0);
cursor.close();
}
}
내 조언은 이미지가 올바르게 작동하도록 노력하는 것입니다. 문제는 SD 카드의 이미지에 액세스하는 내용이라고 생각합니다. SD 카드에 이미지 표시 하기를 살펴보십시오 .
올바른 공급자를 제공하는 예를 통해이를 시작하고 실행할 수 있다면 코드에 대한 해결 방법을 찾을 수 있어야합니다.
진행 상황에 따라이 질문을 업데이트하여 계속 업데이트하십시오. 행운을 빕니다
답변
이것은이 주제에 대한 나의 방문이며, 여기에있는 모든 정보와 다른 관련 스택 오버플로 질문을 수집합니다. 메모리 부족 조건 및 이미지 회전을 처리하면서 일부 공급자의 이미지를 반환합니다. 드롭 박스와 같은 갤러리, picasa 및 파일 관리자를 지원합니다. 사용법은 간단합니다. 입력으로 생성자가 콘텐츠 확인자와 URI를받습니다. 출력은 최종 비트 맵입니다.
/**
* Creates resized images without exploding memory. Uses the method described in android
* documentation concerning bitmap allocation, which is to subsample the image to a smaller size,
* close to some expected size. This is required because the android standard library is unable to
* create a reduced size image from an image file using memory comparable to the final size (and
* loading a full sized multi-megapixel picture for processing may exceed application memory budget).
*/
public class UserPicture {
static int MAX_WIDTH = 600;
static int MAX_HEIGHT = 800;
Uri uri;
ContentResolver resolver;
String path;
Matrix orientation;
int storedHeight;
int storedWidth;
public UserPicture(Uri uri, ContentResolver resolver) {
this.uri = uri;
this.resolver = resolver;
}
private boolean getInformation() throws IOException {
if (getInformationFromMediaDatabase())
return true;
if (getInformationFromFileSystem())
return true;
return false;
}
/* Support for gallery apps and remote ("picasa") images */
private boolean getInformationFromMediaDatabase() {
String[] fields = { Media.DATA, ImageColumns.ORIENTATION };
Cursor cursor = resolver.query(uri, fields, null, null, null);
if (cursor == null)
return false;
cursor.moveToFirst();
path = cursor.getString(cursor.getColumnIndex(Media.DATA));
int orientation = cursor.getInt(cursor.getColumnIndex(ImageColumns.ORIENTATION));
this.orientation = new Matrix();
this.orientation.setRotate(orientation);
cursor.close();
return true;
}
/* Support for file managers and dropbox */
private boolean getInformationFromFileSystem() throws IOException {
path = uri.getPath();
if (path == null)
return false;
ExifInterface exif = new ExifInterface(path);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
this.orientation = new Matrix();
switch(orientation) {
case ExifInterface.ORIENTATION_NORMAL:
/* Identity matrix */
break;
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
this.orientation.setScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
this.orientation.setRotate(180);
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
this.orientation.setScale(1, -1);
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
this.orientation.setRotate(90);
this.orientation.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_90:
this.orientation.setRotate(90);
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
this.orientation.setRotate(-90);
this.orientation.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
this.orientation.setRotate(-90);
break;
}
return true;
}
private boolean getStoredDimensions() throws IOException {
InputStream input = resolver.openInputStream(uri);
Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(resolver.openInputStream(uri), null, options);
/* The input stream could be reset instead of closed and reopened if it were possible
to reliably wrap the input stream on a buffered stream, but it's not possible because
decodeStream() places an upper read limit of 1024 bytes for a reset to be made (it calls
mark(1024) on the stream). */
input.close();
if (options.outHeight <= 0 || options.outWidth <= 0)
return false;
storedHeight = options.outHeight;
storedWidth = options.outWidth;
return true;
}
public Bitmap getBitmap() throws IOException {
if (!getInformation())
throw new FileNotFoundException();
if (!getStoredDimensions())
throw new InvalidObjectException(null);
RectF rect = new RectF(0, 0, storedWidth, storedHeight);
orientation.mapRect(rect);
int width = (int)rect.width();
int height = (int)rect.height();
int subSample = 1;
while (width > MAX_WIDTH || height > MAX_HEIGHT) {
width /= 2;
height /= 2;
subSample *= 2;
}
if (width == 0 || height == 0)
throw new InvalidObjectException(null);
Options options = new Options();
options.inSampleSize = subSample;
Bitmap subSampled = BitmapFactory.decodeStream(resolver.openInputStream(uri), null, options);
Bitmap picture;
if (!orientation.isIdentity()) {
picture = Bitmap.createBitmap(subSampled, 0, 0, options.outWidth, options.outHeight,
orientation, false);
subSampled.recycle();
} else
picture = subSampled;
return picture;
}
}
참고 문헌 :