picture rotated 90 degrees when copy the picture from URI to file - java

I was trying to copy a picture from URI to a file path. Then I read the picture from the path, but the picture I got was rotated 90 degrees down. Below is my function. Anybody can help on this?
public boolean copyPicture(Context context, Uri source, String dest) {
boolean result = false;
int bytesum = 0;
int byteread = 0;
File destFile = new File(dest);
String scheme = source.getScheme();
if (ContentResolver.SCHEME_CONTENT.equals(scheme)
|| ContentResolver.SCHEME_FILE.equals(scheme)) {
InputStream inStream = null;
try {
inStream = context.getContentResolver().openInputStream(source);
if (!destFile.exists()) {
result = destFile.createNewFile();
}
if (result) {
FileOutputStream fs = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
while ((byteread = inStream.read(buffer)) != -1) {
bytesum += byteread; //字节数 文件大小
System.out.println(bytesum);
fs.write(buffer, 0, byteread);
}
inStream.close();
fs.flush();
fs.close();
}
} catch (Exception e) {
e.printStackTrace();
result = false;
}
}
return result;
}

EXIF INTERFACE is the answer. It allows you to read specified attributes from a image file.
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
try {
ExifInterface exif = new ExifInterface(path);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int angle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
angle = 90;
}
else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
angle = 180;
}
else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
angle = 270;
}
Matrix mat = new Matrix();
mat.postRotate(angle);
Bitmap correctBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mat, true);
bitmap=correctBmp;
}
catch(Exception e){
}

Related

Losing bitmap image quality

I'm getting an image from gallery into a layout , then I'm getting the bitmap of that layout by using getBitmap(), after getting bitmap I'm saving the image into device storage by using saveImage().
After getting bitmap and saving the bitmap, the quality and pixel of that bitmap reduces too much as shown in the pictureSaved image AND Orignal image
Here is the code for getting and saving bitmap
private Bitmap getBitmap(View v) {
v.clearFocus();
v.setPressed(false);
boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
if (color != 0) {
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null) {
Toast.makeText(this, "Something Wrong", Toast.LENGTH_SHORT).show();
return null;
}
Bitmap lastimage = Bitmap.createBitmap(cacheBitmap);
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
//2048x2048 resolution
int newWidth = 2048;
int newHeight = 2048;
int width = lastimage.getWidth();
int height = lastimage.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(lastimage, 0, 0, width, height, matrix, true);
lastimage.recycle();
saveImage(resizedBitmap);
return resizedBitmap;
}
For Saving:
private void saveImage (Bitmap finalBitmap) {
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/NewFolder");
myDir.mkdirs();
String fname = "Image-.png";
File file = new File(myDir, fname);
try {
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Thanks for anyone's help.

save image file with bitmap factory

I'm encountering an issue with bitmap factory.
I've got a method to reduce and rotate an image to show a preview in an image view, but I would like to save this with the new size.
I'm just turning around with inputfilestream and outputfilestream but don't get to save it.
Is anybody know a clear method to put my bitmap in an outpufilestream?
Thanks a lot
here's my code
#Override
protected void onResume() {
super.onResume();
File[] fileArray;
final File root;
File chemin = Environment.getExternalStorageDirectory();
String filepath = chemin + "/SmartCollecte/PARC/OUT/" + fichano + "_" + conteneur_s+"_"+cpt+".jpg";
try {
decodeFile(filepath);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}}
public void decodeFile(String filePath) {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, 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 width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap b1 = BitmapFactory.decodeFile(filePath, o2);
Bitmap b = ExifUtils.rotateBitmap(filePath, b1);
FileOutputStream fos = new FileOutputStream(filePath);
b.compress(Bitmap.CompressFormat.PNG,100,fos);
fos.close();
showImg.setImageBitmap(b);
}
Have you tried doing it like this?
Assuming bitmap is bitmap you want to save.
Also, take a look at some existing system directories.
final FileOutputStream fos = new FileOutputStream(new File(filepath + "_scaled.jpg"));
try {
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
} catch (IOException e) {
// handle exception
} finally {
fos.close
}
Source
Where first parameter of Bitmap.compress() is your desired output format (see CompressFormat) and the second parameter is compression quality.
ok I found out what was missing.
had to create a new byte array to convert my bitmap to file :
String filepathcomp = Environment.getExternalStorageDirectory()+"/SmartCollecte/PARC/OUT/"+ fichano + "_" + conteneur_s+"_"+cpt+".jpg";
File f = new File(filepathcomp);
Bitmap newbitmap = b;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
newbitmap.compress(Bitmap.CompressFormat.JPEG,80,bos);
byte[] bitmapdata = bos.toByteArray();
FileOutputStream fos = new FileOutputStream(f);
fos.write(bitmapdata);
fos.flush();
fos.close();

Captured image returns small size

I am capturing the image from camera. The captured image's size shows too small when captured. But later if I check in gallery the captured image size shows in MB.
I tried debugging the code, so while debugging I checked length of the file after image is captured the length shows 26956 bytes, and when I checked same image in gallery the size of the image is 1.3 MB.
Why the image size shows reduced when captured?
private void cameraIntent() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, REQUEST_CAMERA);
}
private void onCaptureImageResult(Intent data) {
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
(thumbnail.getWidth()/2),(int)(thumbnail.getHeight()/2),true);
thumbnail.compress(Bitmap.CompressFormat.PNG, 100, bytes);
File destination = new File(Environment.getExternalStorageDirectory(),
System.currentTimeMillis() + ".png");
FileOutputStream fo;
try {
destination.createNewFile();
fo = new FileOutputStream(destination);
fo.write(bytes.toByteArray());
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
long size = destination.length();// here size of the image is too small
selectFile = false;
loadImageFromFile(destination.getAbsolutePath());
}
public void loadImageFromFile(String imageFile) {
try {
ExifInterface ei = new ExifInterface(imageFile);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
Bitmap bitmap = BitmapFactory.decodeFile(imageFile);
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:
rotatedBitmap = bitmap;
break;
default:
rotatedBitmap = bitmap;
break;
}
if (rotatedBitmap != null) {
if (selectFile && fileSizeInKB > 500) {
rotatedBitmap = Bitmap.createScaledBitmap(rotatedBitmap, (int) (rotatedBitmap.getWidth() * 0.3), (int) (rotatedBitmap.getHeight() * 0.3), true);
}
else if(selectFile && fileSizeInKB > 1024){
rotatedBitmap = Bitmap.createScaledBitmap(rotatedBitmap, (int) (rotatedBitmap.getWidth() * 0.2), (int) (rotatedBitmap.getHeight() * 0.2), true);
}
else if(selectFile && fileSizeInMB > 2){
rotatedBitmap = Bitmap.createScaledBitmap(rotatedBitmap, (int) (rotatedBitmap.getWidth() * 0.1), (int) (rotatedBitmap.getHeight() * 0.1), true);
}
profileImageView.setImageBitmap(rotatedBitmap);
selectedBitmap = rotatedBitmap;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
selectedBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); //replace 100 with desired quality percentage.
byte[] byteArray = stream.toByteArray();
File tempFile = File.createTempFile("temp", null, getCacheDir());
FileOutputStream fos = new FileOutputStream(tempFile);
fos.write(byteArray);
Long size = tempFile.length();
profileImage = tempFile;
}
} catch (IOException ex) {
}
}
I am scaling the images selected from gallery, I too want to scale the images captured from camera, but the size of the image I am not getting appropriate.
Can anyone help for this please? Thank you...
Edit :
private void cameraIntent() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
try {
photoFile = createImageFile();
} catch (IOException ex) {
}
// Continue only if the File was successfully created
if (photoFile != null) {
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
startActivityForResult(intent, REQUEST_CAMERA);
}
}
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "image";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
fileName = image.getAbsolutePath();
return image;
}
private void onCaptureImageResult(Uri data) {
try {
Bitmap thumbnail = MediaStore.Images.Media.getBitmap(this.getContentResolver(), data);
selectFile = false;
long fileSizeInBytes = photoFile.length();
// Convert the bytes to Kilobytes (1 KB = 1024 Bytes)
fileSizeInKB = fileSizeInBytes / 1024;
// Convert the KB to MegaBytes (1 MB = 1024 KBytes)
fileSizeInMB = fileSizeInKB / 1024;
loadImageFromFile(photoFile.getAbsolutePath());
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void loadImageFromFile(String imageFile) {
try {
ExifInterface ei = new ExifInterface(imageFile);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
Bitmap bitmap = BitmapFactory.decodeFile(imageFile);
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:
rotatedBitmap = bitmap;
break;
default:
rotatedBitmap = bitmap;
break;
}
if (rotatedBitmap != null) {
//
if (selectFile && fileSizeInMB < 1 && fileSizeInKB > 500) {
rotatedBitmap = Bitmap.createScaledBitmap(rotatedBitmap, (int) (rotatedBitmap.getWidth() * 0.9), (int) (rotatedBitmap.getHeight() * 0.9), true);
}
else if(selectFile && fileSizeInMB < 2){
rotatedBitmap = Bitmap.createScaledBitmap(rotatedBitmap, (int) (rotatedBitmap.getWidth() * 0.3), (int) (rotatedBitmap.getHeight() * 0.3), true);
}
else if(selectFile && fileSizeInMB > 2){
rotatedBitmap = Bitmap.createScaledBitmap(rotatedBitmap, (int) (rotatedBitmap.getWidth() * 0.2), (int) (rotatedBitmap.getHeight() * 0.2), true);
}
else if(selectFile && fileSizeInMB > 3){
rotatedBitmap = Bitmap.createScaledBitmap(rotatedBitmap, (int) (rotatedBitmap.getWidth() * 0.1), (int) (rotatedBitmap.getHeight() * 0.1), true);
}
// resize(rotatedBitmap,bitmap.getWidth()/2,bitmap.getHeight()/2);
profileImageView.setImageBitmap(rotatedBitmap);
selectedBitmap = rotatedBitmap;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
selectedBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); //replace 100 with desired quality percentage.
byte[] byteArray = stream.toByteArray();
File tempFile = File.createTempFile("temp", null, getCacheDir());
FileOutputStream fos = new FileOutputStream(tempFile);
fos.write(byteArray);
Long size = tempFile.length();
profileImage = tempFile;
}
} catch (IOException ex) {
// UiUtils.showAlert(getString(R.string.error),NewGroupAcvitity.this);
}
}
Now with this code, when I capture the image after capturing it takes time to load on image view and show blank screen till the image is set to the image view.
You are using the Thumbnail instead of the actual image.
To get the actual image you have to pass Image file uri to the Camera intent as MediaStore.EXTRA_OUTPUT
Sample :
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);//photoURI - file uri where you want the image to be saved
startActivityForResult(intent, REQUEST_CAMERA);
Refer https://developer.android.com/training/camera/photobasics.html#TaskPath for the required steps and complete code.
To get a scaled Bitmap from file path
int targetW = 800;
int targetH = 1000;
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
int scaleFactor = Math.min(photoW / targetW, photoH / targetH);
// Decode the image file into a Bitmap
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);

Why i cannot show my byte[] image after converting it from bitmap?

I'm trying to write a method that accepts an image(Bitmap) and returns a byte[] array. finally, I try to write this byte[] array to a folder so I can see the difference, but my byte[] arraycan not displayed, and in addition, it is not scaled down! This is my method:
private byte[] changeSize(Bitmap image) {
byte[] picture;
int width = image.getWidth();
int height = image.getHeight();
int newHeight = 0, newWidth = 0;
if (width > 250 || height > 250) {
if (width > height) { //landscape-mode
newHeight = 200;
newWidth = (newHeight * width) / height;
} else { //portrait-mode
newWidth = 200;
newHeight = (newWidth * height) / width;
}
} else {
Toast.makeText(this, "Something wrong!", Toast.LENGTH_LONG).show();
}
Bitmap sizeChanged = Bitmap.createScaledBitmap(image, newWidth, newHeight, true);
//Convert bitmap to a byte array
int bytes = sizeChanged.getByteCount();
ByteBuffer bb = ByteBuffer.allocate(bytes);
sizeChanged.copyPixelsFromBuffer(bb);
picture = bb.array();
//Write to a hd
picturePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
String fileName = edFile.getText().toString() + "_downscaled" + ".jpg";
File file = new File(picturePath, fileName);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write(picture);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
return image;
}
I tried several hours to get my byte[] array visible, but I could simply not do this. Any help or hints to show me where I derail is/are very appreciated.
This was working for me
public static Bitmap byteArraytoBitmap(byte[] bytes) {
return (BitmapFactory.decodeByteArray(bytes, 0, bytes.length));
}
public static byte[] bitmaptoByteArray(Bitmap bmp) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream); //PNG format is lossless and will ignore the quality setting!
byte[] byteArray = stream.toByteArray();
return byteArray;
}
public static Bitmap bitmapFromFile(File file) {
//returns null if could not decode
return BitmapFactory.decodeFile(file.getPath());
}
public static boolean saveImage(Bitmap image, String filePath) {
LogInfo(TAG, "Saving image to: " + filePath);
File file = new File(filePath);
File fileDirectory = new File(file.getParent());
LogInfo(TAG, fileDirectory.getPath());
if (!fileDirectory.exists()) {
if (!fileDirectory.mkdirs()) {
Log.e(TAG, "ERROR CREATING DIRECTORIES");
return false;
}
}
try {
file.createNewFile();
FileOutputStream fo = new FileOutputStream(file);
fo.write(bitmaptoByteArray(image));
fo.flush();
fo.close();
return true;
}
catch (Exception e) {
e.printStackTrace();
return false;
}
}

Camera to nfc - best photoquality

For my application, I need to save a photo, taken from camera of a device, on an 7.7k nfc chip.
In the onActivityResult, I resize the bitmap as here :
String fileName = "original";
String path = Environment.getExternalStorageDirectory() + "/" + fileName + ".jpg";
//Resizing
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap current = BitmapFactory.decodeFile(path);
Bitmap resized = resizeBitMapImage(path,largeur,(int)(largeur*1.8));
with
public static Bitmap resizeBitMapImage(String filePath, int targetWidth, int targetHeight) {
Bitmap bitMapImage = null;
try {
Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
double sampleSize = 0;
Boolean scaleByHeight = Math.abs(options.outHeight - targetHeight) >= Math.abs(options.outWidth
- targetWidth);
if (options.outHeight * options.outWidth * 2 >= 1638) {
sampleSize = scaleByHeight ? options.outHeight / targetHeight : options.outWidth / targetWidth;
sampleSize = (int) Math.pow(2d, Math.floor(Math.log(sampleSize) / Math.log(2d)));
}
options.inJustDecodeBounds = false;
options.inTempStorage = new byte[128];
while (true) {
try {
options.inSampleSize = (int) sampleSize;
Log.v(LOG_TAG,"inSampleSize" + options.inSampleSize);
bitMapImage = BitmapFactory.decodeFile(filePath, options);
break;
} catch (Exception ex) {
try {
sampleSize = sampleSize + 1 ;
} catch (Exception ex1) {
}
}
}
} catch (Exception ex) {
}
return bitMapImage;
}
(Found on SO)
And then, I save it on the chip with :
NdefRecord picRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, "image/jpeg".getBytes(), null, byteArray);
When I choose a width of 200, and a compression of 50, the picture takes about 7k, but the quality is quite low. The bitmap is a contact photo.
So my questions :
What should I use as width, height, compression, in order to get the best photo quality (less than 7k?
Should the camera be set on high or low resolution ?
PNG or JPEG compression ?

Categories