DecodeStream throwing null while storing in bitmap - java

This is my code... I am getting exception NULL at imageBitmap = BitmapFactory.decodeStream(is2,null, options);
First time it can decode but why now, decodeStream throwing null ?
public void showImageThumb(FileInputStream is)
{
final int IMAGE_MAX_SIZE = 100;
FileInputStream is2 = is;
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap imageBitmap = BitmapFactory.decodeStream(is,null, options);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int height = options.outHeight;
int width = options.outWidth;
int scale = 1;
if ( height > IMAGE_MAX_SIZE || width > IMAGE_MAX_SIZE)
{
scale = (int)Math.pow(2, (int) Math.round(Math.log(IMAGE_MAX_SIZE / (double) Math.max(options.outHeight, options.outWidth)) / Math.log(0.5)));
}
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
options = new BitmapFactory.Options();
options.inSampleSize = scale*2;
imageBitmap = BitmapFactory.decodeStream(is2,null, options);
height = options.outHeight;
width = options.outWidth;
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); //ERROR HERE
imageSelectedThumb = baos.toByteArray();

you get a nullpointer exception because you are copying the
is
reference in
is2
so when you close is, you are closing is2 too. Instead of assing is to is2 you have to create a new InpustStream

You have to make a deep copy of InputStream Object.Source Code in details ,please see https://stackoverflow.com/a/12797510/952386

Related

How to reduce image size mb to kb in android?

I am trying to reduce image size mb to kb using bitmap. but the code I have done is not working. I am new in android programming please can anyone help.
thanks.
I expect like this to convert image.
enter image description here
I have tried this
public void compressBitmap(File file, int sampleSize, int quality) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = sampleSize;
FileInputStream inputStream = new FileInputStream(file);
Bitmap selectedBitmap = BitmapFactory.decodeStream(inputStream, null, options);
inputStream.close();
File files = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath());
FileOutputStream outputStream = new FileOutputStream(files);
selectedBitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
outputStream.close();
long lengthInKb = file.length() / 1024; //in kb
if (lengthInKb > 1000) {
compressBitmap(file, (sampleSize*2), (quality/4));
}
selectedBitmap.recycle();
} catch (Exception e) {
e.printStackTrace();
}
}

save image file with bitmap factory

I'm encountering an issue with bitmap factory.
I've got a method to reduce and rotate an image to show a preview in an image view, but I would like to save this with the new size.
I'm just turning around with inputfilestream and outputfilestream but don't get to save it.
Is anybody know a clear method to put my bitmap in an outpufilestream?
Thanks a lot
here's my code
#Override
protected void onResume() {
super.onResume();
File[] fileArray;
final File root;
File chemin = Environment.getExternalStorageDirectory();
String filepath = chemin + "/SmartCollecte/PARC/OUT/" + fichano + "_" + conteneur_s+"_"+cpt+".jpg";
try {
decodeFile(filepath);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}}
public void decodeFile(String filePath) {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 1024;
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap b1 = BitmapFactory.decodeFile(filePath, o2);
Bitmap b = ExifUtils.rotateBitmap(filePath, b1);
FileOutputStream fos = new FileOutputStream(filePath);
b.compress(Bitmap.CompressFormat.PNG,100,fos);
fos.close();
showImg.setImageBitmap(b);
}
Have you tried doing it like this?
Assuming bitmap is bitmap you want to save.
Also, take a look at some existing system directories.
final FileOutputStream fos = new FileOutputStream(new File(filepath + "_scaled.jpg"));
try {
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
} catch (IOException e) {
// handle exception
} finally {
fos.close
}
Source
Where first parameter of Bitmap.compress() is your desired output format (see CompressFormat) and the second parameter is compression quality.
ok I found out what was missing.
had to create a new byte array to convert my bitmap to file :
String filepathcomp = Environment.getExternalStorageDirectory()+"/SmartCollecte/PARC/OUT/"+ fichano + "_" + conteneur_s+"_"+cpt+".jpg";
File f = new File(filepathcomp);
Bitmap newbitmap = b;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
newbitmap.compress(Bitmap.CompressFormat.JPEG,80,bos);
byte[] bitmapdata = bos.toByteArray();
FileOutputStream fos = new FileOutputStream(f);
fos.write(bitmapdata);
fos.flush();
fos.close();

Change the size of a bitmap in android to avoid OOM

I have been working on changing the size of the bitmap that I download from my server because I know that this is the issue with my OOM error I have been getting. I have tried the follow other examples and this one as well https://developer.android.com/training/displaying-bitmaps/load-bitmap.html but I cannot make heads or tails about how to use it and where to use it either. I want to scale my bitmaps down to screen resolution but can't seam to figure that out. Thank you for any help with this.
Also not that this is being done in a AsyncTask if that makes a difference.
Here is my code for setting up the bitmap:
public class ImageDownloaderTask extends AsyncTask<String, Void, Bitmap> {
BitmapFactory.Options options = new BitmapFactory.Options();
private final WeakReference<ImageView> imageViewReference;
Resources resources;
public ImageDownloaderTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}
#Override
protected Bitmap doInBackground(String... params)
{
return downloadBitmap(params[0]);
}
#Override
protected void onPostExecute(Bitmap bitmap) {
if (isCancelled()) {
bitmap = null;
Log.d("HTTPS No go", bitmap.toString());
}
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
if (bitmap != null) {
//Scale the bitmap to a smaller size
imageView.setImageBitmap(bitmap);
} else {
Log.d("Downloading the image: ", "No Image found");
}
}
}
}
//URL connection to download the image
private Bitmap downloadBitmap(String url) {
HttpURLConnection urlConnection = null;
try{
URL uri = new URL(url);
urlConnection = (HttpURLConnection) uri.openConnection();
urlConnection.setRequestMethod("GET");
int statusCode = urlConnection.getResponseCode();
//check if the HTTP status code is equal to 200, which means that it is ok
if (statusCode != 200) {
return null;
}
InputStream inputStream = urlConnection.getInputStream();
if (inputStream != null) {
/*
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
int sampleSize = calculateInSampleSize(options, imageWidth, imageHeight);
*/
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
}
}catch (ProtocolException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} {}
return null;
}
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;
}
}
UPDATE:
This fixed it a bit. It allows me to log out just once but when I logout a second time it crashes with the good old OOM error.
InputStream inputStream = urlConnection.getInputStream();
if (inputStream != null) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize=1; //try to decrease decoded image
Bitmap bitmap = BitmapFactory.decodeStream(inputStream , null, options);
return bitmap;
}
}catch (ProtocolException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} {}
I faced with the same issue several days ago. Theoretically there are two ways to do this. Either you completely download image and then resize image, or you must ask your server to do this instead of app. I preferred second solution, where I send required Width, Height and needed image. Server calculates possible scale, then reduces size and returns back, prints image. After which I just download bitmap using HttpURLConnection and create bitmap from input stream of my connection without any problem.
What about your error, maybe you are trying to calculate first from stream and then create it. Of course it will cause a crash, because you are trying to read input stream second time. Your cursor has already moved into stream while reading meta data of image to learn size. Now when it tries to create Bitmap it fails, cause it doesn't start from 0th byte of stream. But somewhere in the middle, where your cursor stopped last time. So if it is necessary to read stream twice, you need to copy your input stream first somewhere to be able to read stream twice. Hope it helps you.
I used this code:
Bitmap outBitmap;
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(photoPath, o);
// The new size we want to scale to ensure memory usage is optimal
int targetWidth;
int targetHeight;
if (o.outHeight > o.outWidth) {
targetWidth = getResources().getInteger(R.integer.pic_width_px);
targetHeight = getResources().getInteger(R.integer.pic_height_px);
} else if (o.outHeight == o.outWidth) {
targetWidth = targetHeight = getResources().getInteger(R.integer.pic_width_px);
} else {
targetWidth = getResources().getInteger(R.integer.pic_width_px);
targetHeight = getResources().getInteger(R.integer.pic_height_px);
}
if (o.outWidth <= targetWidth && o.outHeight <= targetHeight) {
// Return image as is without any additional scaling
Bitmap origBitmap = BitmapFactory.decodeFile(photoPath, null);
outBitmap = Bitmap.createBitmap(origBitmap, 0, 0, o.outWidth, o.outHeight, m, true);
origBitmap.recycle();
return outBitmap;
}
// Find the correct scale value. It should be the power of 2.
int scale = 1;
while(o.outWidth / scale / 2 >= targetWidth &&
o.outHeight / scale / 2 >= targetHeight) {
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options scaleOptions = new BitmapFactory.Options();
scaleOptions.inSampleSize = scale;
Bitmap scaledBitmap = BitmapFactory.decodeFile(photoPath, scaleOptions);
return Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), m, true);
I think your need change your image's size before you read it into memory.
private Bitmap downloadBitmap(String url) {
HttpURLConnection urlConnection = null;
try{
URL uri = new URL(url);
urlConnection = (HttpURLConnection) uri.openConnection();
urlConnection.setRequestMethod("GET");
int statusCode = urlConnection.getResponseCode();
//check if the HTTP status code is equal to 200, which means that it is ok
if (statusCode != 200) {
return null;
}
InputStream inputStream = urlConnection.getInputStream();
if (inputStream != null) {
//scale down the image and load
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
options.inSampleSize = calculateInSampleSize(options, 100, 100);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(inputStream, null, options); //I'm not sure here, because the inputStream used twice.
}
}catch (ProtocolException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} {}
return null;
}
Thanks everyone that helped out. I found my issue was not the size of the downloading bitmap because I am resizing them automatically when i add them into my recycle view each time. It was caused by a gif I had playing on the Login Page which took just that much memory that it would kill the device once any other thing occupied the memory at all.
I really appreciate everyone here and thank you. I thought myself that the issue was with the downloading of the image because that is what the usual culperat is.

Base64 Encoding takes too long time in Android

I'm capturing an Image with the Camera. I save the File in the public photo directory and save the Uri to that file.
I want to save the Image in a Base64 String and put it on a HashMap to put it then in a XML file later.
protected Void doInBackground(Void...voids) {
options.inJustDecodeBounds = false;
//Bitmap bmp = BitmapFactory.decodeFile(imageFilePath,options);
InputStream in = null;
try {
in = getContentResolver().openInputStream(Uri.parse(mCurrentPhotoPath));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
options.inSampleSize = 2;
Bitmap image = BitmapFactory.decodeStream(in,null,options);
int imgHeight = image.getHeight();
int imgWidth = image.getWidth();
while(imgHeight>2000){
imgHeight = imgHeight / 2;
}
while(imgWidth>2000){
imgWidth = imgWidth / 2;
}
Bitmap test = Bitmap.createScaledBitmap(image,imgWidth,imgHeight,false);
String stest = base64EncodeDecode.encodeToBase64(test);
items.put("image",base64EncodeDecode.encodeToBase64(test);
return null;
}
The Base64 takes too long to encode it.
encodeToBase64 Method
public String encodeToBase64(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
return Base64.encodeToString(b, Base64.DEFAULT);
}
Can you tell me if I do something wrong while encoding?
I hope my problem is clear.
Kind Regards!
If you are getting !!! FAILED BINDER TRANSACTION !!! error is probably because you are passing to much data to the other Activity, there is a limit of how much you can send. Try compressing your image to 50% or 30% image.compress(Bitmap.CompressFormat.JPEG, 50, baos);

Camera to nfc - best photoquality

For my application, I need to save a photo, taken from camera of a device, on an 7.7k nfc chip.
In the onActivityResult, I resize the bitmap as here :
String fileName = "original";
String path = Environment.getExternalStorageDirectory() + "/" + fileName + ".jpg";
//Resizing
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap current = BitmapFactory.decodeFile(path);
Bitmap resized = resizeBitMapImage(path,largeur,(int)(largeur*1.8));
with
public static Bitmap resizeBitMapImage(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;
Log.v(LOG_TAG,"inSampleSize" + options.inSampleSize);
bitMapImage = BitmapFactory.decodeFile(filePath, options);
break;
} catch (Exception ex) {
try {
sampleSize = sampleSize + 1 ;
} catch (Exception ex1) {
}
}
}
} catch (Exception ex) {
}
return bitMapImage;
}
(Found on SO)
And then, I save it on the chip with :
NdefRecord picRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, "image/jpeg".getBytes(), null, byteArray);
When I choose a width of 200, and a compression of 50, the picture takes about 7k, but the quality is quite low. The bitmap is a contact photo.
So my questions :
What should I use as width, height, compression, in order to get the best photo quality (less than 7k?
Should the camera be set on high or low resolution ?
PNG or JPEG compression ?

Categories