我正在使用意图来启动相机:
Intent cameraIntent = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
getParent().startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);
并使用:
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
photoImage.setImageBitmap(thumbnail);
photoImage.setVisibility(View.VISIBLE);
但这只是缩略图,如何获得完整的位图?我知道我可以使用自己的 Activity 并使用:
Camera.PictureCallback()
但是有没有办法使用 Intent 来做到这一点?
谢谢!
编辑:
我也尝试过:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
Uri uri = data.getData();
imageView.setImageURI(uri);
}
它适用于从图库中选择的照片,但对于相机意图,data.getData() 返回 null。
要获得全尺寸的相机图像,您应该将相机指向将图片保存在临时文件中,例如:
private URI mImageUri;
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
File photo;
try
{
// place where to store camera taken picture
photo = this.createTemporaryFile("picture", ".jpg");
photo.delete();
}
catch(Exception e)
{
Log.v(TAG, "Can't create file to take picture!");
Toast.makeText(activity, "Please check SD card! Image shot is impossible!", 10000);
return false;
}
mImageUri = Uri.fromFile(photo);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
//start camera intent
activity.startActivityForResult(this, intent, MenuShootImage);
private File createTemporaryFile(String part, String ext) throws Exception
{
File tempDir= Environment.getExternalStorageDirectory();
tempDir=new File(tempDir.getAbsolutePath()+"/.temp/");
if(!tempDir.exists())
{
tempDir.mkdirs();
}
return File.createTempFile(part, ext, tempDir);
}
然后,在图像捕获意图完成工作后 - 只需使用以下代码从
imageUri
抓取您的图片:
public void grabImage(ImageView imageView)
{
this.getContentResolver().notifyChange(mImageUri, null);
ContentResolver cr = this.getContentResolver();
Bitmap bitmap;
try
{
bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, mImageUri);
imageView.setImageBitmap(bitmap);
}
catch (Exception e)
{
Toast.makeText(this, "Failed to load", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Failed to load", e);
}
}
//called after camera intent finished
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent)
{
//MenuShootImage is user defined menu option to shoot image
if(requestCode==MenuShootImage && resultCode==RESULT_OK)
{
ImageView imageView;
//... some code to inflate/create/find appropriate ImageView to place grabbed image
this.grabImage(imageView);
}
super.onActivityResult(requestCode, resultCode, intent);
}
P.S. 代码需要根据 Android M 中应用的新安全限制进行修改 - FileProvider:
mImageUri
必须用 FileProvider
打包
打开相机并将图像保存到某个特定目录
private String pictureImagePath = "";
private void openBackCamera() {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = timeStamp + ".jpg";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
pictureImagePath = storageDir.getAbsolutePath() + "/" + imageFileName;
File file = new File(pictureImagePath);
Uri outputFileUri = Uri.fromFile(file);
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(cameraIntent, 1);
}
处理图像
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
File imgFile = new File(pictureImagePath);
if(imgFile.exists()){
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
ImageView myImage = (ImageView) findViewById(R.id.imageviewTest);
myImage.setImageBitmap(myBitmap);
}
}
}
尽管这是一个老问题并且有一个公认的答案,
我想分享我的解决方案。
在这种情况下,您不必创建临时文件。
此外,我们创建了一个选择器,为用户提供以下两种功能:用相机拍照或从图库中选择现有的一张照片。
Intent galleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
chooser.putExtra(Intent.EXTRA_INTENT, galleryIntent);
chooser.putExtra(Intent.EXTRA_TITLE, getString(R.string.chooseaction));
Intent[] intentArray = {cameraIntent};
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
startActivityForResult(chooser, RESULT_LOAD_IMAGE);
我们在这里检索结果:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// todo use appropriate resultCode in your case
if (requestCode == RESULT_LOAD_IMAGE && resultCode == FragmentActivity.RESULT_OK) {
if (data.getData() != null) {
// this case will occur in case of picking image from the Gallery,
// but not when taking picture with a camera
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), data.getData());
// do whatever you want with the Bitmap ....
} catch (IOException e) {
e.printStackTrace();
}
} else {
// this case will occur when taking a picture with a camera
Bitmap bitmap = null;
Cursor cursor = getActivity().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_ADDED,
MediaStore.Images.ImageColumns.ORIENTATION}, MediaStore.Images.Media.DATE_ADDED,
null, "date_added DESC");
if (cursor != null && cursor.moveToFirst()) {
Uri uri = Uri.parse(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)));
String photoPath = uri.toString();
cursor.close();
if (photoPath != null) {
bitmap = BitmapFactory.decodeFile(photoPath);
}
}
if (bitmap == null) {
// for safety reasons you can
// use thumbnail if not retrieved full sized image
bitmap = (Bitmap) data.getExtras().get("data");
}
// do whatever you want with the Bitmap ....
}
super.onActivityResult(requestCode, resultCode, data);
}
}
我还使用了 Vicky 的答案,但我必须将 uri 保存到一个包中,以避免在方向更改时丢失它。因此,如果您在倾斜设备后没有从意图中得到结果,可能是因为您的 uri 无法承受方向变化。
static final int CAMERA_CAPTURE_REQUEST = 1;
static final String ARG_CURRENT_PIC_URI = "CURRENT_PIC_URI";
String pictureImagePath = folderName + "/" + imageFileName;
File file = new File(Environment.getExternalStorageDirectory(), pictureImagePath);
Uri outputFileUri = Uri.fromFile(file);
mCurrentPicUri = outputFileUri.getPath();
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(cameraIntent, CAMERA_CAPTURE_REQUEST);
活动结果代码:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA_CAPTURE_REQUEST && resultCode == Activity.RESULT_OK)
{
File imgFile = new File(mCurrentPicUri);
// do something with your image
// delete uri
mCurrentPicUri = "";
}
}
将 uri 保存到包中:
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// save uri to bundle
outState.putString(ARG_CURRENT_PIC_URI, mCurrentPicUri);
}
在创建过程中从保存的捆绑包中检索它:
if (bundle.containsKey(ARG_CURRENT_PIC_URI))
mCurrentPicUri = bundle.getString(ARG_CURRENT_PIC_URI);
请勿使用
onActivityResult
的数据。我花了很多时间来测试不同的解决方案。相机保存了一张图片(即使您没有在 AndroidManifest 中设置相机和读卡的权限),但随后 onActivityResult
返回 data == null
并且 MediaStore
返回错误的路径。在这些解决方案中,您只需获取最后一个画廊图像,而不是您的照片。
private Uri photoUri;
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
...
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_RESULT) {
if (resultCode == RESULT_OK) {
if (photoUri != null) {
image.setImageURI(photoUri);
}
}
}
}
private void showCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getContext().getPackageManager()) != null) {
File file = null;
try {
file = createImageFile();
} catch (IOException e) {
e.printStackTrace();
}
photoUri = null;
if (file != null) {
photoUri = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(intent, CAMERA_REQUEST);
}
}
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File storageDir = getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
// File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
return File.createTempFile(timeStamp, ".jpg", storageDir);
}
还款时间到了。
因此您在清单中拥有权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
您还有提供商元数据:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
一个遗漏的细节是 (android:authorities applicationId) - 您需要将其添加到您自己的应用程序包名称中。
因此,正如我们在
xml
上提到的,您在 res
文件夹下有 manifest
文件,并在其下创建了 file_paths
,其中:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path
name="my_images"
path="Pictures" />
</paths>
我们已经完成了复制粘贴第 1 部分。现在开始我们上面的活动
onCreate(savedInstanceState: Bundle?)
定义这些美丽
val REQUEST_IMAGE_CAPTURE = 1
lateinit var currentPhotoPath: String
var cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
您可能想查看原始资源,但像往常一样缺少详细信息 Android 开发者:link
另一个缺失的细节是
packageName + ".fileprovider",
小心,如果你已经有方法,你需要给出你自己的包名称。
// org android developers
private fun dispatchTakePictureIntent() {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
// Ensure that there's a camera activity to handle the intent
takePictureIntent.resolveActivity(packageManager)?.also {
// Create the File where the photo should go
val photoFile: File? = try {
createImageFile()
} catch (ex: IOException) {
// Error occurred while creating the File
ex.message
null
}
// Continue only if the File was successfully created
photoFile?.also {
val photoURI: Uri = FileProvider.getUriForFile(
this,
packageName + ".fileprovider",
it
)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
}
}
}
}
createImageFile
功能
// org android developers
@Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir: File = this!!.getExternalFilesDir(Environment.DIRECTORY_PICTURES)!!
return File.createTempFile(
"JPEG_${timeStamp}_", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = absolutePath
}
}
测试。
使用 onClick 事件调用您的
dispatchTakePictureIntent()
方法,确保允许权限
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_IMAGE_CAPTURE) {
var mBitmap_org = MediaStore.Images.Media.getBitmap(
this.getContentResolver(),
//Uri.parse(currentPhotoPath)
Uri.fromFile(File(currentPhotoPath))
);
//mImg_display?.setImageBitmap(mBitmap_org)
}
}
不检查数据,我们将通过imagePath获取数据。如果您正在检查
Uri.parse(currentPhotoPath)
,请确保它是 Uri.fromFile(File(currentPhotoPath))
现在您有了位图,有时间花其他时间/天来调整解码大小,保存。
还有一种保存令牌图像的方法,也许你可以帮我看看我应该把它放在哪里,如果我需要将令牌图像保存在图库上
// org android developers
private fun galleryAddPic() {
Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE).also { mediaScanIntent ->
val f = File(currentPhotoPath)
mediaScanIntent.data = Uri.fromFile(f)
sendBroadcast(mediaScanIntent)
}
}
API 级别 29
我尝试了接受的答案,但接受的答案中使用的
Environment.getExternalStorageDirectory()
和后续答案中使用的 Environment.getExternalStoragePublicDirectory()
在 API 级别 29 中均已弃用。API 级别 29 中弃用的第三个答案中使用的 MediaStore.Images.Media.DATA
也是如此。以下代码(在 Kotlin 中)将完整图像存储在 MediaStore
中,如针对不同问题的 this stackoverflow 答案 中所示,并且不依赖于 FileProvider
:
var imageUri: Uri? = null
fun takePhoto(view: View?) {
val values = ContentValues()
values.put(MediaStore.MediaColumns.DISPLAY_NAME, "myimage.jpg")
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
imageUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
startActivityForResult(intent, TAKE_PHOTO_REQUEST)
}
要从相机捕获最大图片尺寸,我希望这些简单的步骤非常有用
public static Camera mCamera;
Camera.Parameters parameters = mCamera.getParameters();
parameters.getSupportedPictureSizes();
List<Camera.Size> supportedSizes = parameters.getSupportedPictureSizes();
mSizePicture1 = supportedSizes.get(0);
int cameraSize = supportedSizes.size();
mSizePicture2 = supportedSizes.get(cameraSize - 1);
if (mSizePicture1.height < mSizePicture2.height)
mSizePicture = supportedSizes.get(cameraSize - 1);
else
mSizePicture = supportedSizes.get(0);
parameters.setPictureSize(mSizePicture.width, mSizePicture.height);
这里,每个手机支持的尺寸是取最大尺寸的,固定为要捕获的图片尺寸。