I am trying to create an app that lets users click a button and select an image.
I used the second answer from this question to prompt the user for an image: How to pick an image from gallery (SD Card) for my app?
But sometimes if I choose an image that appears to be oriented correctly in the gallery, when I display it it will have a wrong orientation (I read that this usually happens with pictures taken by camera because they save their rotation in their ExifInterface)
So this code runs when the user chooses an image:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
switch(requestCode) {
case SELECT_PHOTO:
if(resultCode == RESULT_OK){
Uri si = imageReturnedIntent.getData();
InputStream imageStream = null;
try {
imageStream = getContentResolver().openInputStream(si);
Bitmap image = Utils.decodeUri(this, si);
addPerson(selectedName, selectedDate, image);
imageStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
addPerson() adds the person to the list and calls saveData() which is here:
try {
FileOutputStream out = new FileOutputStream(new File(folder, person.getName() + ".png"));
person.getImage().compress(Bitmap.CompressFormat.PNG, 100, out);
} catch (IOException e) {
e.printStackTrace();
};
And on onCreate() I run this code to load the items:
Bitmap notRotated = BitmapFactory.decodeFile(file.getPath());
Matrix matrix = new Matrix();
ExifInterface exif = new ExifInterface(file.getPath());
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int rotationInDegrees = Utils.exifToDegrees(rotation);
if(rotation != 0f)
matrix.preRotate(rotationInDegrees);
image = Bitmap.createBitmap(notRotated, 0, 0, notRotated.getWidth(), notRotated.getHeight(), matrix, true);
notRotated.recycle();
But when I run the above code it just ends up with black images and when I debug it says rotation is always 0 although there are obviously images with different rotation.
How can I fix this problem?
EDIT:
Here's my code to downsample my bitmaps to prevent OutOfMemoryExceptions:
public static Bitmap decodeUri(Context context, Uri selectedImage) throws FileNotFoundException {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(context.getContentResolver().openInputStream(selectedImage), null, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 140;
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE
|| height_tmp / 2 < REQUIRED_SIZE) {
break;
}
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(context.getContentResolver().openInputStream(selectedImage), null, o2);
}
Could me downsampling affect the rotation?
Okay so thanks to #CommonsWare for the help. Some errors in my code that he pointed out were saving the bitmaps in PNG format, not rotating them before saving and using ExifInterface in a wrong way. I changed the saving format to JPEG and used this example of an ExifInterface use (with a custom ExifInterface).
Related
I'm using this method:
public Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException {
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);
final int REQUIRED_SIZE = 800;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) {
break;
}
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o2);
}
To decode an URI from mi camera and then send to my webserver via an HttpURLConnection object in POST headers. But my instead get my original image:
I get an cropped imagen:
I don't know why. Perhaps my decodeURI method is wrong? Anybody know other best method to send my image compressed to my webserver?
I used right now the next way insteaf of my decodeUri method:
mybitMap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImageUri);
and I have the same problem. And when I tried to open the image in my webserver with Photoshop, I see an advertisement wich says "This document may be damaged (the file may be truncated or incomplete). Do you want continue?" And , after continue, I see a black space in the bottom of the image...
Anybody knows why? My code:
Bitmap mybitMap = null;
try {
mybitMap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImageUri);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imagen.compress(Bitmap.CompressFormat.JPEG, 100, baos);
And I send this in POST Headers:
Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
I've seen several questions regarding this topic, but none that address my problem.
I dynamically create ImageViews and allow the user to take/add photos of items for an inventory. The following code exists to generate the Bitmap and populate the ImageView:
protected void addPhotosToView(ArrayList<String> uris) {
for (String uriString : uris) {
try {
Uri uri = Uri.parse(uriString);
File imageFile = new File(uri.getPath());
int orientation = resolveBitmapOrientation(imageFile);
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
bitmap = applyOrientation(bitmap, orientation);
ImageView image = new ImageView(ItemActivity.this);
int h = 100; // height in pixels
int w = 100; // width in pixels
Bitmap scaled = Bitmap.createScaledBitmap(bitmap, h, w, true);
image.setImageBitmap(scaled);
LinearLayout photoLayout = (LinearLayout) findViewById(R.id.itemPhotoLayout);
photoLayout.addView(image);
addClickListener(image, uri);
} catch (Exception e) {
e.printStackTrace();
}
}
}
But once the image is added or taken, some images appear with the wrong orientation. Some of the photos stored in the phone in portrait are displayed in portrait, while others appear to be in landscape. Landscape photos are equally arbitrary.
This does not appear to be happening on all devices (the device that I'm seeing this on is a Samsung S4)
As you can see in the code, I have tried getting/applying orientation changes using Exif tags, but I'm always getting 0 for the orientation with this device and have not seen any answers for questions that ask for a solution when orientation is always 0.
I'm looking to ship this software soon and need some sort of workaround or solution, so I'm willing to accept some other way of going from Uris/strings to a dynamic, horizontally scrollable list of properly oriented images if this can't be resolved any other way.
you need to decode the bitmap that's all try this tutorial you can download the source.
that application dose exactly what you want maybe it will help you i hope because it worked fine with my application
Please use this method to show/decode your bitmap. It is taken from another SO post I cant remember which and is modified for my use. This method returns bitmap according to the exif orientation data if present on the image:
public Bitmap decodeFile(String path) {// you can provide file path here
int orientation;
try {
if (path == null) {
return null;
}
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
// Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 70;
// final int REQUIRED_SIZE = 20;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 0;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE
|| height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale++;
}
// decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap bm = BitmapFactory.decodeFile(path, o2);
Bitmap bitmap = bm;
ExifInterface exif = new ExifInterface(path);
orientation = exif
.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Matrix m = new Matrix();
if ((orientation == ExifInterface.ORIENTATION_ROTATE_180)) {
m.postRotate(180);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
bm.getHeight(), m, true);
photo(bitmap, path);
return bitmap;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
m.postRotate(90);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
bm.getHeight(), m, true);
photo(bitmap, path);
return bitmap;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
m.postRotate(270);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
bm.getHeight(), m, true);
photo(bitmap, path);
return bitmap;
}
return bitmap;
} catch (Exception e) {
return null;
}
}
I want to rotate and save my Captured Image using Android Native Camera to sdcard. As native cameras is in landscape by default. But the I don't want to use bitmap. Is it possible to do so ? please help. I am new to android development.
As my image is rotated by 90 degrees I need to rotate it using Bitmap before saving.
But on some devices bmp is coming null.
Camera Activity Layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</RelativeLayout>
ManifestFile
<activity
android:name="com.example.androiddms.CameraActivity"
android:configChanges="keyboardHidden|orientation"
android:label="#string/title_activity_camera"
android:screenOrientation="landscape"
android:theme="#android:style/Theme.NoTitleBar.Fullscreen" >
</activity>
Camera Activity.java
FileOutputStream fos = new FileOutputStream(pictureFile);
Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
Matrix matrix = new Matrix();
matrix.postRotate(90);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
bmp.compress(Bitmap.CompressFormat.JPEG, 100,fos);
You should call onActivityResult after taking picture from camera and show your captured picture on ImageView. Bitmap takes memory but you should handle it. Follow the following steps below hopefully solve your Problem
STEP 1: open camera Intent and capture image from it:
private static final int REQUEST_CAMERA = 0;
Bitmap bmp;
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, REQUEST_CAMERA);
STEP 2: override onActivityResult Method
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK)
{
if(requestCode == REQUEST_CAMERA)
{
Uri uri = (Uri) data.getData();
try
{
bmp = decodeUri(uri);
your_image_view.setImageBitmap(bmp);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
}
}
}
STEP 3: copy below method and paste it in your Activity
private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException
{
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(
getContentResolver().openInputStream(selectedImage), null, o);
final int REQUIRED_SIZE = 70;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true)
{
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
{
break;
}
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(
getContentResolver().openInputStream(selectedImage), null, o2);
}
and you are done after following these steps you will be able to capture image from camera and set it to your imageview without having memory error. Hope this will help you.
I have a listview where each list item has some imageview and some textview. I'm using intent to open gallery, pick an selected image and assign it to imageview but my problem is that when the image is set to that imageview as soon as I scroll my listview, the selected image disappears and the original image appears on that place.
So can any one tell me why is it so and how can i avoid it ?
Intent photoPickerIntent = new Intent(
Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent,
#Override
protected void onActivityResult(int requestCode, int resultCode,
Intent imageReturnedIntent) {
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
switch (requestCode) {
case SELECT_PHOTO:
if (resultCode == RESULT_OK) {
Uri selectedImage = imageReturnedIntent.getData();
/*
* InputStream imageStream=null; try { imageStream =
* getContentResolver().openInputStream(selectedImage); } catch
* (FileNotFoundException e) { // TODO Auto-generated catch
* block e.printStackTrace(); } Bitmap image =
* BitmapFactory.decodeStream(imageStream);
*/
try {
LinearLayout ll = (LinearLayout) lv.getChildAt(position);
ImageView im = (ImageView) ll
.findViewById(R.id.image);
Bitmap b = decodeUri(selectedImage);
Bitmap circleBitmap = Bitmap.createBitmap(b.getWidth(),
b.getHeight(), Bitmap.Config.ARGB_8888);
BitmapShader shader = new BitmapShader(b, TileMode.CLAMP,
TileMode.CLAMP);
Paint paint = new Paint();
paint.setShader(shader);
Canvas c = new Canvas(circleBitmap);
c.drawCircle(b.getWidth() / 2, b.getHeight() / 2,
b.getWidth() / 2, paint);
im.setImageBitmap(circleBitmap);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} SELECT_PHOTO);
private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(
getContentResolver().openInputStream(selectedImage), null, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 40;
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) {
break;
}
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(
getContentResolver().openInputStream(selectedImage), null, o2);
}
You should update your listadapter, or the source of your listadapter. The adapter is the model for your data. Your view will automatically update when you call notifyDatasetChanged on the adapter afer you updated it with the new value.
I am trying to take an image of specified dimensions and saving it in a desired location on the SD card. I am using intent.putExtra to take the image via the default camera application.
Here goes the code
public void onClick(View v) {
//Setting up the URI for the desired location
imageFile = "bmp"+v.getId()+".png";
File f = new File (folder,imageFile);
imageUri = Uri.fromFile(f);
//Setting the desired size parameters
private Camera mCamera;
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(width, height);
mCamera.setParameters(parameters);
//Passing intent.PutExtras to defaul camera activity
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(i,CAMERA_PIC_REQUEST);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
return;
}
The camera activiy force closes after taking an image.
Is it possible to modify the size of the images taken by the default camera activity in this way??
Or A separate camera application is necessary??
If your image is saved as a file, create a bitmap from that file and decrease its size using this method and pass this bitmap to your Activity:
public static Bitmap decodeFile(File file, int requiredSize) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(file), null, o);
// The new size we want to scale to
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < requiredSize
|| height_tmp / 2 < requiredSize)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(file), null,
o2);
} catch (FileNotFoundException e) {
}
return null;
}