I was practicing around with the Camera API
for which I did the following:
a. Setup a directory for the image captured (for startActivityForResult
)
b. Setup the Bitmap so that the image could be shown once saved in the app itself.
Here's the code for the following:
Setting up the directory.
private static File getOutputMediaFile(int type) {
// External sdcard location
File mediaStorageDir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
IMAGE_DIRECTORY_NAME);
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d(IMAGE_DIRECTORY_NAME, "Oops! Failed create "
+ IMAGE_DIRECTORY_NAME + " directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
Locale.getDefault()).format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + timeStamp + ".jpg");
} else {
return null;
}
return mediaFile;
}
Global variables in the application
// Activity request codes
private static final int CAMERA_CAPTURE_IMAGE_REQUEST_CODE = 100;
public static final int MEDIA_TYPE_IMAGE = 1;
// directory name to store the captured images
private static final String IMAGE_DIRECTORY_NAME = "my_camera_app";
private Uri fileUri;
// Views
ImageView photo;
Button camera;
Camera implementation logic
// Use camera function
private void captureImage() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
// start the image capture Intent
startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// Successfully captured the image
// display in imageview
previewImage();
} else {
// failed to capture image
Toast.makeText(getApplicationContext(),
"Sorry! Failed to capture image", Toast.LENGTH_SHORT)
.show();
}
}
}
private void previewImage() {
try {
// Bitmap factory
BitmapFactory.Options options = new BitmapFactory.Options();
// Downsizing image as it throws OutOfMemory exception for larger
// images
options.inSampleSize = 3;
final Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getPath(),
options);
photo.setImageBitmap(bitmap);
} catch (NullPointerException e) {
e.printStackTrace();
}
}
The problem I am having is that ... for some of the devices that I tested the app, the app shows a blank preview of the image shot while in others the app works completely well.
Why am I getting a blank feedback ? and in some of the cases, when an image is saved, the user is not directed to my app, instead the user is stuck in the camera app.
Please do help.
At least for Kitkat 4.4.2 on a Galaxy S4, with a relative layout, I had to call invalidate() on the ImageView that i just setImageBitmap on. If i didn't, i got the blank screen. After adding the invalidate() after setImageBitmap(), then I got the image.
I had the same problem and solved it by changing the rendering of the view to software
ImageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
try loading bitmap efficiently:
public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
//BitmapFactory.Options optionss = new BitmapFactory.Options();
//optionss.inPreferredConfig = Bitmap.Config.RGB_565;
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
BitmapFactory.decodeFile(path,options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;}
One way I got around this problem was when setting the FileUri
, I stored the Uri
using SharedPreferences
. So in my code:
public void takePhoto() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = FileHelper.getOutputMediaFileUri();
// Store uri to SharedPreferences
pref.setImageUri(fileUri.toString());
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(intent, TAKE_PICTURE);
}
In my onActivityResult
callback:
if (requestCode == TAKE_PICTURE && resultCode == RESULT_OK) {
// If user is taking photo then only call the SharedPreferences
// If user is selecting photo from gallery, we can use the Intent data
fileUri = Uri.parse(pref.getImageUri());
if (fileUri.getPath().toString().length() < 1) {
Toast.makeText(getApplicationContext(),
"Sorry something went wrong ... Please try again",
Toast.LENGTH_LONG).show();
} else {
String path = fileUri.getPath().toString();
db_img_path = path;
imageholder.setVisibility(View.VISIBLE);
Bitmap bitmap = PathtoImage.previewImage(path);
imagepreview.setImageBitmap(bitmap);
}
}
Bonus :)
In my previewImage
method, I have made adjustments for orientation, the code looks like this :
public static Bitmap previewImage(String path) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
final Bitmap bitmap = BitmapFactory.decodeFile(path, options);
// Providing adjustment so that the image is shown in the correct orientation
Matrix adjustment = adjustOrientation(path);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(), adjustment, true);
return resizedBitmap;
}
In this method I call another method adjustOrientation
which gives me the Matrix
fix to the image.
// Adjustment for orientation of images
public static Matrix adjustOrientation(String path) {
Matrix matrix = new Matrix();
try {
ExifInterface exifReader = new ExifInterface(path);
int orientation = exifReader.getAttributeInt(
ExifInterface.TAG_ORIENTATION, -1);
if (orientation == ExifInterface.ORIENTATION_NORMAL) {
// do nothing
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
matrix.postRotate(90);
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
matrix.postRotate(180);
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
matrix.postRotate(270);
}
} catch (IOException e) {
e.printStackTrace();
}
return matrix;
}
This is my implementation for the issue, if anyone has a better implementation to this, please do post :)
Actually it is setting but it doesnt appear for some reason.
profileImageView.post(new Runnable() {
@Override
public void run() {
profileImageView.setImageBitmap(bm);
}
});
This works for me.