Bitmap being null / imagepath not existing - android

I have multiple Activities that are supposed to work on one image that is taken through an Intent as described here
https://developer.android.com/training/camera/photobasics.html
I then have a path to my image, which I use to access the photo and manipulate it (changing size, colors)
But when I try to create a Bitmap from the path, it always give Errors like
E/BitmapFactory: Unable to decode stream: java.lang.NullPointerException: Attempt to invoke virtual method 'char[] java.lang.String.toCharArray()' on a null object reference
I have the imagePath saved in a private variable, and pass it in a Bundle betweeen the activities, which works fine the first time. When I pass it the same way to the third activity, the abobe error shows.
Here's a bit of my code to scale the image before putting it in the ImageView:
public class scaleImage {
static Bitmap setPic(ImageView mImageView, String mCurrentPhotoPath) {
// Get the dimensions of the View
int targetW = mImageView.getWidth();
int targetH = mImageView.getHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
//bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
mImageView.setImageBitmap(bitmap);
return bitmap;
}
}
The function in the first Activity that creates a file that the image is saved to (like in the example):
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
imageFileName = image.getName();
return image;
}
The second Activity gets the imagePath through a Bundle when called and passes it to the third one the same way like this:
void callPictureScalerActivity() {
Intent intent = new Intent(this, ConvertToGrayscale.class);
Bundle b = new Bundle();
b.putString("imagePath", mCurrentPhotoPath);
intent.putExtras(b);
startActivity(intent);
}
The third Activity tries get a Bitmap from the imagepath which isn't working anymore. (Have to do this not in onCreate since the size of the imageView is not known yet):
public void onWindowFocusChanged(boolean focus) {
super.onWindowFocusChanged(focus);
scaleImage.setPic((ImageView) findViewById(R.id.scalablePicture), photoPath);
}
So I'm wondering, does the file for the image get deleted after calling more then one Activity or is the fault somewhere else? At this point I'm clueless at what other way I should access the Image.
Edit: The error above appears in the line where I'm trying to get the Bitmap from the path:
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
so it's an error that occurs in the decodeFile function, which I can't look into.
Also the third Activity is called when a Button is pressed in the second, calling the callPictureScalerActivity function.
The photo is saved with following function:
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) {
// Error occurred while creating the File
Log.w("Error", "Error creating the image file");
}
// Continue only if the File was successfully created
if (photoFile != null) {
photoURI = FileProvider.getUriForFile(this,
"com.example.android.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
I know the photo is saved since I looked up the path from mCurrentPhotoPath.

Related

Android Bitmap.Compress saves image of Low Quality and Scaled down image

I am trying to make an app that takes a picture and embed another image like a logo onto the original image. But I have a problem in the initial stages.
I am trying to save the image from the Bitmap received from onActivityResult for the camera intent. But after using the following code, the images are scaled-down and compressed too much and looks bad. Can someone help me retain the picture quality and size?
Here are the pictures that the app saved:
public void saveBitmapToGallery(Bitmap bm,String picturename){
String root = Environment.getExternalStorageDirectory().toString();
File mydir = new File(picturepath);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
displayheight = dm.heightPixels;
displaywidth = dm.widthPixels;
File file = new File(mydir, picturename+".JPG");
try {
FileOutputStream fos = new FileOutputStream(file);
bm.createScaledBitmap(bm,displaywidth,displayheight,true);
bm.compress(Bitmap.CompressFormat.JPEG,100, fos);
fos.flush();
fos.close();
}catch (FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
I expect an image like the general camera app so that I can work on embedding the logo once I can get my app to save good quality images.
the image did not convert into byte output
also, Go for My Github Profile for this
https://github.com/axarlotwala/CafeDelearenter code here
// using intent open file chooser option
private void ShowFileChooser() {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Picture"),PICK_IMAGE_REQUEST);
}
// show selected and path image in imageview
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
PATH = data.getData();
try {
bitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(),PATH);
cat_image.setImageBitmap(bitmap);
tv_path.setText("Path : " .concat(GetPath(PATH)));
} catch (IOException e) {
e.printStackTrace();
}
}
//get correct path of image
private String GetPath(Uri uri){
String result;
Cursor cursor = getActivity().getContentResolver().query(uri,null,null,null,null);
if (cursor == null){
result = uri.getPath();
}else {
cursor.moveToFirst();
int id = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
result = cursor.getString(id);
cursor.close();
}
return result;
}
Well, I figured out what was wrong with the output image. We need to use EXTRA_OUTPUT for the picture to be saved in full size, otherwise only a thumbnail is saved.
Here is what we need to to before starting camera activity for result
if (picturefile != null) {
Uri pictureUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() +
".provider", picturefile);
imageIntent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri); //This makes the image to save in full rather than just a low quality scaled-down thumbnail.
}
startActivityForResult(imageIntent, REQUEST_IMAGE_CAPTURE);

How to get Good Quality Bitmap image after capture from camera in Android?

I am trying to get Bitmap image after Capture image from camera. What i am doing first i save a image into memory and then getting a bitmap image from image path.
private String imageFilePath =null;
private void openCameraIntent() {
Intent pictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(pictureIntent.resolveActivity(getPackageManager()) != null){
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
}
if (photoFile != null) {
photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID +".fileprovider", photoFile);
pictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(pictureIntent, REQUEST_CAPTURE_IMAGE);
}
}
}
private File createImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
Locale.getDefault()).format(new Date());
String imageFileName = "IMG_" + timeStamp + "_";
File storg =
getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storg /* directory */
);
imageFilePath = image.getAbsolutePath();
return image;
}
public Bitmap bitmapimage(String path) {
return BitmapFactory.decodeFile(path);
}
But in my case i don't want to save image into memory. I want to get bitmap image after Capture image. I tried it but i am getting very low quality image. How can i get good quality bitmap image without saving into memory. please help me to do this. Thank you
That's true. The camera intent can only pass a high resolution image as a file. You can delete it as soon as your app recovers control, even though it is usually done in onActivityResult() callback.
Note that by then, the picture have been indexed in device MediaStore, a.k a. Gallery.
The alternative is to use the camera API instead of intent. Some wrapper libraries, like fotoapparat, may help.

Android saving PNG from the device camera (Poor quality)

I am having a problem while trying to save a photo to storage with an Android app. The app uses the devices camera to take a photo and save it as a PNG to the device.
For some reason no matter what I do or where I store the image the quality is very poor. The app is an existing project that is quite large so I was wondering if there are other factors to consider when saving images to a device or maybe another way of overriding the quality.
This is the function that was coded by the previous dev:
public String saveImageToDevice(Bitmap image) {
saveCanvasImage(image);
String root = Environment.getExternalStorageDirectory().toString()+"/Android/data/com.app.android";
File myDir = new File(root + "/saved_images");
myDir.mkdirs();
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fname = "Image-"+ timeStamp +".png";
File file = new File (myDir, fname);
if (file.exists ()){
file.delete ();
}
try {
Toast.makeText(getActivity(), "Saving Image...", Toast.LENGTH_SHORT).show();
Log.i("Image saved", root+"/saved_images/"+fname);
FileOutputStream out = new FileOutputStream(file);
image.compress(CompressFormat.PNG, 100, out);
imageLocations.add(fname);
out.flush();
out.close();
//return myDir.getAbsolutePath() + "/" +fname;
return fname;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
And this is a function I have tried myself from an example online:
public void saveCanvasImage(Bitmap b) {
File f = new File(Environment.getExternalStorageDirectory().toString() + "/img.png");
try {
f.createNewFile(); // your mistake was at here
FileOutputStream fos = new FileOutputStream(f);
b.compress(CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
}catch (IOException e){
e.printStackTrace();
}
}
Both of these produce the same very poor images. I have posted a before and after segment below.
This is what the camera preview looks like.
This is the resulting image once it has saved.
After speaking to a few people i am including my camera intent code:
public void startCameraIntent(){
/*************************** Camera Intent Start ************************/
// Define the file-name to save photo taken by Camera activity
String fileName = "Camera_Example.png";
// Create parameters for Intent with filename
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, fileName);
values.put(MediaStore.Images.Media.DESCRIPTION,"Image capture by camera");
// imageUri is the current activity attribute, define and save it for later usage
#SuppressWarnings("unused")
Uri imageUri = getActivity().getContentResolver().insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
/**** EXTERNAL_CONTENT_URI : style URI for the "primary" external storage volume. ****/
// Standard Intent action that can be sent to have the camera
// application capture an image and return it.
Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE );
//intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // set the image file name
startActivityForResult( intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
/*************************** Camera Intent End ************************/
}
As you can see the EXTRA_OUTPUT line is has been commented out due to it causing crashes with the below error:
12-17 13:31:37.339: E/AndroidRuntime(16123): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=65537, result=-1, data=null} to activity {}: java.lang.NullPointerException
I have also included my onActivityresult code too:
public void onActivityResult( int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
int page = mViewPager.getCurrentItem();
NotesPagerFragment note = pages.get(page);
Log.i("Request Code", ""+requestCode);
//For the ImageCapture Activity
if ( requestCode == 1) {
if ( resultCode != 0) {
/*********** Load Captured Image And Data Start ****************/
Bitmap bp = (Bitmap) data.getExtras().get("data");
//add the image to the note through a function call
note.addImage(bp);
note.saveImageToDevice(bp);
//String imageId = convertImageUriToFile( imageUri,CameraActivity);
// Create and excecute AsyncTask to load capture image
// new LoadImagesFromSDCard().execute(""+imageId);
/*********** Load Captured Image And Data End ****************/
} else if ( resultCode == 0) {
Toast.makeText(this.getActivity(), " Picture was not taken ", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this.getActivity(), " Picture was not taken ", Toast.LENGTH_SHORT).show();
}
}
//For the deleting an Image
if (requestCode == 2) {
String location = (String) data.getExtras().get("imageLocation");
if(data.getExtras().get("back") != null){
//just going back, don't mind me
}else {
//Toast.makeText(this.getActivity(), "BOO", Toast.LENGTH_SHORT).show();
note.removeNoteImageFromView(location);
database.removeSingleNoteImageFromSystemByLocation(location);
}
}
}
OK so after a lot of help from MelquiadesI have eventually solved this issue. The problem I had was that my intent and onActivityResult were retrieving the thumbnail of the image and scaling it up (hence the poor quality).
The line below is responsible for getting the thumbnail preview (120px x 160px):
Bitmap bp = (Bitmap) data.getExtras().get("data");
In order to access the full image I need to add EXTRA_OUTPUT to the intent which looks as follows:
public void startCameraIntent(){
/*************************** Camera Intent Start ************************/
File imageFile = new File(imageFilePath);
Uri imageFileUri = Uri.fromFile(imageFile); // convert path to Uri
// Standard Intent action that can be sent to have the camera
// application capture an image and return it.
Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE );
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri); // set the image file name
startActivityForResult( intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
/*************************** Camera Intent End ************************/
}
I also declared my imageFilePath as a string at the top of my activity:
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFilePath = Environment.getExternalStorageDirectory().toString()+"/Android/data/com.my.app/Image-"+timeStamp+".png";
I then had to change onActivityResult so it could access the full image to use:
public void onActivityResult( int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
int page = mViewPager.getCurrentItem();
NotesPagerFragment note = pages.get(page);
Log.i("Request Code", ""+requestCode);
//For the ImageCapture Activity
if ( requestCode == 1) {
if ( resultCode != 0) {
/*********** Load Captured Image And Data Start ****************/
// Decode it for real
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = false;
//imageFilePath image path which you pass with intent
Bitmap bp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
//rotate image by 90 degrees
Matrix rotateMatrix = new Matrix();
rotateMatrix.postRotate(90);
Bitmap rotatedBitmap = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), rotateMatrix, false);
//add the image to the note through a function call
note.addImage(rotatedBitmap);
note.saveImageToDevice(rotatedBitmap);
//String imageId = convertImageUriToFile( imageUri,CameraActivity);
// Create and excecute AsyncTask to load capture image
// new LoadImagesFromSDCard().execute(""+imageId);
/*********** Load Captured Image And Data End ****************/
} else if ( resultCode == 0) {
Toast.makeText(this.getActivity(), " Picture was not taken ", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this.getActivity(), " Picture was not taken ", Toast.LENGTH_SHORT).show();
}
}
//For the deleting an Image
if (requestCode == 2) {
String location = (String) data.getExtras().get("imageLocation");
if(data.getExtras().get("back") != null){
//just going back, don't mind me
}else {
//Toast.makeText(this.getActivity(), "BOO", Toast.LENGTH_SHORT).show();
note.removeNoteImageFromView(location);
database.removeSingleNoteImageFromSystemByLocation(location);
}
}
}
The key part here is:
// Decode it for real
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = false;
//imageFilePath image path which you pass with intent
Bitmap bp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
This code decodes the image you saved at imageFilePath into a usable bitmap. From here you can use it as normal.
Sometimes (apparently this is quite common) the image comes in rotated by 90°, the next bit of code will rotate that back if you need it to:
//rotate image by 90 degrees
Matrix rotateMatrix = new Matrix();
rotateMatrix.postRotate(90);
Bitmap rotatedBitmap = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), rotateMatrix, false);

error creating a directory for Camera app to store photo

Im working on an app that will take a picture, then return it and put it in an imageview.
I was able to get it working when it would return a thumbnail size image. I followed the directions on the android developer page the creates an image file but for some reason it isnt working for me. I have a button that launches a method that calls the createImageFile() before starting the intent. however this method fails and the camera is never even started.
here is my version:
private File createImageFile() throws IOException
{
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").
format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
Log.i("storage: ",storageDir.getAbsolutePath());
File image = File.createTempFile(imageFileName,
".jpg",storageDir);
Log.i("filename: ", "afterimage");
FILENAME = "file:" + image.getAbsolutePath();
Log.i("filename: ", FILENAME);
return image;
}
however my code never makes it past File image = File.createTempFile(imageFileName,
".jpg",storageDir)
becasuse i never see the following Log.i();
I tried creating storageDir with context.getCacheDir() and the camera actually starts but then after taking a photo i am unable to click the check mark and return to the main activity.
Here is the rest of the Activity if necessary:
public class Camera extends Activity
{
private final int PICTURE_ACTIVITY_CODE = 1;
String FILENAME;
File f;
Button b;
ImageView image;
#Override
/**
* onCreate method. Instantiates buttons and textfield
* and sets a listener for button that launches launchTakePhoto
* method.
*/
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
image = (ImageView) findViewById(R.id.img);
b = (Button) findViewById(R.id.b1);
b.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
launchTakePhoto();
}
});
}
/**
* method that finds storage location on devices. Then
* creates a file and launches an actvitiy for result
* to retrieve the data later and store it in that file,
* in that storage space.
*/
private void launchTakePhoto()
{
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED))
{
try
{
f = createImageFile();
}
catch(IOException e)
{
Log.i("Error","error");
}
}
else
{
f = new File(getCacheDir(), FILENAME);
}
if (f != null)
{
Uri outputFileUri = Uri.fromFile(f);
i.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(i, PICTURE_ACTIVITY_CODE);
}
}
protected void onActivityResult(int req, int res, Intent data)
{
if ((req == PICTURE_ACTIVITY_CODE)&&(res == RESULT_OK))
{
Log.i("res: ", "PASSED"); ImageView iv = (ImageView) findViewById(R.id.img);
Uri uriImage = Uri.fromFile(f);
iv.setImageURI(uriImage);
}
}
Thanks for any help. Ive seen a lot of different possible answers but nothing is working for me so far. I just want to be able to return a full size image and place it in the image holder.
I think you might be best to look at the Android API for image capture as it has recently changed since API 21. Possibly the best way to perform this operation is to open the camera, allow the user to capture the image and use the onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result)function defined in: http://developer.android.com/reference/android/hardware/camera2/CameraCaptureSession.CaptureCallback.html to receive the results of the image capture and then set the image viewer to the result. If you are also trying to save the image then try using the file handler process as defined in the Android Documentation at: http://developer.android.com/training/camera/photobasics.html
String mCurrentPhotoPath;
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
return image;
}

Android: Capture and store pictures

I'm following this tutorial on taking pictures, displaying thumbnails and storing the full pictures on local public storage available to my application only.
The problem: EACCESS (Permission denied) when trying to access local storage for my application
11-12 10:36:30.765 3746-3746/com.test.example.photo W/System.err﹕ java.io.IOException: open failed: EACCES (Permission denied)
11-12 10:36:30.765 3746-3746/com.test.example.photo W/System.err﹕ at java.io.File.createNewFile(File.java:948)
11-12 10:36:30.765 3746-3746/com.test.example.photo W/System.err﹕ at java.io.File.createTempFile(File.java:1013)
I've looked at this question but it appears to be outdated as none of the solutions work any more today. This question also provides no working solutions. Other results and solutions I've seen and tried seem only vaguely related.
My manifest permissions
</application>
<!-- PERMISSIONS -->
<permission
android:name="android.hardware.Camera.any"
android:required="true" />
<permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:required="true" />
<!-- android:maxSdkVersion="18" seemingly does nothing-->
</manifest>
The method that crashes
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
//THIS IS WHERE IT CRASHES
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
return image;
}
I am using an i9250 Galaxy Nexus 3 phone to run the examples, since my emulator doesn't have a camera and automatically GONEs the elements. My target SDK is 16 and I have updated my both my build tools and Android Studio to the latest versions.
I feel like I'm missing something obvious here, since taking pictures is so common in applications and I can't imagine it not working for everyone, but I'm stuck and I'd appreciate your guidance. I am quite new to android, the literature I'm primarily using is Beginning Android 4 Game Programming, Beginning Android 4 and Pro Android 4.
Thank you for your time!
Thanks for the help everyone, it works now!
Apparently I was using the SD card storage which required permissions as explained in permission vs uses-permisson instead of local sandboxed storage which requires no permissions starting from API level 19.
SD card access, requires write permission: Environment.getExternalStoragePublicDirectory
Sandboxed local storage for your app: getExternalFilesDir
I use this code for API level 16, it should require minimal effort to implement and change but if you encounter problems, leave a message and I'll try to help or clarify.
Most of the explanation is in the code as commentary
//OnClick hook, requires implements View.OnClickListener to work
public void takePicture(View v) {
dispatchTakePictureIntent();
}
private void dispatchTakePictureIntent() {
//Create intent to capture an image from the camera
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 directory File where the photo should go, do NOT try to create the image file itself
File photoFile = null;
try {
//mCurrentPhotoPath is a File outside of the methods, so all methods know the last directory for the last picture taken
mCurrentPhotoPath = createImageFile();
photoFile = mCurrentPhotoPath;
} catch (IOException ex) {
// Error occurred while creating the File
ex.printStackTrace();
}
// Continue only if the File was successfully created
if (photoFile != null) {
//photoFile MUST be a directory or the camera will hang on an internal
//error and will refuse to store the picture,
//resulting in not being able to to click accept
//MediaStore will automatically store a jpeg for you in the specific directory and add the filename to the path
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
//unique name, can be pretty much whatever you want
imageId = generateImageId();
//Get file.jpg as bitmap from MediaStore's returned File object
Bitmap imageBitmap = BitmapFactory.decodeFile(mCurrentPhotoPath.getAbsolutePath());
//resize it to fit the screen
imageBitmap = Bitmap.createScaledBitmap(imageBitmap,300,300,false);
//Some ImageView in your layout.xml
ImageView imageView = (ImageView)findViewById(R.id.imageView);
imageView.setImageBitmap(imageBitmap);
Bitmap thumbnail = makeThumbnail(mCurrentPhotoPath);
ImageView thumbnail = (ImageView)findViewById(R.id.thumbnail);
thumbnail.setImageBitmap(imageBitmap);
}
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
//completely optional subdirectory structure
storageDir = new File(storageDir, "custom_directory");
return storageDir;
}
private Bitmap makeThumbnail(File currentPhotoPath) {
// Get the dimensions of the View, I strongly recommend creating a <dimens> resource for dip scaled pixels
int targetW = 45;
int targetH = 80;
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(currentPhotoPath.getAbsolutePath(), bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(currentPhotoPath.getAbsolutePath(), bmOptions);
return bitmap;
}
private long generateImageId() {
return Calendar.getInstance().getTimeInMillis();
}
Android 5.0, API 21, will use the Camera2 API where all of this will be hidden far away, from what I understand. You can read about it here
try this:
private File getDir() {
File sdDir = Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
return new File(sdDir, "Your_photo_dir_here");
}
then:
File pictureFileDir = getDir();
if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {
Log.d("TAG", "Can't create directory to save image.");
return;
}
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
String date = dateFormat.format(new Date());
String photoFile = "myphoto_" + date + ".jpg";
String filename = pictureFileDir.getPath() + File.separator + photoFile;
File pictureFile = new File(filename);
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (Exception error) {
Log.d("TAG", "File" + filename + "not saved: "
+ error.getMessage());
}
Instead of permission tag use uses-permission
Add this in manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Categories

Resources