I have converted an image(String url) using a bitmap but sometimes it produces an out of memory error. Here is my code:
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=150;
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++;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
First of all, reduce the size of an image. You can do it without drastically change the quality. And for an experiment just try to save your image as a bitmap. You will be shocked. If, for instance, your jpg is 3MB in size, it will be about 21MB after converting to bmp - huge number!
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
bmpFactoryOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
try {
bmp = BitmapFactory
.decodeStream(
getContentResolver().openInputStream(
imageFileUri), null, bmpFactoryOptions);
bmpFactoryOptions.inSampleSize = quality;
System.out.println("The Quality is" + quality);
bmpFactoryOptions.inJustDecodeBounds = false;
bmp = BitmapFactory
.decodeStream(
getContentResolver().openInputStream(
imageFileUri), null, bmpFactoryOptions);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
String[] orientationColumn = { ImageColumns.ORIENTATION };
#SuppressWarnings("deprecation")
Cursor cur = managedQuery(imageFileUri, orientationColumn, null,
null, null);
int orientation = -1;
if (cur != null && cur.moveToFirst()) {
orientation = cur.getInt(cur
.getColumnIndex(orientationColumn[0]));
}
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(),
bmp.getHeight(), matrix, true);
view.setImageBitmap(bmp);
int quality = 4;
find it more effective with big bitmaps.
Related
I want to compress images that i choose from gallery in android according to there sizes and upload them on to cloud storage. For example if size of an image which i choose is 300kb i don't to reduce it and keep quality 100 but if same is 7Mb i want to reduce it to 10 quality and i want to set max size to 7Mb of the chosen image(original without compression) and similarly puting different conditions on sizes in between.
My code
if (resultCode == RESULT_OK) {
resultUri = result.getUri();
File f = new File(resultUri.getPath());
long sizeUri = f.length()/1024;
try {
bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(getContentResolver(),resultUri));
} catch (IOException e) {
e.printStackTrace();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int baossize= baos.size()/1024;
byte[] uploadbaos = baos.toByteArray();
int lengthbmp = (uploadbaos.length);
int size= lengthbmp/1024;
Log.d(TAG,"baossize: "+baossize+" ByteArray: "+size+" UriSize: "+sizeUri);
// UploadingImage();
}
Just do it:
int quality;
if (sizeUri <= 300)
quality = 90;
else if (sizeUri <= 1000)
quality = 80;
else if (sizeUri <= 2000)
quality = 70;
else if (sizeUri <= 3000)
quality = 50;
else
quality = 30;
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
Note that JPEG quality 100 is probably too high and below 30 can be very blurry.
Here in the given example you can set the max size , like in your case it could be 7MB.
public static boolean reduceImage(String path, long maxSize) {
File img = new File(path);
boolean result = false;
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap bitmap = null;
options.inSampleSize=1;
while (img.length()>maxSize) {
options.inSampleSize = options.inSampleSize+1;
bitmap = BitmapFactory.decodeFile(path, options);
img.delete();
try
{
FileOutputStream fos = new FileOutputStream(path);
img.compress(path.toLowerCase().endsWith("png")?
Bitmap.CompressFormat.PNG:
Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
result = true;
}catch (Exception errVar) {
errVar.printStackTrace();
}
};
return result;
}
I'm try to get a byte array from a picture stored on an android device, but the byte array size is width * heigth * 2, and I need a byte array of the size width * heigth * 3.
My problem is that I need to send a picture byte array to a matlab server that need the array in this RGB format.
Here is the code that creates a byte array of "width * height" size:
Bitmap photo = BitmapHelper.readBitmap(CameraIntentActivity.this, photoUri);
if (photo != null) {
photo = BitmapHelper.shrinkBitmap(photo, 300, rotateXDegrees);
Bitmap bm = Bitmap.createScaledBitmap(photo, 640, 480, true);
final int lnth= bm.getByteCount();
ByteBuffer dst= ByteBuffer.allocate(lnth);
bm.copyPixelsToBuffer( dst);
byte[] byteArray = dst.array();
The readBitmap method:
public static Bitmap readBitmap(Context context, Uri selectedImage) {
Bitmap bm = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inScaled = false;
AssetFileDescriptor fileDescriptor = null;
try {
fileDescriptor = context.getContentResolver().openAssetFileDescriptor(selectedImage, "r");
} catch (FileNotFoundException e) {
return null;
} finally {
try {
bm = BitmapFactory.decodeFileDescriptor(
fileDescriptor.getFileDescriptor(), null, options);
fileDescriptor.close();
} catch (IOException e) {
return null;
}
}
return bm;
}
I am uploading an image to the amazon server. Everything works well but only on few devices the orientation changes to landscape. At the time of uploading the orientation changes on a few Samsung devices and tablets. I have tried to fix it but nothing seems to be working. Below mentioned is my code.
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
value = true;
viewPager.setVisibility(View.VISIBLE);
Uri takenPhotoUri = getPhotoFileUri(photoFileName); //get the uri of the photo in order to get the path.
System.out.println("URI==" + takenPhotoUri);
al.add(takenPhotoUri);
Bitmap takenImage = BitmapFactory.decodeFile(takenPhotoUri.getPath());
final int maxSize = 1560;
int outWidth, outHeight;
int inWidth = takenImage.getWidth();
int inHeight = takenImage.getHeight();
if (inWidth > inHeight) {
outHeight = maxSize;
outWidth = (inHeight * maxSize) / inWidth;
} else {
outHeight = maxSize;
outWidth = (inWidth * maxSize) / inHeight;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
takenImage = Bitmap.createScaledBitmap(takenImage, outWidth, outHeight, false);
String newDate = sdf.format(new Date());
Canvas canvas = new Canvas(takenImage); //bmp is the bitmap to dwaw into
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setTextSize(30);
paint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText(newDate, 200, 100, paint);
//Creating a byte array output stream which is used to store the image once it has been compressed.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//Compress the image and store it in our ByteArrayOutPutStream
takenImage.compress(Bitmap.CompressFormat.JPEG, 90, bos);
int rotate = 0;
try {
getContentResolver().notifyChange(takenPhotoUri, null);
File imageFile = new File(String.valueOf(al.get(0)));
ExifInterface exif = new ExifInterface(
imageFile.getAbsolutePath());
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
}
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
} catch (Exception e) {
e.printStackTrace();
}
try {
s3Client = new AmazonS3Client(
new BasicAWSCredentials(MY_ACCESS_KEY_ID, MY_SECRET_KEY));
byte[] contentBytes = bos.toByteArray(); //Create a byte array to store the size of the stream.
is = new ByteArrayInputStream(contentBytes);
Long contentLength = Long.valueOf(contentBytes.length);
objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(contentLength);
myAsyncTask = new MyAsyncTask();
myAsyncTask.execute();
responseUrl += s3Client.getResourceUrl(BUCKET_NAME, photoFileName) + " ";
System.out.println("URL IS +==========" + responseUrl);
} catch (Exception e) {
e.printStackTrace();
}
//Add the path of the image to the array list and pass it to our custom adapter.
bitmapArrayList.add(takenImage);
imageSwipeAdapter = new ImageSwipeAdapter(this, iv, bitmapArrayList, viewPager, this, al,
viewPagerLayout, cameraBtn);
viewPager.setAdapter(imageSwipeAdapter);
} else {
Toast.makeText(this, "Picture Wasn't taken!", Toast.LENGTH_SHORT).show();
}
My AsyncTask is uploading the image in the background.
In my app when i upload an image i want to reduce the data so i call this function. But this piece of code is giving me an outOfMemoryError.
LOGCAT: 09-17 15:32:01.712: E/AndroidRuntime(7771): at com.technow.pereo.FileHelper.reduceImageForUpload(FileHelper.java:64)
public static byte[] reduceImageForUpload(byte[] imageData) {
Bitmap bitmap = ImageResizer.resizeImageMaintainAspectRatio(imageData,
SHORT_SIDE_TARGET);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, outputStream);
bitmap.recycle();
byte[] reducedData = outputStream.toByteArray();
try {
outputStream.close();
} catch (IOException e) {
// Intentionally blank
}
return reducedData;
}
What is causing this error and how do I resolve it?!
Seems ImageResizer is a custom class. Use the snippet below to re-size the image before you brought the image for further processing.
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//Find the correct scale value. It should be the power of 2.
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;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
Hey I am not sure why this keeps coming up every time I select an image in my gallery?
Here is the code:
if (v == uploadImageButton) {
// below allows you to open the phones gallery
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(
Intent.createChooser(intent, "Complete action using"), 1);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && requestCode == 1 && null != data) {
// Bitmap photo = (Bitmap) data.getData().getPath();
Uri selectedImageUri = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(selectedImageUri,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
Log.e("Picture", picturePath);
decodeFile(picturePath);
}
}
public void decodeFile(String filePath) {
// TODO Auto-generated method stub
// 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 bitmap = BitmapFactory.decodeFile(filePath, o2);
imageview.setImageBitmap(bitmap);
}
Error:
01-17 23:18:04.642: D/Documents(25157): onFinished() [content://com.android.providers.media.documents/document/image%3A901]
01-17 23:18:04.682: E/BitmapFactory(24993): Unable to decode stream: java.lang.NullPointerException
01-17 23:18:04.682: E/BitmapFactory(24993): Unable to decode stream: java.lang.NullPointerException
01-17 23:18:09.732: I/InputReader(766): Reconfiguring input devices. changes=0x00000004
01-17 23:18:09.732: I/InputReader(766): Device reconfigured: id=4, name='touch_dev', size 1080x1920, orientation 3, mode 1, display id 0
Don't assume that there is a file path. Android 4.4 and up are about to remove them. And the uri you got has already no path.
You can still access the file content either through an InputStream (ContentResolver#openInputStream(Uri uri)) or through a file descriptor.
It's explained here: ContentProviders: Open a document (scroll down, link to section seems to be broken)
And that does work on older android versions too.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && requestCode == 1 && null != data) {
decodeUri(data.getData());
}
}
public void decodeUri(Uri uri) {
ParcelFileDescriptor parcelFD = null;
try {
parcelFD = getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor imageSource = parcelFD.getFileDescriptor();
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(imageSource, null, 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 bitmap = BitmapFactory.decodeFileDescriptor(imageSource, null, o2);
imageview.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
// handle errors
} catch (IOException e) {
// handle errors
} finally {
if (parcelFD != null)
try {
parcelFD.close();
} catch (IOException e) {
// ignored
}
}
}