Skip to main content

What's the best way to handle the Android camera?

Bothie makes extensive use
of the Camera APIs.
This article is adapted from a response I gave on Reddit to the question "What's the best way to handle the camera?" in r/androiddev...

The Camera and Camera2 APIs are far from painless to use. If you've ever written an app that uses the camera (embedded in an activity or not), you've almost certainly come up against orientation issues, stretched previews, or weird quirks that change from manufacturer to manufacturer...

There are three good libraries out there that can save you from many common pitfalls:
Each has different strengths. If you don't have time to read this whole article, here's a quick rule of thumb:
  • If you want to capture photos in a full-screen preview, but you don't want to have to rely on the native camera app, then use CWAC-Cam2.
  • If you want to embed a preview into your Activity, use CameraKit. It's forked from the CameraView library, and offers a few more features.
The CWAC-Cam2 library excels at helping you take a photo (or video) using a fullscreen preview, without leaving your app - which can help when you wish to keep the image away from the public storage on the device. It responds to Intents that are constructed in a similar fashion to standard Camera request Intents.

The original CWAC-Cam was superb at coping with the old Camera API and the hoops you had to jump through to outwit the (sometimes bizarre) quirks introduced by each manufacturer. When the Camera2 API came out, Mark released CWAC-Cam2 to support it - and the library is steadily improving. It supports a variety of features, including flash modes, focus modes, and orientation normalization. Image orientation is a source of frustration for many Android developers who work with the camera. More on that later...

The CameraView library is clean, tidy and works for most simple cases. It is limited to still photography at present. You can embed a CameraView into your layout, and use it there - with only a small amount of supporting code in your Activity class. The library takes care of the proportions of the view, to prevent a stretched preview, and orients it correctly too. (the Camera2 API is supposed to "just take care of that").

CameraKit was originally forked from CameraView and offers a few more features - including tap-to-focus, cropped output, and video capture.

There are a couple of issues with the CameraView library that will very likely also affect CameraKit. These are interesting edge cases that relate to doing things like:
  • Stopping the CameraView and attempting to close the Activity. (This leads to the app crashing sometimes - as it seems that the CameraView needs time to close the Camera it's using safely.)
  • Stopping one CameraView and starting another in quick succession. (This also sometimes leads to the app crashing, and seems to be again because the first Camera isn't released as the second CameraView tries to start - and so it cannot claim a Camera of its own.)
These are pretty rare edge cases, but you should be aware of them if you're doing anything more complex than a simple preview inside an Activity. My workaround was to .postDelayed a Runnable to my CameraView that took the actions I wanted after the Camera was safely closed.

All three libraries are well maintained - although they're constantly playing catch-up, as each manufacturer manages to introduce some new utterly strange behaviour to their own camera. (Who remembers trying to understand why making a photo size request different to the preview size led to washed out images with no white-balance? Or which of the permitted preview sizes didn't lead to green static on certain phones?)

Make sure to grab a recent version of the library you choose when building your app, and update regularly.

A word of warning about orientation: When actually taking a photo, CameraView (and CameraKit) will return it oriented according to how the camera chip in the phone provided it - not how the preview was arranged. This can be confusing until you realise what's going on. You'll have to reorient the image yourself to get back on the road.

Your choices are:
  1. Read the orientation information from the image's EXIF data. Unfortunately, this is not always available. (In fact, on most phones I've worked with I don't remember being able to get that data.)
  2. Guess based on the orientation of the device itself when the photo was taken. This approach appears quite frequently in examples found online, and seems to be the preferred choice amongst developers.
  3. Fall back on educated guesswork. Take a look at the image in question - is it wider or taller than the preview's dimensions? If so, perhaps you should rotate it 90 degrees (or -90 degrees).
See this gist for some methods to help you read the EXIF data in your image and rotate a bitmap accordingly. It relies on Drew Noakes' metadata-extractor library to read the tags from your image. To add it to your project using gradle, you can use the following formula in your module's build.gradle file:

    compile 'com.drewnoakes:metadata-extractor:+'

One final word: You may also find that photos taken through the front-facing camera are flipped around the vertical axis (left and right don't match the preview!) To flip it back, you could adjust the Matrix you're using: matrix.postScale(-1.0f, 1.0f); should mirror the image for you, although you'll also have to apply a matrix.postTranslate(imageWidth, 0.0f); to put it back to the same position.

I hope that's helpful!

Popular posts from this blog

Google Play Services with Android Studio

Edit: This post is extremely deprecated -- with prejudice! It was written in an era when Google Play Services were not well integrated with Android Studio project work, and Android Studio itself was in its infancy.

This is a very quick guide to incorporating Google Play Services with your new Android Studio project.

Edit: [16:20 22/05/2013] I'll investigate the runtime NoClassDefFound error reported in the comments, and follow up later!

Edit: [23:17 27/05/2013] I'm coming to the conclusion that - as many have already pointed out - you really do need to include the entire library project in your solution. I'll post an update once I've fully tested this. 

In the meantime, please consider the advice below to be deprecated!

The first thing to say is: I fully expect the advice and guidance about how to work in Android Studio to change over time. Android Studio is in early access preview right now, and I'll bet my bottom dollar (is that a thing?) that over time it becomes m…

Manually Testing Web Services in Visual Studio

The first time you debug a web service after creating it, Visual Studio will launch the WCF Test Client - a very useful piece of kit - and preload it with the details of your service.

In this article, we'll look first at testing your WCF service, and then an all-too-familiar issue that might crop up and spoil your fun!

Using the WCF Test Client

The WCF Test Client looks a bit like SoapUI, and is pretty similar in purpose: It allows you to connect to a service, enter some parameters and submit them to any given service method to see what you get.

After the first time you run the WCF Client, Visual Studio will forget all about launching it again until you make significant changes to it - which means when you subsequently hit f5 or choose Debug, it won't run again. It's worth knowing how to bring it up...

You can find it again by launching the Visual Studio Command Prompt, and launching wcftestclient.exe from there.

Once connected, making use of it is as simple as filling in …