I downloaded an image to use following this excellent article. My own image I'm using is a google map static image that is 300x400. I've fiddle with a few of the settings and have expanded it to fill across the screen, however it just appears very blurry.
<ImageView
android:id="#+id/image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_x="0dp"
android:layout_y="0dp"
android:adjustViewBounds="true"
android:clickable="false"
android:gravity="center_vertical"
android:longClickable="false"
android:scaleType="fitCenter" />
That is what I have in the screen xml layout. Is this a common problem? I did a good search and couldn't find an answer. Is 300x400 not a good res for android?
Is 300x400 not a good res for android?
it depends on original image orientation and a couple of other things like your layout and device display. Alternatively, you could try the following code to download an image, this works fine for me:
don't forget to add
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
to your Manifest
public class MainActivity extends Activity {
private Button get;
private ImageView pic;
private static final String SRC = "http://www.allindiaflorist.com/imgs/arrangemen4.jpg";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
get = (Button)findViewById(R.id.button1);
pic = (ImageView)findViewById(R.id.imageView1);
get.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pic.setImageBitmap(getBitmapFromURL(SRC));
}
});
}
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();
Log.e("getBmpFromUrl error: ", e.getMessage().toString());
return null;
}
}
}
I found the reason why they were low, the image loader class had a built in compression:
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
So just remove this part so you are left with:
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
return BitmapFactory.decodeStream(new FileInputStream(f));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
Crystal clear images.
Related
I'm trying to set wallpaper from file path. However it takes more than 10 seconds and causes my app to freeze.
Here's the code I'm using:
public void SET_WALLPAPER_FROM_FILE_PATH (String file_path)
{
Bitmap image_bitmap;
File image_file;
FileInputStream fis;
try {
WallpaperManager wallpaper_manager = WallpaperManager.getInstance(m_context);
image_file = new File(file_path);
fis = new FileInputStream(image_file);
image_bitmap = BitmapFactory.decodeStream(fis);
wallpaper_manager.setBitmap(image_bitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
I have tried to use:
wallpaper_manager.setStream(fis)
instead of:
wallpaper_manager.setBitmap(image_bitmap);
as suggested in this answer but couldn't load the wallpaper.
Can anyone guide me?
Thanks
Try to use AsyncTask,
in doInBackground method write something like this
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;
}
Please suggest me,
I am getting url of images and need to place in google map as marker
for(AtmInfo info :atmInfoList){
//latitude = Double.parseDouble(pub.getLatitude()) ;
// longitude = Double.parseDouble(getIntent().getStringExtra("lon"));
Marker source = mMap.addMarker(
new MarkerOptions()
.position(
new LatLng(
Double.parseDouble(info.getLatitude()),
Double.parseDouble(info.getLongitude())))
.title(info.getBankName())
.snippet(info.getBankAddress())
.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_green)));
}
mMap.setInfoWindowAdapter(new CustomInfoWindowAdapter());
here is the complete solution.
create Marker like this
Marker source = mMap.addMarker(
new MarkerOptions()
.position(
new LatLng(
Double.parseDouble(info.getLatitude()),
Double.parseDouble(info.getLongitude())))
.title(info.getBankName())
.snippet(info.getBankAddress())
.icon(BitmapDescriptorFactory.fromResource(getBitmap(url,this)))); //call getbitmap() method to download image from url
Download bitmap from url
add method getBitmap and decode method in your project(for ex. util class or common function)
public static Bitmap getBitmap(String url,Context context)
{
FileCache fileCache=new FileCache(context);
MemoryCache memoryCache=new MemoryCache();
File f=fileCache.getFile(url);
//from SD cache
//CHECK : if trying to decode file which not exist in cache return null
Bitmap b = decodeFile(f);
if(b!=null)
return b;
// Download image file from web
try {
Bitmap bitmap=null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream is=conn.getInputStream();
// Constructs a new FileOutputStream that writes to file
// if file not exist then it will create file
OutputStream os = new FileOutputStream(f);
// See Utils class CopyStream method
// It will each pixel from input stream and
// write pixels to output stream (file)
Utils.CopyStream(is, os);
os.close();
conn.disconnect();
//Now file created and going to resize file with defined height
// Decodes image and scales it to reduce memory consumption
b = decodeFile(f);
return bitmap;
} catch (Throwable ex){
ex.printStackTrace();
if(ex instanceof OutOfMemoryError)
memoryCache.clear();
return null;
}
}
//Decodes image and scales it to reduce memory consumption
private static Bitmap decodeFile(File f){
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1=new FileInputStream(f);
BitmapFactory.decodeStream(stream1,null,o);
stream1.close();
//Find the correct scale value. It should be the power of 2.
// Set width/height of recreated image
final int REQUIRED_SIZE=85;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
//decode with current scale values
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
FileInputStream stream2=new FileInputStream(f);
Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
Firstly, get the image from URL.
Secondly, after getting the image you can use overlay for adding custom marker on map.
I'm trying to take a picture and add an overlay on top of it. Here is my code (only the callback) :
private PictureCallback mPicture = new PictureCallback() {
#Override
public void onPictureTaken(final byte[] data, Camera camera) {
if(!dirFile.exists()){
dirFile.mkdirs();
}
try {
String name = new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date()) + ".jpg";
picturePath = new File(dirFile, name);
new AsyncTask<Void, Void, Void>(){
FileOutputStream fos = new FileOutputStream(picturePath);
Bitmap photo;
#Override
protected Void doInBackground(Void... params) {
photo = BitmapFactory.decodeByteArray(data, 0, data.length).copy(Config.ARGB_8888, true);
Bitmap cadre = BitmapFactory.decodeResource(getResources(), R.drawable.cadre16001200);
Canvas canvas = new Canvas(photo);
canvas.drawBitmap(cadre, new Matrix(), null);
cadre.recycle();
photo.compress(CompressFormat.JPEG, 100, fos);
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
geotag(picturePath.toString());
return null;
}
protected void onPostExecute(Void result) {
dialog.dismiss();
mCamera.startPreview();
//Affiche la nouvelle photo
picture.setImageBitmap(photo);
};
}.execute();
} catch (FileNotFoundException e) {
Log.d("PhotoActivity", "File not found: " + e.getMessage());
}
}
};
I get the following error on my Samsung Galaxy S3 (android 4.1.2) , with an OutOfMemoryException
07-04 10:01:24.076: E/dalvikvm-heap(2980): Out of memory on a 7680016-byte allocation.
Weird thing is that it works perfectly on the Samsung Gio (android 2.2.1) with the same resolution of 1600x1200.
I googled a lot, and I can't use the main solution of downsizing the picture. It is a memory issue, but I don't know how I can reduce the memory usage.
EDIT : I found this, seems it was the real matter : https://stackoverflow.com/a/12377158/1343969
you should decode the bitmap before proccessing it to the UI, here's a code example
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1=new FileInputStream(f);
BitmapFactory.decodeStream(stream1,null,o);
stream1.close();
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
FileInputStream stream2=new FileInputStream(f);
Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
You should simply call the empty constructor of Canvas and draw the photo on it. This would remove the copy() call and reduce the memory usage.
photo = BitmapFactory.decodeByteArray(data, 0, data.length);
Bitmap cadre = BitmapFactory.decodeResource(getResources(), R.drawable.cadre16001200);
Canvas canvas = new Canvas();
canvas.drawBitmap(photo, 0, 0, null);
canvas.drawBitmap(cadre, new Matrix(), null);
cadre.recycle();
photo.compress(CompressFormat.JPEG, 100, fos);
I am trying to download images from URL. The image type is PNG and the resolution is 400x400 pixels.
Here is the download code snippet.
Bitmap bitmap=null;
URL imageUrl = new URL(url);
conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream ins=conn.getInputStream();
os = new FileOutputStream(f);
Utilities.getUtilities().copyStream(ins, os);
os.flush();
Log.i(TAG_NAME, "file size : "+ f.length());
Log.i(TAG_NAME, "file exists in cache? " + f.exists());
bitmap = decodeFile(f);
return bitmap;
Here is the file writer.
public void copyStream(InputStream is, OutputStream os) {
final int buffer_size=1024;
try
{
byte[] bytes=new byte[buffer_size];
for(;;)
{
int count=is.read(bytes, 0, buffer_size);
if(count==-1)
break;
os.write(bytes, 0, count);
}
}
catch(Exception ex){
ex.printStackTrace();
}
}
And the decode method
private Bitmap decodeFile(File f){
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
try {
BitmapFactory.decodeStream(new FileInputStream(f));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
final int REQUIRED_SIZE = 400; //for testing, it is set to b a constant
System.out.println("REQUIRED_SIZE >>> " + REQUIRED_SIZE);
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
//o2.inJustDecodeBounds = true;
o2.inPreferredConfig = Bitmap.Config.ARGB_8888;
o2.inSampleSize=scale; //scale is set off since android:src automatically scales the image to fit the screen
try {
return BitmapFactory.decodeStream(new FileInputStream(f));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
I can see that the file exists in the device. However, the decode stream is failing. I spent hours searching on the internet; tried almost everything, no success and almost my heads rolling.
Decode streams is causing the following error.
SkImageDecoder::Factory returned null
Do you find anything missing here?
EDIT:
Issue is now solved. The server was expecting cookie details which I failed to attach. Spent almost a day, beating around the bushes :-)
Thanks all for the valuable comments!
IMO, you may want to re-evaluate merits of httpurlconn vs native httpclient implementation. Android/google go for httpurlconn but, many opt to take greater control of low level details surrounding net protocol.
Here is sample async httpclient that wraps in bitmap handler. You can easily extend the sample method=processBitmapEntity() with your rules affecting bmp size.
Sample getbitmap url:
public int getBitmap(String mediaurl, int ctr){
Handler handler = new Handler() {
public void handleMessage(Message message) {
switch (message.what) {
case HttpConnection.DID_START: {
Log.d(TAG, "Starting connection...");
break;
}
case HttpConnection.DID_SUCCEED: {
//message obj is type bitmap
Log.d(TAG, "OK bmpARRAY " +message.arg1);
Bitmap response = (Bitmap) message.obj;
break;
}
case HttpConnection.DID_ERROR: {
Exception e = (Exception) message.obj;
e.printStackTrace();
Log.d(TAG, "Connection failed.");
break;
}
}
}
};
new HttpConnection(handler, PreferenceManager.getDefaultSharedPreferences(this), ctr).bitmap(mediaurl);
return -1;
And the bitmap handler in HttpConnection class that is part of the link sample above:
private void processBitmapEntity(HttpEntity entity) throws IOException {
BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);
Bitmap bm = BitmapFactory.decodeStream(bufHttpEntity.getContent());
handler.sendMessage(Message.obtain(handler, DID_SUCCEED, bm));
}
And a git project
I'm trying to download imags from a url and then decode them.
The problem is that I don't know how large are they and if I decode them right away, the app crashes with too-big images.
I'm doing the following and it works with most of the images but with some of them, it throws the java.io.IOException: Mark has been invalidated exception.
It's not a matter of size because it happens with a 75KB or a 120KB image and not with a 20MB or 45KB image.
Also the format is not important as it can happen either with a jpg or png image.
pis is an InputStream.
Options opts = new BitmapFactory.Options();
BufferedInputStream bis = new BufferedInputStream(pis);
bis.mark(1024 * 1024);
opts.inJustDecodeBounds = true;
Bitmap bmImg=BitmapFactory.decodeStream(bis,null,opts);
Log.e("optwidth",opts.outWidth+"");
try {
bis.reset();
opts.inJustDecodeBounds = false;
int ratio = opts.outWidth/800;
Log.e("ratio",String.valueOf(ratio));
if (opts.outWidth>=800)opts.inSampleSize = ratio;
return BitmapFactory.decodeStream(bis,null,opts);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
I think you want to decode large image. I did it by selecting gallery image.
File photos= new File("imageFilePath that you select");
Bitmap b = decodeFile(photos);
"decodeFile(photos)" function is used for decode large image. I think you need to get image .png or .jpg formet.
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale++;
}
//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;
}
you can display it by using imageView.
ImageView img = (ImageView)findViewById(R.id.sdcardimage);
img.setImageBitmap(b);