load bitmap from url the right way - java

ok guys need a little help, so I’ve got an app that creates a bitmap images from memory and displays it as an image view, i got to this stage by following the android developer guidelines so it has image scaling, cashing and so on, but now i want to replace the image in memory with one from a website, here is my current code
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight){
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;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight){
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);
}
and this is some code i found to make an image from url
public static Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
}catch(IOException e){
e.printStackTrace();
return null;
}
}
i want to know how to implement this to my existing code to incorporate scaling the image to the right resolution to fit my imageView before loading it into memory with the inJustDecodeBounds set to true inorder to avoid outOfMemory exception or is there no longer any need to do this

If you want to do it online i would recommend you using volley imageLoader, the code you are using is downloading. I would recommend you do some research before going into this though, it is a tad bit different that what you would usually do, but once you get it image loading only requires a few lines.On another note if you still wish to download it, change it into bitmap and read it straight from the file.Furthermore to display image from storage doesn't require that much work, an example is at the bottom.
http://blog.lemberg.co.uk/volley-part-3-image-loader
private void loadImageFromStorage(String path, String Name) {
try {
File f = new File(path, Name+".jpg");
double bytes = f.length();
Bitmap b;
if(bytes < 1){
b = BitmapFactory.decodeResource(getResources(), R.drawable.placeholder);
}
else{
b = BitmapFactory.decodeStream(new FileInputStream(f));
}
imageView = (ImageView).findViewById(R.id.grid_image);
imageView.setImageBitmap(b);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}

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.

How to set image as wallpaper without causing OutOfMemory error

I have a straight-forward wallpaper app which I've just finished coding. I've used the tutorial here ( http://developer.android.com/training/displaying-bitmaps/load-bitmap.html ) to load the image on the screen at a lower resolution, while I use the code below to set the wallpaper. imageId represents the currently selected drawable.
InputStream is = getResources().openRawResource(imageId);
Bitmap bitmap = BitmapFactory.decodeStream(is);
WallpaperManager myWallpaperManager = WallpaperManager
.getInstance(getApplicationContext());
try {
myWallpaperManager.setBitmap(bitmap);
Toast.makeText(MainActivity.this, "Teamwork! Wallpaper set.",
Toast.LENGTH_LONG).show();
} catch (IOException e) {
Toast.makeText(
MainActivity.this,
"Damnit, clickers! Wallpaper wasn't set. Try killing and restarting the app?",
Toast.LENGTH_LONG).show();
}
However, I fear that the above code may cause phones of less memory to crash when it is called. Is there anything I can do to prevent this from happening, or is there nothing to fear?
EDIT:
I used this code to display the images in the app:
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;
}
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);
}
public void setImage() {
switch (imageNum) {
case 1:
options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.aaaae,
options);
display.setImageBitmap(decodeSampledBitmapFromResource(
getResources(), R.drawable.aaaae, 300, 300));
imageId = R.drawable.aaaae;
break;
// Etc, etc.
}
}
The method setImage is called every time the "Next" button is pressed.
I guess you are not handling images properly
Here is the solution to handle bitmaps in android
(This approach can handle 25000px by 25000px images in a non-ui thread.)
First, you should calculate the sampleBitmapSize of the bitmap ( to load the lower version of the same bitmap )
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);
}
Below is the util function to calculate InSampleSize ( an integer that defines the value (rating) of quality of a bitmap).
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;
}
}
Log.i("ImageUtil", "InSampleSize: "+inSampleSize);
return inSampleSize;
}

Decrease the quality of image . OutOfMemory Exception - Android

I am trying to implement the application which is doing lots of operations on an image. I have the problem with optimalization. The time of running my application is too long. I need to compress the images that I'm processing. I was trying with this tutorial:
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
It works well when I want to take the image from drawable folder. The problem is when I want to take the picture from camera or gallery. I have no idea what should I put in " R.id.myimage"
So the question is, how to use this line of code:
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
when I want to use the camera or gallery instead of drawable folder ?
To avoid OOM error, scale image using:
//For resource
image.setImageBitmap(decodeSampledBitmapFromResource("android.resource://com.my.package/drawable/image_name"));
//For file
image.setImageBitmap(decodeSampledBitmapFromResource(filepath));
Sampling function:
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 2;
if (height >= reqHeight || width >= reqWidth) {
inSampleSize *= 2;
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(String file,
int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(file, options);
}

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"

How to know the type of a image file

Given a file path (without extension) I'd like to know if the image inside the file is a JPEG or a PNG.
How can I do it?
Try looking for the image headers, somewhat like this:
File file = /* (get your file) */;
byte[] data = new byte[2];
try {
new FileInputStream(file).read(data);
} catch (Exception e) {
// handle the error somehow!
}
if (data[0] == 0xFF && data[1] == 0xD8) {
// jpeg
} else if (data[0] == 0x89 && data[1] == 0x50) {
// png
} else {
// error?
}
JPEG headers will always be FFD8, and PNG headers are 89504E470D0A1E0A (for which we only need to look at the first two bytes to distinguish from JPEG).
You can find it like this:
step 1: You just get the image bounds only....
step 2: You can change your image with your corresponding size using the below method
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
in.mark(in.available());
BitmapFactory.decodeStream(in, null, options);
(or)
BitmapFactory.decodeFile(pathName);
(or)
BitmapFactory.decodeResource(MainActivity.this.getResources(), R.drawable.ic_launcher);
String name = options.outMimeType;
this below method is used to get the large bitmaps loading with efficiently
re-sizing the image with your required height and width
public static Bitmap decodeSampledBitmapFromResource(InputStream in,
int reqWidth, int reqHeight) throws IOException {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
in.mark(in.available());
BitmapFactory.decodeStream(in, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
in.reset();
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(in, null, 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;
}
Do you search for this? Why don't you have the extension?
"In Java 7 you can now just use
Files.probeContentType(path)"
-> source
but we are not sure if it's supported in android.
So why don't you just get the full path and extract the file extension with substring?

Categories