Why am I getting java.io.IOException: Mark has been invalidated? - android

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);

Related

Android - Setting wallpaper from file path takes longer than expected

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;
}

How to examine the potential filesize/bitmap size before decoding the bitmap from file path in android?

After using the device camera I get a 52MB bitmap and I decode it this way:
try {
bitmapLarge = BitmapFactory.decodeFile(pathName, bitmapOptions);
} catch (OutOfMemoryError ex) {
ex.printStackTrace();
try {
bitmapOptions.inSampleSize = 2;
bitmapOptions.inJustDecodeBounds = false;
bitmapLarge = BitmapFactory.decodeFile(pathName, bitmapOptions);
bitmapOptions.inSampleSize = 1;
} catch (OutOfMemoryError ex2) {
ex2.printStackTrace();
try {
bitmapOptions.inSampleSize = 4;
bitmapOptions.inJustDecodeBounds = false;
bitmapLarge = BitmapFactory.decodeFile(pathName, bitmapOptions);
} catch (OutOfMemoryError ex3) {
ex3.printStackTrace();
bitmapOptions.inSampleSize = 8;
bitmapOptions.inJustDecodeBounds = false;
bitmapLarge = BitmapFactory.decodeFile(pathName, bitmapOptions);
bitmapOptions.inSampleSize = 1;
}
bitmapOptions.inSampleSize = 1;
}
} catch (Exception ex) {
ex.printStackTrace();
Log.e("resizing bitmap", "#### NULL");
bitmapLarge = null;
return null;
}
I get a huge OutOfMemoryError at the first attempt to decodeFile:
12-15 18:24:24.393: E/dalvikvm-heap(12890): Out of memory on a 51916816-byte allocation.
How do I know what the size of the bitmap would be BEFORE trying to do anything with it?
And even if this is possible, how do I decode it downsampled somehow?
Instead of doing bitmapOptions.inJustDecodeBounds = false; change that to true and you will get back the bounds of the image
you should probably read this too http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
with inJustDecodeBounds = true. You will get back a null bitmap, but the bitmapOptions object will be filled with Bitmap's width and height. Then it is just Mathematic.. You need width * height * 4 bytes to keep your bitmap in memory

How to prevent out of memory exception while trying to convert input stream object into bitmap in android?

I had used following code to convert inputstream object into bitmap. But it returns "out of memory error", and BitmapFactory Options always returns Zero.
S3ObjectInputStream inputStreamReceiptObject = objectReceiptFromAmazonS3
.getObjectContent();
Bitmap bitmapImageFromAmazon = null;
try {
if (inputStreamReceiptObject != null){
BitmapFactory.Options o = new BitmapFactory.Options();
o.inSampleSize = 8;
o.inJustDecodeBounds = true;
bitmapImageFromAmazon = BitmapFactory.decodeStream(inputStreamReceiptObject,null,o); // o is always null
if(bitmapImageFromAmazon == null){
System.out.println("Bitmap null");
}
}
Advance Thanks for any help !
SOLUTION : ( Lot of thanks to Honourable Don and Honourable Akshat )
ByteArrayOutputStream baos = null ;
InputStream is1 = null,is2 = null;
try {
baos = new ByteArrayOutputStream();
// Fake code simulating the copy
// You can generally do better with nio if you need...
// And please, unlike me, do something about the Exceptions :D
byte[] buffer = new byte[1024];
int len;
while ((len = inputStreamReceiptObject.read(buffer)) > -1 ) {
baos.write(buffer, 0, len);
}
baos.flush();
// Open new InputStreams using the recorded bytes
// Can be repeated as many times as you wish
is1 = new ByteArrayInputStream(baos.toByteArray());
is2 = new ByteArrayInputStream(baos.toByteArray());
bitmapImageFromAmazon = getBitmapFromInputStream(is1,is2);
if(bitmapImageFromAmazon == null)
System.out.println("IMAGE NULL");
else
System.out.println("IMAGE NOT NULL");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
baos.close();
is1.close();
is2.close();
}
public Bitmap getBitmapFromInputStream(InputStream is1,InputStream is2) throws IOException {
Bitmap bitmap = null;
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is1,null,o);
//Find the correct scale value. It should be the power of 2.
int scale=1;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
bitmap = BitmapFactory.decodeStream(is2, null, o2);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
Why dont you try and scale the bitmap image down? Thats mostly the reason why your app showed OOM exception
BitmapFactory.Options o = new BitmapFactory.Options();
o.inScaled = false;
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; //This is the max size of the bitmap in kilobytes
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;
The Out Of Memory error should be as it says: you do not have enough memory on your device to render the entire image. You need to ensure that the image you're downloading from S3 is not too big for the device.
To help you debug, try running downloading a smaller image to see if you are still receiving the OOM errors
URLConnection conn = new URL("http://upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Victoria_Parade_postcard.jpg/120px-Victoria_Parade_postcard.jpg").openConnection();
InputStream stream = conn.getInputStream();
Bitmap image = BitmapFactory.decodeStream(stream, null, null);
The o you pass into decodeStream is null because of the OOM error (it must have gone out of scope when you examined it in the debugger).

Failed to decode bitmap from an image file

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

Downloaded Image Appears very blurry

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.

Categories

Resources