Camera and Gallery
Taking full-sized photo from camera
Section titled “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 attributerequiredis set totrueyou 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
Section titled “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(); }}
@Overridepublic 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
Section titled “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
Section titled “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 :
@Overrideprotected 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 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 :
@Overridepublic 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
Section titled “Set camera resolution”Set High resolution programmatically.
Camera mCamera = Camera.open();Camera.Parameters params = mCamera.getParameters();
// Check what resolutions are supported by your cameraList<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
Section titled “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";
@Nullablepublic 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;}