How reduce size of image raw? - java

I'm creating an app on android that uses a fingerprint reader, the problem is that the images are in real time, with dimensions of 800x750 and with a byte array size of 600000, when converting it to bitmap and assigning it At the imageview, the app is too encouraging and crashing.
how can I reduce the size of that array of bytes that is a raw image so that my application can draw fingerprints without problems
imagePreview.setImageBitmap(imageData.toBitmap());
I tried this but it's still slow
Bitmap bmp = imageData.toBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 30, stream);
byte[] byteArray = stream.toByteArray();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray,0,byteArray.length,options);

You can't. If you're using ARGB_8888, the image will take 4*width*height bytes in memory. There is no way to reduce that. If you're having problems, look for memory leaks, and consider caching.

This Answer will help
if you want bitmap ratio same and reduce bitmap size. then pass your maximum
size bitmap.
public Bitmap getResizedBitmap(Bitmap image, int maxSize) {
int width = image.getWidth();
int height = image.getHeight();
float bitmapRatio = (float)width / (float) height;
if (bitmapRatio > 1) {
width = maxSize;
height = (int) (width / bitmapRatio);
} else {
height = maxSize;
width = (int) (height * bitmapRatio);
}
return Bitmap.createScaledBitmap(image, width, height, true);
}

Related

Bitmap resizing causes out of memory

I have a simple class for resizing bitmap images according to my requirement. There is a simple method responsible for it as follows:
public static Bitmap ResizeRichImages(Bitmap bitmap, Context mContext){
try {
float originalBitmapWidth = bitmap.getWidth();
float originalBitmapHeight = bitmap.getHeight();
float originalAspectRatio = originalBitmapWidth/originalBitmapHeight;
double width_percentage = (0.05*screenWidthPixels(mContext));
float newWidth = (float)((int)screenWidthPixels(mContext)-width_percentage);
float newBitmapWidth = newWidth;
float newBitmapHeight = newBitmapWidth/originalAspectRatio;
bitmap = Bitmap.createScaledBitmap(bitmap, (int) newWidth, (int)newBitmapHeight, false);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
And this is how I call this method:
String URL = "https://maps.googleapis.com/maps/api/staticmap?center=-33.86527274921529,151.2050531328867&zoom=15&size=640x360&sensor=false&markers=color:blue%7Clabel:!%7C-33.86527274921529,151.2050531328867";
try {
bmp = Picasso.with(ViewStory.this).load(URL)
.get();
bmp = ImageController.ResizeRichImages(bmp, ViewStory.this);
} catch (Exception e) {
e.printStackTrace();
}
But, almost every time I am getting the out of memory exception while calling the ResizeRichImages method. Where am I going wrong?
Instead using largeHeap option in manifest which should be always last option, you can try compressing like below code snippet.
*
byteArrImage = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if(data != null) thumbnail = (Bitmap) data.getExtras().get("data");
if(thumbnail != null) {
//thumbnail.compress(Bitmap.CompressFormat.PNG, 85, baos);
thumbnail.compress(Bitmap.CompressFormat.JPEG, 85, baos);
byteArrImage = baos.toByteArray();
uploadImageToServer();
}
I got same error before, but After some searching i found another way to resize large Bitmap image. When you use Bitmap with large image you have to scale image with BitmapFactory.Options.inSampleSize . The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. When you use inSampleSize = 4 it returns an image that is 1/4 the width/height of the original.You can also see the more detail in android developer site.
Use this Method for resizing
private Bitmap decodeFileWithSmallSize(String sdcard_path) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap myBitmap = BitmapFactory.decodeFile(sdcard_path, options);
return myBitmap;
}
Use in Activity
try {
Bitmap bitmap = null;
if (bitmap != null) {
bitmap.recycle();
bitmap = null;
}
bitmap = decodeFileWithSmallSize("path");
}
catch (OutOfMemoryError e)
{
Log.e("TAG",
"OutOfMemoryError Exception" + e.getMessage());
}
Generally while deal with bitmap we need to reduce the memory size by reducing the samplesize of bitmap based on our required width and height.
This functions takes bitmap file path if you want to pass bitmap change it with your requirement.But this the proper way to load images efficently.
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
This function calculates the sample size of required image in order to reduct he memory..
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;
}
For more info refer this link:http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
In your case if you are targeting min level as 19 then go with reconfigure function which is available on api level 19
visit developers site
You haven't told us how big your bitmap is. Perhaps it's simply using up all of your free memory, especially if you have other large bitmaps (or something else) taking up much of it.
I would try running the procedure on a small bitmap, and with newBitmapWidth and newBitmapHeight reduced to a tenth of what they are now. If this eliminates the exception, it's pretty sure you need to optimize your memory use before you can handle the full size.

Bitmap: Decoded image width and height returns -1

I have written this code to assist me on working on a bitmap, to improve the quality of the bitmap after resizing the image.
My problem is that the decoded bitmap returns -1 for both width and height and as a result the image never gets decoded to the output stream. This is the code:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(new File (this.imageFileUri.getPath()).getAbsolutePath(), options);
int srcWidth = options.outWidth;
int srcHeight = options.outHeight;
System.out.println("The image width is>>>>>> " + srcWidth + "The image height is >>>>>>" + srcHeight);
int scale = 1;
int desiredWidth = 10;
while(srcWidth / 2 < desiredWidth){
srcWidth /= 2;
srcHeight /= 2;
scale *= 2;
}
options.inJustDecodeBounds = false;
options.inDither = false;
options.inSampleSize = scale;
this.bmp = BitmapFactory.decodeFile(file1.getAbsolutePath(), options);
Please where is my mistake and how can I avoid this.
Kindly assist!
BitmapFactory.decodeFile();
This method returns a decoded Bitmap image (you can check the Bitmap documentation here: http://developer.android.com/reference/android/graphics/Bitmap.html )
Try saving it like this:
Bitmap yourBitmap = BitmapFactory.decodeFile(..,..);
Then to acces the width and height:
yourBitmap.getWidth(); // returns int
yourBitmap.getheight(); //returns int

How to reduce image without losing quality and preserving the aspect ratio? [duplicate]

This question already has answers here:
Strange OutOfMemory issue while loading an image to a Bitmap object
(44 answers)
Closed 7 years ago.
I have image 3264х2448.
I load it in bitmap crudeImage = BitmapFactory.decodeFile(picturePath); then set to the ImageView imageCrop.setImageBitmap(crudeImage);
the problem is that it very big(3264х2448) and my library cropper
work very slowly with this image.
I want reduce the image to a smaller size. but to preserve the quality and proportion. how can this be done?
You should read Loading Large Bitmaps Efficiently.
Essentially, calculate the sample size first by
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;
}
then load the image using the sample size:
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
I use this to resize my bitmap's. Maybe can be useful for you.
public Bitmap resizeBitmap(Bitmap bitmap, int newWidth, int newHeight)
{
//bitmap it's the bitmap you want to resize
//newWidth and newHeight are the with and height that you want to the new bitmap
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) /height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
I hope this help you.
If you read the tutorial here you'll see google gives you a very comprehensive guide on how to scale bitmaps without excessive memory usage.
In particular, these two methods (from the tutorial):
public static Bitmap decodeSampledBitmapFromResource(File file, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(file, options);
}
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;
}
Will accomplish your scaling whilst preserving aspect ratio.
The trick with these two methods is that the first decode operation is set to only decode the image's properties (dimensions and other information) as set by:
options.inJustDecodeBounds = true;
in which the new scale factor is calculated proportionally by the method calculateInSampleSize().
Then the image is decoded again, this time with
options.inJustDecodeBounds = false;
as well as the scale factor set, so the bitmap factory automatically scales whilst decoding, reducing the memory footprint.
Regarding what resolution the image needs to be decoded to, that really depends on your use-case. But, if the particular image does not need to be zoomed in later, you need no more than the device's physical screen size, which can be obtained via:
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getRealSize(size);
in which object size will hold the device's screen size.

Android OutOfMemoryError for large images

The method throws OutOfMemoryError for large images in size( not by resolution)
i have 12 MP photos, all of them are different in size(1.5MB, 2.5MB, 3.2MB, 4.1MB) etc and the resolution for all of them are same 4000 x 3000 (pixels).
The resizer method works fine for images less than 3MB in size, but for those images that are >3MB it throws OutOfMemoryError i dont know what could fix it, my app is mainly for resizing large images, and this is really getting me nowhere.
The resizer method is:
public File resizeBitmap(String imPath, int reqSize) {
File fl = null;
try{
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imPath, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqSize);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap saveImg = BitmapFactory.decodeFile(imPath, options);
//save resized image
String tmpName = "IMG_"+String.valueOf(System.currentTimeMillis()) + ".jpg";
fl = fileCache.getRawFile(tmpName);
FileOutputStream fos = new FileOutputStream(fl);
saveImg.compress(Bitmap.CompressFormat.JPEG, 95, fos);
saveImg.recycle();
return fl;
}
catch (Throwable eex){
eex.printStackTrace();
if(eex instanceof OutOfMemoryError) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(Resizer.this, "Memory ran out", Toast.LENGTH_SHORT).show();
}
});
}
return null;
}
}
//Method for calculating insamplesize
public int calculateInSampleSize(BitmapFactory.Options options, int reqSize) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
Log.i("width",""+width);
Log.i("height",""+height);
int inSampleSize = 1;
if (height > reqSize || width > reqSize) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqSize);
} else {
inSampleSize = Math.round((float) width / (float) reqSize);
}
}
return inSampleSize;
}
//Stacktrace
04-11 09:01:19.832: W/System.err(8832): java.lang.OutOfMemoryError
04-11 09:01:19.953: W/System.err(8832): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
04-11 09:01:19.972: W/System.err(8832): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:529)
04-11 09:01:19.993: W/System.err(8832): at com.scale.app.Resizer.resizeBitmap(Resizer.java:1290)
Read Article
Image Size : 4000*3000 in px
When the image load : 4000*3000*4 = ? KB
So,Vitrual Heap Memory of the Android device are : 32 MB, 64 MB , 128 MB ... so on
if you using:
<application
android:largeHeap="true">
</application>
This will increase the VHM double (if 32 MB = 2* 32 MB). BUt this will not an good way to do this, effect on OS
You need to decrease the size of the image.
Use the below class and pass the path of the image and width , height what you want
Bitmap bitmap = BitmapSize.getDecodedBitmap(path, 400, 400);
Class::::
public class BitmapSize{
public static Bitmap getDecodedBitmap(String path, float target_width, float target_height) {
Bitmap outBitmap = null;
try {
Options decode_options = new Options();
decode_options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path,decode_options); //This will just fill the output parameters
int inSampleSize = calculateInSampleSize(decode_options, target_width, target_height);
Options outOptions = new Options();
outOptions.inJustDecodeBounds = false;
outOptions.inSampleSize = inSampleSize;
outOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
outOptions.inScaled = false;
Bitmap decodedBitmap = BitmapFactory.decodeFile(path,outOptions);
outBitmap = Bitmap.createScaledBitmap(decodedBitmap,// (int)target_width, (int)target_height, true);
(int)((float)decodedBitmap.getWidth() / inSampleSize),
(int)((float)decodedBitmap.getHeight() / inSampleSize), true);
System.out.println("Decoded Bitmap: Width " + outBitmap.getWidth() + " Height = " + outBitmap.getHeight() + " inSampleSize = " + inSampleSize);
} catch (Exception e) {
// TODO: handle exception
}
return outBitmap;
}
public static int calculateInSampleSize(Options options, float reqWidth, float 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;
}
return inSampleSize;
}
}
Please read http://developer.android.com/training/displaying-bitmaps/load-bitmap.html how to deal with large Bitmaps.
The BitmapFactory class provides several decoding methods
(decodeByteArray(), decodeFile(), decodeResource(), etc.) for creating
a Bitmap from various sources. Choose the most appropriate decode
method based on your image data source. These methods attempt to
allocate memory for the constructed bitmap and therefore can easily
result in an OutOfMemory exception
Please try with these Option properties..
BitmapFactory.Options opts=new BitmapFactory.Options();
opts.inDither=false; //Disable Dithering mode
opts.inPurgeable=true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared
opts.inInputShareable=true; //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
opts.inTempStorage=new byte[32 * 1024];
opts.inSampleSize = 1;
To reduce the quality of image file increase the number of opts.inSampleSize. Click here for more details
And add one more attribute in Manifest.xml in application tag
android:largeHeap="true"

Resizing an image in java

I have an java application allows user to take a photo from his camera and send it to me using a web service, But my problem is while sending the image. The send progress takes long time because image is big so i want to compress image. I have tried to:
1- Use this code:
Bitmap img = BitmapFactory.decodeFile("C:\\test.jpg");
ByteArrayOutputStream streem = new ByteArrayOutputStream();
img.compress(Bitmap.CompressFormat.JPEG, 75, streem);
byte[] b = streem.toByteArray();
But this code is useless in my case because it make image very bad and dosent affect on image size a lot.
2- Search a lot about ways to resize but all results is using BufferedImage. I cant use this type(Class) because it takes a lot of memory size:
private static BufferedImage resizeImage(BufferedImage originalImage, int type)
{
BufferedImage resizedImage = new BufferedImage(new_w, new_h, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, new_w, new_h, null);
g.dispose();
return resizedImage;
}
I want to use Bitmap instead, Any body can help me in my application???
Use ImageIO to write the BufferedImage to the format you need
You can supply a output stream to ImageIOso you should be able to write to just about anywhere.
Check out Writing/Saving an Image for more details
I have found these tow method:
private static int CalculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
float height = (float) options.outHeight;
float width = (float) options.outWidth;
float inSampleSize = 0;
if (height > reqHeight || width > reqWidth) {
inSampleSize = width > height ? height / reqHeight : width
/ reqWidth;
}
return (int) Math.round(inSampleSize);
}
public static byte[] ResizeImage(int reqWidth, int reqHeight, byte[] buffer) {
BitmapFactory.Options op = new Options();
op.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(buffer, 0, buffer.length, op);
op.inSampleSize = CalculateInSampleSize(op, reqWidth, reqHeight);
op.inJustDecodeBounds = false;
try {
return ToByte(BitmapFactory.decodeByteArray(buffer, 0,
buffer.length, op));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

Categories