Sampling a bitmap from url - android

I am trying to reduce the size of bitmap from a url. I saw many posts, but all were about sampling a local file. I want to sample the image at url. Here is my code:
public Bitmap getScaledFromUrl(String url) {
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1 / 10;
try {
return BitmapFactory.decodeStream((InputStream) new URL(url)
.getContent());
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
Is this approach correct? I am getting out of memory crashes in my app at this function. Any ideas?

This works. I found it at http://blog.vandzi.com/2013/01/get-scaled-image-from-url-in-android.html . Use the following snippet of code, pass params as you like.
private static Bitmap getScaledBitmapFromUrl(String imageUrl, int requiredWidth, int requiredHeight) throws IOException {
URL url = new URL(imageUrl);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(url.openConnection().getInputStream(), null, options);
options.inSampleSize = calculateInSampleSize(options, requiredWidth, requiredHeight);
options.inJustDecodeBounds = false;
//don't use same inputstream object as in decodestream above. It will not work because
//decode stream edit input stream. So if you create
//InputStream is =url.openConnection().getInputStream(); and you use this in decodeStream
//above and bellow it will not work!
Bitmap bm = BitmapFactory.decodeStream(url.openConnection().getInputStream(), null, options);
return bm;
}
private 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) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
It's really flexible.. I think you should try it out.

You are using it wrong. You are asking to make the picture 10 times bigger :) You should give the command in normal numbers, not fraction. For example:
final BitmapFactory.Options options2 = new BitmapFactory.Options();
options2.inSampleSize = 8;
b = BitmapFactory.decodeFile(image, options2);
with this configuration you obtain 8 times smaller picture than the original.
UPDATE: To load image from internet add this class to the project and do the following:
ImageLoader loader = new ImageLoader(context);
Bitmap image = loader.getBitmap(URL);

Related

outofmemory exception for Large Bitmap

I found a lot of documentation on how to load large Bitmaps and avoid outofmemory exception. but the problem is that I have to take the image from my MediaStore.Images.media so the classical
decodeFile(path,options) indicated in the google documentation does not work to me
As you can see below I decommented the line // Bitmap photo= Mediastore.Images, that is the one that triggers the out of memory. on the other side adding
the line Bitmap bm=BitmapFactory.decodeFile(selectedImageToUri,options) returns null, although the compiler can see both the path in selectedImageToUri (that indicates the content provider where the pics are) than the options value, that I set to 8, because I want to subscale all the images
My question is how can I insert in bm the bitmap that is referring to the image selected by the user in the gallery. in the line BitMap photo does not return null and work really well, but I decommented because after I change a couple of images gives me outofmemory exception.
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable final Bundle savedInstanceState) {
if (flagVariable) {
if (selectedImageToUri != null) {
// BitMap photo = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), Uri.parse(selectedImageToUri));
final BitmapFactory.Options options= new BitmapFactory.Options();
options.inSampleSize=8;
Bitmap bm = BitmapFactory.decodeFile(selectedImageToUri, options);
pic = new BitmapDrawable(bm);
getActivity().getWindow().setBackgroundDrawable(pic);
} else {
getDefaultImageBackground(inflater, container);
}
hiddenList = inflater.inflate(R.layout.fragment_as_list_layout_temp, container, false);
} else {
getDefaultImageBackground(inflater, container);
}
listView = (ListView) hiddenList.findViewById(R.id.list_hidden);
MediaStore.getBitmap is just a simple convienence method, it looks like this:
public static final Bitmap getBitmap(ContentResolver cr, Uri url)
throws FileNotFoundException, IOException {
InputStream input = cr.openInputStream(url);
Bitmap bitmap = BitmapFactory.decodeStream(input);
input.close();
return bitmap;
}
You can create your own method based on this that takes the options and calls a different overload on BitmapFactory:
public static final Bitmap getBitmap(ContentResolver cr,
Uri url,
BitmapFactory.Options options)
throws FileNotFoundException, IOException {
InputStream input = cr.openInputStream(url);
Bitmap bitmap = BitmapFactory.decodeStream(input, null, options);
input.close();
return bitmap;
}
Usage:
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap bm = getBitmap(getActivity().getContentResolver(),
Uri.parse(selectedImageToUri),
options);
I spent a lot of time on this problem, but no one will give me exact answer and finally i solved it. First create method and provide Image URI as argument, and this will return bitmap basically here i calculated image size on bases of, we can manage memory as well as image and get exact image in bitmap form.
you can even display 5000×8000 and 12MiB picture without any error code is tested just copy paste in your class and enjoy.
Use
Bitmap mBitmap = getPhoto(MYIMAGEURI);
Provide URI to method and get Bitmap
Bitmap getPhoto(Uri selectedImage) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
int width = metrics.widthPixels;
Bitmap photoBitmap = null;
InputStream inputStream = null;
try {
inputStream = getContentResolver().openInputStream(selectedImage);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeStream(inputStream, null, bitmapOptions);
int imageWidth = bitmapOptions.outWidth;
int imageHeight = bitmapOptions.outHeight;
#SuppressWarnings("unused")
InputStream is = null;
try {
is = getContentResolver().openInputStream(selectedImage);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
float scale = 1.0f;
if (imageWidth < imageHeight) {
if (imageHeight > width * 1.0f) {
scale = width * 1.0f / (imageHeight * 1.0f);
}
} else {
if (imageWidth > width * 1.0f) {
scale = width * 1.0f / (imageWidth * 1.0f);
}
}
photoBitmap = decodeSampledBitmapFromResource(this,
selectedImage, (int) (imageWidth * scale),
(int) (imageHeight * scale));
return photoBitmap;
}
Decode Bitmap Sample using image size
public static Bitmap decodeSampledBitmapFromResource(Context context,
Uri uri, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
InputStream is = null;
try {
is = context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
BitmapFactory.decodeStream(is, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode editBitmap with inSampleSize set
options.inJustDecodeBounds = false;
InputStream inputs = null;
try {
inputs = context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return BitmapFactory.decodeStream(inputs, null, options);
}
Calculate Sample Size
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) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height
/ (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = Math.min(heightRatio, widthRatio);
// inSampleSize = heightRatio < widthRatio ? heightRatio :
// widthRatio;
}
return inSampleSize;
}
Or may be possible to solved using one line of code in manifiest.xml
is in application tag use this
android:largeHeap="true"

How Get bitmap from input stream after decode size

I want to get bitmap from a inputstream, then resize it. But I am getting null pointer exception.
I try inputstream.reset() but not working.
Can anybody help please?
BufferedInputStream my_is = new BufferedInputStream(is);
Bitmap bit = null;
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(my_is, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
try {
my_is.reset();
} catch (IOException e) {
e.printStackTrace();
}
bit = BitmapFactory.decodeStream(my_is, null, options);
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
Locale.getDefault()).format(new Date());
FileOutputStream fos = null;
try {
fos = getActivity().openFileOutput(timeStamp + ".png", Context.MODE_PRIVATE);
bit.compress(Bitmap.CompressFormat.PNG,90,fos);
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
crud.update_photo_path(String.valueOf(position), timeStamp);
return bit;
I used this utils:
public static Bitmap decodeSampledBitmapFromResource(String uri,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(uri, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(uri, options);
}
private 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) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}

How to change the size of the image without changing resoultion?

I am developing an app in which i want to reduce the size of my image.For example if size is 1MB then i want it to get reduce into kb.
But resolution should not get changed.
Can anyone help in this?
I tried this code but its not working
public static Bitmap resizeBitMapImage1(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;
bitMapImage = BitmapFactory.decodeFile(filePath, options);
break;
} catch (Exception ex) {
try {
sampleSize = sampleSize * 2;
} catch (Exception ex1) {
}
}
}
} catch (Exception ex) {
}
return bitMapImage;
}
Using this code it reduces the resolution but not much size of the image.
I also tried
public static Bitmap reduceImgSizeToHundredKB(Bitmap bitmap) {
Bitmap scaled = bitmap;
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, stream);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
return scaled;
}
If you don't want to resize your image then your only option is to compress it.
Here is an example on how to do that:
byte[] data = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bi.compress(Bitmap.CompressFormat.JPEG, 100, baos);
data = baos.toByteArray();
In my thought, In most cases, we can't do that. Because it related to resolution of the image and the color range of the image.
so, If we have a large image with a lot of colors, then reduce the size of the image will induce to reduce resolution of it.
There are two aproches: lossy (where you'll lose quality of the image) and lossless.
The answer provided by rickman is lossy so it will work well but reduce the quality of the image - it works particularly well for pictures taken with a camera.
The lossless approach is using PNG, which consists of using Bitmap.CompressFormat.PNG as argument to the compress method.
A not as well known but very efficient format is WebP. It's also available as an argument to the compress method (Bitmap.CompressFormat.PNG). I'd suggest testing with WebP, specially considering it supports both lossy and lossless compression.
Use this method if you are decoding from path
public Bitmap decodeSampledBitmapFromPath(String path, int reqWidth,
int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeFile(path, options);
return bmp;
}
}
public 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) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
Use this if you are decoding from resources
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 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) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
If you want to reduce the file size of the image without losing a great ammount of quality you can do this:
First you need to flatten the image, then save it for web (ctrl+alt+shift+s)
Then select the preset PNG-8 128 Dithered.
You can now customize this preset by setting the colors to "256", then select "selective" under the PNG-8, under "selective" change dither to "diffusion", deselect the "interlaced" option and make shure that the web snap option is set to 0%.

Load large bitmap from url and resize it

I want load huge image from url and show on my device. I read this post for doing this.
In that example they use native drawable but I want get image from server.
I am using this code
private void getBitmap(ImageView imageView,final String url){
mBitmapOptions = new BitmapFactory.Options();
mBitmapOptions.inJustDecodeBounds = true;
URL mUrl = null;
InputStream is= null;
try {
mUrl = new URL(url);
is = mUrl.openStream();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// BitmapFactory.decodeStream(is,null,mBitmapOptions);
mCurrentBitmap = Bitmap.createBitmap(mBitmapOptions.outWidth,
mBitmapOptions.outHeight, Bitmap.Config.ARGB_8888);
mBitmapOptions.inJustDecodeBounds = false;
mBitmapOptions.inBitmap = mCurrentBitmap;
mBitmapOptions.inSampleSize = 1;
BitmapFactory.decodeStream(is,null,mBitmapOptions);
imageView.setImageBitmap(mCurrentBitmap);
// Bitmap croppedBitmap=Bitmap.createBitmap(Bitmap.createBitmap(mCurrentBitmap, 0, mCurrentBitmap.getHeight()/2, mCurrentBitmap.getWidth(), mCurrentBitmap.getHeight()/2));
// imageView.setImageBitmap(croppedBitmap);
}
I want here get image from url and resize it but I have an exception.
java.lang.IllegalArgumentException: width and height must be > 0
What I did wrong here? or could you suggest me better answer?
I would use Picasso, then what you want to achieve is as simple as this:
Picasso.with(context).load(url).resize(50, 50).into(imageView)
http://square.github.io/picasso/
You get the exception because of:
// BitmapFactory.decodeStream(is,null,mBitmapOptions);
There are no mBitmapOptions set when you try to call:
mCurrentBitmap = Bitmap.createBitmap(mBitmapOptions.outWidth, mBitmapOptions.outHeight, Bitmap.Config.ARGB_8888);
Have a look at the answer in this question to further optimize your code: Getting the size of an image inputstream
I developped a solution based on http://developer.android.com/training/displaying-bitmaps/load-bitmap.html tutorial. Here is my code. The tricky part consist of using a byte array to store image data (because unfortunatly markSupported() is not available for connection.getInputStream()).
public static Bitmap getBitmapFromURL(final String imageUrl, final Options options, int reqWidth, int reqHeight) {
try {
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
final InputStream input = connection.getInputStream();
// using byte array to prevent open 2 times a stream
final BufferedInputStream bis = new BufferedInputStream(input, 4*1024);
ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
while ((current = bis.read()) != -1) {
baf.append((byte)current);
}
bis.close();
byte[] imageData = baf.toByteArray();
if(options != null){
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options optionsSize = new BitmapFactory.Options();
optionsSize.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageData, 0, imageData.length, optionsSize);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(optionsSize, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
optionsSize.inJustDecodeBounds = false;
}
Bitmap myBitmap = null;
if(options == null){
myBitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
}
else{
myBitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
}
// close the stream;
input.close();
return myBitmap;
} catch (Exception e) {
return null;
}
}
private 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;
}
Hope it will helps you.

How to reduce picture size?

I want to send photo taken from camera to server. But it's size around 1M and i believe it is two much. Thus i want to reduce size of the photo. Below method which I am using.
saveFile - simply save bitmap to file and return path to it.
calculateInSampleSize returns inSampleSize to adjust photo dementions to chosen.
decodeSampledBitmapFromResource decodes birmap from file and rebuild it with new parameters.
Evrything is nice but seems not working. Dimentions of small3.png are 1240*768*24 and size is still ~1M.
I call it with
photo = saveFile(decodeSampledBitmapFromResource(picturePath,
800, 800),3);
methods
public String saveFile(Bitmap bm,int id) {
String file_path = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/Mk";
File dir = new File(file_path);
if (!dir.exists())
dir.mkdirs();
File file = new File(dir, "smaller" + id + ".png");
FileOutputStream fOut;
try {
fOut = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.PNG, 85, fOut);
fOut.flush();
fOut.close();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return file.getPath();
}
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) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height
/ (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(String path,
int reqWidth, int reqHeight) {
Log.d("path", path);
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
Why you are writing the image two times just do it in all one time
What i do
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap myBitmap = BitmapFactory.decodeFile({ImagePath}, options);
FileOutputStream fileOutputStream = new FileOutputStream({ImagePath});
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
myBitmapClose.compress(CompressFormat.JPEG, imageQuality, bos);
if (bos != null) {
bos.flush();
bos.close();
}
if (fileOutputStream != null) {
fileOutputStream.flush();
fileOutputStream.close();
}
It will definitely compress Mind the line
myBitmapClose.compress(CompressFormat.JPEG, imageQuality, bos);
where set imageCompression type CompressFormat.JPEG
Thats my code...I want to reduce the size of image where path is String.
String pics=(arraylist.get(position).getImage());
try{
BitmapFactory.Options op = new BitmapFactory.Options();
op.inJustDecodeBounds = true;
//op.inSampleSize = 20; op.outWidth = 25;
op.outHeight = 35;
bmp = BitmapFactory.decodeFile(pics);
image.setImageBitmap(bmp);
}catch(Exception e) {
}

Categories

Resources