Android ACTION_IMAGE_CAPTURE 意图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1910608/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android ACTION_IMAGE_CAPTURE Intent
提问by Drew
We are trying to use the native camera app to let the user take a new picture. It works just fine if we leave out the EXTRA_OUTPUT extra
and returns the small Bitmap image. However, if we putExtra(EXTRA_OUTPUT,...)
on the intent before starting it, everything works until you try to hit the "Ok" button in the camera app. The "Ok" button just does nothing. The camera app stays open and nothing locks up. We can cancel out of it, but the file never gets written. What exactly do we have to do to get ACTION_IMAGE_CAPTURE
to write the picture taken to a file?
我们正在尝试使用本机相机应用程序让用户拍摄新照片。如果我们省略EXTRA_OUTPUT extra
并返回小的位图图像,它就可以正常工作。但是,如果我们putExtra(EXTRA_OUTPUT,...)
在开始之前就有意为之,那么在您尝试点击相机应用程序中的“确定”按钮之前,一切都会正常进行。“确定”按钮什么也不做。相机应用程序保持打开状态,没有任何锁定。我们可以取消它,但文件永远不会被写入。我们究竟需要做什么ACTION_IMAGE_CAPTURE
才能将拍摄的照片写入文件?
Edit: This is done via the MediaStore.ACTION_IMAGE_CAPTURE
intent, just to be clear
编辑:这是通过MediaStore.ACTION_IMAGE_CAPTURE
意图完成的,只是为了清楚
回答by yanokwa
this is a well documented bugin some versions of android. that is, on google experience builds of android, image capture doesn't work as documented. what i've generally used is something like this in a utilities class.
在某些版本的 android 中,这是一个有据可查的错误。也就是说,在 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);
}
then when i launch image capture, i create an intent that checks for the bug.
然后当我启动图像捕获时,我创建了一个检查错误的意图。
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);
then in activity that i return to, i do different things based on the device.
然后在我返回的活动中,我根据设备做不同的事情。
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();
}
}
this saves you having to write a new camera app, but this code isn't great either. the big problems are
这使您不必编写新的相机应用程序,但这段代码也不是很好。最大的问题是
you never get full sized images from the devices with the bug. you get pictures that are 512px wide that are inserted into the image content provider. on devices without the bug, everything works as document, you get a big normal picture.
you have to maintain the list. as written, it is possible for devices to be flashed with a version of android (say cyanogenmod's builds) that has the bug fixed. if that happens, your code will crash. the fix is to use the entire device fingerprint.
你永远不会从有 bug 的设备上得到全尺寸的图像。您将获得插入图像内容提供程序的 512 像素宽的图片。在没有 bug 的设备上,一切都像文档一样工作,你会得到一张大的普通图片。
你必须维护列表。正如所写的那样,设备可以使用修复了错误的 android 版本(例如cyanogenmod 的构建)进行刷新。如果发生这种情况,您的代码将崩溃。解决方法是使用整个设备指纹。
回答by Donn Felker
I know this has been answered before but I know a lot of people get tripped up on this, so I'm going to add a comment.
我知道之前已经回答过这个问题,但我知道很多人对此感到困惑,所以我要添加评论。
I had this exact same problem happen on my Nexus One. This was from the file not existing on the disk before the camera app started. Therefore, I made sure that the file existing before started the camera app. Here's some sample code that I used:
我的 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();
}
I first create a unique (somewhat) file name using an MD5 hash and put it into the appropriate folder. I then check to see if it exists (shouldn't, but its good practice to check anyway). If it does not exist, I get the parent dir (a folder) and create the folder hierarchy up to it (therefore if the folders leading up to the location of the file don't exist, they will after this line. Then after that I create the file. Once the file is created I get the Uri and pass it to the intent and then the OK button works as expected and all is golden.
我首先使用 MD5 哈希创建一个唯一的(有点)文件名,并将其放入适当的文件夹中。然后我检查它是否存在(不应该,但无论如何检查它是一种很好的做法)。如果它不存在,我会获取父目录(一个文件夹)并创建文件夹层次结构(因此,如果指向文件位置的文件夹不存在,它们将在此行之后。然后在那之后我创建文件。创建文件后,我获取 Uri 并将其传递给 Intent,然后 OK 按钮按预期工作,一切顺利。
Now,when the Ok button is pressed on the camera app, the file will be present in the given location. In this example it would be /sdcard/Android/data/com.example.myapp/files/234asdioue23498ad.jpg
现在,当在相机应用程序上按下 Ok 按钮时,文件将出现在给定的位置。在这个例子中,它将是 /sdcard/Android/data/com.example.myapp/files/234asdioue23498ad.jpg
There is no need to copy the file in the "onActivityResult" as posted above.
无需复制上面发布的“onActivityResult”中的文件。
回答by deepwinter
I've been through a number of photo capture strategies, and there always seems to be a case, a platform or certain devices, where some or all of the above strategies will fail in unexpected ways. I was able to find a strategy that uses the URI generation code below which seems to work in most if not all cases.
我经历了许多照片捕获策略,似乎总有一个案例,一个平台或某些设备,其中部分或全部上述策略会以意想不到的方式失败。我能够找到一种使用下面的 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);
To contribute further to the discussion and help out newcomers I've created a sample/test app that shows several different strategies for photo capture implementation. Contributions of other implementations are definitely encouraged to add to the discussion.
为了进一步促进讨论并帮助新人,我创建了一个示例/测试应用程序,其中显示了几种不同的照片捕获实施策略。绝对鼓励其他实现的贡献添加到讨论中。
回答by Yenchi
I had the same problem where the OK button in camera app did nothing, both on emulator and on nexus one.
我遇到了同样的问题,相机应用程序中的 OK 按钮在模拟器和 nexus one 上什么也没做。
The problem went away after specifying a safe filename that is without white spaces, without special characters, in MediaStore.EXTRA_OUTPUT
Also, if you are specifying a file that resides in a directory that has not yet been created, you have to create it first. Camera app doesn't do mkdir for you.
指定一个没有空格、没有特殊字符的安全文件名后问题就消失了,MediaStore.EXTRA_OUTPUT
此外,如果您指定的文件驻留在尚未创建的目录中,则必须先创建它。相机应用程序不会为你做 mkdir。
回答by Reto Meier
The workflow you describe should work as you've described it. It might help if you could show us the code around the creation of the Intent. In general, the following pattern should let you do what you're trying.
您描述的工作流程应该像您描述的那样工作。如果您能向我们展示有关创建 Intent 的代码,可能会有所帮助。一般来说,下面的模式应该让你做你正在尝试的事情。
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
}
}
}
Note that it is the CameraActivity that will be creating and saving the file, and it's not actually part of your application, so it won't have write permission to your application folder. To save a file to your app folder, create a temporary file on the SD card and move it to your app folder in the onActivityResult
handler.
请注意,相机活动将创建和保存文件,它实际上不是您应用程序的一部分,因此它没有对您的应用程序文件夹的写权限。要将文件保存到您的应用程序文件夹,请在 SD 卡上创建一个临时文件并将其移动到onActivityResult
处理程序中您的应用程序文件夹。
回答by Joe
To follow up on Yenchi's comment above, the OK button will also do nothing if the camera app can't write to the directory in question.
为了跟进 Yenchi 的上述评论,如果相机应用程序无法写入相关目录,则 OK 按钮也不会执行任何操作。
That means that you can't create the file in a place that's only writeable by your application (for instance, something under getCacheDir())
Something under getExternalFilesDir()
ought to work, however.
这意味着您不能在只能由您的应用程序写入的位置创建文件(例如,getCacheDir())
Something 下的某些内容getExternalFilesDir()
应该可以工作。
It would be nice if the camera app printed an error message to the logs if it could not write to the specified EXTRA_OUTPUT
path, but I didn't find one.
如果相机应用程序无法写入指定EXTRA_OUTPUT
路径,那么如果相机应用程序将错误消息打印到日志中会很好,但我没有找到。
回答by nabulaer
to have the camera write to sdcard but keep in a new Album on the gallery app I use this :
要让相机写入 SD 卡,但在图库应用程序上保存在新相册中,我使用这个:
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);
Please note that you will need to generate a unique filename every time and replace teh 1111.jpg that I wrote. This was tested with nexus one. the uri is declared in the private class , so on activity result I am able to load the image from the uri to imageView for preview if needed.
请注意,您每次都需要生成一个唯一的文件名并替换我写的 1111.jpg。这是用连接一测试的。uri 在私有类中声明,因此根据活动结果,如果需要,我可以将图像从 uri 加载到 imageView 以进行预览。
回答by Goddchen
I had the same issue and i fixed it with the following:
我遇到了同样的问题,我用以下方法修复了它:
The problem is that when you specify a file that only your app has access to (e.g. by calling getFileStreamPath("file");
)
问题是,当您指定只有您的应用程序有权访问的文件时(例如通过调用getFileStreamPath("file");
)
That is why i just made sure that the given file really exists and that EVERYONE has write access to it.
这就是为什么我只是确保给定的文件确实存在并且每个人都可以对其进行写访问。
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);
This way, the camera app has write access to the given Uri and the OK button works fine :)
这样,相机应用程序就可以对给定的 Uri 进行写访问,并且 OK 按钮可以正常工作:)
回答by JuanVC
回答by svenkapudija
I created simple library which will manage choosing images from different sources (Gallery, Camera), maybe save it to some location (SD-Card or internal memory) and return the image back so please free to use it and improve it - Android-ImageChooser.
我创建了一个简单的库,它将管理从不同来源(图库、相机)中选择图像,可能会将其保存到某个位置(SD 卡或内部存储器)并将图像返回,因此请自由使用它并对其进行改进 - Android-ImageChooser.