Related
BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opts);
bitmap = Bitmap.createScaledBitmap(bitmap, 150, 50, false);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int newWidth = 150;
int newHeight = 50;
// calculate the scale - in this case = 0.4f
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// createa matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// rotate the Bitmap
matrix.postRotate(-90);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
width, height, matrix, true);
// HomePage.image.setImageBitmap(resizedBitmap);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
resizedBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
Intent in1 = new Intent(CameraView.this, ImageDisplay.class);
in1.putExtra("picture",byteArray);
startActivity(in1);
This is my code. I am unable to set image because image becomes stretched. It's not coming clear image full screen. Where am I doing wrong?
My image come like this we have fix it it should not stretched.
It can be due to 'createScaledBitmap' as may be the image size is small and when you try to resize it it gets streched
You can use this:
public Bitmap compressImage(String imageUri) {
String filePath = getRealPathFromURI(imageUri);
Bitmap scaledBitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
// by setting this field as true, the actual bitmap pixels are not loaded in the memory. Just the bounds are loaded. If
// you try the use the bitmap here, you will get null.
options.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(filePath, options);
int actualHeight = options.outHeight;
int actualWidth = options.outWidth;
// max Height and width values of the compressed image is taken as 816x612
float maxHeight = 816.0f;
float maxWidth = 612.0f;
float imgRatio = actualWidth / actualHeight;
float maxRatio = maxWidth / maxHeight;
// width and height values are set maintaining the aspect ratio of the image
if (actualHeight > maxHeight || actualWidth > maxWidth) {
if (imgRatio < maxRatio) {
imgRatio = maxHeight / actualHeight;
actualWidth = (int) (imgRatio * actualWidth);
actualHeight = (int) maxHeight;
} else if (imgRatio > maxRatio) {
imgRatio = maxWidth / actualWidth;
actualHeight = (int) (imgRatio * actualHeight);
actualWidth = (int) maxWidth;
} else {
actualHeight = (int) maxHeight;
actualWidth = (int) maxWidth;
}
}
// setting inSampleSize value allows to load a scaled down version of the original image
options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);
// inJustDecodeBounds set to false to load the actual bitmap
options.inJustDecodeBounds = false;
// this options allow android to claim the bitmap memory if it runs low on memory
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[16 * 1024];
try {
// load the bitmap from its path
bmp = BitmapFactory.decodeFile(filePath, options);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}
try {
scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.ARGB_8888);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}
float ratioX = actualWidth / (float) options.outWidth;
float ratioY = actualHeight / (float) options.outHeight;
float middleX = actualWidth / 2.0f;
float middleY = actualHeight / 2.0f;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));
// check the rotation of the image and display it properly
ExifInterface exif;
try {
exif = new ExifInterface(filePath);
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION, 0);
Log.d("EXIF", "Exif: " + orientation);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
Log.d("EXIF", "Exif: " + orientation);
} else if (orientation == 3) {
matrix.postRotate(180);
Log.d("EXIF", "Exif: " + orientation);
} else if (orientation == 8) {
matrix.postRotate(270);
Log.d("EXIF", "Exif: " + orientation);
}
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,
scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix,
true);
} catch (IOException e) {
e.printStackTrace();
}
return scaledBitmap;
}
Code for saving:
FileOutputStream outStream = null;
File sdCard = Environment.getExternalStorageDirectory();
File dir = new File(sdCard.getAbsolutePath() + "/camtest");
dir.mkdirs();
String fileName = String.format("%d.jpg", System.currentTimeMillis());
File outFile = new File(dir, fileName);
outStream = new FileOutputStream(outFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
outStream.flush();
outStream.close();
refreshGallery(outFile);
Permissions:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Finally:
Go to Device Settings>Device>Applications>Application Manager>"your app">Permissions>Enable Storage permission!
I have a written a code to pick image from gallery or capture image from camera you can use this to achieve what you want and you will get the file path of capture from camera or picked from gallery image file path in onactivityforResult
private static final int CAMERA_CAPTURE_IMAGE_REQUEST_CODE = 100;
public static final int MEDIA_TYPE_IMAGE = 1;
private static final int CROP_FROM_CAMERA = 2;
private static final int PICK_FROM_FILE = 3;
public static final int camPermissionRequestCode=6;
public static final int galleryPermissionRequestCode=4;
private Uri imageUri;
private File profilePicPicked;
#Override
public void onClick(View v) {
int id=v.getId();
switch (id){
case R.id.camera:
if (Build.VERSION.SDK_INT >= 23) {
//do your check here
isStoragePermissionGranted(camPermissionRequestCode);
} else {
captureImage();
}
break;
case R.id.upload_image:
if (Build.VERSION.SDK_INT >= 23) {
//do your check here
isStoragePermissionGranted(galleryPermissionRequestCode);
} else {
pickFromGallery();
}
break;
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
if (resultCode != Activity.RESULT_OK)
return;
switch (requestCode) {
case CAMERA_CAPTURE_IMAGE_REQUEST_CODE:
/**
* After taking a picture, do the crop
*/
File file2 = handleImageUri(imageUri,getContext());
try {
ExifInterface ei = new ExifInterface(file2.getAbsolutePath());
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
file2=rotateImage(file2, 90);
/* Toast.makeText(getActivity(),"90",Toast.LENGTH_SHORT).show();*/
break;
case ExifInterface.ORIENTATION_ROTATE_180:
file2=rotateImage(file2, 180);
/* Toast.makeText(getActivity(),"180",Toast.LENGTH_SHORT).show();*/
break;
case ExifInterface.ORIENTATION_ROTATE_270:
file2=rotateImage(file2, 270);
/* Toast.makeText(getActivity(),"270",Toast.LENGTH_SHORT).show();*/
break;
case ExifInterface.ORIENTATION_NORMAL:
/*Toast.makeText(getActivity(),"default",Toast.LENGTH_SHORT).show();*/
default:
break;
}
}catch (Exception e){
e.printStackTrace();
}
profilePicPicked= file2;
break;
case PICK_FROM_FILE:
/**
* After selecting image from files, save the selected path
*/
/*Toast.makeText(getContext(), "Image Taken", Toast.LENGTH_LONG).show();*/
imageUri = data.getData();
//iv_post.setImageURI(fileUri);
File fileGAllr = getRealPathFromURIForGallery(getActivity(),imageUri);
profilePicPicked=fileGAllr;
// new Updata().execute("");
// btn_gallery.setVisibility(View.GONE);
break;
case CROP_FROM_CAMERA:
break;
}
}
public static File getRealPathFromURIForGallery(Context context, Uri uri) {
File file = null;
try {
String extension="";
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(uri, filePathColumn, null, null, null);
if (cursor.moveToFirst()) {
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String filePath = cursor.getString(columnIndex);
extension= filePath.substring(filePath.lastIndexOf("."));
System.out.print("");
}
cursor.close();
InputStream input = null;
input = context.getContentResolver().openInputStream(uri);
if (input == null) {
return null;
}
file = new File(context.getCacheDir(), System.currentTimeMillis()+"_Photo"+extension);
OutputStream output = new FileOutputStream(file);
try {
byte[] buffer = new byte[4 * 1024];
int read;
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
output.flush();
} finally {
output.close();
input.close();
}
} catch (IOException e) {
Log.d("Error", e.toString());
}
return file;
}
public File rotateImage(File f, float angle) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap source = BitmapFactory.decodeFile(f.getAbsolutePath(), options);
Matrix matrix = new Matrix();
matrix.postRotate(angle);
Bitmap finalBm= Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
File editedFile=getOutputMediaFile(MEDIA_TYPE_IMAGE);
FileOutputStream out = null;
try {
out = new FileOutputStream(editedFile);
finalBm.compress(Bitmap.CompressFormat.JPEG, 100, out); // bmp is your Bitmap instance
// PNG is a lossless format, the compression factor (100) is ignored
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
f.delete();
return editedFile;
}
public static File handleImageUri(Uri uri, Context context) {
Pattern pattern = Pattern.compile("(content://media/.*\\d)");
Matcher matcher = pattern.matcher(uri.getPath());
if (matcher.find()) {
return getRealPathFromURI(context, uri);
} else {
return new File(uri.getPath());
}
}
public static File getRealPathFromURI(Context context, Uri uri) {
File file = null;
try {
InputStream input = null;
input = context.getContentResolver().openInputStream(uri);
if (input == null) {
return null;
}
file = new File(context.getCacheDir(), System.currentTimeMillis()+"Photo.png");
OutputStream output = new FileOutputStream(file);
try {
byte[] buffer = new byte[4 * 1024];
int read;
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
output.flush();
} finally {
output.close();
input.close();
}
} catch (IOException e) {
Log.d("Error", e.toString());
}
return file;
}
public boolean isStoragePermissionGranted(int requsetCode) {
if (Build.VERSION.SDK_INT >= 23) {
if (ContextCompat.checkSelfPermission(getActivity(),android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
if(requsetCode==camPermissionRequestCode){
captureImage();
}else{
pickFromGallery();
}
return true;
} else {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requsetCode);
return false;
}
}
else { //permission is automatically granted on sdk<23 upon installation
if(requsetCode==camPermissionRequestCode){
captureImage();
}else{
pickFromGallery();
}
return true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
if(requestCode==camPermissionRequestCode){
captureImage();
}else if(requestCode==galleryPermissionRequestCode){
pickFromGallery();
}
//resume tasks needing this permission
}
}
private void captureImage() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
imageUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
// start the image capture Intent
startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
}
private void pickFromGallery(){
Intent i = new Intent(
Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, PICK_FROM_FILE);
}
public Uri getOutputMediaFileUri(int type) {
return Uri.fromFile(getOutputMediaFile(type));
}
private File getOutputMediaFile(int type) {
// TODO Auto-generated method stub
// External sdcard location
File mediaStorageDir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"marcopolo");
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
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;
}
> public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight){
> final int height = options.outHeight;
> final int width = options.outWidth;
> int inSampleSize = 1;
> if (height > reqHeight || width > reqWidth) {final int heightRatio = Math.round((float) height / (float) reqHeight);
> final int widthRatio = Math.round((float) width / (float) reqWidth);
> inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;}
> final float totalPixels = width * height;
> final float totalReqPixelsCap = reqWidth * reqHeight * 2;
> while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {inSampleSize++;}
> return inSampleSize;}
>
> > `Blockquote`
Hello I am working on one android app where I need to capture the image using camera intent and set the bitmap in the imageview but here bitmap is rotated by 90 degree. I have checked many threads of stackoverflow like Photo rotate 90 degree while capture in some phones but did not work for me.
Here when I am executing this exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1); then it is returning 0 ORIENTATION_UNDEFINED and in my getImage function no condition is satisfying.
Intent cameraIntent = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
capturedPhotoName = System.currentTimeMillis() + ".png";
File photo = new File(Environment.getExternalStorageDirectory(),
capturedPhotoName);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
imageUri = Uri.fromFile(photo);
startActivityForResult(cameraIntent, CAMERA_INTENT_REQUEST);
onActivityResult
Uri selectedImage = imageUri;
getContentResolver().notifyChange(selectedImage, null);
ContentResolver cr = getContentResolver();
Bitmap bitmap;
try {
bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr,
selectedImage);
bitmap = Util.getImage(bitmap, selectedImage.toString());
mPictureImageView.setImageBitmap(bitmap);
} catch (Exception e) {
Log.e("New Issue Activity", e.toString());
}
/**
* Get the image orientation
*
* #param imagePath
* #return orietation angle
* #throws IOException
*/
public static Bitmap getImage(Bitmap bitmap, String path) throws IOException {
Matrix m = new Matrix();
ExifInterface exif = new ExifInterface(path);
int orientation = exif
.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
if ((orientation == ExifInterface.ORIENTATION_ROTATE_180)) {
m.postRotate(180);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), m, true);
return bitmap;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
m.postRotate(90);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), m, true);
return bitmap;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
m.postRotate(270);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), m, true);
return bitmap;
}
return bitmap;
}
I implemented one photo take activity which you can take the photo and set the orientation of the photo. It is supported by every device I tested including Samsung galaxy series, tablets, sony xperia series, tablets.
You can check out my accepted answer about rotation of images on this topic:
Camera capture orientation on samsung devices in android
If you also need to save and use that image that you have rotated, saving and using the photo functions additional to my answer I gave above:
savePhoto function:
public void savePhoto(Bitmap bmp) {
imageFileFolder = new File(Environment.getExternalStorageDirectory(),
cc.getDirectoryName());
imageFileFolder.mkdir();
FileOutputStream out = null;
Calendar c = Calendar.getInstance();
String date = fromInt(c.get(Calendar.MONTH))
+ fromInt(c.get(Calendar.DAY_OF_MONTH))
+ fromInt(c.get(Calendar.YEAR))
+ fromInt(c.get(Calendar.HOUR_OF_DAY))
+ fromInt(c.get(Calendar.MINUTE))
+ fromInt(c.get(Calendar.SECOND));
imageFileName = new File(imageFileFolder, date.toString() + ".jpg");
try {
out = new FileOutputStream(imageFileName);
bmp.compress(Bitmap.CompressFormat.JPEG, 70, out);
out.flush();
out.close();
scanPhoto(imageFileName.toString());
out = null;
} catch (Exception e) {
e.printStackTrace();
}
}
scanPhoto function:
public void scanPhoto(final String imageFileName) {
geniusPath = imageFileName;
msConn = new MediaScannerConnection(MyClass.this,
new MediaScannerConnectionClient() {
public void onMediaScannerConnected() {
msConn.scanFile(imageFileName, null);
}
#Override
public void onScanCompleted(String path, Uri uri) {
msConn.disconnect();
}
});
msConn.connect();
}
SavePhotoTask class:
class SavePhotoTask extends AsyncTask<byte[], String, String> {
#Override
protected String doInBackground(byte[]... jpeg) {
File photo = new File(Environment.getExternalStorageDirectory(),
"photo.jpg");
if (photo.exists()) {
photo.delete();
}
try {
FileOutputStream fos = new FileOutputStream(photo.getPath());
fos.write(jpeg[0]);
fos.close();
} catch (java.io.IOException e) {
}
return (null);
}
}
Try below code:-
Uri selectedImageURI = data.getData();
imageFile = new File(getRealPathFromURI(selectedImageURI));
ExifInterface exif = new ExifInterface(imageFile.toString());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
Bitmap bitmap = Utility.getOrientationFromExif(new Utility().compressImage1(imageFile.toString(),((Activity)context)),orientation);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG , 50 , bos);
Utility.java
public class Utility
{
public Bitmap compressImage1(String imageUri, Activity act)
{
String filePath = getRealPathFromURI(imageUri, act);
BitmapFactory.Options options = new BitmapFactory.Options();
// by setting this field as true, the actual bitmap pixels are not
// loaded in the memory. Just the bounds are loaded. If
// you try the use the bitmap here, you will get null.
options.inJustDecodeBounds = true;
// Bitmap bmp = decodeBitmap(Uri.parse(imageUri), 612, 816, act);
Bitmap bmp = BitmapFactory.decodeFile(filePath, options);
// setting inSampleSize value allows to load a scaled down version of
// the original image
options.inSampleSize = calculateInSampleSize(options, 612, 816);
// inJustDecodeBounds set to false to load the actual bitmap
options.inJustDecodeBounds = false;
// this options allow android to claim the bitmap memory if it runs low
// on memory
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[16 * 1024];
// load the bitmap from its path
bmp = BitmapFactory.decodeFile(filePath, options);
return bmp;
}
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;
}
public static Bitmap getOrientationFromExif(Bitmap bitmap, int orientation)
{
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int newWidth = 612;
int newHeight = 816;
// calculate the scale - in this case = 0.4f
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
switch (orientation)
{
case ExifInterface.ORIENTATION_NORMAL:
return bitmap;
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
// matrix.setScale(-1, 1);
matrix.postScale(scaleWidth, scaleHeight);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.setRotate(180);
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
matrix.setRotate(180);
// matrix.postScale(-1, 1);
matrix.postScale(scaleWidth, scaleHeight);
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
matrix.setRotate(90);
// matrix.postScale(-1, 1);
matrix.postScale(scaleWidth, scaleHeight);
break;
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.setRotate(90);
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
matrix.setRotate(-90);
// matrix.postScale(-1, 1);
matrix.postScale(scaleWidth, scaleHeight);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
matrix.setRotate(-90);
break;
default:
return bitmap;
}
try
{
Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
bitmap.recycle();
return bmRotated;
}
catch (OutOfMemoryError e)
{
e.printStackTrace();
return null;
}
}
}
This function worked for me, try your luck.
public static Bitmap rotateImage(Bitmap bmp, String imageUrl) {
if (bmp != null) {
ExifInterface ei;
int orientation = 0;
try {
ei = new ExifInterface(imageUrl);
orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
} catch (IOException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
int bmpWidth = bmp.getWidth();
int bmpHeight = bmp.getHeight();
Matrix matrix = new Matrix();
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.postRotate(90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.postRotate(180);
break;
default:
break;
// etc.
}
Bitmap resizedBitmap = Bitmap.createBitmap(bmp, 0, 0, bmpWidth,
bmpHeight, matrix, true);
return resizedBitmap;
} else {
return bmp;
}
}
Here is the disk cache tutorial I'm following. I've downloaded the source code to DiskLruCache but none of the methods used in this example exist in the source code.
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html#disk-cache
Do I need to implement these methods myself or is there a version of DiskLruCache that I'm missing somewhere?
Here is the complete implementation of DiskLruCache.
First download DiskLruCache.java from AOSP.
Here is my DiskCache.java a helper class for basic cache operations.
/**
* Created by Babar on 12-Aug-15.
*/
public class DiskCache
{
private Context context;
private static DiskCache diskCache;
public DiskLruCache mDiskLruCache;
private final Object mDiskCacheLock = new Object();
private BitmapProcessor bitmapProcessor;
private static final int DISK_CACHE_INDEX = 0;
public static boolean mDiskCacheStarting = true;
private static final String DISK_CACHE_SUBDIR = "ooredoo_thumbnails";
private static final int DISK_CACHE_SIZE = 1024 * 1024 * 100; // 100MB
public static DiskCache getInstance()
{
if(diskCache == null)
{
diskCache = new DiskCache();
}
return diskCache;
}
private DiskCache() {}
public void requestInit(Context context)
{
this.context = context;
bitmapProcessor = new BitmapProcessor();
new DiskCacheTask(this).execute(DiskCacheTask.INIT);
}
public void init() throws IOException {
synchronized (mDiskCacheLock)
{
if(mDiskLruCache == null || mDiskLruCache.isClosed())
{
File cacheDir = FileUtils.getDiskCacheDir(context, DISK_CACHE_SUBDIR);
if(!cacheDir.exists())
{
cacheDir.mkdir();
}
if(FileUtils.getUsableSpace(cacheDir) > DISK_CACHE_SIZE)
{
mDiskLruCache = DiskLruCache.open(cacheDir, 1, 1, DISK_CACHE_SIZE);
}
else
{
Logger.print("InitDiskCache failed: NOT enough space on disk");
}
}
mDiskCacheStarting = false; // Finished initialization
mDiskCacheLock.notifyAll(); // Wake any waiting threads
}
}
public void addBitmapToDiskCache(final String key, final Bitmap value) {
if (key == null || value == null) {
return;
}
synchronized (mDiskCacheLock)
{
if (mDiskLruCache != null) {
OutputStream out = null;
String encryptedKey = CryptoUtils.encryptToMD5(key);
Logger.print("addBitmapToDiskCache encryptToMD5: " + encryptedKey);
try {
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(encryptedKey);
if (snapshot == null) {
final DiskLruCache.Editor editor = mDiskLruCache.edit(encryptedKey);
if (editor != null) {
out = editor.newOutputStream(DISK_CACHE_INDEX);
value.compress(Bitmap.CompressFormat.JPEG, 100, out);
editor.commit();
out.close();
}
} else {
snapshot.getInputStream(DISK_CACHE_INDEX).close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
/**
* Get from disk cache.
*
* #param key Unique identifier for which item to get
* #return The bitmap if found in cache, null otherwise
*/
public Bitmap getBitmapFromDiskCache(final String key)
{
Bitmap bitmap = null;
String encryptedKey = CryptoUtils.encryptToMD5(key);
Logger.print("getBitmapFromDiskCache encryptToMD5: " + encryptedKey);
synchronized (mDiskCacheLock)
{
Logger.print("mDiskcachestarting: "+mDiskCacheStarting);
// Wait while disk cache is started from background thread
while (mDiskCacheStarting)
{
try
{
mDiskCacheLock.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
if(mDiskLruCache != null)
{
InputStream inputStream = null;
try
{
final DiskLruCache.Snapshot snapshot = mDiskLruCache.get(encryptedKey);
if(snapshot != null)
{
Logger.print("Disk cache hit");
inputStream = snapshot.getInputStream(DISK_CACHE_INDEX);
if(inputStream != null)
{
FileDescriptor fd = ((FileInputStream) inputStream).getFD();
// Decode bitmap, but we don't want to sample so give
// MAX_VALUE as the target dimensions
bitmap = bitmapProcessor.decodeSampledBitmapFromDescriptor(fd);
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if(inputStream != null)
{
try
{
inputStream.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
Logger.print("dCache getBitmapFromDiskCache synchronized completed");
}
Logger.print("dCache getBitmapFromDiskCache returning Bitmap");
return bitmap;
}
public void requestFlush()
{
new DiskCacheTask(this).execute(DiskCacheTask.FLUSH);
}
/**
* Flushes the disk cache associated with this ImageCache object. Note that this includes
* disk access so this should not be executed on the main/UI thread.
*/
public void flush()
{
synchronized (mDiskCacheLock)
{
if(mDiskLruCache != null)
{
try
{
mDiskLruCache.flush();
Logger.print("flush: disk cache flushed");
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
public void requestClose()
{
new DiskCacheTask(this).execute(DiskCacheTask.CLOSE);
}
/**
* Closes the disk cache associated with this ImageCache object. Note that this includes
* disk access so this should not be executed on the main/UI thread.
*/
public void close()
{
synchronized (mDiskCacheLock)
{
if(mDiskLruCache != null)
{
if(!mDiskLruCache.isClosed())
{
try
{
mDiskLruCache.close();
mDiskLruCache = null;
Logger.print("disk cache closed");
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}
/**
* Do not call this method unless you need to explicitly clear disk cache
*/
public void requestTearDown()
{
new DiskCacheTask(this).execute(DiskCacheTask.TEAR_DOWN);
}
public final void tearDown()
{
synchronized (mDiskCacheLock)
{
mDiskCacheStarting = true;
if(mDiskLruCache != null && !mDiskLruCache.isClosed())
{
try
{
mDiskLruCache.delete();
Logger.print("disk cache cleared");
}
catch (IOException e)
{
e.printStackTrace();
}
mDiskLruCache = null;
}
}
}
}
Here is BitmapProcesser.java
/**
* #author Babar
* #since 15-Jun-15.
*/
public class BitmapProcessor
{
public Bitmap decodeSampledBitmapFromStream(InputStream inputStream, URL url,
int reqWidth, int reqHeight) throws IOException {
Bitmap bitmap;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(inputStream, null, options);
int width = options.outWidth;
int height = options.outHeight;
Logger.print("#Req Width: "+reqWidth);
Logger.print("#Req Height: " + reqHeight);
Logger.print("#Actual Width: "+width);
Logger.print("#Actual Height: " + height);
int sampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
inputStream = url.openStream();
bitmap = BitmapFactory.decodeStream(inputStream, null, options);
if(bitmap != null)
{
width = bitmap.getWidth();
height = bitmap.getHeight();
Logger.print("#inSample:"+sampleSize);
Logger.print("#Modified Width: "+width);
Logger.print("#Modified Height: " + height);
}
return bitmap;
}
public Bitmap decodeSampledBitmapFromDescriptor(FileDescriptor fd)
{
/*final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(fd, null, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;*/
return BitmapFactory.decodeFileDescriptor(fd);
}
public Bitmap decodeSampledBitmapFromFile(String pathName, int reqWidth, int reqHeight) throws IOException {
Bitmap bitmap;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
int width = options.outWidth;
int height = options.outHeight;
Logger.print("#Req Width: "+reqWidth);
Logger.print("#Req Height: " + reqHeight);
Logger.print("#Actual Width: "+width);
Logger.print("#Actual Height: " + height);
int sampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
bitmap = BitmapFactory.decodeFile(pathName, options);
if(bitmap != null)
{
width = bitmap.getWidth();
height = bitmap.getHeight();
Logger.print("#inSample:"+sampleSize);
Logger.print("#Modified Width: "+width);
Logger.print("#Modified Height: " + height);
}
return bitmap != null ? rotateBitmapIfNeeded(pathName, bitmap) : null;
}
public int calculateInSampleSize(BitmapFactory.Options options,
int requiredWidth, int requiredHeight)
{
final int width = options.outWidth;
final int height = options.outHeight;
int inSampleSize = 1;
if(width > requiredWidth || height > requiredHeight)
{
final int halfWidth = width / 2;
final int halfHeight = height / 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 ((halfWidth / inSampleSize) > requiredWidth
&&
(halfHeight / inSampleSize) > requiredHeight)
{
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap rotateBitmapIfNeeded(String pathName, Bitmap bitmap) throws IOException {
ExifInterface exifInterface = new ExifInterface(pathName);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
Logger.logI("BITMAP_ORIENTATION: " + orientation, pathName);
switch (orientation)
{
case ExifInterface.ORIENTATION_ROTATE_90:
return rotateBitmap(bitmap, 90);
case ExifInterface.ORIENTATION_ROTATE_180:
return rotateBitmap(bitmap, 180);
case ExifInterface.ORIENTATION_ROTATE_270:
return rotateBitmap(bitmap, 270);
}
return bitmap;
}
public Bitmap makeBitmapRound(Bitmap src)
{
int width = src.getWidth();
int height = src.getHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// Canvas canvas = new Canvas(bitmap);
BitmapShader shader = new BitmapShader(src, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(shader);
RectF rectF = new RectF(0.0f, 0.0f, width, height);
// rect contains the bounds of the shape
// radius is the radius in pixels of the rounded corners
// paint contains the shader that will texture the shape
Canvas canvas = new Canvas(src);
canvas.drawRoundRect(rectF, 30, 30, paint);
return src;
}
public static Bitmap rotateBitmap(Bitmap bitmap, int degree) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
}
Here is CryptoUtils.java
/**
* #author Babar
* #since 29-Jun-15.
*/
public class CryptoUtils
{
private static final String MD5_ALGO = "MD5";
public static String encryptToMD5(String text)
{
try
{
java.security.MessageDigest md = java.security.MessageDigest.getInstance(MD5_ALGO);
md.update(text.getBytes());
byte[] bytes = md.digest();
String hex = bytesToHexString(bytes);
return hex;
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
return String.valueOf(text.hashCode());
}
}
private static String bytesToHexString(byte[] bytes)
{
StringBuffer sb = new StringBuffer();
for(int i = 0; i < bytes.length; i++)
{
String hex = Integer.toHexString(0xFF & bytes[i]);
if(hex.length() == 1)
{
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
public static String encodeToBase64(String str) {
String tmp = "";
if(isNotNullOrEmpty(str)) {
try {
tmp = new String(Base64.encode(str.getBytes(), Base64.DEFAULT)).trim();
} catch(Throwable e) {
e.printStackTrace();
}
}
return tmp;
}
}
Here is DiskCacheTask.java
/**
* Created by Babar on 12-Aug-15.
*/
public class DiskCacheTask extends BaseAsyncTask<Integer, Void, Void>
{
private DiskCache diskCache;
public static final int INIT = 1;
public static final int FLUSH = 2;
public static final int CLOSE = 3;
public static final int TEAR_DOWN = 4;
public static final int REMOVE = 5;
public DiskCacheTask(DiskCache diskCache)
{
this.diskCache = diskCache;
}
#Override
protected Void doInBackground(Integer... params)
{
switch (params[0])
{
case INIT:
try
{
diskCache.init();
}
catch (IOException e)
{
e.printStackTrace();
}
break;
case FLUSH:
diskCache.flush();
break;
case CLOSE:
diskCache.close();
break;
case TEAR_DOWN:
diskCache.tearDown();
break;
case REMOVE:
diskCache.remove();
break;
}
return null;
}
}
To initialize the cache simply call new DiskCache().getInstance().requestInit(); ideally from your MainActivity's onCreate(). Also note Disk operation should be done in separate thread for example Handler , AsyncTask. So when ever you want to add/get bitmap to/from disk cache do this from a worker thread.
You will need to wrap the DiskLruCache with your own cache that offers higher level abstractions. Someone has already done this for bitmaps, see Using DiskLruCache in android 4.0 does not provide for openCache method
Alternatively, you can use an open source library such as Picasso.
User can capture image from camera in any mode but I want to restrict result to be in portrait only (result should be in portrait only).
To achieve this I am using ExifInterface and at some extends I am succeeded too, its working fine in LG & HTC devices but not working in Samsung devices.
Code:
ExifInterface exif = new ExifInterface(path);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Log.e("orientation",""+orientation);
Matrix m=new Matrix();
if((orientation==3)){
m.postRotate(180);
m.postScale((float)bm.getWidth(), (float)bm.getHeight());
// if(m.preRotate(90)){
Log.e("in orientation",""+orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0,bm.getWidth(),bm.getHeight(), m, true);
return bitmap;
}
else if(orientation==6){
m.postRotate(90);
Log.e("in orientation",""+orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0,bm.getWidth(),bm.getHeight(), m, true);
return bitmap;
}
else if(orientation==8){
m.postRotate(270);
Log.e("in orientation",""+orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0,bm.getWidth(),bm.getHeight(), m, true);
return bitmap;
}
return bitmap;
}
catch (Exception e) {
}
return null;
}
Your suggestions are appreciable.
Try this it works for me
public static Bitmap scaleImage(Context context, Uri photoUri) throws IOException {
InputStream is = context.getContentResolver().openInputStream(photoUri);
BitmapFactory.Options dbo = new BitmapFactory.Options();
dbo.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, dbo);
is.close();
int rotatedWidth, rotatedHeight;
int orientation = getOrientation(context, photoUri);
if (orientation == 90 || orientation == 270) {
rotatedWidth = dbo.outHeight;
rotatedHeight = dbo.outWidth;
} else {
rotatedWidth = dbo.outWidth;
rotatedHeight = dbo.outHeight;
}
Bitmap srcBitmap;
is = context.getContentResolver().openInputStream(photoUri);
if (rotatedWidth > 100 || rotatedHeight > 100) {
float widthRatio = ((float) rotatedWidth) / ((float) 100);
float heightRatio = ((float) rotatedHeight) / ((float) 100);
float maxRatio = Math.max(widthRatio, heightRatio);
// Create the bitmap from file
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = (int) maxRatio;
srcBitmap = BitmapFactory.decodeStream(is, null, options);
} else {
srcBitmap = BitmapFactory.decodeStream(is);
}
is.close();
/*
* if the orientation is not 0 (or -1, which means we don't know), we
* have to do a rotation.
*/
if (orientation > 0) {
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
srcBitmap.getHeight(), matrix, true);
}
String type = context.getContentResolver().getType(photoUri);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (type.equals("image/png")) {
srcBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
} else if (type.equals("image/jpg") || type.equals("image/jpeg")) {
srcBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
}
byte[] bMapArray = baos.toByteArray();
baos.close();
return BitmapFactory.decodeByteArray(bMapArray, 0, bMapArray.length);
}
public static int getOrientation(Context context, Uri photoUri) {
/* it's on the external media. */
Cursor cursor = context.getContentResolver().query(photoUri,
new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
if (cursor.getCount() != 1) {
return -1;
}
cursor.moveToFirst();
return cursor.getInt(0);
}
private void openGalleryImage(Intent data)
{
Uri selectedimg = data.getData();
Uri uriselectedimage=data.getData();
mString=uriselectedimage.getPath();
try
{
mInputStream= getContentResolver().openInputStream(selectedimg);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
String[] path = { MediaStore.Images.Media.DATA };
Cursor c = getContentResolver().query(selectedimg, path, null, null,null);
c.moveToFirst();
int columnIndex = c.getColumnIndex(path[0]);
selectedImagePath=c.getString(columnIndex);
uri_outputFileUri= Uri.parse(selectedImagePath);
c.close();
}
private void saveImage(String mPath)
{
System.out.println("Paths "+mPath);
mediaDir= new File(Environment.getExternalStorageDirectory() +"/MyFolder");
mediaDir.mkdir();
File myImage = new File(mediaDir, Long.toString(System.currentTimeMillis()) + ".png");
try
{
FileOutputStream out = new FileOutputStream(myImage);
mbitmap_outputImage=BitmapFactory.decodeFile(mPath);
mbitmap_outputImage=Bitmap.createScaledBitmap(mbitmap_outputImage, 390, 310, true);
mbitmap_outputImage.compress(Bitmap.CompressFormat.PNG, 100, out);
img.setImageBitmap(mbitmap_outputImage);
out.flush();
out.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
When I load an image from the media gallery into a Bitmap, everything is working fine, except that pictures that were shot with the camera while holding the phone vertically, are rotated so that I always get a horizontal picture even though it appears vertical in the gallery.
Why is that and how can I load it correctly?
So, as an example...
First you need to create an ExifInterface:
ExifInterface exif = new ExifInterface(filename);
You can then grab the orientation of the image:
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Here's what the orientation values mean:
http://sylvana.net/jpegcrop/exif_orientation.html
So, the most important values are 3, 6 and 8.
If the orientation is ExifInterface.ORIENTATION_ROTATE_90 (which is 6), for example, you can rotate the image like this:
Matrix matrix = new Matrix();
matrix.postRotate(90);
rotatedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(), matrix, true);
That's just a quick example, though. I'm sure there are other ways of performing the actual rotation. But you will find those on StackOverflow as well.
Solved it in my case with this code using help of this post:
Bitmap myBitmap = getBitmap(imgFile.getAbsolutePath());
try {
ExifInterface exif = new ExifInterface(imgFile.getAbsolutePath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Log.d("EXIF", "Exif: " + orientation);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
}
else if (orientation == 3) {
matrix.postRotate(180);
}
else if (orientation == 8) {
matrix.postRotate(270);
}
myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true); // rotating bitmap
}
catch (Exception e) {
}
ImageView img = (ImageView) findViewById(R.id.imgTakingPic);
img.setImageBitmap(myBitmap);
Hope it saves someone's time!
This is a full solution (found in the Hackbook example from the Facebook SDK). It has the advantage of not needing access to the file itself. This is extremely useful if you are loading an image from the content resolver thingy (e.g. if your app is responding to a share-photo intent).
public static int getOrientation(Context context, Uri photoUri) {
/* it's on the external media. */
Cursor cursor = context.getContentResolver().query(photoUri,
new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
if (cursor.getCount() != 1) {
return -1;
}
cursor.moveToFirst();
return cursor.getInt(0);
}
And then you can get a rotated Bitmap as follows. This code also scales down the image (badly unfortunately) to MAX_IMAGE_DIMENSION. Otherwise you may run out of memory.
public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri) throws IOException {
InputStream is = context.getContentResolver().openInputStream(photoUri);
BitmapFactory.Options dbo = new BitmapFactory.Options();
dbo.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, dbo);
is.close();
int rotatedWidth, rotatedHeight;
int orientation = getOrientation(context, photoUri);
if (orientation == 90 || orientation == 270) {
rotatedWidth = dbo.outHeight;
rotatedHeight = dbo.outWidth;
} else {
rotatedWidth = dbo.outWidth;
rotatedHeight = dbo.outHeight;
}
Bitmap srcBitmap;
is = context.getContentResolver().openInputStream(photoUri);
if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) {
float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
float maxRatio = Math.max(widthRatio, heightRatio);
// Create the bitmap from file
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = (int) maxRatio;
srcBitmap = BitmapFactory.decodeStream(is, null, options);
} else {
srcBitmap = BitmapFactory.decodeStream(is);
}
is.close();
/*
* if the orientation is not 0 (or -1, which means we don't know), we
* have to do a rotation.
*/
if (orientation > 0) {
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
srcBitmap.getHeight(), matrix, true);
}
return srcBitmap;
}
Use a Utility to do the Heavy Lifting.
9re created a simple utility to handle the heavy lifting of dealing with EXIF data and rotating images to their correct orientation.
You can find the utility code here: https://gist.github.com/9re/1990019
Simply download this, add it to your project's src directory and use ExifUtil.rotateBitmap() to get the correct orientation, like so:
String imagePath = photoFile.getAbsolutePath(); // photoFile is a File class.
Bitmap myBitmap = BitmapFactory.decodeFile(imagePath);
Bitmap orientedBitmap = ExifUtil.rotateBitmap(imagePath, myBitmap);
Have you looked at the EXIF data of the images? It may know the orientation of the camera when the picture was taken.
Kotlin code:
if (file.exists()){
val bitmap = BitmapFactory.decodeFile(file.absolutePath)
val exif = ExifInterface(file.absoluteFile.toString())
val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
val matrix = Matrix()
when(orientation){
ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90F)
ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180F)
ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270F)
}
val rotatedBitmap = Bitmap.createBitmap(bitmap, 0,0 , bitmap.width, bitmap.height, matrix, true)
bitmap.recycle()
iv_capture.setImageBitmap(rotatedBitmap)
}
its because gallery correct displaying rotated images but not ImageView
look at here:
myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(),optionss);
ExifInterface exif = new ExifInterface(selectedImagePath);
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int rotationInDegrees = exifToDegrees(rotation);
deg = rotationInDegrees;
Matrix matrix = new Matrix();
if (rotation != 0f) {
matrix.preRotate(rotationInDegrees);
myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true);
}
and you need this:
private static int exifToDegrees(int exifOrientation) {
if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { return 90; }
else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) { return 180; }
else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) { return 270; }
return 0;
}
Got it to work after many attempts thanks to a post I can no longer find :-(
Exif seems to work always, the difficulty was to get the filepath. The code I found makes a different between API older than 4.4 and after 4.4. Basically the picture URI for 4.4+ contains "com.android.providers". For this type of URI, the code uses DocumentsContract to get the picture id and then runs a query using the ContentResolver, while for older SDK, the code goes straight to query the URI with the ContentResolver.
Here is the code (sorry I cannot credit who posted it):
/**
* Handles pre V19 uri's
* #param context
* #param contentUri
* #return
*/
public static String getPathForPreV19(Context context, Uri contentUri) {
String res = null;
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
if(cursor.moveToFirst()){;
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
res = cursor.getString(column_index);
}
cursor.close();
return res;
}
/**
* Handles V19 and up uri's
* #param context
* #param contentUri
* #return path
*/
#TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPathForV19AndUp(Context context, Uri contentUri) {
String wholeID = DocumentsContract.getDocumentId(contentUri);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = { MediaStore.Images.Media.DATA };
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = context.getContentResolver().
query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{ id }, null);
String filePath = "";
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
return filePath;
}
public static String getRealPathFromURI(Context context,
Uri contentUri) {
String uriString = String.valueOf(contentUri);
boolean goForKitKat= uriString.contains("com.android.providers");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && goForKitKat) {
Log.i("KIKAT","YES");
return getPathForV19AndUp(context, contentUri);
} else {
return getPathForPreV19(context, contentUri);
}
}
You can just read the path from sd card and do the following code...it'll Replace the existing photo after rotating it..
Not: Exif doesnt work on most of the devices, it gives the wrong data so it's good to hard code the rotating before saving to any degree you want to,You just have to change the angle value in postRotate to any you want to.
String photopath = tempphoto.getPath().toString();
Bitmap bmp = BitmapFactory.decodeFile(photopath);
Matrix matrix = new Matrix();
matrix.postRotate(90);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
FileOutputStream fOut;
try {
fOut = new FileOutputStream(tempphoto);
bmp.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
fOut.flush();
fOut.close();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I improved upon the answer by Teo Inke. It no longer rotates the image unless it is actually necessary. It is also easier to read, and should run faster.
// Load Image
Bitmap bitmap = BitmapFactory.decodeFile(filePath);
// Rotate Image if Needed
try
{
// Determine Orientation
ExifInterface exif = new ExifInterface(filePath);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
// Determine Rotation
int rotation = 0;
if (orientation == 6) rotation = 90;
else if (orientation == 3) rotation = 180;
else if (orientation == 8) rotation = 270;
// Rotate Image if Necessary
if (rotation != 0)
{
// Create Matrix
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
// Rotate Bitmap
Bitmap rotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
// Pretend none of this ever happened!
bitmap.recycle();
bitmap = rotated;
rotated = null;
}
}
catch (Exception e)
{
// TODO: Log Error Messages Here
}
// TODO: Use Result Here
xxx.setBitmap(bitmap);
The first thing you need is the real File path
If you have it great, if you are using URI then use this method to
get the real Path:
public static String getRealPathFromURI(Uri contentURI,Context context) {
String path= contentURI.getPath();
try {
Cursor cursor = context.getContentResolver().query(contentURI, null, null, null, null);
cursor.moveToFirst();
String document_id = cursor.getString(0);
document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
cursor.close();
cursor = context.getContentResolver().query(
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
cursor.moveToFirst();
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
}
catch(Exception e)
{
return path;
}
return path;
}
extract your Bitmap for example:
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImage);
}
catch (IOException e)
{
Log.e("IOException",e.toString());
}
you can use decodeFile() instead if you wish.
Now that you have the Bitmap and the real Path get the Orientation of the Image:
private static int getExifOrientation(String src) throws IOException {
int orientation = 1;
ExifInterface exif = new ExifInterface(src);
String orientationString=exif.getAttribute(ExifInterface.TAG_ORIENTATION);
try {
orientation = Integer.parseInt(orientationString);
}
catch(NumberFormatException e){}
return orientation;
}
and finally rotate it to the right position like so:
public static Bitmap rotateBitmap(String src, Bitmap bitmap) {
try {
int orientation = getExifOrientation(src);
if (orientation == 1) {
return bitmap;
}
Matrix matrix = new Matrix();
switch (orientation) {
case 2:
matrix.setScale(-1, 1);
break;
case 3:
matrix.setRotate(180);
break;
case 4:
matrix.setRotate(180);
matrix.postScale(-1, 1);
break;
case 5:
matrix.setRotate(90);
matrix.postScale(-1, 1);
break;
case 6:
matrix.setRotate(90);
break;
case 7:
matrix.setRotate(-90);
matrix.postScale(-1, 1);
break;
case 8:
matrix.setRotate(-90);
break;
default:
return bitmap;
}
try {
Bitmap oriented = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
bitmap.recycle();
return oriented;
} catch (OutOfMemoryError e) {
e.printStackTrace();
return bitmap;
}
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
That's it , you now have the bitmap rotated to the right position.
cheers.
This works, but probably not the best way to do it, but it might help someone.
String imagepath = someUri.getAbsolutePath();
imageview = (ImageView)findViewById(R.id.imageview);
imageview.setImageBitmap(setImage(imagepath, 120, 120));
public Bitmap setImage(String path, final int targetWidth, final int targetHeight) {
Bitmap bitmap = null;
// Get exif orientation
try {
ExifInterface exif = new ExifInterface(path);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
if (orientation == 6) {
orientation_val = 90;
}
else if (orientation == 3) {
orientation_val = 180;
}
else if (orientation == 8) {
orientation_val = 270;
}
}
catch (Exception e) {
}
try {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Adjust extents
int sourceWidth, sourceHeight;
if (orientation_val == 90 || orientation_val == 270) {
sourceWidth = options.outHeight;
sourceHeight = options.outWidth;
} else {
sourceWidth = options.outWidth;
sourceHeight = options.outHeight;
}
// Calculate the maximum required scaling ratio if required and load the bitmap
if (sourceWidth > targetWidth || sourceHeight > targetHeight) {
float widthRatio = (float)sourceWidth / (float)targetWidth;
float heightRatio = (float)sourceHeight / (float)targetHeight;
float maxRatio = Math.max(widthRatio, heightRatio);
options.inJustDecodeBounds = false;
options.inSampleSize = (int)maxRatio;
bitmap = BitmapFactory.decodeFile(path, options);
} else {
bitmap = BitmapFactory.decodeFile(path);
}
// Rotate the bitmap if required
if (orientation_val > 0) {
Matrix matrix = new Matrix();
matrix.postRotate(orientation_val);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
// Re-scale the bitmap if necessary
sourceWidth = bitmap.getWidth();
sourceHeight = bitmap.getHeight();
if (sourceWidth != targetWidth || sourceHeight != targetHeight) {
float widthRatio = (float)sourceWidth / (float)targetWidth;
float heightRatio = (float)sourceHeight / (float)targetHeight;
float maxRatio = Math.max(widthRatio, heightRatio);
sourceWidth = (int)((float)sourceWidth / maxRatio);
sourceHeight = (int)((float)sourceHeight / maxRatio);
bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
}
} catch (Exception e) {
}
return bitmap;
}
maybe this will help (rotate 90 degree)(this worked for me)
private Bitmap rotateBitmap(Bitmap image){
int width=image.getHeight();
int height=image.getWidth();
Bitmap srcBitmap=Bitmap.createBitmap(width, height, image.getConfig());
for (int y=width-1;y>=0;y--)
for(int x=0;x<height;x++)
srcBitmap.setPixel(width-y-1, x,image.getPixel(x, y));
return srcBitmap;
}
The methods below scales AND rotates the bitmap according to the orientation:
public Bitmap scaleAndRotateImage(String path, int orientation, final int targetWidth, final int targetHeight)
{
Bitmap bitmap = null;
try
{
// Check the dimensions of the Image
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Adjust the Width and Height
int sourceWidth, sourceHeight;
if (orientation == 90 || orientation == 270)
{
sourceWidth = options.outHeight;
sourceHeight = options.outWidth;
}
else
{
sourceWidth = options.outWidth;
sourceHeight = options.outHeight;
}
// Calculate the maximum required scaling ratio if required and load the bitmap
if (sourceWidth > targetWidth || sourceHeight > targetHeight)
{
float widthRatio = (float)sourceWidth / (float)targetWidth;
float heightRatio = (float)sourceHeight / (float)targetHeight;
float maxRatio = Math.max(widthRatio, heightRatio);
options.inJustDecodeBounds = false;
options.inSampleSize = (int)maxRatio;
bitmap = BitmapFactory.decodeFile(path, options);
}
else
{
bitmap = BitmapFactory.decodeFile(path);
}
// We need to rotate the bitmap (if required)
int orientationInDegrees = exifToDegrees(orientation);
if (orientation > 0)
{
Matrix matrix = new Matrix();
if (orientation != 0f)
{
matrix.preRotate(orientationInDegrees);
};
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
// Re-scale the bitmap if necessary
sourceWidth = bitmap.getWidth();
sourceHeight = bitmap.getHeight();
if (sourceWidth != targetWidth || sourceHeight != targetHeight)
{
float widthRatio = (float)sourceWidth / (float)targetWidth;
float heightRatio = (float)sourceHeight / (float)targetHeight;
float maxRatio = Math.max(widthRatio, heightRatio);
sourceWidth = (int)((float)sourceWidth / maxRatio);
sourceHeight = (int)((float)sourceHeight / maxRatio);
bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
}
}
catch (Exception e)
{
Logger.d("Could not rotate the image");
Logger.d(e.getMessage());
}
return bitmap;
}
Example:
public void getPictureFromDevice(Uri Uri,ImageView imageView)
{
try
{
ExifInterface exifInterface = new ExifInterface(Uri.getPath());
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
Bitmap bitmap = scaleAndRotateImage(Uri.getPath(), orientation, imageView.getWidth(), imageView.getHeight());
imageView.setImageBitmap(bitmap);
}
catch (OutOfMemoryError outOfMemoryError)
{
Logger.d(outOfMemoryError.getLocalizedMessage());
Logger.d("Failed to load image from filePath (out of memory)");
Logger.d(Uri.toString());
}
catch (Exception e)
{
Logger.d("Failed to load image from filePath");
Logger.d(Uri.toString());
}
}
The cursor should be closed after opening it.
Here is an example.
public static int getOrientation(Context context, Uri selectedImage)
{
int orientation = -1;
Cursor cursor = context.getContentResolver().query(selectedImage,
new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
if (cursor.getCount() != 1)
return orientation;
cursor.moveToFirst();
orientation = cursor.getInt(0);
cursor.close(); // ADD THIS LINE
return orientation;
}
I have melted #Timmmm answer and #Manuel. If you do this solution, you will not get a Run Out Of Memory Exception.
This method retrieves the image orientation:
private static final int ROTATION_DEGREES = 90;
// This means 512 px
private static final Integer MAX_IMAGE_DIMENSION = 512;
public static int getOrientation(Uri photoUri) throws IOException {
ExifInterface exif = new ExifInterface(photoUri.getPath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
orientation = ROTATION_DEGREES;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
orientation = ROTATION_DEGREES * 2;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
orientation = ROTATION_DEGREES * 3;
break;
default:
// Default case, image is not rotated
orientation = 0;
}
return orientation;
}
Therefore, you would use this method to resize image before load it on memory. In that way, you will not get a Memory Exception.
public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri) throws IOException {
InputStream is = context.getContentResolver().openInputStream(photoUri);
BitmapFactory.Options dbo = new BitmapFactory.Options();
dbo.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, dbo);
is.close();
int rotatedWidth, rotatedHeight;
int orientation = getOrientation(photoUri);
if (orientation == 90 || orientation == 270) {
rotatedWidth = dbo.outHeight;
rotatedHeight = dbo.outWidth;
} else {
rotatedWidth = dbo.outWidth;
rotatedHeight = dbo.outHeight;
}
Bitmap srcBitmap;
is = context.getContentResolver().openInputStream(photoUri);
if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) {
float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
float maxRatio = Math.max(widthRatio, heightRatio);
// Create the bitmap from file
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = (int) maxRatio;
srcBitmap = BitmapFactory.decodeStream(is, null, options);
} else {
srcBitmap = BitmapFactory.decodeStream(is);
}
is.close();
// if the orientation is not 0, we have to do a rotation.
if (orientation > 0) {
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
srcBitmap.getHeight(), matrix, true);
}
return srcBitmap;
}
This works perfectly for me. I hope this helps somebody else
Improving on the solution above by Timmmm to add some extra scaling at the end to ensure that the image fits within the bounds:
public static Bitmap loadBitmap(String path, int orientation, final int targetWidth, final int targetHeight) {
Bitmap bitmap = null;
try {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Adjust extents
int sourceWidth, sourceHeight;
if (orientation == 90 || orientation == 270) {
sourceWidth = options.outHeight;
sourceHeight = options.outWidth;
} else {
sourceWidth = options.outWidth;
sourceHeight = options.outHeight;
}
// Calculate the maximum required scaling ratio if required and load the bitmap
if (sourceWidth > targetWidth || sourceHeight > targetHeight) {
float widthRatio = (float)sourceWidth / (float)targetWidth;
float heightRatio = (float)sourceHeight / (float)targetHeight;
float maxRatio = Math.max(widthRatio, heightRatio);
options.inJustDecodeBounds = false;
options.inSampleSize = (int)maxRatio;
bitmap = BitmapFactory.decodeFile(path, options);
} else {
bitmap = BitmapFactory.decodeFile(path);
}
// Rotate the bitmap if required
if (orientation > 0) {
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
// Re-scale the bitmap if necessary
sourceWidth = bitmap.getWidth();
sourceHeight = bitmap.getHeight();
if (sourceWidth != targetWidth || sourceHeight != targetHeight) {
float widthRatio = (float)sourceWidth / (float)targetWidth;
float heightRatio = (float)sourceHeight / (float)targetHeight;
float maxRatio = Math.max(widthRatio, heightRatio);
sourceWidth = (int)((float)sourceWidth / maxRatio);
sourceHeight = (int)((float)sourceHeight / maxRatio);
bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
}
} catch (Exception e) {
}
return bitmap;
}
Use the following code to rotate an image correctly:
private Bitmap rotateImage(Bitmap bitmap, String filePath)
{
Bitmap resultBitmap = bitmap;
try
{
ExifInterface exifInterface = new ExifInterface(filePath);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Matrix matrix = new Matrix();
if (orientation == ExifInterface.ORIENTATION_ROTATE_90)
{
matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_90);
}
else if (orientation == ExifInterface.ORIENTATION_ROTATE_180)
{
matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_180);
}
else if (orientation == ExifInterface.ORIENTATION_ROTATE_270)
{
matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_270);
}
// Rotate the bitmap
resultBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
catch (Exception exception)
{
Logger.d("Could not rotate the image");
}
return resultBitmap;
}
I solved the problem with the following workaround. Note that I am also scaling the image, which was necessary to avoid OutOfMemoryExceptions.
Beware that this solution will not work properly with portrait images or opside-down images (thank you Timmmm for noting). Timmmm's solution above might be the better choice if that is required and it looks more elegant, too: https://stackoverflow.com/a/8914291/449918
File path = // ... location of your bitmap file
int w = 512; int h = 384; // size that does not lead to OutOfMemoryException on Nexus One
Bitmap b = BitmapFactory.decodeFile(path);
// Hack to determine whether the image is rotated
boolean rotated = b.getWidth() > b.getHeight();
Bitmap resultBmp = null;
// If not rotated, just scale it
if (!rotated) {
resultBmp = Bitmap.createScaledBitmap(b, w, h, true);
b.recycle();
b = null;
// If rotated, scale it by switching width and height and then rotated it
} else {
Bitmap scaledBmp = Bitmap.createScaledBitmap(b, h, w, true);
b.recycle();
b = null;
Matrix mat = new Matrix();
mat.postRotate(90);
resultBmp = Bitmap.createBitmap(scaledBmp, 0, 0, h, w, mat, true);
// Release image resources
scaledBmp.recycle();
scaledBmp = null;
}
// resultBmp now contains the scaled and rotated image
Cheers