Bitmaps and out of memory error - android

I am trying to save many bitmaps in my app's folder on sdcard. However I am getting out of memory error. What is the best way to handle bitmaps and memory in this situation. Also where will I call bitmap.recycle() looking at below code? Thanks
Here is the code with which I am saving bitmaps on sdcard
Bitmap b1 = BitmapFactory.decodeResource(getResources(), R.drawable.sky);
ByteArrayOutputStream bStream1 = new ByteArrayOutputStream();
b1.compress(Bitmap.CompressFormat.PNG, 100, bStream1);
File file= new File(Environment.getExternalStorageDirectory() + File.separator + "AppName" + "/image1.png");
if(!file.exists()) {
try {
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
fos.write(bStream1.toByteArray());
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}

I think to use bitmap.recycle() and keep your code nice, you should move if(!file.exists()) into try statement, and then in finally recycle your Bitmap
try {
if(!file.exists()) {
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
fos.write(bStream1.toByteArray());
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
b1.recycle()
}
Something like this.

Related

Problems saving and retrieving images

Ok i'm completely editing this post... I have made it so that I can save the file path to my data base. this works and is saved as /storage/emulated/0/1508blah blah.jpg . Now i cannot get my code to read this item back into a picture.
imagePhoto = (ImageView)findViewById(R.id.detail_recipe_image);
Toast.makeText(this, recipe.image, Toast.LENGTH_SHORT).show();
Bitmap bmp = BitmapFactory.decodeFile(String.valueOf(recipe.image));
imagePhoto.setImageBitmap(bmp);
am I missing something here? cause the Toast Is reading the recipe.image just fine and is displaying the path. why Is the rest not displaying the image?
Storage Code
private void onCaptureImageResult(Intent data) {
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
File destination = new File(Environment.getExternalStorageDirectory(),
System.currentTimeMillis() + ".jpg");
String picturePath = destination.toString();
FileOutputStream fo;
try {
destination.createNewFile();
fo = new FileOutputStream(destination);
fo.write(bytes.toByteArray());
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
textImagePath.setText(picturePath.toString());
ImageView img = (ImageView)findViewById(R.id.addphotoview);
img.setImageBitmap(thumbnail);
}
Adding in the files paths seem to be the best solution to the problem i am having so that you #ModularSynth for your help with this. Always making sure all the info is your code to make the file paths work helps.

Android/Java: Saving a byte array to a file (.jpeg)

I am developing an application for Android, and part of the application has to takes pictures and save them to the SDcard. The onPictureTaken method returned a byte array with the data of the captured image.
All I need to do is save the byte array into a .jpeg image file. I have attempted to do this with the help of BitmapFactory.decodeByteArray (to get a Bitmap) and then bImage.compress (to an OutputStream), a plain OutputStream, and a BufferedOutputStream. All three of these methods seem to give me the same weird bug. My Android phone (8MP camera and a decent processor), seems to save the photo (size looks correct), but in a corrupted way (the image is sliced and each slice is shifted; or I just get almost horizontal lines of various colors); and The weird thing is, that an Android tablet with a 5MP camera and a fast processor, seems to save the image correctly.
So I thought maybe the processor can't keep up with saving large images, because I got OutOfMemory Exceptions after about 3 pictures (even at compression quality of 40). But then how does the built in Camera app do it, and much faster too? I'm pretty sure (from debug) that the OutputStream writes all the data (bytes) and it should be fine, but it's still corrupted.
***In short, what is the best/fastest way (that works) to save a byte array to a jpeg file?
Thanks in advance,
Mark
code I've tried (and some other slight variations):
try {
Bitmap image = BitmapFactory.decodeByteArray(args, 0, args.length);
OutputStream fOut = new FileOutputStream(externalStorageFile);
long time = System.currentTimeMillis();
image.compress(Bitmap.CompressFormat.JPEG,
jpegQuality, fOut);
System.out.println(System.currentTimeMillis() - time);
fOut.flush();
fOut.close();
} catch (Exception e) {
}
and
try {
externalStorageFile.createNewFile();
FileOutputStream fos = new FileOutputStream(externalStorageFile);
fos.write(args);
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
All I need to do is save the byte array into a .jpeg image file.
Just write it out to a file. It already is in JPEG format. Here is a sample application demonstrating this. Here is the key piece of code:
class SavePhotoTask extends AsyncTask<byte[], String, String> {
#Override
protected String doInBackground(byte[]... jpeg) {
File photo=new File(Environment.getExternalStorageDirectory(), "photo.jpg");
if (photo.exists()) {
photo.delete();
}
try {
FileOutputStream fos=new FileOutputStream(photo.getPath());
fos.write(jpeg[0]);
fos.close();
}
catch (java.io.IOException e) {
Log.e("PictureDemo", "Exception in photoCallback", e);
}
return(null);
}
}
Hey this codes for kotlin
camera.addCameraListener(object : CameraListener(){
override fun onPictureTaken(result: PictureResult) {
val jpeg = result.data //result.data is a ByteArray!
val photo = File(Environment.getExternalStorageDirectory(), "/DCIM/androidify.jpg");
if (photo.exists()) {
photo.delete();
}
try {
val fos = FileOutputStream(photo.getPath() );
fos.write(jpeg);
fos.close();
}
catch (e: IOException) {
Log.e("PictureDemo", "Exception in photoCallback", e)
}
}
})
This Code is perfect for saving image in storage, from byte[]...
note that "image" here is byte[]....taken as "byte[] image" as a parameter into a function.
File photo=new File(Environment.getExternalStorageDirectory(), "photo.jpg");
if (photo.exists()) {
photo.delete();
}
try {
FileOutputStream fos=new FileOutputStream(photo.getPath());
Toast.makeText(this, photo.getPath(), Toast.LENGTH_SHORT).show();
fos.write(image);
fos.close();
}
catch (java.io.IOException e) {
Log.e("PictureDemo", "Exception in photoCallback", e);
}
}
Here's the function to convert byte[] into image.jpg
public void SavePhotoTask(byte [] jpeg){
File imagesFolder = new File(Environment.getExternalStorageDirectory(), "Life Lapse");
imagesFolder.mkdirs();
final File photo= new File(imagesFolder, "name.jpg");
try
{
FileOutputStream fos=new FileOutputStream(photo.getPath());
fos.write(jpeg);
fos.close();
}
catch(Exception e)
{
}
}

Store Bitmap image to SD Card in Android

I am facing some strange problem with my android code,
I have an image in Bitmap variable and want to save that file to SD card.
I code as follow,
Bitmap IMAGE // Loaded from internet servers.;
try {
File _sdCard = Environment.getExternalStorageDirectory();
File _picDir = new File(_sdCard, "MyDirectory");
_picDir.mkdirs();
File _picFile = new File(_picDir, "MyImage.jpg");
FileOutputStream _fos = new FileOutputStream(_picFile);
IMAGE.compress(Bitmap.CompressFormat.JPEG, 100, _fos);
_fos.flush();
_fos.close();
Toast.makeText(this, "Image Downloaded", 7000).show();
} catch (Exception ex) {
ex.printStackTrace();
Toast.makeText(this, ex.getMessage(), 7000).show();
}
I am using Sony Experia Arc as my testing device, when the phone is connected to my computer, the code works nice, it stores image and also displays in gallery. But when I disconnect phone from my computer and test the app, it doesn't save picture and doesn't show any exception.
use this function
void saveImage() {
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/saved_images");
String fname = "Image.jpg";
File file = new File (myDir, fname);
if (file.exists ()) file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
myBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Check this answer will give more details Android saving file to external storage
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
//4
File file = new File(Environment.getExternalStorageDirectory()+File.separator + "image.jpg");
try {
file.createNewFile();
FileOutputStream fo = new FileOutputStream(file);
//5
fo.write(bytes.toByteArray());
fo.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
**This Code Cover the Following Topics**
1. Save a bitmap Image on sdcard a jpeg
2. Create a folder on sdcard
3. Create every file Separate name
4. Every file save with date and time
5. Resize the image in very small size
6. Best thing image Quality fine not effected from Resizing
The following method is used to create an image file using the bitmap
public void createImageFromBitmap(Bitmap bmp) {
FileOutputStream fileOutputStream = null;
try {
// create a File object for the parent directory
File wallpaperDirectory = new File("/sdcard/Capture/");
// have the object build the directory structure, if needed.
wallpaperDirectory.mkdirs();
//Capture is folder name and file name with date and time
fileOutputStream = new FileOutputStream(String.format(
"/sdcard/Capture/%d.jpg",
System.currentTimeMillis()));
// Here we Resize the Image ...
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 100,
byteArrayOutputStream); // bm is the bitmap object
byte[] bsResized = byteArrayOutputStream.toByteArray();
fileOutputStream.write(bsResized);
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
and add this in manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

StreamCorruptedException when reading Bitmap from SD card

I have a web service that returns a jpg. I read this jpg into a byte[], convert to a Bitmap, and save it to the SD card. The next time the user comes to this Activity, it will search the SD card to see if the image exists before hitting the web service.
However, the code that checks the SD card returns a StreamCorruptedException if the file exists.
Here is my code that writes to the SD card:
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String root = Environment.getExternalStorageDirectory().toString();
new File(root + "/images").mkdirs();
try {
File file = new File(root + "/images", Integer.toString(intImageId) + "m.jpg");
FileOutputStream os = new FileOutputStream(file);
Bitmap theImageFromByteArray = BitmapFactory.decodeByteArray(image, 0, image.length);
theImageFromByteArray.compress(Bitmap.CompressFormat.JPEG, 80, os);
os.flush();
os.close();
}
catch (FileNotFoundException e) {
}
catch (IOException e) {
}
}
Here is my code that checks the SD card for the existing image:
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
|| Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
try {
File file = new File(Environment.getExternalStorageDirectory() + "/images", Integer.toString(mImageId) + "m.jpg");
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
mImage = (Bitmap)ois.readObject();
ois.close();
}
catch (Exception e) {
}
}
The exception happens during new ObjectInputStream(fis)
You cannot arbitrarily readObject() like this. writeObject() needs to be used in order for readObject() to detect a valid serialized object.

Store and retrieve images into sdcard

I have a set of image urls. I download it to bitmap. Now I want to store these images into sdcard/project folder. If I don't have such a file, I have to create it. What I have done right now is:
String path = Environment.getExternalStorageDirectory().toString();
OutputStream fOut = null;
File file = new File(path, imageName);
if(!file.exists()) {
file.mkdir();
try {
fOut = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.flush();
fOut.close();
MediaStore.Images.Media.insertImage(getContentResolver(), "file://"
+ file.getAbsolutePath(), file.getName(), file.getName());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
But I am not getting images inserted into sdcard. What is wrong in my code? Please reply. Thanks in advance.
Try using the below code:
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
String fileName = edtNameImage.getText().toString().trim();//this can be changed
if (fileName.equalsIgnoreCase("")) {
Toast.makeText(context, "Fields cannot be left blank",
Toast.LENGTH_SHORT).show();
return false;
}
File file = new File(Environment.getExternalStorageDirectory()
+ File.separator + fileName);
// write the bytes in file
FileOutputStream fo;
try {
file.createNewFile();
fo = new FileOutputStream(file);//snapshot image is the image to be stored.
if (snapShotImage!=null)
{
snapShotImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
}else{
return false;
}
fo.write(bytes.toByteArray());
// ChartConstants.IMAGE_STORAGE++;
fo.flush();
fo.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return true;
You can also check for duplicacy in names with some additional code lines.
Let me know if it helps.
Have you made sure that the appropriate permissions for writing to/reading from an external storage device have been set in your Manifest.xml file?
Also, does the code exit with any of the exceptions above? Print more illustrative messages than the stacktrace. Something like so:
try {
} catch (FileNotFoundException e) {
Log.v(this.toString(), "Exception caught in block");
}
or something on these lines..
HTH
Sriram
Problems with your code:
1) You are creating a directory with the filename. Instead try mkdir() with only the 'path'
2) Pass only 'file.getAbsolutePath()' without the "file://" to insertImage() function
3) There is an alternate api to insertImage for which you need not create one more file locally. Pass the bitmap directly to that.
Hope this helps.

Categories

Resources