I have tried almost everything mentioned anywhere but still i am unable to get the profile pic of the logged in user in my android app.
Following is the code which I am using :-
new AsyncTask<String, Void, Bitmap>() {
#Override
protected Bitmap doInBackground(String... params) {
try {
URL url = new URL(params[0]);
return BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (Exception e) {
Log.d("ERROR", "Unable to get Image");
}
return null;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
if(saveFlag) {
saveImage(bitmap);
}
imageView.setImageBitmap(bitmap);
}
}.execute(url);
Url for the image is :- http://graph.facebook.com/{ID}/picture.
I am able to see the image when I go the url from browser.
I have tried both http and https.
Someone help.
Edit: I dont want to use any other api other than fb or normal android's.
you can use picasso and set image using picasso like this:
URL url = new URL(params[0]);
Picasso.with(context).load(url.toString()).into(imageView);
http://square.github.io/picasso/
OR
call the below method in async task and set the returned bitmap as image.
private Bitmap getImage(String imageUrl, int desiredWidth, int desiredHeight)
{
private Bitmap image = null;
int inSampleSize = 0;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inSampleSize = inSampleSize;
try
{
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
InputStream stream = connection.getInputStream();
image = BitmapFactory.decodeStream(stream, null, options);
int imageWidth = options.outWidth;
int imageHeight = options.outHeight;
if(imageWidth > desiredWidth || imageHeight > desiredHeight)
{
System.out.println("imageWidth:"+imageWidth+", imageHeight:"+imageHeight);
inSampleSize = inSampleSize + 2;
getImage(imageUrl);
}
else
{
options.inJustDecodeBounds = false;
connection = (HttpURLConnection)url.openConnection();
stream = connection.getInputStream();
image = BitmapFactory.decodeStream(stream, null, options);
return image;
}
}
catch(Exception e)
{
Log.e("getImage", e.toString());
}
return image;
}
Related
I have the common problem of display a picture in the correct rotation. My images are stored on a server. I call an image and display it in my app. Each image is rotated. So I found a correction with handleSamplingAndRotationBitmap.
public static Bitmap handleSamplingAndRotationBitmap(Context context, Uri selectedImage)
throws IOException {
int MAX_HEIGHT = 1024;
int MAX_WIDTH = 1024;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
InputStream imageStream = context.getContentResolver().openInputStream(selectedImage);
BitmapFactory.decodeStream(imageStream, null, options);
imageStream.close();
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
imageStream = context.getContentResolver().openInputStream(selectedImage);
Bitmap img = BitmapFactory.decodeStream(imageStream, null, options);
img = rotateImageIfRequired(img, selectedImage);
return img;
}
But it's impossible for me to send the correct Uri selectedImage.
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon = null;
final String myUrlStr = urldisplay;
URL url;
try {
url = new URL(myUrlStr);
uri = Uri.fromFile(new File(urldisplay));
uri2 = Uri.parse((urldisplay).toString());
mIcon = handleSamplingAndRotationBitmap(getContext(),uri2);
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
I have the error
} catch (FileNotFoundException e) {
InputStream in = null;
try {
in = new URL(DataConstantes.lien_URLEtb + "Aucune_photo_etablissement.png").openStream();
} catch (IOException e1) {
flagError = true;
}
mIcon = BitmapFactory.decodeStream(in);
} catch (Exception e) {
flagError=true;
}
java.io.FileNotFoundException:
/http:/$$$$$$$$$$/appli/android_connect/Etablissement/abordage.jpg (No
such file or directory)
Do you know how I can send the correct URI ?
Thanks
I am fetching list of urls of images from my server and setting them in recyclerview using adapter.My requirement is to fetch the color from the image and set that color to the background of the textview,for that i am using palette library as below.But i am getting the error InputStream line unable to sort the problem,any help will be appreciated.
#Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
Album albm=malbumlist.get(position);
holder.title.setText(albm.getProductName());
System.out.println("Displaying the image on Recycleview");
Glide.with(mcontext).load(albm.getImageUrl()).into(holder.thumbnail);
try {
URL url=new URL(albm.getImageUrl());
HttpURLConnection connection= (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream is=connection.getInputStream(); /* Getting error here */
bmp=BitmapFactory.decodeStream(is);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Palette.generateAsync(bmp, new Palette.PaletteAsyncListener() {
#Override
public void onGenerated(Palette palette) {
int bgcolor=palette.getVibrantColor(mcontext.getResources().getColor(android.R.color.black));
holder.linearLayout.setBackgroundColor(bgcolor);
}
});
}
check this... i am using this one..if its helpful please make this answer as right.
String path = imageToUploadUri.getPath();
File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap b = BitmapFactory.decodeFile(path, options);
int bmpHeight = b.getHeight();
int bmpWidth = b.getWidth();
if (bmpHeight > 1500) {
bmpHeight = bmpHeight / 4;
bmpWidth = bmpWidth / 4;
}
Bitmap out = Bitmap.createScaledBitmap(b, bmpWidth, bmpHeight, false);
File file = new File(dir, "resize.png");
FileOutputStream fOut;
try {
fOut = new FileOutputStream(file);
out.compress(Bitmap.CompressFormat.PNG, 100, fOut);
fOut.flush();
fOut.close();
b.recycle();
out.recycle();
} catch (Exception e) {
}
try this code
/**
* load image from url and fill it in image view
*
* #param context
* #param imageView the view which will be filled by the bitmap result
* #param imageUrl the image link
* #param imageHolder this drawable for place holder image
*/
public Request loadImage(Context context, ImageView imageView, String imageUrl, #DrawableRes int imageHolder) {
GlideUrl glideUrl = new GlideUrl(imageUrl, new LazyHeaders.Builder()
.build());
(imageHolder == 0)
imageHolder = R.drawable.error_image;
return Glide.with(context)
.load(glideUrl)
.error(imageHolder)
.into(imageView).getRequest();
}
here is my call to the method
loadImage(context, imageView,imageUrl, 0)
Example with Glide library, here you have an example:
Bitmap bitmap = Glide.
with(MainActivity.this).
load("https://YourLink").
asBitmap().
into(50, 50).
get();
Glide Second Example:
Glide.with(getApplicationContext())
.load("https://YourLink")
.asBitmap()
.into(new BitmapImageViewTarget(imgView) {
#Override
protected void setResource(Bitmap resource) {
//Your bitmap here!
super.setResource(resource);
}
});
Another solution here is with Android-Universal-Image-Loader library for loading images from URL, 1) than when image loaded successfully the library callback will return for you Bitmap of that image OR 2) you can get only Bitmap synchronously.
Example with Universal Image Loader library (from library documentation):
ImageLoader imageLoader = ImageLoader.getInstance(); // Get singleton instance
case1:
// Load image, decode it to Bitmap and return Bitmap to callback
imageLoader.loadImage(imageUri, new SimpleImageLoadingListener() {
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
// Do whatever you want with Bitmap
}
});
case2:
// Load image, decode it to Bitmap and return Bitmap synchronously
Bitmap bmp = imageLoader.loadImageSync(imageUri);
I am working on a code sample where I have to choose an image from gallery the code is working but after selection of image from gallery I get OutOfMemoryError in my OnActivityResult
I am able to get small images but large images are creating problem.
Here is my code:
try{
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 filePath = cursor.getString(columnIndex);
cursor.close();
bitmap = BitmapFactory.decodeFile(filePath);
_profileImage.setImageBitmap(bitmap);
_profileImage.setScaleType(ScaleType.FIT_XY);
Constant._addPhotoBitmap=bitmap;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Bitmap resizedbitmap = Bitmap.createScaledBitmap(bitmap, 200, 200, true);
resizedbitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte [] _byteArray = baos.toByteArray();
String base64 = Base64.encodeToString(_byteArray,Base64.DEFAULT);
Constant._addPhotoBase64 = base64;
}catch (OutOfMemoryError e) {
e.printStackTrace();
Constant.showAlertDialog(Constant.errorTitle,
"Image size is too large.Please upload small image.",
DriverProfileScreen.this, false);
} catch (Exception e) {
e.printStackTrace();
}
You are deirectly decoding the file based on its uri path..thats why it is throwing exception..before loading image set some options..this will reduce the memory for the image loading..Use this method for loading image whatever size you want..
/**
* returns the thumbnail image bitmap from the given url
*
* #param path
* #param thumbnailSize
* #return
*/
private Bitmap getThumbnailBitmap(final String path, final int thumbnailSize) {
Bitmap bitmap;
BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, bounds);
if ((bounds.outWidth == -1) || (bounds.outHeight == -1)) {
bitmap = null;
}
int originalSize = (bounds.outHeight > bounds.outWidth) ? bounds.outHeight
: bounds.outWidth;
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = originalSize / thumbnailSize;
bitmap = BitmapFactory.decodeFile(path, opts);
return bitmap;
}
In Android Developer document there is Topic called
Displaying Bitmaps Efficiently
So please go through it.
http://developer.android.com/training/displaying-bitmaps/index.html
Hope this will help you.
Generally android device heap size is only 16MB (varies from device/OS see post Heap Sizes), if you are loading the images and it crosses the size of 16MB , it will throw out of memory exception, instead of using the Bitmap for , loading images from SD card or from resources or even from network try to using getImageUri , loading bitmap require more memory , or you can set bitmap to null if your work done with that bitmap.
So,You need to downscale you image using below code:
public static Bitmap decodeFile(File f,int WIDTH,int HIGHT){
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_WIDTH=WIDTH;
final int REQUIRED_HIGHT=HIGHT;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2>=REQUIRED_WIDTH && o.outHeight/scale/2>=REQUIRED_HIGHT)
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;
}
Scale the bitmap first , then load it. It will solve the problem.
You can use the following method to do that.
private Bitmap getScaledBitmap(Uri uri){
Bitmap thumb = null ;
try {
ContentResolver cr = getContentResolver();
InputStream in = cr.openInputStream(uri);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize=8;
thumb = BitmapFactory.decodeStream(in,null,options);
} catch (FileNotFoundException e) {
Toast.makeText(PhotoTake.this , "File not found" , Toast.LENGTH_SHORT).show();
}
return thumb ;
}
Hope it helps.
try this code:
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import android.app.ActivityManager;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.widget.ImageView;
public class UserImageLoaderWithCache implements ComponentCallbacks {
private KCLruCache cache;
public UserImageLoaderWithCache(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass() * 1024 * 1024;
cache = new KCLruCache(memoryClass);
}
public void display(String url, ImageView imageview, int defaultresource) {
imageview.setImageResource(defaultresource);
Bitmap image = cache.get(url);
if (image != null) {
imageview.setImageBitmap(image);
}
else {
new SetImageTask(imageview).execute(url);
}
}
private class KCLruCache extends LruCache<String, Bitmap> {
public KCLruCache(int maxSize) {
super(maxSize);
}
}
private class SetImageTask extends AsyncTask<String, Void, Integer> {
private ImageView imageview;
private Bitmap bmp;
public SetImageTask(ImageView imageview) {
this.imageview = imageview;
}
#Override
protected Integer doInBackground(String... params) {
String url = params[0];
try {
bmp = getBitmapFromURL(url);
if (bmp != null) {
cache.put(url, bmp);
} else {
return 0;
}
} catch (Exception e) {
e.printStackTrace();
return 0;
} catch (OutOfMemoryError o) {
o.printStackTrace();
return 0;
}
return 1;
}
#Override
protected void onPostExecute(Integer result) {
if (result == 1) {
imageview.setImageBitmap(bmp);
}
super.onPostExecute(result);
}
private 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 (Exception e) {
e.printStackTrace();
return null;
}catch (OutOfMemoryError o) {
o.printStackTrace();
return null;
}
}
}
public void onLowMemory() {
}
/*public void onTrimMemory(int level) {
if (level >= TRIM_MEMORY_MODERATE) {
cache.evictAll();
}
else if (level >= TRIM_MEMORY_BACKGROUND) {
cache.trimToSize(cache.size() / 2);
}
}*/
public void onConfigurationChanged(Configuration arg0) {
// TODO Auto-generated method stub
}
}
I have used below code and used bitmap to store resized Image in local storage and It worked like charm
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap b = BitmapFactory.decodeFile(path, options);
here path is image Uri path in String
I'm trying to download a image from a URL, using the Google Example Page. I've read when I use a InputStream in the BitmapFactory.decodeStream method, I can't use twice. I'm trying to do that, but it doesn't work 'cause it returns null in the decoded image, and I don't know what I can do.
This is my code:
This part is in a doInBackground method in a AsyncTask class
Bitmap bitmapImage;
URL imageUrl = null;
try {
imageUrl = new URL(url[0]);
HttpGet httpRequest = null;
httpRequest = new HttpGet(imageUrl.toURI());
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = (HttpResponse) httpclient.execute(httpRequest);
HttpEntity entity = response.getEntity();
BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);
InputStream instream = bufHttpEntity.getContent();
bitmapImage = CommonMethods.decodeSampledBitmapFromResource(instream, thumb_width, thumb_width);
instream.close();
return bitmapImage;
} catch (URISyntaxException e) {
e.printStackTrace();
return null;
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
public static Bitmap decodeSampledBitmapFromResource(InputStream instream,
int reqWidth, int reqHeight) throws IOException {
//Copy instream for decode twice
ByteArrayOutputStream out = new ByteArrayOutputStream();
copy(instream,out);
ByteArrayInputStream instream2 = new ByteArrayInputStream(out.toByteArray());
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(instream, null, options);
instream2.close();
options.inJustDecodeBounds = false;
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
return BitmapFactory.decodeStream(instream, 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) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
//Copy instream method
public static void copy(InputStream input, OutputStream output) throws IOException{
byte[] buffer = new byte[Constants.IO_BUFFER_SIZE];
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
}
BitmapFactory.decodeStream returns null because the inputstream is used twice, I've not tried your code, but it seams OK, or maybe I'm wrong.
Anyway, I've a better solution. Just use BufferedInputStream to wrap the inputStream, and before your second read, call "reset" first. Note ordinary inputStreams donnot support "reset", you may call it but nothing will happen.
My code:
public static Bitmap decodeSampledBitmapFromStream(InputStream inputStream,
int reqWidth, int reqHeight)
throws IOException {
if (!widthHeightCheck(reqWidth, reqHeight))
return BitmapFactory.decodeStream(inputStream);
// First decode with inJustDecodeBounds=true to check dimensions
if (!(inputStream instanceof BufferedInputStream)) {
inputStream = new BufferedInputStream(inputStream);
}
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Rect rect = new Rect(-1, -1, -1, -1);
BitmapFactory.decodeStream(inputStream, rect, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
inputStream.reset();
return BitmapFactory.decodeStream(inputStream, rect, options);
}
I think you can achieve this by wrapping the stream you get from the httpEntity in a custom WrappedStream. This WrappedStream will feed a second input stream while reading the original stream. (this is done with PipedStream)
After getting the image size with this code :
options.inJustDecodeBounds = true;
WrappedStream wrappedStream = new WrappedStream(instream);
BitmapFactory.decodeStream(wrappedStream, null, options);
You can call
InputStream reReadStream = wrappedStream.getReReadStream();
options.inJustDecodeBounds = false;
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
return BitmapFactory.decodeStream(reReadStream, null, options);
And finally, here is the implementation of WrappedStream (it simply delegates all calls to the wrapped inputStream, and writes all bytes that are read (or skipped) in a pipedOutputStream)
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/** Simple class wrapping an InputStream and feeding a secondary InputStream
* to re-read the data that was originally available in the inputStream.
**/
public class WrappedStream extends InputStream {
private InputStream urlStream;
private PipedOutputStream pipedStream;
public WrappedStream(InputStream urlStream) {
this.urlStream = urlStream;
this.pipedStream = new PipedOutputStream();
}
/**
* return a fresh InputStream to re-read the data
*/
public InputStream getReReadStream() throws IOException {
return new PipedInputStream(pipedStream);
}
#Override
public int available() throws IOException {
return urlStream.available();
}
#Override
public void close() throws IOException {
urlStream.close();
}
#Override
public void mark(int readlimit) {
urlStream.mark(readlimit);
}
#Override
public boolean markSupported() {
return urlStream.markSupported();
}
#Override
public int read() throws IOException {
int b = urlStream.read();
pipedStream.write(b);
return b;
}
#Override
public int read(byte[] buffer) throws IOException {
int l = urlStream.read(buffer);
pipedStream.write(buffer);
return l;
}
#Override
public int read(byte[] buffer, int offset, int length) throws IOException {
int l = urlStream.read(buffer, offset, length);
pipedStream.write(buffer, offset, length);
return l;
}
#Override
public void reset() throws IOException {
urlStream.reset();
}
#Override
//bytes skipped must available on the re-read stream so we read and write them.
public long skip(long byteCount) throws IOException {
long bytesToSkip = byteCount;
long skippedBytes = 0;
//ugly trick required to not loosing bytes if we ever skip more than Integer.MAX_VALUE bytes
while(bytesToSkip>Integer.MAX_VALUE){
_skip(Integer.MAX_VALUE);
bytesToSkip -=Integer.MAX_VALUE;
skippedBytes +=Integer.MAX_VALUE;
}
byte[] b = new byte[(int)bytesToSkip];
skippedBytes += read(b);
return skippedBytes;
}
private int _skip(int byteCount) throws IOException {
byte[] b = new byte[(int)byteCount];
return read(b);
}
}
Please note that I didn't test this code. This is just to give you some ideas on how to solve your problem.
Another point: even if this code never create a huge bitmap, the whole stream will be kept in memory until the scaled Bitmap is build.
Found the code which will work for you
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
inputStream = entity.getContent();
BitmapFactory.Options options = new BitmapFactory.Options();
//options.inSampleSize = 2;
final Bitmap bitmap = BitmapFactory
.decodeStream(inputStream, null, options);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
Please replace the proper variable and if you wanted to scale the image you can scale it after getting the bitmap.
here is the method to download bitmap from server with less code you can fulfill your requirement
Bitmap downloadBitmap(String url)
{
Bitmap image = null;
InputStream in = null;
try
{
in = new java.net.URL(url).openStream();
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 2;
image = BitmapFactory.decodeStream(new FlushedInputStream(in),null,opts);
in.close();
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
return image;
}
in the above code we use
opts.inSampleSize = 2;
it means the bitmap will be reduced to half size of its original size to avoid memory exception we have to do this if we are loading lot of images
some other class used in it
static class FlushedInputStream extends FilterInputStream
{
public FlushedInputStream( InputStream inputStream )
{
super(inputStream);
}
#Override
public long skip(long n) throws IOException
{
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n)
{
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L)
{
int byte1 = read();
if (byte1 < 0)
{
break; // we reached EOF
}
else
{
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
Please Use below code for download and display image into imageview.
public class image extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Bitmap bitmap = DownloadImage("http://www.gophoto.it/view.php?i=http://1.bp.blogspot.com/-2LTvCCufBKc/T3L3KgcTj2I/AAAAAAAABbQ/Ki60e1LU9sE/s1600/Sachin%2BTendulkar.png");
ImageView img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(bitmap);
}
private InputStream OpenHttpConnection(String urlString) throws IOException {
InputStream in = null;
int response = -1;
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
if (!(conn instanceof HttpURLConnection))
throw new IOException("Not an HTTP connection");
try {
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
}
} catch (Exception ex) {
throw new IOException("Error connecting");
}
return in;
}
private Bitmap DownloadImage(String URL) {
Bitmap bitmap = null;
InputStream in = null;
try {
in = OpenHttpConnection(URL);
bitmap = BitmapFactory.decodeStream(in);
in.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return bitmap;
}
}
I'm new to android and I'm confused about how to deal with Bitmaps.
I want to download a Bitmap, it could be quite large, and save it to a temporary internal file. I'm then going to draw this Bitmap to a Canvas later.
My current method is to
1. Download the input stream
2. copy the stream
3. use one stream to work out bounds using bitmapFactory.options
4. use the other stream to decode the full bitmap with the sample size
However, I need landscape and portrait versions, so now I will have to do this twice and save two images.
Or - I have seen people use bm.compress(Bitmap.CompressFormat.JPEG, 50, bos); to save a file instead. This by-passes the decoding with sample size as its saved direct from a stream. I guess then I would use a matrix to scale when I draw to my Canvas.
Basically, I am confused as the best approach for this task , which method is less likely to run into out of memory and is the more commonly used approach?
Cheers
byte[] imagesByte = getLogoImage(Your url);
set to imageview...
imgView.setImageBitmap(BitmapFactory.decodeByteArray( imagesByte, 0, imagesByte.length));
Method for Download
public static byte[] getLogoImage(String url){
try {
URL imageUrl = new URL(url);
URLConnection ucon = imageUrl.openConnection();
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
ByteArrayBuffer baf = new ByteArrayBuffer(500);
int current = 0;
while ((current = bis.read()) != -1) {
baf.append((byte) current);
}
return baf.toByteArray();
} catch (Exception e) {
Log.d("ImageManager", "Error: " + e.toString());
}
return null;
}
In Android you have to e aware of limited memory, so large images would't fit in memory and you will have OutOfMemory exceptions.
The key is, after saving te image in internal storage, load it at the display resolution:
First download te image, this should be done outside the UI thread, let _url an URL intance with the image addres and _file the String containing destination file :
URLConnection conn = _url.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
boolean success = false; //track succesful operation
if( _file != null)
{
try
{
FileOutputStream fos = new FileOutputStream(_file);
byte data[] = new byte[4086]; //use 4086 bytes buffer
int count = 0;
while ((count = is.read(data)) != -1)
{
fos.write(data, 0, count);//write de data
}
is.close();
fos.flush();
fos.close();
int len = conn.getContentLength();
File f = new File( _file);//check fie length is correct
if( len== f.length())
{
success = true;
}
else
{
//error downloading, delete de file
File tmp = new File( _file);
if( tmp.exists())
{
tmp.delete();
}
}
}catch (Exception e )
{
try
{
e.printStackTrace();
//delete file with errors
File tmp = new File( _file);
if( tmp.exists())
{
tmp.delete();
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
finally
{
is.close();//cleanup
}
Then when you have to load the image at the desired resolution, here the key is use BitmapFactory to read bitmap info and get scaled bitmap:
public static Bitmap bitmapFromFile(int width, int height, String file)
{
Bitmap bitmap = null;
final BitmapFactory.Options options = new BitmapFactory.Options();
if( height >0 && width > 0 ) {
options.inJustDecodeBounds = true;//only read bitmap metadata
BitmapFactory.decodeFile(file,options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, width, height);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
}
try
{
bitmap = BitmapFactory.decodeFile(file, options);//decode scaled bitmap
}catch (Throwable t)
{
if( bitmap != null)
{
bitmap.recycle();//cleanup memory, very important!
}
return null;
}
return bitmap
}
The final step is to calculate the scale factor:
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;
final int halfWidth = width;
// 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 ((couldShrink(halfWidth, reqWidth, inSampleSize)&&
couldShrink(halfHeight,reqHeight, inSampleSize))
//&&(halfHeight*halfWidth)/inSampleSize > maxsize)
)
{
inSampleSize *= 2;
}
}
return inSampleSize;
}
private static boolean couldShrink ( int dimension, int req_dimension, int divider)
{
int actual = dimension / divider;
int next = dimension / (divider*2);
int next_error = Math.abs(next - req_dimension);
int actual_error = Math.abs(actual-req_dimension);
return next > req_dimension ||
(actual > req_dimension && (next_error < actual_error) )
;
}
That is if you want to do it by hand, I recommend you to use Picasso that will handle donwloading, disk caching and memory caching of your image:
To load into a ImageView called image showing a backgroud (R.drawable.img_bg) while downloading :
Picasso.with(image.getContext())
.load(url).placeholder(R.drawable.img_bg).fit()
.into(image, new Callback.EmptyCallback()
{
#Override
public void onSuccess()
{
holder.progress.setVisibility(View.GONE); //hide progress bar
}
#Override
public void onError()
{
holder.progress.setVisibility(View.GONE); //hide progress bar
//do whatever you design to show error
}
});
to handle yourself a bitmap:
//first declare a target
_target = new Target()
{
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from)
{
//handle your bitmap (store it and use it on you canvas
}
#Override
public void onBitmapFailed(Drawable errorDrawable)
{
//handle your fail state
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable)
{//for example for drawing a placeholder while downloading
}
};
Now you just have to load and resize your image:
Picasso.with(context).load(url).resize(192, 192).centerCrop().into(_target);
Hope that helps.