android - realizar - fotos de 360 grados
¿Por qué una imagen capturada con la intención de la cámara se gira en algunos dispositivos en Android? (18)
Estoy capturando una imagen y configurándola como vista de imagen.
public void captureImage() {
Intent intentCamera = new Intent("android.media.action.IMAGE_CAPTURE");
File filePhoto = new File(Environment.getExternalStorageDirectory(), "Pic.jpg");
imageUri = Uri.fromFile(filePhoto);
MyApplicationGlobal.imageUri = imageUri.getPath();
intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intentCamera, TAKE_PICTURE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intentFromCamera) {
super.onActivityResult(requestCode, resultCode, intentFromCamera);
if (resultCode == RESULT_OK && requestCode == TAKE_PICTURE) {
if (intentFromCamera != null) {
Bundle extras = intentFromCamera.getExtras();
if (extras.containsKey("data")) {
bitmap = (Bitmap) extras.get("data");
}
else {
bitmap = getBitmapFromUri();
}
}
else {
bitmap = getBitmapFromUri();
}
// imageView.setImageBitmap(bitmap);
imageView.setImageURI(imageUri);
}
else {
}
}
public Bitmap getBitmapFromUri() {
getContentResolver().notifyChange(imageUri, null);
ContentResolver cr = getContentResolver();
Bitmap bitmap;
try {
bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, imageUri);
return bitmap;
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
Pero el problema es que la imagen en algunos dispositivos cada vez que se gira. Por ejemplo, en un dispositivo Samsung funciona bien, pero en un Sony Xperia la imagen se gira 90 grados y en Toshiba Thrive (tableta) 180 grados.
Al combinar la answer Jason Robinson con la answer de Felix y completar las partes faltantes, aquí está la solución completa final para este problema que hará lo siguiente después de probarla en Android Android 4.1 ( Jelly Bean ), Android 4.4 ( KitKat ) y Android 5.0 ( Lollipop ).
Pasos
Baje la imagen si era más grande que 1024x1024.
Gire la imagen a la orientación correcta solo si giró 90, 180 o 270 grados.
Recicle la imagen girada para propósitos de memoria.
Aquí está la parte del código:
Llame al siguiente método con el Context
actual y la imagen URI
que desea corregir
/**
* This method is responsible for solving the rotation issue if exist. Also scale the images to
* 1024x1024 resolution
*
* @param context The current context
* @param selectedImage The Image URI
* @return Bitmap image results
* @throws IOException
*/
public static Bitmap handleSamplingAndRotationBitmap(Context context, Uri selectedImage)
throws IOException {
int MAX_HEIGHT = 1024;
int MAX_WIDTH = 1024;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
InputStream imageStream = context.getContentResolver().openInputStream(selectedImage);
BitmapFactory.decodeStream(imageStream, null, options);
imageStream.close();
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
imageStream = context.getContentResolver().openInputStream(selectedImage);
Bitmap img = BitmapFactory.decodeStream(imageStream, null, options);
img = rotateImageIfRequired(context, img, selectedImage);
return img;
}
Aquí está el método CalculateInSampleSize
de la source mencionada anteriormente:
/**
* Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding
* bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates
* the closest inSampleSize that will result in the final decoded bitmap having a width and
* height equal to or larger than the requested width and height. This implementation does not
* ensure a power of 2 is returned for inSampleSize which can be faster when decoding but
* results in a larger bitmap which isn''t as useful for caching purposes.
*
* @param options An options object with out* params already populated (run through a decode*
* method with inJustDecodeBounds==true
* @param reqWidth The requested width of the resulting bitmap
* @param reqHeight The requested height of the resulting bitmap
* @return The value to be used for inSampleSize
*/
private 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) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee a final image
// with both dimensions larger than or equal to the requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
// This offers some additional logic in case the image has a strange
// aspect ratio. For example, a panorama may have a much larger
// width than height. In these cases the total pixels might still
// end up being too large to fit comfortably in memory, so we should
// be more aggressive with sample down the image (=larger inSampleSize).
final float totalPixels = width * height;
// Anything more than 2x the requested pixels we''ll sample down further
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
}
return inSampleSize;
}
Luego viene el método que verificará la orientación de la imagen actual para decidir el ángulo de rotación
/**
* Rotate an image if required.
*
* @param img The image bitmap
* @param selectedImage Image URI
* @return The resulted Bitmap after manipulation
*/
private static Bitmap rotateImageIfRequired(Context context, Bitmap img, Uri selectedImage) throws IOException {
InputStream input = context.getContentResolver().openInputStream(selectedImage);
ExifInterface ei;
if (Build.VERSION.SDK_INT > 23)
ei = new ExifInterface(input);
else
ei = new ExifInterface(selectedImage.getPath());
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
return rotateImage(img, 90);
case ExifInterface.ORIENTATION_ROTATE_180:
return rotateImage(img, 180);
case ExifInterface.ORIENTATION_ROTATE_270:
return rotateImage(img, 270);
default:
return img;
}
}
Finalmente el propio método de rotación.
private static Bitmap rotateImage(Bitmap img, int degree) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
img.recycle();
return rotatedImg;
}
-No te olvides de votar por las respuestas de esos muchachos por su esfuerzo y Shirish Herwade, que hizo esta pregunta útil.
Es fácil detectar la orientación de la imagen y reemplazar el mapa de bits usando:
/**
* Rotate an image if required.
* @param img
* @param selectedImage
* @return
*/
private static Bitmap rotateImageIfRequired(Context context,Bitmap img, Uri selectedImage) {
// Detect rotation
int rotation = getRotation(context, selectedImage);
if (rotation != 0) {
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
img.recycle();
return rotatedImg;
}
else{
return img;
}
}
/**
* Get the rotation of the last image added.
* @param context
* @param selectedImage
* @return
*/
private static int getRotation(Context context,Uri selectedImage) {
int rotation = 0;
ContentResolver content = context.getContentResolver();
Cursor mediaCursor = content.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[] { "orientation", "date_added" },
null, null, "date_added desc");
if (mediaCursor != null && mediaCursor.getCount() != 0) {
while(mediaCursor.moveToNext()){
rotation = mediaCursor.getInt(0);
break;
}
}
mediaCursor.close();
return rotation;
}
Para evitar el recuerdo de recuerdos con imágenes grandes, te recomiendo que vuelvas a escalar la imagen usando:
private static final int MAX_HEIGHT = 1024;
private static final int MAX_WIDTH = 1024;
public static Bitmap decodeSampledBitmap(Context context, Uri selectedImage)
throws IOException {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
InputStream imageStream = context.getContentResolver().openInputStream(selectedImage);
BitmapFactory.decodeStream(imageStream, null, options);
imageStream.close();
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
imageStream = context.getContentResolver().openInputStream(selectedImage);
Bitmap img = BitmapFactory.decodeStream(imageStream, null, options);
img = rotateImageIfRequired(img, selectedImage);
return img;
}
No es posible utilizar ExifInterface para obtener la orientación debido a un problema del sistema operativo Android: https://code.google.com/p/android/issues/detail?id=19268
Y aqui esta calculateInSampleSize
muestra
/**
* Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding
* bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates
* the closest inSampleSize that will result in the final decoded bitmap having a width and
* height equal to or larger than the requested width and height. This implementation does not
* ensure a power of 2 is returned for inSampleSize which can be faster when decoding but
* results in a larger bitmap which isn''t as useful for caching purposes.
*
* @param options An options object with out* params already populated (run through a decode*
* method with inJustDecodeBounds==true
* @param reqWidth The requested width of the resulting bitmap
* @param reqHeight The requested height of the resulting bitmap
* @return The value to be used for inSampleSize
*/
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) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee a final image
// with both dimensions larger than or equal to the requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
// This offers some additional logic in case the image has a strange
// aspect ratio. For example, a panorama may have a much larger
// width than height. In these cases the total pixels might still
// end up being too large to fit comfortably in memory, so we should
// be more aggressive with sample down the image (=larger inSampleSize).
final float totalPixels = width * height;
// Anything more than 2x the requested pixels we''ll sample down further
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
}
return inSampleSize;
}
He pasado mucho tiempo buscando una solución para esto. Y finalmente logró hacer esto. No te olvides de votar hasta @Jason Robinson respuesta porque mi se basa en la suya.
Entonces, primero debes saber que desde Android 7.0 tenemos que usar FileProvider
y algo llamado ContentUri
, de lo contrario obtendrás un error molesto al intentar invocar tu Intent
. Este es un código de muestra:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, getUriFromPath(context, "[Your path to save image]"));
startActivityForResult(intent, CAPTURE_IMAGE_RESULT);
El método getUriFromPath(Context, String)
en la versión del usuario de Android crea FileUri (file://...)
o ContentUri (content://...)
y ahí está:
public Uri getUriFromPath(Context context, String destination) {
File file = new File(destination);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
return FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file);
} else {
return Uri.fromFile(file);
}
}
Después de onActivityResult
, puedes capturar ese uri
donde la imagen es guardada por la cámara, pero ahora debes detectar la rotación de la cámara, aquí usaremos la respuesta moddified @Jason Robinson
Primero necesitamos crear ExifInterface
basado en Uri
@Nullable
public ExifInterface getExifInterface(Context context, Uri uri) {
try {
String path = uri.toString();
if (path.startsWith("file://")) {
return new ExifInterface(path);
}
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (path.startsWith("content://")) {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
return new ExifInterface(inputStream);
}
}
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
El código anterior se puede simplificar, pero quiero mostrar todo. Entonces, desde FileUri
podemos crear ExifInterface
basado en String path
, pero desde ContentUri
no podemos, Android no lo admite.
En ese caso tenemos que usar otro constructor basado en InputStream
. Recuerde que este constructor no está disponible de forma predeterminada, debe agregar una biblioteca adicional:
compile "com.android.support:exifinterface:XX.X.X"
Ahora podemos usar el método getExifInterface
para obtener nuestro ángulo:
public float getExifAngle(Context context, Uri uri) {
try {
ExifInterface exifInterface = getExifInterface(context, uri);
if(exifInterface == null) {
return -1f;
}
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
return 90f;
case ExifInterface.ORIENTATION_ROTATE_180:
return 180f;
case ExifInterface.ORIENTATION_ROTATE_270:
return 270f;
case ExifInterface.ORIENTATION_NORMAL:
return 0f;
case ExifInterface.ORIENTATION_UNDEFINED:
return -1f;
default:
return -1f;
}
}
catch (Exception e) {
e.printStackTrace();
return -1f;
}
}
Ahora tienes un ángulo para rotar correctamente tu imagen :).
La answer Jason Robinson y la answer Sami Eltamawy son excelentes.
Solo una mejora para completar el enfoque, debe usar compat ExifInterface.
com.android.support:exifinterface:${lastLibVersion}
Podrá crear una instancia de ExifInterface (API pior <24) con InputStream
(de ContentResolver
) en lugar de las rutas uri evitando "Excepciones de archivo no encontrado"
https://android-developers.googleblog.com/2016/12/introducing-the-exifinterface-support-library.html
La mayoría de las cámaras de los teléfonos son horizontales, lo que significa que si toma la foto en vertical, las fotografías resultantes se girarán 90 grados. En este caso, el software de la cámara debe llenar los datos Exif con la orientación en la que se debe ver la foto.
Tenga en cuenta que la solución a continuación depende del fabricante del dispositivo / software de la cámara que llena los datos Exif, por lo que funcionará en la mayoría de los casos, pero no es una solución 100% confiable.
ExifInterface ei = new ExifInterface(photoPath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
Bitmap rotatedBitmap = null;
switch(orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotatedBitmap = rotateImage(bitmap, 90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotatedBitmap = rotateImage(bitmap, 180);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotatedBitmap = rotateImage(bitmap, 270);
break;
case ExifInterface.ORIENTATION_NORMAL:
default:
rotatedBitmap = bitmap;
}
Aquí está el método rotateImage
:
public static Bitmap rotateImage(Bitmap source, float angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(),
matrix, true);
}
La respuesta seleccionada utiliza el método más común que se responde a esta y otras preguntas similares. Sin embargo, no funciona con las cámaras delantera y trasera de Samsung. Para aquellos que buscan una solución que funcione con cámaras frontal y trasera para Samsung y otros fabricantes importantes, esta respuesta de nvhausid es increíble:
https://.com/a/18915443/6080472
Para aquellos que no quieren hacer clic, la magia relevante es utilizar CameraInfo en lugar de confiar en EXIF.
Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(mCurrentCameraId, info);
Bitmap bitmap = rotate(realImage, info.orientation);
Código completo en el enlace.
Lamentablemente, la respuesta de @ jason-robinson no funcionó para mí.
Aunque la función de rotación funciona perfectamente:
public static Bitmap rotateImage(Bitmap source, float angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix,
true);
}
Tuve que hacer lo siguiente para obtener la orientación ya que la orientación Exif siempre fue 0
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode,resultCode,data);
if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && data != null) {
Uri selectedImage = data.getData();
String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
Cursor cur = managedQuery(imageUri, orientationColumn, null, null, null);
int orientation = -1;
if (cur != null && cur.moveToFirst()) {
orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
}
InputStream imageStream = getContentResolver().openInputStream(selectedImage);
Bitmap bitmap = BitmapFactory.decodeStream(imageStream);
switch(orientation) {
case 90:
bitmap = rotateImage(chosen_image_bitmap, 90);
break;
case 180:
bitmap = rotateImage(chosen_image_bitmap, 180);
break;
case 270:
bitmap = rotateImage(chosen_image_bitmap, 270);
break;
default:
break;
}
imageView.setImageBitmap(bitmap );
Mejor tratar de tomar la foto en una orientación específica.
android:screenOrientation="landscape"
android:configChanges="orientation|keyboardHidden"
Para obtener los mejores resultados, da orientación horizontal en la actividad de vista de la cámara.
Normalmente se recomienda resolver el problema con ExifInterface , como sugirió @Jason Robinson. Si este enfoque no funciona, podría intentar buscar la Orientation de la última imagen tomada ...
private int getImageOrientation(){
final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.ImageColumns.ORIENTATION };
final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
imageColumns, null, null, imageOrderBy);
if(cursor.moveToFirst()){
int orientation = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION));
cursor.close();
return orientation;
} else {
return 0;
}
}
Si alguien experimenta problemas con ExifInterface
en Android 4.4 (KitKat) para obtener la orientación, podría deberse a una ruta incorrecta obtenida desde el URI. Vea una solución para propoer getPath
en la pregunta de desbordamiento de pila Obtenga una ruta real desde URI, Android KitKat nuevo marco de acceso de almacenamiento
Simplemente puede leer la orientación del sensor de la cámara como lo indica Google en la documentación: https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html
SENSOR_ORIENTATION
Added in API level 21
Key<Integer> SENSOR_ORIENTATION
Clockwise angle through which the output image needs to be rotated to be upright on the device screen in its native orientation.
Also defines the direction of rolling shutter readout, which is from top to bottom in the sensor''s coordinate system.
Units: Degrees of clockwise rotation; always a multiple of 90
Range of valid values:
0, 90, 180, 270
This key is available on all devices.
Código de muestra:
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
int orientation = 0;
try {
String cameraId = manager.getCameraIdList()[0];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
orientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
}
catch (Exception e)
{
}
Tal vez sea evidente, pero siempre recuerde que puede manejar algunos de estos problemas de manejo de imágenes en su servidor. Utilicé respuestas como las contenidas en este hilo para manejar la visualización inmediata de la imagen. Sin embargo, mi aplicación requiere que las imágenes se almacenen en el servidor (este es probablemente un requisito común si desea que la imagen persista a medida que los usuarios cambian de teléfono).
Las soluciones contenidas en muchos de los subprocesos relacionados con este tema no discuten la falta de persistencia de los datos EXIF que no sobreviven a la compresión de la imagen del Mapa de bits, lo que significa que deberá rotar la imagen cada vez que el servidor la carga. Alternativamente, puede enviar los datos de orientación EXIF a su servidor, y luego girar la imagen allí si es necesario.
Fue más fácil para mí crear una solución permanente en un servidor porque no tenía que preocuparme por las rutas de archivos clandestinos de Android.
Una solución de línea:
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
O
Picasso.with(context).load("file:" + photoPath).into(imageView);
Esto detectará automáticamente la rotación y colocará la imagen en la orientación correcta
Picasso es una biblioteca muy poderosa para manejar imágenes en su aplicación que incluye: Transformaciones complejas de imágenes con un uso mínimo de memoria.
esto me funcionó
display_image = findViewById(R.id.image);
imagePath = getIntent().getStringExtra("image_path");
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
display_image.setImageBitmap(bitmap);
this.display_image.setRotation(90);
Hay un comando más simple para corregir este error.
Simplemente agregue después de yourImageView.setBitmap (mapa de bits); este yourImageView.setRotation (90);
Esto arregló la mía. Espero eso ayude !
Intente lo siguiente, si está enfrentando un problema con S4.
android:configChanges="locale|touchscreen|orientation|screenLayout|screenSize|keyboardHidden|uiMode"
La solución más simple para este problema:
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,
characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION));
Estoy guardando la imagen en formato jpg.
// Try this way,hope this will help you to solve your problem...
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center">
<ImageView
android:id="@+id/imgFromCameraOrGallery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/ic_launcher"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btnCamera"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Camera"/>
<Button
android:id="@+id/btnGallery"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_marginLeft="5dp"
android:layout_height="wrap_content"
android:text="Gallery"/>
</LinearLayout>
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
private ImageView imgFromCameraOrGallery;
private Button btnCamera;
private Button btnGallery;
private String imgPath;
final private int PICK_IMAGE = 1;
final private int CAPTURE_IMAGE = 2;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imgFromCameraOrGallery = (ImageView) findViewById(R.id.imgFromCameraOrGallery);
btnCamera = (Button) findViewById(R.id.btnCamera);
btnGallery = (Button) findViewById(R.id.btnGallery);
btnCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, setImageUri());
startActivityForResult(intent, CAPTURE_IMAGE);
}
});
btnGallery.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, ""), PICK_IMAGE);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == CAPTURE_IMAGE) {
setCapturedImage(getImagePath());
} else if (requestCode == PICK_IMAGE) {
imgFromCameraOrGallery.setImageBitmap(BitmapFactory.decodeFile(getAbsolutePath(data.getData())));
}
}
}
private String getRightAngleImage(String photoPath) {
try {
ExifInterface ei = new ExifInterface(photoPath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int degree = 0;
switch (orientation) {
case ExifInterface.ORIENTATION_NORMAL:
degree = 0;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
case ExifInterface.ORIENTATION_UNDEFINED:
degree = 0;
break;
default:
degree = 90;
}
return rotateImage(degree,photoPath);
} catch (Exception e) {
e.printStackTrace();
}
return photoPath;
}
private String rotateImage(int degree, String imagePath){
if(degree<=0){
return imagePath;
}
try{
Bitmap b= BitmapFactory.decodeFile(imagePath);
Matrix matrix = new Matrix();
if(b.getWidth()>b.getHeight()){
matrix.setRotate(degree);
b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(),
matrix, true);
}
FileOutputStream fOut = new FileOutputStream(imagePath);
String imageName = imagePath.substring(imagePath.lastIndexOf("/") + 1);
String imageType = imageName.substring(imageName.lastIndexOf(".") + 1);
FileOutputStream out = new FileOutputStream(imagePath);
if (imageType.equalsIgnoreCase("png")) {
b.compress(Bitmap.CompressFormat.PNG, 100, out);
}else if (imageType.equalsIgnoreCase("jpeg")|| imageType.equalsIgnoreCase("jpg")) {
b.compress(Bitmap.CompressFormat.JPEG, 100, out);
}
fOut.flush();
fOut.close();
b.recycle();
}catch (Exception e){
e.printStackTrace();
}
return imagePath;
}
private void setCapturedImage(final String imagePath){
new AsyncTask<Void,Void,String>(){
@Override
protected String doInBackground(Void... params) {
try {
return getRightAngleImage(imagePath);
}catch (Throwable e){
e.printStackTrace();
}
return imagePath;
}
@Override
protected void onPostExecute(String imagePath) {
super.onPostExecute(imagePath);
imgFromCameraOrGallery.setImageBitmap(decodeFile(imagePath));
}
}.execute();
}
public Bitmap decodeFile(String path) {
try {
// Decode deal_image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 1024;
// Find the correct scale value. It should be the power of 2.
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE && o.outHeight / scale / 2 >= REQUIRED_SIZE)
scale *= 2;
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeFile(path, o2);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
public String getAbsolutePath(Uri uri) {
if(Build.VERSION.SDK_INT >= 19){
String id = "";
if(uri.getLastPathSegment().split(":").length > 1)
id = uri.getLastPathSegment().split(":")[1];
else if(uri.getLastPathSegment().split(":").length > 0)
id = uri.getLastPathSegment().split(":")[0];
if(id.length() > 0){
final String[] imageColumns = {MediaStore.Images.Media.DATA };
final String imageOrderBy = null;
Uri tempUri = getUri();
Cursor imageCursor = getContentResolver().query(tempUri, imageColumns, MediaStore.Images.Media._ID + "=" + id, null, imageOrderBy);
if (imageCursor.moveToFirst()) {
return imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
}else{
return null;
}
}else{
return null;
}
}else{
String[] projection = { MediaStore.MediaColumns.DATA };
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if (cursor != null) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} else
return null;
}
}
private Uri getUri() {
String state = Environment.getExternalStorageState();
if(!state.equalsIgnoreCase(Environment.MEDIA_MOUNTED))
return MediaStore.Images.Media.INTERNAL_CONTENT_URI;
return MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
public Uri setImageUri() {
Uri imgUri;
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
File file = new File(Environment.getExternalStorageDirectory() + "/DCIM/",getString(R.string.app_name) + Calendar.getInstance().getTimeInMillis() + ".png");
imgUri = Uri.fromFile(file);
imgPath = file.getAbsolutePath();
}else {
File file = new File(getFilesDir() ,getString(R.string.app_name) + Calendar.getInstance().getTimeInMillis()+ ".png");
imgUri = Uri.fromFile(file);
this.imgPath = file.getAbsolutePath();
}
return imgUri;
}
public String getImagePath() {
return imgPath;
}
}