I'm saving an image from the device's camera to a directory on the SD card (ex: /sdcard/appName/image.jpg), then I save the path into a database. My problem is that I can't seem to load the images into a ListView with a cursor adapter.
I tried the following code, where helper.getImg(); is a method from my database helper that returns a String (the file path), but it is not working.
icon=(ImageView)row.findViewById(R.id.icon_pura);
String imgPath=helper.getImg(c);
Bitmap myBitmap=BitmapFactory.decodeFile(imgPath);
icon.setImageBitmap(myBitmap);
the answer has to do with URIs, and you need to use the externalstorage() function. Using set paths won't work on every device
anyway you store path into the URI which is more flexible for retrieving and parsings items at that path
String filepath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/Directory name/";
File file = new File(filepath,imagename);
FileInputStream fs = null;
try
{
fs = new FileInputStream(file);
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BitmapFactory.Options bfOptions = new BitmapFactory.Options();
/*
* bfOptions.inDither=false; //Disable Dithering mode
* bfOptions.inPurgeable=true; //Tell to gc that whether it needs
* free memory, the Bitmap can be cleared
* bfOptions.inInputShareable=true;*/
bfOptions.inJustDecodeBounds = false;
bfOptions.inTempStorage = new byte[32 * 1024];
try {
Bitmap originalImage = BitmapFactory.decodeFileDescriptor(fs.getFD(), null,bfOptions);
icon.setImageBitmap(originalImage);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
If you follow himanshu's (correct) advice, make sure that if you're going to allow the user the option of loading and re-loading the image, make sure to manually icon.setImageBitmap(null); between loads, because otherwise Android will leak that memory and you'll crash your app. It's not 100% consistant, and has something to do with the sizes of the images you're loading, but I just found this leak a few days ago and am 100% certain that it's there.
Related
I am using edmodo/cropper library to crop the image after the user has taken the image from camera.
Link: https://github.com/edmodo/cropper/wiki
I got this issue on device GT-N7000 and some other android phones.
java.lang.OutOfMemoryError
1 at android.graphics.Bitmap.nativeCreate(Native Method)
2 at android.graphics.Bitmap.createBitmap(Bitmap.java:669)
3 at android.graphics.Bitmap.createBitmap(Bitmap.java:604)
4 at android.graphics.Bitmap.createBitmap(Bitmap.java:530)
5 at com.edmodo.cropper.CropImageView.getCroppedImage(CropImageView.java:357)
Does anyone know how to solve this issue. Please help me ,the device keep getting crashes.
I solved it by subsampling the captured image before storing it in cropView using BitmapFactory.Options.
Here is the code:
// setting path to the clicked image and cropped image
path_click = "sdcard/Pictures/Candice/Clicked.jpg";
path_crop = "sdcard/Pictures/Candice/Cropped.jpg";
final BitmapFactory.Options options = new BitmapFactory.Options();
//If set to a value > 1,requests the decoder to subsample the
//original image, returning a smaller image to save memory.
options.inSampleSize = 2;
clickedImage = BitmapFactory.decodeFile(path_click, options);
cropImageView.setImageBitmap(clickedImage);
// Sets initial aspect ratio to 10/10, for demonstration purposes
cropImageView.setAspectRatio(DEFAULT_ASPECT_RATIO_VALUES,
DEFAULT_ASPECT_RATIO_VALUES);
cropButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Here we save the cropped image and then call the next
// activity
// To retrieve the image contained within the Cropper window,
// use the provided method, getCroppedImage() to retrieve a
// Bitmap of the cropped image.
croppedImageBitmap = cropImageView.getCroppedImage();
/** Save cropped image to SD card using output streams **/
// An output stream that writes bytes to a file.
// If it does not exist, a new file will be created.
FileOutputStream out = null;
try {
out = new FileOutputStream(path_crop);
// Writing a compressed version of bitmap to outputstream.
croppedImageBitmap.compress(Bitmap.CompressFormat.JPEG, 90,
out);
// Just after compression,add
croppedImageBitmap.recycle();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
startActivity(chooseIntent);
}
});
I don't know how big is your image, but have you tried adding android:largeHeap="true" to your <application> tag in the AndroidManifest.xml?
I got this little function that allows me to load an image from a path, named name. It works, the problem is that I have to call this many times, una tantum. Let's say, a dozen of times at the load of a specific activity. It takes few seconds to load them all.
Is it optimal? Is there a lighter way to achieve the same result?
public static Bitmap loadImageFrom(File path, String name)
{
try {
File f = new File(path, name);
return BitmapFactory.decodeStream(new FileInputStream(f));
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}
I tried adding if(!f.exists()) return null; like this:
public static Bitmap loadImageFrom(File path, String name)
{
try {
File f = new File(path, name);
if(!f.exists()) return null;
return BitmapFactory.decodeStream(new FileInputStream(f));
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}
I know that is redundant, but I can't remove the Try Catch clause, cause it giving me an error if I do. However, no speed up noticed.
Any suggestion?
It's not that your code is inefficient, as far as I know, loading pictures manually on the main thread will hurt your app's performance. Especially when you have a large amount of pictures and/or using them to populate your ListView or GridView.
Have a look at Picasso or Universal Image Loader, these libraries should help load your pictures efficiently thus speeding up your app.
I have a folder with a few images, these images are added by user dynamically. So i need to get the R.drawable ID's of these images in android.... ???
Where are you saving these images too? When images are being added dynamically at runtime usually you need to store them on the phones storage. If you want the images to be stored in the external storage (SDCard) then you can use the following code to retrieve them and add them to your view (Which I assume your doing). This code assumes the images are being stored to your devices SDCard, which is where they will be pulled from.
//Get root directory of storage directory, pass in the name of the Folder if they are being stored farther down, i.e getExternalFilesDir("FolderName/FolderName2")
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// We can read and write the media
File dir = getExternalFilesDir(null);
Bitmap bmap = null;
try {
InputStream is = new FileInputStream(new File(dir,"image.jpg"));
bmap = BitmapFactory.decodeStream(is);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (bmap!=null) {
ImageView view = new ImageView(this);
view.setImageBitmap(bmap);
}
}
My application is some kind of "mini paint" and I would like to save my current view to the device memory... I would like to do the the opposite process too (Load an image from the device memory and set it as my currentview)
MiniPaint
yeah that's suppose to be a flamingo, I'm an artist!
Haven't tried it myself, but this answer shows taking a screenshot programmatically by getting the root view and saving off its drawing cache. That may be all you need to save your painting.
EDIT: Fixed link
First off I am assuming you are performing this drawing by overriding the onDraw() method on a View object, which passes in a Canvas object that you then perform some drawing operations on.
Here's a very basic way to approach this problem. There are probably lots of additional considerations to take into account, such as the file format(s) you read from and write to, and some extra error handling in the I/O code. But this should get you going.
To save what drawing you currently have, write out your View's drawingCache to a Picture object, then use the Picture's writeToStream method.
To load a pre-existing picture, you can use the Picture.readFromStream method, then in your onDraw call, draw the loaded picture to your Canvas.
To Wit:
/**
* Saves the current drawing cache of this View object to external storage.
* #param filename a file to be created in the device's Picture directory on the SD card
*/
public void SaveImage(String filename) {
// Grab a bitmap of what you've drawn to this View object so far
Bitmap b = this.getDrawingCache();
// It's easy to save a Picture object to disk, so we copy the contents
// of the Bitmap into a Picture
Picture pictureToSave = new Picture();
// To copy the Bitmap into the Picture, we have to use a Canvas
Canvas c = pictureToSave.beginRecording(b.getWidth(), b.getHeight());
c.drawBitmap(b, 0, 0, new Paint());
pictureToSave.endRecording();
// Create a File object where we are going to write the Picture to
File file = new File(this.getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES), filename);
try {
file.createNewFile();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
// Write the contents of the Picture object to disk
try {
OutputStream os = new FileOutputStream(file);
pictureToSave.writeToStream(os);
os.close();
}
catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
}
/**
* Returns a Picture object loaded from external storage
* #param filename the name of the file in the Pictures directory on the SD card
* #return null if the file is not found, or a Picture object.
*/
public Picture LoadImage(String filename) {
// Load a File object where we are going to read the Picture from
File file = new File(this.getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES), filename);
Picture pictureToLoad = null;
try {
InputStream is = new FileInputStream(file);
pictureToLoad = Picture.createFromStream(is);
is.close();
}
catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
// Return the picture we just loaded. Draw the picture to canvas using the
// Canvas.draw(Picture) method in your View.onDraw(Canvas) method
return pictureToLoad;
}
Useful links I read to figure this out:
Reference on generating file paths in the device's external storage
Picture
Canvas
Bitmap
I am trying to use an image from the sd card and set it as the background for a relativelayout. I have tried other solutions that i have found here and elsewhere but they havent seemed to work for me. here is my code. I have commented out other ways that i have tried and didnt work. the only thing that worked for me was using setBackgroudnResource and using a resource from the app, but this was just to test to make sure mRoot was set up correctly. when I have tried all the other ways, it just doesn't set anything. Anyone know what I am doing wrong, or if there is a better way to do this?
//one way i tired...
//String extDir = Environment.getExternalStorageDirectory().toString();
//Drawable d = Drawable.createFromPath(extDir + "/pic.png");
//mRoot.setBackgroundDrawable(d);
//another way tried..
//Drawable d = Drawable.createFromPath("/sdcard/pic.png");
//mRoot.setBackgroundDrawable(d);
//last way i tried...
mRoot.setBackgroundDrawable(Drawable.createFromPath(new File(Environment.getExternalStorageDirectory(), "pic.png").getAbsolutePath()));
//worked, only to verify mRoot was setup correctly and it could be changed
//mRoot.setBackgroundResource(R.drawable.bkg);
You do not load a drawable from SD card but a bitmap. Here is a method to load it with the reduced sampling (quality) so the program will not complain if the image is too large. Then I guess you need to process this bitmap i.e. crop it and resize for the background.
// Read bitmap from Uri
public Bitmap readBitmap(Uri selectedImage) {
Bitmap bm = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2; //reduce quality
AssetFileDescriptor fileDescriptor =null;
try {
fileDescriptor = this.getContentResolver().openAssetFileDescriptor(selectedImage,"r");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
finally{
try {
bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);
fileDescriptor.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bm;
}
The Uri here can be supplied from a gallery picker activity.
The image then can be saved into application resources and loaded into an imageView
private void saveBackground(Bitmap Background) {
String strBackgroundFilename = "background_custom.jpg";
try {
Background.compress(CompressFormat.JPEG, 80, openFileOutput(strBackgroundFilename, MODE_PRIVATE));
} catch (Exception e) {
Log.e(DEBUG_TAG, "Background compression and save failed.", e);
}
Uri imageUriToSaveCameraImageTo = Uri.fromFile(new File(BackgroundSettings.this.getFilesDir(), strBackgroundFilename));
// Load this image
Bitmap bitmapImage = BitmapFactory.decodeFile(imageUriToSaveCameraImageTo.getPath());
Drawable bgrImage = new BitmapDrawable(bitmapImage);
//show it in a view
ImageView backgroundView = (ImageView) findViewById(R.id.BackgroundImageView);
backgroundView.setImageURI(null);
backgroundView.setImageDrawable(bgrImage);
}
File file = new File( url.getAbsolutePath(), imageUrl);
if (file.exists()) {
mDrawable = Drawable.createFromPath(file.getAbsolutePath());
}
I suggest checking that the drawable is being loaded correctly. Some things to try:
Try using a different image on the sd card
Put pic.png in R.drawable and make sure mRoot.setBackgroundResource() does what you expect
After loading the drawable, check d.getBounds() to make sure it is what you expect