简体   繁体   English

摘要:使用Camera Intent拍摄照片并以正确的方向显示照片(希望所有设备都可以使用)

[英]Summary: Take a picture utilizing Camera Intent and display the photo with correct orientation (works on hopefully all devices)

It seems to be the simplest thing in the world: taking a picture within your Android app using the default camera activity. 这似乎是世界上最简单的事情:使用默认的相机活动在Android应用中拍照。 However, there are many pitfalls which are covered in several posts across StackOverflow and the web as, for instance, Null Intents being passed back, the orientation of the picture not being correct or OutOfMemoryErrors. 但是,StackOverflow和Web上的几个帖子中都有许多陷阱,例如,Null Intents被传回,图片的方向不正确或OutOfMemoryErrors。

I'm looking for a solution that allows me to 我正在寻找一个允许我的解决方案

  1. start the camera activity via the camera intent, 通过相机意图启动相机活动,
  2. retrieve the Uri of the photo, and 检索照片的Uri,和
  3. retrieve the correct orientation of the photo. 检索照片的正确方向。

Moreover, I would like to avoid a device configuration (manufacturer, model, os version) specific implementation as far as possible. 而且,我想尽可能避免设备配置(制造商,型号,操作系统版本)的具体实现。 So I'm wondering: what is the best way to achieve this? 所以我想知道:实现这一目标的最佳方法是什么?

UPDATE: January 2nd, 2014: I tried really hard to avoid implementing different strategies based on the device manufacturer. 更新:2014年1月2日:我努力避免基于设备制造商实施不同的策略。 Unfortunately, I did not get around it. 不幸的是,我没有绕过它。 Going through hundreds of posts and talking to several developers, nobody found a solution that works on all devices without implementing device manufacturer specific code. 通过数百个帖子并与几个开发人员交谈,没有人找到适用于所有设备的解决方案,而无需实现设备制造商特定的代码。

After I posted my solution here on StackOverflow, some developers asked me to publish my code on github. 在StackOverflow上发布我的解决方案之后,一些开发人员让我在github上发布我的代码。 So here it is now: AndroidCameraUtil on github 所以现在就是: github上的AndroidCameraUtil

The code was successfully tested on a wide variety of devices with Android API-Level >= 8. For a complete list, please see the Readme file on github. 该代码已在各种Android API级别> = 8的设备上成功测试。有关完整列表,请参阅github上的自述文件。

The CameraIntentHelperActivity provides the main functionality, which is also described in more detail in the following. CameraIntentHelperActivity提供主要功能,下面还将对其进行更详细的描述。

Calling the default camera activity: 调用默认的相机活动:

  • for Samsung and Sony devices : I call the camera activity with the method call to startActivityForResult. 对于三星和索尼设备 :我通过调用startActivityForResult的方法调用相机活动。 I only set the constant CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE. 我只设置了常量CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE。 I do NOT set any other intent extras. 我没有设置任何其他意图的额外内容。
  • for all other devices : I call the camera activity with the method call to startActivityForResult as previously. 对于所有其他设备 :我使用方法调用startActivityForResult调用相机活动,如前所述。 This time, however, I additionally set the intent extra MediaStore.EXTRA_OUTPUT and provide an URI, where I want the image to be stored. 然而,这一次,我另外设置了额外的MediaStore.EXTRA_OUTPUT,并提供了一个URI,我想要存储图像。

In both cases I remember the time the camera activity was started. 在这两种情况下,我都记得相机活动开始的时间。


On camera activity result: 关于相机活动结果:

  1. Mediastore: First, I try to read the photo being captured from the MediaStore. Mediastore:首先,我尝试阅读从MediaStore中捕获的照片。 Using a mangedQuery on the MediaStore content, I retrieve the latest image being taken, as well as its orientation property and its timestamp. 在MediaStore内容上使用mangedQuery,我检索正在拍摄的最新图像,以及它的orientation属性和时间戳。 If I find an image and it was not taken before the camera intent was called, it is the image I was looking for. 如果我找到一个图像并且在调用相机意图之前没有拍摄,那就是我正在寻找的图像。 Otherwise, I dismiss the result and try one of the following approaches. 否则,我会忽略结果并尝试以下方法之一。
  2. Intent extra: Second, I try to get an image Uri from intent.getData() of the returning intent. 意图额外:其次,我尝试从返回意图的intent.getData()获取图像Uri。 If this is not successful either, I continue with step 3. 如果这也不成功,我继续第3步。
  3. Default photo Uri : If all of the above mentioned steps did not work, I use the image Uri I passed to the camera activity. 默认照片Uri :如果上述所有步骤都不起作用,我会使用我传递给相机活动的图像Uri。

At this point, I retrieved the photo Uri and its orientation which I pass to my UploadPhotoActivity. 此时,我检索了照片Uri及其传递给我的UploadPhotoActivity的方向。


Image processing 图像处理

Please take a close look at my BitmapHelper class. 请仔细查看我的BitmapHelper类。 It is based on the code described in detail in that tutorial . 它基于该教程中详细描述的代码。

Moreover, the shrinkBitmap method also rotates the image if required based on the orientation information extracted earlier. 此外,如果需要,shrinkBitmap方法还会根据先前提取的方向信息旋转图像。


I hope this is helpful to some of you. 我希望这对你们中的一些人有所帮助。

I have tested this code with a Sony Xperia Go, Samsung Galaxy SII, Samsung Galaxy SIII mini and a Samsung Galaxy Y it worked on all devices! 我用Sony Xperia Go,三星Galaxy SII,三星Galaxy SIII mini和三星Galaxy Y测试了这个代码,它适用于所有设备!

But on the LG E400 (2.3.6) it didn't work and you get double pictures in the gallery. 但是在LG E400(2.3.6)上它没有用,你在画廊中得到了双张图片。 So i have added the manufacturer.contains("lge") in the void startCameraIntent() and it fixed the problem. 所以我在void startCameraIntent()中添加了manufacturer.contains(“lge”)并修复了问题。

if(!(manufacturer.contains("samsung")) && !(manufacturer.contains("sony")) && !(manufacturer.contains("lge"))) {
    String filename = System.currentTimeMillis() + ".jpg";
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.TITLE, filename);
    cameraPicUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraPicUri);
}

On a Galaxy S3 with CM 10.1 I get a nullpointer exception in BitmapHelper: 在带有CM 10.1的Galaxy S3上,我在BitmapHelper中得到一个nullpointer异常:

bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options); bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(),null,options);

subsequently my UploadPhotoActivity fails at: 随后我的UploadPhotoActivity失败了:

  try { photo = BitmapHelper.readBitmap(this, cameraPicUri); if (photo != null) { photo = BitmapHelper.shrinkBitmap(photo, 600, rotateXDegrees); thumbnail = BitmapHelper.shrinkBitmap(photo, 100); ImageView imageView = (ImageView) findViewById(R.id.sustainable_action_photo); imageView.setImageBitmap(photo); } else { Log.e(TAG,"IMAGE ERROR 1"); } } catch (Exception e) { Log.e(TAG,"IMAGE ERROR 2"); e.printStackTrace(); } 

at the second log (IMAGE ERROR 2). 在第二个日志(IMAGE ERROR 2)。 After a couple of tries my camera broke and I got a "Could not connect to camera"-error. 经过几次尝试,我的相机坏了,我得到了“无法连接相机” - 恐怖。

Tested it on a nexus 7 and it works perfectly. 在nexus 7上测试它,它完美地工作。

Edit: Narrowed it down to this: 编辑:将其缩小到这个:

fileDescriptor = context.getContentResolver().openAssetFileDescriptor(selectedImage, "r"); fileDescriptor = context.getContentResolver()。openAssetFileDescriptor(selectedImage,“r”);

Although selectedImage contains this: 虽然selectedImage包含:

file:///storage/emulated/0/DCIM/Camera/IMG_20131023_183343.jpg 文件:///storage/emulated/0/DCIM/Camera/IMG_20131023_183343.jpg

The fileDescriptor returns a FileNotFoundException. fileDescriptor返回FileNotFoundException。 I checked the file system and the image is not saved at this location. 我检查了文件系统,图像未保存在此位置。 The cameraPicUri in TakePhotoActivity points to a non existant image. TakePhotoActivity中的cameraPicUri指向不存在的图像。 I am currently checking where it all goes wrong. 我目前正在检查一切都出错了。

Edit2: I figured out the error: Since the device is a Samsung, and tells the App that it is a Samsung device, your Samsung specific fixes are applied. 编辑2:我发现错误:由于该设备是三星,并告诉应用程序它是一个三星设备,您的三星特定修复程序已应用。 Cyanogenmod does not need those fixes though, and in the end the code breaks. Cyanogenmod虽然不需要那些修复,但最终代码中断了。 Once you remove 一旦你删除

(manufacturer.contains("samsung")) && (manufacturer.contains(“samsung”))&&

It works. 有用。 Since this is a custom ROM you could not plan for that of course. 由于这是一个自定义ROM,你当然无法计划。 I am trying to figure out a way to detect if the device is running cyanogenmod and then include this in your code. 我试图找出一种方法来检测设备是否正在运行cyanogenmod,然后将其包含在您的代码中。

Thanks for a nice camera fix! 谢谢你一个漂亮的相机修复!

Edit3: I fixed it to run on Cyanogenmod on the Galaxy S3 by changing your code to this: Well, now it sometimes works, sometimes it does not. 编辑3: 我修改它以在Galaxy S3上的Cyanogenmod上运行,将代码更改为: 嗯,现在它有时可以工作,有时它不会。 Strange. 奇怪。

if (getPackageManager().hasSystemFeature("com.cyanogenmod.android") || (!(manufacturer.contains("samsung")) && !(manufacturer.contains("sony")) && !(manufacturer.contains("lge")))) if(getPackageManager()。hasSystemFeature(“com.cyanogenmod.android”)||(!(manufacturer.contains(“samsung”))&&!(manufacturer.contains(“sony”))&&!(manufacturer.contains(“ LGE“))))

I experience some problems when using this with Sony Xperia Z5. 使用Sony Xperia Z5时遇到一些问题。

I added this and it got a lot better. 我添加了这个,它变得更好了。

if (buildType.contains("sony")&& buildDevice.contains("e5823")) {
                setPreDefinedCameraUri = true;}

But 4 times out of 22 it restarted the camera and once it restarted two times. 但是22次中有4次它重新启动了相机并且重启了两次。 I restarted the App due to every test. 由于每次测试我都重新启动了应用程序。 Is there some way to get around this or do I accept this result? 有没有办法绕过这个或我接受这个结果?

The thing is that if the camera restarts I can press the back button twice and boom, the image is there in my Imageview and saved 问题是,如果相机重新启动,我可以按两次后退按钮并进行操作,图像就在我的Imageview中并保存

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM