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.
Related
I've had a specific issue when running some basic code on a Samsung Galaxy S4 (model: GT-I9500).
I was implementing a image picker via the camera or gallery, and could not for the life of me figure out why the ImageView was blank when calling -
imageView.setImageURI(uri);
It wasn't until I ran the exact same code in the emulator (and then a Nexus 5) that I found that this was a Samsung S4 issue.
Full sample project can be found on Github & ready to run
Code I used was taken from this SO post:
In OnCreate:
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Choose Image Source");
builder.setItems(new CharSequence[]{"Gallery", "Camera"},
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
//Launching the gallery
Intent i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, GALLERY);
break;
case 1:
//Specify a camera intent
Intent getCameraImage = new Intent("android.media.action.IMAGE_CAPTURE");
File cameraFolder;
//Check to see if there is an SD card mounted
if (android.os.Environment.getExternalStorageState().equals
(android.os.Environment.MEDIA_MOUNTED))
cameraFolder = new File(android.os.Environment.getExternalStorageDirectory(),
IMAGEFOLDER);
else
cameraFolder = MainActivity.this.getCacheDir();
if (!cameraFolder.exists())
cameraFolder.mkdirs();
//Appending timestamp to "picture_"
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
String timeStamp = dateFormat.format(new Date());
String imageFileName = "picture_" + timeStamp + ".jpg";
File photo = new File(Environment.getExternalStorageDirectory(),
IMAGEFOLDER + imageFileName);
getCameraImage.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
//Setting a global variable to be used in the OnActivityResult
imageURI = Uri.fromFile(photo);
startActivityForResult(getCameraImage, CAMERA);
break;
default:
break;
}
}
});
builder.show();
}
});
OnActivityResult:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case GALLERY:
Uri selectedImage = data.getData();
imageView.setImageURI(selectedImage);
break;
case CAMERA:
imageView.setImageURI(imageURI);
break;
}
}
}
Also occurs when using Picasso
if (resultCode == RESULT_OK) {
switch (requestCode) {
case GALLERY:
Uri selectedImage = data.getData();
Picasso.with(context)
.load(selectedImage)
.into(imageView);
break;
case CAMERA:
Picasso.with(context)
.load(imageURI)
.into(imageView);
break;
}
}
Also occurs when using Bitmap Factory
try {
Bitmap bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(imageURI));
imageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
The results when ran on a Samsung S4 running 4.2.2
The results when ran on a GenyMotion 2.4.0 running Android 4.4.4
Anyone know why this happens?
So the problem turns out to be the image bitmaps being too large for the Samsung S4 to handle.
Frustratingly no errors are thrown - The correct solution is as follows:
switch (requestCode) {
case GALLERY:
Bitmap bitmap = createScaledBitmap(getImagePath(data, getApplicationContext()), imageView.getWidth(), imageView.getHeight());
imageView.setImageBitmap(bitmap);
break;
case CAMERA:
String path = imageURI.getPath();
Bitmap bitmapCamera = createScaledBitmap(path, imageView.getWidth(), imageView.getHeight());
imageView.setImageBitmap(bitmapCamera);
break;
}
Helper methods:
// Function to get image path from ImagePicker
public static String getImagePath(Intent data, Context context) {
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(selectedImage, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
return picturePath;
}
public Bitmap createScaledBitmap(String pathName, int width, int height) {
final BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, opt);
opt.inSampleSize = calculateBmpSampleSize(opt, width, height);
opt.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(pathName, opt);
}
public int calculateBmpSampleSize(BitmapFactory.Options opt, int width, int height) {
final int outHeight = opt.outHeight;
final int outWidth = opt.outWidth;
int sampleSize = 1;
if (outHeight > height || outWidth > width) {
final int heightRatio = Math.round((float) outHeight / (float) height);
final int widthRatio = Math.round((float) outWidth / (float) width);
sampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return sampleSize;
}
When using Picasso, use fit() or resize(). It handles resizing the bitmap.
Are they using different apps by any chance? 4.4 introduced several new URIs for image selecting, as they can be local, google plus etc.
Try this: BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri))
It returns a Bitmap that can be used in the image view as
imgView.setImageBitmap(bitmap)
So last night i thought i had my app working, however, this morning the gremlins have invaded and have now made a function of my app not work correctly.
Basically, a button allows the user to take a photo, and have that photo displayed in an Imageview, then attach the image to an email.. It lets me take the photo, and it is still present as an attachment, but the preview in the image view is completely empty.
Can anybody see what is going on?
Hoon_Image = (ImageView) findViewById(R.id.CapturedImage);
button_take_photo = (Button)findViewById(R.id.btn_take_photo);
button_take_photo.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
try {
f = createImageFile();
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
startActivityForResult(cameraIntent, CAMERA_REQUEST);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
public File getAlbumDir()
{
File storageDir = new File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES
),
"BAC/"
);
// Create directories if needed
if (!storageDir.exists()) {
storageDir.mkdirs();
}
return storageDir;
}
private File createImageFile() throws IOException {
// Create an image file name
String imageFileName =getAlbumDir().toString() +"/image.jpg";
File image = new File(imageFileName);
return image;
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if(requestCode == CAMERA_REQUEST ){
Bitmap photo = BitmapFactory.decodeFile(f.getAbsolutePath());
Hoon_Image.setImageBitmap(photo);
}
}
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
//OI FILE Manager
filemanagerstring = selectedImageUri.getPath();
//MEDIA GALLERY
selectedImagePath = getPath(selectedImageUri);
//DEBUG PURPOSE - you can delete this if you want
if(selectedImagePath!=null)
System.out.println(selectedImagePath);
else System.out.println("selectedImagePath is null");
if(filemanagerstring!=null)
System.out.println(filemanagerstring);
else System.out.println("filemanagerstring is null");
//NOW WE HAVE OUR WANTED STRING
if(selectedImagePath!=null)
System.out.println("selectedImagePath is the right one for you!");
else
System.out.println("filemanagerstring is the right one for you!");
}
Bitmap photo = BitmapFactory.decodeFile(selectedImagePath);
Hoon_Image.setImageBitmap(photo);
Photo_Selected = 1;
}
}
What I've done for the image to be shown in the ImageView in Android is to use a method decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight) that decodes the File object with a required width and height. Below is a sample code.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RESULT_OK) {
File file = new File(Environment.getExternalStorageDirectory()
+ File.separator + "image.jpg");
bitmap = decodeSampledBitmapFromFile(file.getAbsolutePath(),
600, 450);
imageView.setImageBitmap(bitmap);
}
}
public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth,
int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
// Query bitmap without allocating memory
options.inJustDecodeBounds = true;
// decode file from path
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
// decode according to configuration or according best match
options.inPreferredConfig = Bitmap.Config.RGB_565;
int inSampleSize = 1;
if (height > reqHeight) {
inSampleSize = Math.round((float) height / (float) reqHeight);
}
int expectedWidth = width / inSampleSize;
if (expectedWidth > reqWidth) {
// if(Math.round((float)width / (float)reqWidth) > inSampleSize) //
// If bigger SampSize..
inSampleSize = Math.round((float) width / (float) reqWidth);
}
// if value is greater than 1,sub sample the original image
options.inSampleSize = inSampleSize;
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
So i found to what i was doing wrong - derp moment coming right up.
this section of code:
if (resultCode == RESULT_OK) {
if(requestCode == CAMERA_REQUEST ){
it was just looking of ok result (which happened both for selecting a photo and taking a photo successfully) rather than first looking for the RequestCode.
rearranging the code to this worked:
if(requestCode == CAMERA_REQUEST ) {
if (resultCode == RESULT_OK){
Bitmap photo = BitmapFactory.decodeFile(f.getAbsolutePath());
Hoon_Image.setImageBitmap(photo);
I'm trying to set image taken from the camera into an ImageView. I launch the camera intent and then I got a NullPointerException in OnActivityResult an I don't understand the error.
Here, I launche the camera intent and I store the image in the gallery of the phone :
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "New Picture");
imageUri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
pictureActionIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, CAMERA_REQUEST);
Now, the image token by the camera is saved in the gallery of the phone (high quality).
In onActivityResult, I want to put the image into a ImageView. This is my code :
else if (requestCode == CAMERA_REQUEST)
{
if (resultCode == RESULT_OK)
{
imageUri = data.getData();
try
{
Bitmap bitmap = Media.getBitmap(getContentResolver(), imageUri); //NullPointerException
myImageView.setImageBitmap(bitmap);
}
catch (IOException e)
{
e.printStackTrace();
}
I have a NullPointerException, why ? How can I resolve it please ?
This make your result save in mediaStore, so data.getData(); will return NULL:
pictureActionIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
Remove it and you will get data for show on ImageView. However, if you get image from data directly, it's in bad quality
Your code is incomplete and you haven't added the logcat errors!
so in this condition it very difficult to guide you! but what you want to acheive is not that much difficult.Try this:
public class LaunchCamera extends Activity {
ImageView imVCature_pic;
Button btnCapture;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch_camera);
initializeControls();
}
private void initializeControls() {
imVCature_pic=(ImageView)findViewById(R.id.imVCature_pic);
btnCapture=(Button)findViewById(R.id.btnCapture);
btnCapture.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
/* create an instance of intent
* pass action android.media.action.IMAGE_CAPTURE
* as argument to launch camera
*/
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
/*create instance of File with name img.jpg*/
File file = new File(Environment.getExternalStorageDirectory()+File.separator + "img.jpg");
/*put uri as extra in intent object*/
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
/*start activity for result pass intent as argument and request code */
startActivityForResult(intent, 1);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//if request code is same we pass as argument in startActivityForResult
if(requestCode==1){
//create instance of File with same name we created before to get image from storage
File file = new File(Environment.getExternalStorageDirectory()+File.separator + "img.jpg");
//get bitmap from path with size of
imVCature_pic.setImageBitmap(decodeSampledBitmapFromFile(file.getAbsolutePath(), 600, 450));
}
}
public static Bitmap decodeSampledBitmapFromFile(String path,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
//Query bitmap without allocating memory
options.inJustDecodeBounds = true;
//decode file from path
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
//decode according to configuration or according best match
options.inPreferredConfig = Bitmap.Config.RGB_565;
int inSampleSize = 1;
if (height > reqHeight) {
inSampleSize = Math.round((float)height / (float)reqHeight);
}
int expectedWidth = width / inSampleSize;
if (expectedWidth > reqWidth) {
//if(Math.round((float)width / (float)reqWidth) > inSampleSize) // If bigger SampSize..
inSampleSize = Math.round((float)width / (float)reqWidth);
}
//if value is greater than 1,sub sample the original image
options.inSampleSize = inSampleSize;
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
}
complete code snippet is described well here.
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!
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.