# Camera and Gallery
# Taking full-sized photo from camera
To take a photo, first we need to declare required permissions in AndroidManifest.xml
. We need two permissions:
Camera
- to open camera app. If attributerequired
is set totrue
you will not be able to install this app if you don't have hardware camera.WRITE_EXTERNAL_STORAGE
- This permission is required to create new file, in which captured photo will be saved.
# AndroidManifest.xml
<uses-feature android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
The main idea in taking full-sized photo from camera is that we need to create new file for photo, before we open camera app and capture photo.
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Log.e("DEBUG_TAG", "createFile", ex);
}
// Continue only if the File was successfully created
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getAlbumDir();
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
private File getAlbumDir() {
File storageDir = null;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
storageDir = new File(Environment.getExternalStorageDirectory()
+ "/dcim/"
+ "MyRecipes");
if (!storageDir.mkdirs()) {
if (!storageDir.exists()) {
Log.d("CameraSample", "failed to create directory");
return null;
}
}
} else {
Log.v(getString(R.string.app_name), "External storage is not mounted READ/WRITE.");
}
return storageDir;
}
private void setPic() {
/* There isn't enough memory to open up more than a couple camera photos */
/* So pre-scale the target bitmap into which the file is decoded */
/* Get the size of the ImageView */
int targetW = recipeImage.getWidth();
int targetH = recipeImage.getHeight();
/* Get the size of the image */
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
/* Figure out which way needs to be reduced less */
int scaleFactor = 2;
if ((targetW > 0) && (targetH > 0)) {
scaleFactor = Math.max(photoW / targetW, photoH / targetH);
}
/* Set bitmap options to scale the image decode target */
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Matrix matrix = new Matrix();
matrix.postRotate(getRotation());
/* Decode the JPEG file into a Bitmap */
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
/* Associate the Bitmap to the ImageView */
recipeImage.setImageBitmap(bitmap);
}
private float getRotation() {
try {
ExifInterface ei = new ExifInterface(mCurrentPhotoPath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
return 90f;
case ExifInterface.ORIENTATION_ROTATE_180:
return 180f;
case ExifInterface.ORIENTATION_ROTATE_270:
return 270f;
default:
return 0f;
}
} catch (Exception e) {
Log.e("Add Recipe", "getRotation", e);
return 0f;
}
}
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
}
private void handleBigCameraPhoto() {
if (mCurrentPhotoPath != null) {
setPic();
galleryAddPic();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
handleBigCameraPhoto();
}
}
# Take photo
Add a permission to access the camera to the AndroidManifest file:
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Xml file :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<SurfaceView android:id="@+id/surfaceView" android:layout_height="0dip" android:layout_width="0dip"></SurfaceView>
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView"></ImageView>
</LinearLayout>
Activity
import java.io.IOException;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.ImageView;
public class TakePicture extends Activity implements SurfaceHolder.Callback
{
//a variable to store a reference to the Image View at the main.xml file
private ImageView iv_image;
//a variable to store a reference to the Surface View at the main.xml file
private SurfaceView sv;
//a bitmap to display the captured image
private Bitmap bmp;
//Camera variables
//a surface holder
private SurfaceHolder sHolder;
//a variable to control the camera
private Camera mCamera;
//the camera parameters
private Parameters parameters;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//get the Image View at the main.xml file
iv_image = (ImageView) findViewById(R.id.imageView);
//get the Surface View at the main.xml file
sv = (SurfaceView) findViewById(R.id.surfaceView);
//Get a surface
sHolder = sv.getHolder();
//add the callback interface methods defined below as the Surface View callbacks
sHolder.addCallback(this);
//tells Android that this surface will have its data constantly replaced
sHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
{
//get camera parameters
parameters = mCamera.getParameters();
//set camera parameters
mCamera.setParameters(parameters);
mCamera.startPreview();
//sets what code should be executed after the picture is taken
Camera.PictureCallback mCall = new Camera.PictureCallback()
{
@Override
public void onPictureTaken(byte[] data, Camera camera)
{
//decode the data obtained by the camera into a Bitmap
bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
String filename=Environment.getExternalStorageDirectory()
+ File.separator + "testimage.jpg";
FileOutputStream out = null;
try {
out = new FileOutputStream(filename);
bmp.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap instance
// PNG is a lossless format, the compression factor (100) is ignored
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//set the iv_image
iv_image.setImageBitmap(bmp);
}
};
mCamera.takePicture(null, null, mCall);
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
// The Surface has been created, acquire the camera and tell it where
// to draw the preview.
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException exception) {
mCamera.release();
mCamera = null;
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
//stop the preview
mCamera.stopPreview();
//release the camera
mCamera.release();
//unbind the camera from this object
mCamera = null;
}
}
# How to start camera or gallery and save camera result to storage
First of all you need Uri
and temp Folders and request codes :
public final int REQUEST_SELECT_PICTURE = 0x01;
public final int REQUEST_CODE_TAKE_PICTURE = 0x2;
public static String TEMP_PHOTO_FILE_NAME ="photo_";
Uri mImageCaptureUri;
File mFileTemp;
Then init mFileTemp :
public void initTempFile(){
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
mFileTemp = new File(Environment.getExternalStorageDirectory() + File.separator
+ getResources().getString(R.string.app_foldername) + File.separator
+ getResources().getString(R.string.pictures_folder)
, TEMP_PHOTO_FILE_NAME
+ System.currentTimeMillis() + ".jpg");
mFileTemp.getParentFile().mkdirs();
} else {
mFileTemp = new File(getFilesDir() + File.separator
+ getResources().getString(R.string.app_foldername)
+ File.separator + getResources().getString(R.string.pictures_folder)
, TEMP_PHOTO_FILE_NAME + System.currentTimeMillis() + ".jpg");
mFileTemp.getParentFile().mkdirs();
}
}
Opening Camera
and Gallery
intents :
public void openCamera(){
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
try {
mImageCaptureUri = null;
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
mImageCaptureUri = Uri.fromFile(mFileTemp);
} else {
mImageCaptureUri = InternalStorageContentProvider.CONTENT_URI;
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
intent.putExtra("return-data", true);
startActivityForResult(intent, REQUEST_CODE_TAKE_PICTURE);
} catch (Exception e) {
Log.d("error", "cannot take picture", e);
}
}
public void openGallery(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
requestPermission(Manifest.permission.READ_EXTERNAL_STORAGE,
getString(R.string.permission_read_storage_rationale),
REQUEST_STORAGE_READ_ACCESS_PERMISSION);
} else {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)), REQUEST_SELECT_PICTURE);
}
}
Then in onActivityResult
method :
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
}
Bitmap bitmap;
switch (requestCode) {
case REQUEST_SELECT_PICTURE:
try {
Uri uri = data.getData();
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
Bitmap bitmapScaled = Bitmap.createScaledBitmap(bitmap, 800, 800, true);
Drawable drawable=new BitmapDrawable(bitmapScaled);
mImage.setImageDrawable(drawable);
mImage.setVisibility(View.VISIBLE);
} catch (IOException e) {
Log.v("act result", "there is an error : "+e.getContent());
}
} catch (Exception e) {
Log.v("act result", "there is an error : "+e.getContent());
}
break;
case REQUEST_CODE_TAKE_PICTURE:
try{
Bitmap bitmappicture = MediaStore.Images.Media.getBitmap(getContentResolver() , mImageCaptureUri);
mImage.setImageBitmap(bitmappicture);
mImage.setVisibility(View.VISIBLE);
}catch (IOException e){
Log.v("error camera",e.getMessage());
}
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
You need theese permissions in AndroidManifest.xml
:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
And you need to handle runtime permissions (opens new window) such as Read/Write external storage etc ...
I am checking READ_EXTERNAL_STORAGE
permission in my openGallery
method :
My requestPermission
method :
protected void requestPermission(final String permission, String rationale, final int requestCode) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
showAlertDialog(getString(R.string.permission_title_rationale), rationale,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(BasePermissionActivity.this,
new String[]{permission}, requestCode);
}
}, getString(android.R.string.ok), null, getString(android.R.string.cancel));
} else {
ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
}
}
Then Override onRequestPermissionsResult
method :
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_STORAGE_READ_ACCESS_PERMISSION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
handleGallery();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
showAlertDialog
method :
protected void showAlertDialog(@Nullable String title, @Nullable String message,
@Nullable DialogInterface.OnClickListener onPositiveButtonClickListener,
@NonNull String positiveText,
@Nullable DialogInterface.OnClickListener onNegativeButtonClickListener,
@NonNull String negativeText) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(title);
builder.setMessage(message);
builder.setPositiveButton(positiveText, onPositiveButtonClickListener);
builder.setNegativeButton(negativeText, onNegativeButtonClickListener);
mAlertDialog = builder.show();
}
# Set camera resolution
Set High resolution programmatically.
Camera mCamera = Camera.open();
Camera.Parameters params = mCamera.getParameters();
// Check what resolutions are supported by your camera
List<Size> sizes = params.getSupportedPictureSizes();
// Iterate through all available resolutions and choose one.
// The chosen resolution will be stored in mSize.
Size mSize;
for (Size size : sizes) {
Log.i(TAG, "Available resolution: "+size.width+" "+size.height);
mSize = size;
}
}
Log.i(TAG, "Chosen resolution: "+mSize.width+" "+mSize.height);
params.setPictureSize(mSize.width, mSize.height);
mCamera.setParameters(params);
# Decode bitmap correctly rotated from the uri fetched with the intent
private static final String TAG = "IntentBitmapFetch";
private static final String COLON_SEPARATOR = ":";
private static final String IMAGE = "image";
@Nullable
public Bitmap getBitmap(@NonNull Uri bitmapUri, int maxDimen) {
InputStream is = context.getContentResolver().openInputStream(bitmapUri);
Bitmap bitmap = BitmapFactory.decodeStream(is, null, getBitmapOptions(bitmapUri, maxDimen));
int imgRotation = getImageRotationDegrees(bitmapUri);
int endRotation = (imgRotation < 0) ? -imgRotation : imgRotation;
endRotation %= 360;
endRotation = 90 * (endRotation / 90);
if (endRotation > 0 && bitmap != null) {
Matrix m = new Matrix();
m.setRotate(endRotation);
Bitmap tmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
if (tmp != null) {
bitmap.recycle();
bitmap = tmp;
}
}
return bitmap;
}
private BitmapFactory.Options getBitmapOptions(Uri uri, int imageMaxDimen){
BitmapFactory.Options options = new BitmapFactory.Options();
if (imageMaxDimen > 0) {
options.inJustDecodeBounds = true;
decodeImage(null, uri, options);
options.inSampleSize = calculateScaleFactor(options, imageMaxDimen);
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.RGB_565;
addInBitmapOptions(options);
}
}
private int calculateScaleFactor(@NonNull BitmapFactory.Options bitmapOptionsMeasureOnly, int imageMaxDimen) {
int inSampleSize = 1;
if (bitmapOptionsMeasureOnly.outHeight > imageMaxDimen || bitmapOptionsMeasureOnly.outWidth > imageMaxDimen) {
final int halfHeight = bitmapOptionsMeasureOnly.outHeight / 2;
final int halfWidth = bitmapOptionsMeasureOnly.outWidth / 2;
while ((halfHeight / inSampleSize) > imageMaxDimen && (halfWidth / inSampleSize) > imageMaxDimen) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public int getImageRotationDegrees(@NonNull Uri imgUri) {
int photoRotation = ExifInterface.ORIENTATION_UNDEFINED;
try {
boolean hasRotation = false;
//If image comes from the gallery and is not in the folder DCIM (Scheme: content://)
String[] projection = {MediaStore.Images.ImageColumns.ORIENTATION};
Cursor cursor = context.getContentResolver().query(imgUri, projection, null, null, null);
if (cursor != null) {
if (cursor.getColumnCount() > 0 && cursor.moveToFirst()) {
photoRotation = cursor.getInt(cursor.getColumnIndex(projection[0]));
hasRotation = photoRotation != 0;
Log.d("Cursor orientation: "+ photoRotation);
}
cursor.close();
}
//If image comes from the camera (Scheme: file://) or is from the folder DCIM (Scheme: content://)
if (!hasRotation) {
ExifInterface exif = new ExifInterface(getAbsolutePath(imgUri));
int exifRotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (exifRotation) {
case ExifInterface.ORIENTATION_ROTATE_90: {
photoRotation = 90;
break;
}
case ExifInterface.ORIENTATION_ROTATE_180: {
photoRotation = 180;
break;
}
case ExifInterface.ORIENTATION_ROTATE_270: {
photoRotation = 270;
break;
}
}
Log.d(TAG, "Exif orientation: "+ photoRotation);
}
} catch (IOException e) {
Log.e(TAG, "Error determining rotation for image"+ imgUri, e);
}
return photoRotation;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private String getAbsolutePath(Uri uri) {
//Code snippet edited from: http://stackoverflow.com/a/20559418/2235133
String filePath = uri.getPath();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
// Will return "image:x*"
String[] wholeID = TextUtils.split(DocumentsContract.getDocumentId(uri), COLON_SEPARATOR);
// Split at colon, use second item in the array
String type = wholeID[0];
if (IMAGE.equalsIgnoreCase(type)) {//If it not type image, it means it comes from a remote location, like Google Photos
String id = wholeID[1];
String[] column = {MediaStore.Images.Media.DATA};
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = context.getContentResolver().
query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{id}, null);
if (cursor != null) {
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
}
Log.d(TAG, "Fetched absolute path for uri" + uri);
}
}
return filePath;
}