Android ACTION_IMAGE_CAPTURE Intent
Мы пытаемся использовать собственное приложение для камеры, чтобы пользователь мог сделать новое изображение. Он отлично работает, если оставить EXTRA_OUTPUT extra
и вернуть небольшое изображение растрового изображения. Однако, если мы putExtra(EXTRA_OUTPUT,...)
в намерении перед запуском, все работает, пока вы не попытаетесь нажать кнопку "ОК" в приложении камеры. Кнопка "ОК" просто ничего не делает. Приложение камеры остается открытым и ничего не блокируется. Мы можем отказаться от него, но файл никогда не записывается. Что именно нам нужно сделать, чтобы получить ACTION_IMAGE_CAPTURE
, чтобы записать снимок, сделанный в файл?
Изменить: это делается с помощью намерения MediaStore.ACTION_IMAGE_CAPTURE
, чтобы быть четким
Ответы
Ответ 1
это хорошо документированная ошибка в некоторых версиях android. т.е. при сборке google на основе android, захват изображения не работает, как документировано. то, что я обычно использовал, это что-то вроде этого в классе утилит.
public boolean hasImageCaptureBug() {
// list of known devices that have the bug
ArrayList<String> devices = new ArrayList<String>();
devices.add("android-devphone1/dream_devphone/dream");
devices.add("generic/sdk/generic");
devices.add("vodafone/vfpioneer/sapphire");
devices.add("tmobile/kila/dream");
devices.add("verizon/voles/sholes");
devices.add("google_ion/google_ion/sapphire");
return devices.contains(android.os.Build.BRAND + "/" + android.os.Build.PRODUCT + "/"
+ android.os.Build.DEVICE);
}
тогда, когда я запускаю захват изображения, я создаю намерение, проверяющее ошибку.
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
if (hasImageCaptureBug()) {
i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File("/sdcard/tmp")));
} else {
i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
}
startActivityForResult(i, mRequestCode);
затем в действии, к которому я возвращаюсь, я делаю разные вещи на основе устройства.
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
switch (requestCode) {
case GlobalConstants.IMAGE_CAPTURE:
Uri u;
if (hasImageCaptureBug()) {
File fi = new File("/sdcard/tmp");
try {
u = Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(), fi.getAbsolutePath(), null, null));
if (!fi.delete()) {
Log.i("logMarker", "Failed to delete " + fi);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
} else {
u = intent.getData();
}
}
это избавит вас от необходимости писать новое приложение для камеры, но этот код тоже невелик. большие проблемы:
-
вы никогда не получите полноразмерные изображения из
устройства с ошибкой. Вы получаете
изображения шириной 512 пикселей,
вставляются в содержимое изображения
поставщик. на устройствах без
ошибка, все работает как документ,
вы получаете большую нормальную картину.
-
вам нужно вести список. в виде
написано, возможно для устройств
для сверки с версией
android (скажем cyanogenmod's
builds), в котором исправлена ошибка.
если это произойдет, ваш код будет
авария. исправление заключается в использовании всего
отпечаток устройства.
Ответ 2
Я знаю, что на это был дан ответ раньше, но я знаю, что многие люди спотыкаются об этом, поэтому я собираюсь добавить комментарий.
У меня была такая же проблема на моем Nexus One. Это было из файла, не существующего на диске, перед запуском приложения для камеры. Поэтому я убедился, что файл, существовавший до запуска приложения камеры. Вот пример кода, который я использовал:
String storageState = Environment.getExternalStorageState();
if(storageState.equals(Environment.MEDIA_MOUNTED)) {
String path = Environment.getExternalStorageDirectory().getName() + File.separatorChar + "Android/data/" + MainActivity.this.getPackageName() + "/files/" + md5(upc) + ".jpg";
_photoFile = new File(path);
try {
if(_photoFile.exists() == false) {
_photoFile.getParentFile().mkdirs();
_photoFile.createNewFile();
}
} catch (IOException e) {
Log.e(TAG, "Could not create file.", e);
}
Log.i(TAG, path);
_fileUri = Uri.fromFile(_photoFile);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE );
intent.putExtra( MediaStore.EXTRA_OUTPUT, _fileUri);
startActivityForResult(intent, TAKE_PICTURE);
} else {
new AlertDialog.Builder(MainActivity.this)
.setMessage("External Storeage (SD Card) is required.\n\nCurrent state: " + storageState)
.setCancelable(true).create().show();
}
Сначала я создаю уникальное (несколько) имя файла, используя хеш MD5 и помещаю его в соответствующую папку. Затем я проверяю, существует ли он (не должен, но его хорошая практика проверять в любом случае). Если он не существует, я получаю родительский каталог (папку) и создаю иерархию папок до него (поэтому, если папки, ведущие к местоположению файла, не существуют, они будут после этой строки. Я создаю файл. После создания файла я получаю Uri и передаю его намерению, а затем кнопка OK работает так, как ожидалось, и все золотые.
Теперь, когда кнопка ОК нажата в приложении камеры, файл будет присутствовать в данном месте. В этом примере это будет /sdcard/Android/data/com.example.myapp/files/234asdioue23498ad.jpg
Нет необходимости копировать файл в "onActivityResult", как указано выше.
Ответ 3
Я прошел через несколько стратегий захвата фотографий, и всегда кажется, что это случай, платформа или определенные устройства, где некоторые или все из вышеперечисленных стратегий будут непредсказуемыми. Я смог найти стратегию, которая использует код генерации URI, который, по-видимому, работает в большинстве, если не во всех случаях.
mPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new ContentValues());
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoUri);
startActivityForResult(intent,CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE_CONTENT_RESOLVER);
Чтобы внести свой вклад в обсуждение и помочь новичкам, я создал образец/тестовое приложение, которое показывает несколько различных стратегий для реализации фотосъемки. Вклад в другие реализации определенно рекомендуется добавить к обсуждению.
https://github.com/deepwinter/AndroidCameraTester
Ответ 4
У меня была та же проблема, когда кнопка ОК в приложении камеры ничего не делала, как на эмуляторе, так и на нейксу.
Проблема исчезла после указания безопасного имени файла без белых пробелов без специальных символов в MediaStore.EXTRA_OUTPUT
Кроме того, если вы указываете файл, который находится в каталоге, который еще не был создан, вам необходимо создать это сначала. Приложение камеры не делает mkdir для вас.
Ответ 5
Рабочий процесс, который вы описываете, должен работать так, как вы его описали. Это может помочь, если вы можете показать нам код вокруг создания намерения. В общем, следующий шаблон должен позволить вам делать то, что вы пытаетесь.
private void saveFullImage() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file = new File(Environment.getExternalStorageDirectory(), "test.jpg");
outputFileUri = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(intent, TAKE_PICTURE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if ((requestCode == TAKE_PICTURE) && (resultCode == Activity.RESULT_OK)) {
// Check if the result includes a thumbnail Bitmap
if (data == null) {
// TODO Do something with the full image stored
// in outputFileUri. Perhaps copying it to the app folder
}
}
}
Обратите внимание, что это Операция Camera, которая будет создавать и сохранять файл, а на самом деле это не часть вашего приложения, поэтому у него не будет права на запись в папку вашего приложения. Чтобы сохранить файл в папке вашего приложения, создайте временный файл на SD-карте и переместите его в папку приложения в обработчике onActivityResult
.
Ответ 6
Чтобы следить за комментариями Yenchi выше, кнопка OK также ничего не сделает, если приложение камеры не сможет записать в соответствующий каталог.
Это означает, что вы не можете создать файл в месте, которое может быть записано только вашим приложением (например, что-то под getCacheDir())
Что-то в getExternalFilesDir()
должно работать.
Было бы неплохо, если бы приложение камеры напечатало сообщение об ошибке в журналах, если оно не могло записать указанный путь EXTRA_OUTPUT
, но я его не нашел.
Ответ 7
чтобы камера записывала на SDCard, но сохранила в новом альбоме приложение галереи. Я использую это:
File imageDirectory = new File("/sdcard/signifio");
String path = imageDirectory.toString().toLowerCase();
String name = imageDirectory.getName().toLowerCase();
ContentValues values = new ContentValues();
values.put(Media.TITLE, "Image");
values.put(Images.Media.BUCKET_ID, path.hashCode());
values.put(Images.Media.BUCKET_DISPLAY_NAME,name);
values.put(Images.Media.MIME_TYPE, "image/jpeg");
values.put(Media.DESCRIPTION, "Image capture by camera");
values.put("_data", "/sdcard/signifio/1111.jpg");
uri = getContentResolver().insert( Media.EXTERNAL_CONTENT_URI , values);
Intent i = new Intent("android.media.action.IMAGE_CAPTURE");
i.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(i, 0);
Обратите внимание, что вам нужно будет генерировать уникальное имя файла каждый раз и заменить текст 1111.jpg, который я написал.
Это было протестировано с помощью нексуса.
uri объявляется в приватном классе, поэтому на результат активности я могу загрузить изображение с uri в imageView для предварительного просмотра, если это необходимо.
Ответ 8
Я рекомендую вам следить за инструкцией по андроиду для съемки фотографии. Они показывают в примере, как делать маленькие и большие фотографии. Вы также можете скачать исходный код здесь
Ответ 9
У меня была такая же проблема, и я исправил ее следующим образом:
Проблема заключается в том, что при указании файла, к которому имеет доступ только ваше приложение (например, путем вызова getFileStreamPath("file");
)
Вот почему я просто убедился, что данный файл действительно существует и что у ВСЕГО есть доступ на него.
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File outFile = getFileStreamPath(Config.IMAGE_FILENAME);
outFile.createNewFile();
outFile.setWritable(true, false);
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT,Uri.fromFile(outFile));
startActivityForResult(intent, 2);
Таким образом, приложение камеры имеет доступ на запись к данному Uri, и кнопка OK работает нормально:)
Ответ 10
Очень просто решить эту проблему с помощью кода результата деятельности. Простой метод:
if (reqCode == RECORD_VIDEO) {
if(resCode == RESULT_OK) {
if (uri != null) {
compress();
}
} else if(resCode == RESULT_CANCELED && data!=null){
Toast.makeText(MainActivity.this,"No Video Recorded",Toast.LENGTH_SHORT).show();
}
}
Ответ 11
Я создал простую библиотеку, которая будет управлять выбором изображений из разных источников (Галерея, Камера), возможно, сохранит ее в каком-либо месте (SD-Card или внутренняя память) и вернет изображение, чтобы, пожалуйста, бесплатно использовать его и улучшить его - Android-ImageChooser.
Ответ 12
Файл должен быть доступен для записи камерой, как указано Praveen.
В моем использовании я хотел сохранить файл во внутреннем хранилище. Я сделал это с помощью:
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (i.resolveActivity(getPackageManager()!=null)){
try{
cacheFile = createTempFile("img",".jpg",getCacheDir());
cacheFile.setWritavle(true,false);
}catch(IOException e){}
if(cacheFile != null){
i.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(cacheFile));
startActivityForResult(i,REQUEST_IMAGE_CAPTURE);
}
}
Здесь cacheFile
- это глобальный файл, используемый для ссылки на файл, который написан.
Затем в методе результата возвращаемое намерение равно null.
Затем метод обработки намерения выглядит так:
protected void onActivityResult(int requestCode,int resultCode,Intent data){
if(requestCode != RESULT_OK){
return;
}
if(requestCode == REQUEST_IMAGE_CAPTURE){
try{
File output = getImageFile();
if(output != null && cacheFile != null){
copyFile(cacheFile,output);
//Process image file stored at output
cacheFile.delete();
cacheFile=null;
}
}catch(IOException e){}
}
}
Здесь getImageFile()
- это метод утилиты для указания и создания файла, в котором должно храниться изображение, а copyFile()
- метод копирования файла.
Ответ 13
Вы можете использовать этот код
private Intent getCameraIntent() {
PackageManager packageManager = mContext.getPackageManager();
List<ApplicationInfo> list = packageManager.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
Intent main = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
List<ResolveInfo> launchables = packageManager.queryIntentActivities(main, 0);
if (launchables.size() == 1)
return packageManager.getLaunchIntentForPackage(launchables.get(0).activityInfo.packageName);
else
for (int n = 0; n < list.size(); n++) {
if ((list.get(n).flags & ApplicationInfo.FLAG_SYSTEM) == 1) {
Log.d("TAG", "Installed Applications : " + list.get(n).loadLabel(packageManager).toString());
Log.d("TAG", "package name : " + list.get(n).packageName);
String defaultCameraPackage = list.get(n).packageName;
if (launchables.size() > 1)
for (int i = 0; i < launchables.size(); i++) {
if (defaultCameraPackage.equals(launchables.get(i).activityInfo.packageName)) {
return packageManager.getLaunchIntentForPackage(defaultCameraPackage);
}
}
}
}
return null;
}
Ответ 14
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_CANCELED)
{
//do not process data, I use return; to resume activity calling camera intent
enter code here
}
}