i am making an app of which it can initialize the camera and then after taking the photo, the photo could be imported and the user to further draw on it.
Coding:
Class A:
public OnClickListener cameraButtonListener = new OnClickListener()
{
#Override
public void onClick(View v)
{
vibrate();
Toast.makeText(Doodlz.this, R.string.message_initalize_camera, Toast.LENGTH_SHORT).show();
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
}
};
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK)
{
Bitmap photo = (Bitmap) data.getExtras().get("data");
Bitmap photocopy = photo.copy(Bitmap.Config.ARGB_8888, true);
doodleView.get_camera_pic(photocopy);
}
}
doodleView:
public void get_camera_pic (Bitmap photocopy)
{
// get screen dimension first
WindowManager wm = (WindowManager) context_new.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
final int screenWidth = display.getWidth();
final int screenHeight = display.getHeight();
bitmap = photocopy;
bitmap = Bitmap.createScaledBitmap(bitmap, screenWidth, screenHeight, true);
bitmapCanvas = new Canvas(bitmap);
invalidate(); // refresh the screen
}
Question:
The photo can be successfully captured using the camera and return to doodleView for user. Yet since the imported image dimension is very small, just a thumbnail size!! (dont know why), so I tired scaling it up and then the resolution is very poor.
My question is that, how modify the above code so as to set the photo taken dimension be fitting to the screen's dimension and the returned photo be 1:1 of the screen instead of getting like a thumbnail one? (best to be fit 1:1 of screen, because if it is then importing as original photo size the photo dimension is then greater then the screen, it then need to scale down and distorted by different ratio of width and height ratio to fit full screen)
Thanks!!
This is normal for the default camera application. The way to get the full size image is to tell the camera activity to put the result into a file. First create a file and then start the camera application as follows:
outputFileName = createImageFile(".tmp");
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outputFileName));
startActivityForResult(takePictureIntent, takePhotoActionCode);
Then in your onActivityResult, you can get this image file back and manipulate it.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == takePhotoActionCode)
{
if (resultCode == RESULT_OK)
{
// NOTE: The intent returned might be NULL if the default camera app was used.
// This is because the image returned is in the file that was passed to the intent.
processPhoto(data);
}
}
}
processPhoto will look a bit like this:
protected void processPhoto(Intent i)
{
int imageExifOrientation = 0;
// Samsung Galaxy Note 2 and S III doesn't return the image in the correct orientation, therefore rotate it based on the data held in the exif.
try
{
ExifInterface exif;
exif = new ExifInterface(outputFileName.getAbsolutePath());
imageExifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
}
catch (IOException e1)
{
e1.printStackTrace();
}
int rotationAmount = 0;
if (imageExifOrientation == ExifInterface.ORIENTATION_ROTATE_270)
{
// Need to do some rotating here...
rotationAmount = 270;
}
if (imageExifOrientation == ExifInterface.ORIENTATION_ROTATE_90)
{
// Need to do some rotating here...
rotationAmount = 90;
}
if (imageExifOrientation == ExifInterface.ORIENTATION_ROTATE_180)
{
// Need to do some rotating here...
rotationAmount = 180;
}
int targetW = 240;
int targetH = 320;
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(outputFileName.getAbsolutePath(), bmOptions);
int photoWidth = bmOptions.outWidth;
int photoHeight = bmOptions.outHeight;
int scaleFactor = Math.min(photoWidth/targetW, photoHeight/targetH);
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap scaledDownBitmap = BitmapFactory.decodeFile(outputFileName.getAbsolutePath(), bmOptions);
if (rotationAmount != 0)
{
Matrix mat = new Matrix();
mat.postRotate(rotationAmount);
scaledDownBitmap = Bitmap.createBitmap(scaledDownBitmap, 0, 0, scaledDownBitmap.getWidth(), scaledDownBitmap.getHeight(), mat, true);
}
ImageView iv2 = (ImageView) findViewById(R.id.photoImageView);
iv2.setImageBitmap(scaledDownBitmap);
FileOutputStream outFileStream = null;
try
{
mLastTakenImageAsJPEGFile = createImageFile(".jpg");
outFileStream = new FileOutputStream(mLastTakenImageAsJPEGFile);
scaledDownBitmap.compress(Bitmap.CompressFormat.JPEG, 75, outFileStream);
}
catch (Exception e)
{
e.printStackTrace();
}
}
One thing to note is that on Nexus devices the calling activity is not normally destroyed. However on Samsung Galaxy S III and Note 2 devices the calling activity is destroyed. Therefore the just storing the outputFileName as a member variable in the Activity will result in it being null when the camera app returns unless you remember to save it when the activity dies. It's good practice to do that anyhow, but this is a mistake that I've made before so I thought I'd mention it.
EDIT:
Regarding your comment, the createImageFile is a not in the standard API, it's something I wrote (or I may have borrowed :-), I don't remember), here is the method for createImageFile():
private File createImageFile(String fileExtensionToUse) throws IOException
{
File storageDir = new File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES
),
"MyImages"
);
if(!storageDir.exists())
{
if (!storageDir.mkdir())
{
Log.d(TAG,"was not able to create it");
}
}
if (!storageDir.isDirectory())
{
Log.d(TAG,"Don't think there is a dir there.");
}
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "FOO_" + timeStamp + "_image";
File image = File.createTempFile(
imageFileName,
fileExtensionToUse,
storageDir
);
return image;
}
To access the full image, you either need to access the intent URI by using data.getData() in your doodleView, or (better) provide your own URI for storing the image by passing it to the intent by supplying a URI in EXTRA_OUTPUT extra.
Related
I am getting image from gallery and trying to reduce its quality before uploading it on a server but I am not getting it how to do it correctly.
Below is my code:
openGallery.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent();
i.setType("image/*");
i.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(i,"Select picture"),GALLERY_IMAGE);
}
});
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == GALLERY_IMAGE && resultCode == RESULT_OK && data != null){
selectedImage = data.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),selectedImage);
} catch (IOException e) {
e.printStackTrace();
}
if(bitmap != null){
bookImage.setImageBitmap(bitmap);
}
}
else{
TastyToast.makeText(getApplicationContext(),"No image selected",TastyToast.LENGTH_SHORT,TastyToast.INFO).show();
}
}
Someone please let me know what should I add in above code to get result any help would be appreciated.
THANKS
I use code like below to both shrink and set JPG quality. The code below saves the JPG stream to a file, but you should be able to send to a memory stream and to byte array instead.
Having said that, you should also consider having ANDROID return a reduced sized picture to you. With older devices especially, your app may not have enough memory to store a full sized picture. I don't have any code for you to do this though, sorry.
// Shrink to fit picture in a max size
Point newSize = util.fitSizeInBounds(new Point(rawBitmap.getWidth(), rawBitmap.getHeight()), new Point(_maxPicSize, _maxPicSize));
if (rawBitmap.getWidth() > newSize.x || rawBitmap.getHeight() > newSize.y) {
scaledBitmap = Bitmap.createScaledBitmap(rawBitmap, newSize.x, newSize.y, false);
// Because I was concerned about memory leaks, I call recycle, but maybe this is not nessessary
rawBitmap.recycle(); rawBitmap = null;
}
else {
scaledBitmap = rawBitmap; rawBitmap = null;
}
// Save file
try {
FileOutputStream outStream = new FileOutputStream(_tempDir + fileName);
if (ext.equals("png")) scaledBitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
else scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 70, outStream); // Here you can compress JPG (70% quality here)
outStream.close();
}
catch (Exception e) {}
public Point fitSizeInBounds(Point size, Point bounds) {
// return size that can fit in bounds. Result will keep same proportion as orig size
int newWidth = size.x;
int newHeight = size.y;
if (newWidth > bounds.x) {
newHeight = (newHeight * bounds.x) / newWidth;
newWidth = bounds.x;
}
if (newHeight > bounds.y) {
newWidth = (newWidth * bounds.y) / newHeight;
newHeight = bounds.y;
}
return new Point(newWidth, newHeight);
}
My app is crashing after capturing 5 to 6 photos using intents.log cat shows nothing. am unable to find the reason why it is crashing. please help me out.
private void capturePhoto() {
File root = new File(Environment.getExternalStorageDirectory(), "Feedback");
if (!root.exists()) {
root.mkdirs();
}
File file = new File(root, Constants.PROFILE_IMAGE_NAME + ".jpeg");
Uri outputFileUri = Uri.fromFile(file);
Intent photoPickerIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
photoPickerIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
photoPickerIntent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
photoPickerIntent.putExtra("return-data", true);
photoPickerIntent.putExtra("android.intent.extras.CAMERA_FACING", 1);
startActivityForResult(photoPickerIntent, requestCode);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (this.requestCode == requestCode && resultCode == RESULT_OK) {
File root = new File(Environment.getExternalStorageDirectory(), "Feedback");
if (!root.exists()) {
root.mkdirs();
}
File file = new File(root, Constants.PROFILE_IMAGE_NAME+".jpeg");
checkFlowIdisPresent(file);
displayPic();
}
}
private void displayPic() {
String filePath = Environment.getExternalStorageDirectory()
.getAbsolutePath() + File.separator + "/Feedback/" + Constants.PROFILE_IMAGE_NAME + ".jpeg";
// Bitmap bmp = BitmapFactory.decodeFile(filePath);
//Bitmap scaled = Bitmap.createScaledBitmap(bmp, 300, 300, true);
File imgFile = new File(filePath);
Bitmap bmp = decodeFile(imgFile);
if (imgFile.exists()) {
dispProfilePic.setImageBitmap(bmp);
} else {
dispProfilePic.setBackgroundResource(R.drawable.user_image);
}
}
private Bitmap decodeFile(File f) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 70;
// Find the correct scale value. It should be the power of 2.
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE &&
o.outHeight / scale / 2 >= REQUIRED_SIZE) {
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
}
return null;
}
And above code is for capturing photo and displaying captured picture in ImageView. And am using MI tab.
Edit actually app is not crashing...it becomes white screen and if i press any button then it is crashing and onActivityResult is not executed when it become white screen
New Edit Am able to replicate this. I clicked on Android Monitor in that i clicked Monitor. Then it shows memory utilization of the app when i interacting with app. now in left side bar i clicked terminate application icon. Now the interesting thing is it destroys current activity and moves to previous activity. That previous activity become white screen.
Please help me out guys.
Try this code. I use it in some of my apps :
Launch intent method:
private void launchCamera() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);
}
Capturing result:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
try {
if (requestCode == CAMERA_PIC_REQUEST) {
if (data != null) {
Bundle extras = data.getExtras();
if (extras != null) {
Bitmap thumbnail = (Bitmap) extras.get("data");
if (thumbnail != null)
displayPic(thumbnail);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Well your code fine....
I think you save the image or overwrite image on same path with same name so there is problem with memory. So I recommended you change the name with System.currentTimeMillis() or any random name Instead of Constants.PROFILE_IMAGE_NAME.
And Also check the permission
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Also check this permission with run time also...for run time follow this
private static final int REQUEST_RUNTIME_PERMISSION = 123;
if (CheckPermission(demo.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
capturePhoto();
} else {
// you do not have permission go request runtime permissions
RequestPermission(demo.this, Manifest.permission.WRITE_EXTERNAL_STORAGE, REQUEST_RUNTIME_PERMISSION);
}
public void RequestPermission(Activity thisActivity, String Permission, int Code) {
if (ContextCompat.checkSelfPermission(thisActivity,
Permission)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Permission)) {
capturePhoto();
} else {
ActivityCompat.requestPermissions(thisActivity,
new String[]{Permission},
Code);
}
}
}
public boolean CheckPermission(Activity context, String Permission) {
if (ContextCompat.checkSelfPermission(context,
Permission) == PackageManager.PERMISSION_GRANTED) {
return true;
} else {
return false;
}
}
If nothing is displayed on the log cat it is very difficult to speculate anything but please check whether the problem is when using the emulator and not on a real device. You can also check if you can recreate the problem by making the emulator capacity smaller (Ram and internal memory). If that is the case, then increase the memory or ram of your emulator and it should work fine. You then need to work on optimizing you image processing task for lower spec devices.
Hope this helps.
This happens possibly because the Calling Activity gets killed and then restarted by OS as IMAGE CAPTURE intent deals with huge amount of memory for processing the BITMAP captured via CAMERA.
Solution: Save the file path of the Image and use it when onActivityResult is called. You can use onSavedInstanceState and onRestoreInstanceState methods to save and retrieve the IMAGE_PATH and other fields of the activity.
You can refer to this link for how to use onSavedInstanceState and onRestoreInstanceState
Try doing it in an Async task because the issue u facing is due to the hug processing done in UI thread
refer here for more help on Async task implementation
This may be memory problem you are taking photos and storing them in bitmap
Check your android Monitor for Memory Detection of APp
Just make this method static
private static Bitmap decodeFile(File f) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 70;
// Find the correct scale value. It should be the power of 2.
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE &&
o.outHeight / scale / 2 >= REQUIRED_SIZE) {
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
}
return null;
}
Save files with different names like saving with timestamp as name
Try to use below code. It works fine for me.
private static final int REQUEST_CAMERA = 1;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK)
{
if (requestCode == REQUEST_CAMERA)
{
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
File destination = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");
FileOutputStream fos;
try
{
destination.createNewFile();
fos = new FileOutputStream(destination);
fos.write(bytes.toByteArray());
fos.close();
}
catch (FileNotFoundException fnfe)
{
fnfe.printStackTrace();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
ivSetImage.setImageBitmap(thumbnail);
}
}
}
In the given code snippet, I have compressed the captured image, due to which app crashing problem is resolved.
In your case, the captured image quality might be high due to which your app is crashing while setting up an image on ImageView.
Just try compressing an image. It will work!
Don't forget to add permission in manifest file.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
check your Manifast.xml file permission
External Storage
and Camera permission.
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" /> <uses-feature
android:name="android.hardware.camera.autofocus" />
if your App run on Marshenter code heremallow check run time permission
Try to use below code:
private void launchCamera() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
try {
if (requestCode == CAMERA_PIC_REQUEST) {
if (data != null) {
Bundle extras = data.getExtras();
if (extras != null) {
Bitmap thumbnail = (Bitmap) extras.get("data");
if (thumbnail != null)
displayPic(thumbnail);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
I am making an app that uses the camera and I would like the default camera open as soon as the app is opened. I currently start my image capture intent in the onCreate method of my main activity. This works perfectly fine sometimes, but other times the camera intent is launched 3 consecutive times.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mImageView = (ImageView) findViewById(R.id.imageView1);
mImageBitmap = null;
Button picBtn = (Button) findViewById(R.id.pictureButton);
setBtnListenerOrDisable(
picBtn,
mTakePicOnClickListener,
MediaStore.ACTION_IMAGE_CAPTURE
);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
mAlbumStorageDirFactory = new FroyoAlbumDirFactory();
} else {
mAlbumStorageDirFactory = new BaseAlbumDirFactory();
}
dispatchTakePictureIntent(ACTION_TAKE_PHOTO_B);
}
private void dispatchTakePictureIntent(int actionCode) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File f;
try {
f = setUpPhotoFile();
mCurrentPhotoPath = f.getAbsolutePath();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
} catch (IOException e) {
e.printStackTrace();
mCurrentPhotoPath = null;
}
startActivityForResult(takePictureIntent, actionCode);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
handleBigCameraPhoto();
}
}
private void handleBigCameraPhoto() {
if (mCurrentPhotoPath != null) {
setPic();
galleryAddPic();
lastPhotoPath = mCurrentPhotoPath;
mCurrentPhotoPath = null;
}
}
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 = mImageView.getWidth();
int targetH = mImageView.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 = 1;
if ((targetW > 0) || (targetH > 0)) {
scaleFactor = Math.min(photoW / targetW, photoH / targetH);
}
/* Set bitmap options to scale the image decode target */
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
/* Decode the JPEG file into a Bitmap */
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
/* Associate the Bitmap to the ImageView */
mImageView.setImageBitmap(bitmap);
mImageView.setVisibility(View.VISIBLE);
}
I think Nathaniel is giving you good advice to move your camera intent launching into onResume.
However, you'll need to differentiate between an onResume that is your activity starting for the first time from one that is happening because of your activity resuming after the camera intent is finished. If you dont, you'll get the loop you see.
To do this, you can alter your onActivityResult() to set a member variable in your Activity called something like isResumingFromCaptureIntent. Set it to true in onActivityResult when the resultCode matches what you used to start the camera intent. Then, in your onResume, check isResumingFromCaptureIntent, if true you know you dont need to start the camera intent and can set is back to false and proceed with whatever else your activity needs to do.
Look here:
Android: onCreate() getting called multiple times (and not by me)
One piece of guidance I can provide is to try and move that call to
public void onResume(){
}
You'll get the desired behavior of automatically going to the camera, but this might cut down on some of the extra calls, since it only occurs when the activity is actually being shown to the user (including returning from other applications etc..).
In the onCreate method I added logic to check if onCreate had previously been called. I did this by checking if the bundle passed in was null or not
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mImageView = (ImageView) findViewById(R.id.imageView1);
mImageBitmap = null;
Button picBtn = (Button) findViewById(R.id.pictureButton);
setBtnListenerOrDisable(
picBtn,
mTakePicOnClickListener,
MediaStore.ACTION_IMAGE_CAPTURE
);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
mAlbumStorageDirFactory = new FroyoAlbumDirFactory();
} else {
mAlbumStorageDirFactory = new BaseAlbumDirFactory();
}
if(savedInstanceState == null)
dispatchTakePictureIntent(ACTION_TAKE_PHOTO_B);
}
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.
I had the same problem and solved it by changing the rendering of the view to software
ImageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
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.
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;}
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.
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 :)
In my case, it's fixed by adding android:layerType="software" in XML.
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layerType="software"
android:src="#drawable/placeholder"/>
Hopefully this will help you too!
Just simple as the title, files opened with BitmapFactory.decodeFile have wrong orientation when it is displayed on the ImageView. The image its captured from the camera and saved on a tmp file so if the device has the bug that returns data.getData() null I have at least a reference to the file.
This just start the camera activity and capture the image file
private void startCamera() {
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
if (hasImageCaptureBug()) {
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Constants.TMPFILE_PATH)));
} else {
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
}
startActivityForResult(intent, CAMERA_PIC_REQUEST);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA_PIC_REQUEST) {
if (resultCode == RESULT_OK) {
Uri uri = null;
if (hasImageCaptureBug()) {
File f = new File(Constants.TMPFILE_PATH);
try {
uri = Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(), f.getAbsolutePath(), null, null));
} catch (FileNotFoundException e) {
}
} else {
uri = data.getData();
}
imageFilePath = Image.getPath(this, uri);
if (Image.exists(imageFilePath)) {
ImageView image = (ImageView) findViewById(R.id.thumbnail);
int targetW = (int) getResources().getDimension(R.dimen.thumbnail_screen_width);
int degrees = (int) Image.getRotation(this, uri);
Bitmap bmp = Image.resize(imageFilePath, targetW);
bmp = Image.rotate(bmp, degrees);
image.setAdjustViewBounds(true);
image.setImageBitmap(bmp);
}
}
}
}
And this file resizes the image
public class Image {
public static Bitmap resize(String pathName, int targetW) {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(pathName, opts);
int photoW = opts.outWidth;
int photoH = opts.outHeight;
int targetH = Math.round((photoH * targetW) / photoW);
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
opts.inJustDecodeBounds = false;
opts.inSampleSize = scaleFactor;
opts.inPurgeable = true;
bmp = BitmapFactory.decodeFile(pathName, opts);
return bmp;
}
}
Tryed to get the ExifOrientation but always its 0 because the file itself its correctly oriented just when I load it the file is displayed with the wrong orientation.
Regards
seems that my issue to preview the image was the Constants.TMPFILE_PATH, the image was not saved there, I just use this fix Display the latest picture taken in the image view layout in android!, but the issue persist if I post it to the server... I'll check this as answered and open a new question to this...
Edited
To solve this issue just refactor the new image and then upload it to the server, because the raw data of the file itself has his exif orientation was wrong.