Android - Saving image into SD Card through AsyncTask fails - android

I have images in my drawables folder. Activity opens them, I choose the needed images and click on button. They must be saved on my SD Card through ImageSavingTask class instance execution which extends AsyncTask.
Here is my onClick code:
#Override
public void onClick(View v) {
for (int i = 0; i < 26; i++)
if (checkBoxes[i].isChecked()) {
imageIndex = new ImageIndex(); //ImageIndex-a class with single index field which reserves the checked checkbox indexes.
imageIndex.index = i;
Bitmap bitmap = ((BitmapDrawable) (images[i].getDrawable())).getBitmap();
SaveImageTask saveImageTask = new SaveImageTask();
saveImageTask.execute(bitmap); //The class SaveImageTask extends AsyncTask<Bitmap, Void, Void>
}
}
Then the selected images are handled in doInBackground method.
#Override
protected Void doInBackground(Bitmap... params) {
FileOutputStream outStream = null;
try {
Bitmap bitmap = params[0];
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] imageBytes = stream.toByteArray();
File sdCard = Environment.getExternalStorageDirectory();
Drawable drawable = new BitmapDrawable(getResources(), bitmap);
File dir = new File(sdCard.getAbsolutePath());
dir.mkdirs();
String fileName = "Saved image " + imageIndex.index; //The reserved index of checkbox creates a name for the new file.
File outFile = new File(dir, fileName);
outStream = new FileOutputStream(outFile);
outStream.write(imageBytes);
outStream.flush();
outStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
The <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> line is added in my manifest.
After I connect the USB to my phone, no error happens, but no images are saved to my SD Card. And I can't find images on my phone using windows search. Debugging doesn't give any answer. What kind of problem this could be?

It seems you have not asked runtime permissions for writing file on SD Card. From Android M and above you need to ask write permission at runtime to save any file on external sd card.
Check this link on how to request runtime permissions- https://developer.android.com/training/permissions/requesting.html
Also you can use google library - https://github.com/googlesamples/easypermissions
to request permissions.

I add the selected indexes into 2 ArrayLists of indexes and bitmaps. In the doInBackground method I created a loop.
For appearing the images on the card immediately I used the MediaScannerConnection.scanFile method.
for (int i = 0; i < 26; i++)
if (checkBoxes[i].isChecked()) {
index.add(i);
bitmap.add(bitmaps[i]);
}
if (bitmap.size() > 0)
new SaveImageTask().execute();
The doInBackground method:
protected Void doInBackground(Void... params) {
for (int i = 0; i < bitmap.size(); i++) {
try {
fname = "Saved image " + (index.get(i)) + ".jpg";
file = new File(myDir, fname);
if (file.exists()) file.delete();
FileOutputStream out = new FileOutputStream(file);
bitmap.get(i).compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
MediaScannerConnection.
scanFile(getApplicationContext(), new String[]{file.getPath()}, new String[]{"image/jpeg"}, null);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
I left the ImageSavingTask without fields and parameters.

I think problem where you try to write bytes.
Use Following Solution..
#Override
protected Void doInBackground(Bitmap... params) {
Bitmap bitmap = params[0];
saveToInternalStorage(bitmap, "MyImage"); // pass bitmap and ImageName
return null;
}
//Method to save Image in InternalStorage
private void saveToInternalStorage(Bitmap bitmapImage, String imageName) {
File mypath = new File(Environment.getExternalStorageDirectory(), imageName + ".jpg");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
NOTE : Make sure you have added storage read/write permission and don't forget to ask permission on Marshmallow and higher version.

Related

Image directory not created when i take picture from my app

I am working in android studio. Building an app in which i am using a camera. When i run my app the app works fine. I capture the image it does captured the image. But the folder i created is not showing in my gallery. I am saving images in my local storage and not in SD CARD. I was very curious that why the folder is not created as it doesn't gives me any error so it should be in my gallery. So i restarted my device and after restarting i can see the folder in my gallery and the images taken in it. I again open the app and took images from it but again the images were not shown in the folder.
Below is my code in which i am making ta directory for saving images
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE)
{
if(resultCode == Activity.RESULT_OK)
{
Bitmap bmp = (Bitmap)data.getExtras().get("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] byteArray = stream.toByteArray();
// convert byte array to Bitmap
Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
if(isStoragePermissionGranted())
{
SaveImage(bitmap);
}
}
}
private void SaveImage(Bitmap finalBitmap) {
String root = Environment.getExternalStorageDirectory().getAbsolutePath().toString();
Log.v(LOG_TAG, root);
File myDir = new File(root + "/captured_images");
myDir.mkdirs();
Random generator = new Random();
int n = 1000;
n = generator.nextInt(n);
String fname = "Image-" + n + ".jpg";
File file = new File(myDir,fname);
if (file.exists())file.delete();
try {
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.JPEG,100,out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Below is the picture of my debugging
**Note: **
As i am using native camera so the pictures are saved in the camera roll folder i.e. the default folder in my device. But the image saved there is not the compressed one, the compress image should be saved in my created folder.
I am stuck to it and don't know what to do.
Any help would be highly appreciated.
You need to invoke scanFile(Context context, String[] paths, String[] mimeTypes, MediaScannerConnection.OnScanCompletedListener callback) method of MediaScannerConnection.
MediaScannerConnection provides a way for applications to pass a newly created or downloaded media file to the media scanner service. This will update your folder with the newly saved media.
private void SaveImage(Bitmap finalBitmap) {
//....
if(!storageDir.exists()){
storageDir.mkdirs();
}
//...
file.createNewFile();
try {
MediaScannerConnection.scanFile(context, new String[] {file.getPath()} , new String[]{"image/*"}, null);
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.JPEG,100,out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
try this
private void saveBitmap(Bitmap bitmap) {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = timeStamp + ".jpg";
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
final String fileLoc = storageDir.getAbsolutePath() + "/folderName/" + imageFileName;
File file = new File(fileLoc);
OutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
try {`enter code here`
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}

Delete cached images from folder

I currently save images that I download from the internet to disk. I want to be able to delete the images when the user closes the app. I want the images all saved in one folder so it will be easy to delete them. I did getActivity().getCacheDir().getAbsolutePath()+ File.separator + "newfoldername" to get a path to a folder. Not sure how to add the images into the folder.
public void saveImage(Context context, Bitmap b, String name_file, String path) {
FileOutputStream out;
try {
out = context.openFileOutput(name_file, Context.MODE_PRIVATE);
b.compress(Bitmap.CompressFormat.JPEG,90, out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public Bitmap getImageBitmap(Context context, String name) {
try {
FileInputStream fis = context.openFileInput(name);
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
Bitmap b = BitmapFactory.decodeStream(fis,null, options);
b.getAllocationByteCount());
fis.close();
return b;
} catch (Exception e) {}
return null;
}
You shouldn't save the images on your cache folder as you can't rely on it as per the documentation. A better approach would be to store them on your SD Card. As per the documentation :
public abstract File getCacheDir()
Returns the absolute path to the application specific cache directory on the filesystem. These files will be ones that get deleted first when the device runs low on storage. There is no guarantee when these files will be deleted. Note: you should not rely on the system deleting these files for you; you should always have a reasonable maximum, such as 1 MB, for the amount of space you consume with cache files, and prune those files when exceeding that space.
FOR SAVING
private String saveToInternalSorage(Bitmap bitmapImage){
File directory = getApplicationContext().getDir("MY_IMAGE_FOLDER"
,Context.MODE_PRIVATE);
File mypath=new File(directory,"profile.jpg");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
return directory.getAbsolutePath();
}
FOR READING
private void loadImageFromStorage(String path)
{
try {
File file = new File(path, "Image.jpg");
Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
ImageView img = (ImageView)findViewById(R.id.my_imgView);
img.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
FOR DELETING :
String dir = getApplicationContext().getDir("MY_IMAGE_FOLDER"
,Context.MODE_PRIVATE);
if (dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
new File(dir, children[i]).delete();
}
}

AsyncTask does not execute in onCreate()

I want that If my app start first time it should download image from web and store that image in Device/Emulator, from Device/Emulator that should be displayed in ImageView.
I have tried in this way :
ImageView myImgView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myImgView = (ImageView) findViewById(R.id.imageView1);
new MyAsnyc();
Log.d(MY_TAGT, "AsyncTask Executed.....");
}
private class MyAsnyc extends AsyncTask<Void, Void,Void>{
public File file ;
InputStream is;
private Bitmap bitmap;
protected void doInBackground() throws IOException{
File path = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
file = new File(path, "DemoPicture.jpg");
try{
// Make sure the Pictures directory exists.
path.mkdirs();
URL url = new URL(BASE_URL);
/* Open a connection to that URL. */
URLConnection ucon = url.openConnection();
/*
* Define InputStreams to read from the URLConnection.
*/
is = ucon.getInputStream();
OutputStream os = new FileOutputStream(file);
byte[] data = new byte[is.available()];
is.read(data);
Log.i(MY_TAGT, "Picture is readable........");
os.write(data);
Log.i(MY_TAGT, "Picture is Saved........");
is.close();
os.close();
}
catch (IOException e) {
Log.d("ImageManager", "Error: " + e);
}
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
try {
doInBackground();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
protected void onPostExecute(){
try{
// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.scanFile(null,
new String[] { file.toString() }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
}
catch (Exception e) {
// TODO: handle exception
}
/*Here I want to set this image in ImageView*/
bitmap = BitmapFactory.decodeFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString()+"/DemoPicture.jpg");
myImgView.setImageBitmap(bitmap);
}
}
But in this way MyAsync class is not executed, please tell how to do that.
EDIT this is my log
Use execute to call it.
new MyAsnyc().execute();
use
new MyAsnyc().execute();
instead of
new MyAsnyc();
because AsyncTask.execute(Params... params) method used for executing an AsyncTask
EDIT :
use While or for loop for writing data in file as :
OutputStream os = new FileOutputStream(file);
byte[] data = new byte[is.available()];
Log.i(MY_TAGT, "Picture is readable........");
int count;
while ( (count = is.read(data)) >= 0 ) {
os.write(data,0,count)
}
Log.i(MY_TAGT, "Picture is Saved........");
is.close();
os.close();
You must try this :
public class DownloadImage {
public static File getImage(String imageUrl, String fileName){
File file = null;
try {
//set the download URL, a url that points to a file on the internet
//this is the file to be downloaded
URL url = new URL(imageUrl);
Log.d("INFORMATION..", "FILE FOUNDED....");
//create the new connection
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
//set up some things on the connection
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
//and connect!
urlConnection.connect();
Log.d("INFORMATION..", "FILE CONECTED....");
//set the path where we want to save the file
//in this case, going to save it on the root directory of the
//sd card.
File SDCardRoot = Environment.getExternalStorageDirectory();
//create a new file, specifying the path, and the filename
//which we want to save the file as.
file = new File(SDCardRoot, fileName);
//this will be used to write the downloaded data into the file we created
FileOutputStream fileOutput = new FileOutputStream(file);
Log.d("INFORMATION..", "WRINTING TO FILE DOWNLOADED...." + file);
//this will be used in reading the data from the internet
InputStream inputStream = urlConnection.getInputStream();
//this is the total size of the file
int totalSize = urlConnection.getContentLength();
//variable to store total downloaded bytes
int downloadedSize = 0;
//create a buffer...
byte[] buffer = new byte[1024];
int bufferLength = 0; //used to store a temporary size of the buffer
//now, read through the input buffer and write the contents to the file
while ( (bufferLength = inputStream.read(buffer)) > 0 ) {
//add the data in the buffer to the file in the file output stream (the file on the sd card
fileOutput.write(buffer, 0, bufferLength);
//add up the size so we know how much is downloaded
downloadedSize += bufferLength;
Log.d("INFORMATION..", "FILE DOWNLOADED....");
//this is where you would do something to report the prgress, like this maybe
//updateProgress(downloadedSize, totalSize);
}
//close the output stream when done
fileOutput.close();
Log.d("INFORMATION..", "FILE DOWNLOADING COMPLETED....");
//catch some possible errors...
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
}
Call this DownloadImage.getImage(String imageUrl, String fileName) in MainActivity.java like this :
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView imageView = (ImageView) findViewById(R.id.imageView1);
String url = "http://4.bp.blogspot.com/-8v_k_fOcfP8/UQIL4ufghBI/AAAAAAAAEDo/9ffRRTM9AnA/s1600/android-robog-alone.png";
String file = DownloadImage.getImage(url, "My Image.jpg").toString();
// Get file path on device and set it to imageView
Bitmap bitmap = BitmapFactory.decodeFile(file);
imageView.setImageBitmap(bitmap);
}
}
I think this what you are looking for! hope this will help you
You forgot to execute the AsyncTask:
(new MyAsnyc()).execute();
Before line Log.d(MY_TAGT, "AsyncTask Executed.....");
you just construct new AsyncTask object but you didn't call execution on it with execute() method..
EDIT: second problem is that it is not so clear WHICH picture actually you want to display in that ImageView.. cause bitmap = BitmapFactory.decodeFile(..blahblahblah..) will probably be null after this.. It seems to me u r giving folder name and you wanted to decode that "file" to bitmap.. Make some logs about this decoding and bitmap value and show us..
Edit2:
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File file = new File(path, "DemoPicture.jpg");
bitmap = BitmapFactory.decodeFile(file);
should work a bit better..

Convert Bitmap to File

I understand that using BitmapFactory can convert a File to a Bitmap, but is there any way to convert a Bitmap image to a File?
Hope it will help u:
//create a file to write bitmap data
File f = new File(context.getCacheDir(), filename);
f.createNewFile();
//Convert bitmap to byte array
Bitmap bitmap = your bitmap;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
byte[] bitmapdata = bos.toByteArray();
//write the bytes in file
FileOutputStream fos = new FileOutputStream(f);
fos.write(bitmapdata);
fos.flush();
fos.close();
Try this:
bitmap.compress(Bitmap.CompressFormat.PNG, quality, outStream);
See this
File file = new File("path");
OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
os.close();
Converting Bitmap to File needs to be done in background (NOT IN THE MAIN THREAD) it hangs the UI specially if the bitmap was large
File file;
public class fileFromBitmap extends AsyncTask<Void, Integer, String> {
Context context;
Bitmap bitmap;
String path_external = Environment.getExternalStorageDirectory() + File.separator + "temporary_file.jpg";
public fileFromBitmap(Bitmap bitmap, Context context) {
this.bitmap = bitmap;
this.context= context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
// before executing doInBackground
// update your UI
// exp; make progressbar visible
}
#Override
protected String doInBackground(Void... params) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
file = new File(Environment.getExternalStorageDirectory() + File.separator + "temporary_file.jpg");
try {
FileOutputStream fo = new FileOutputStream(file);
fo.write(bytes.toByteArray());
fo.flush();
fo.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// back to main thread after finishing doInBackground
// update your UI or take action after
// exp; make progressbar gone
sendFile(file);
}
}
Calling it
new fileFromBitmap(my_bitmap, getApplicationContext()).execute();
you MUST use the file in onPostExecute .
To change directory of file to be stored in cache
replace line :
file = new File(Environment.getExternalStorageDirectory() + File.separator + "temporary_file.jpg");
with :
file = new File(context.getCacheDir(), "temporary_file.jpg");
Most of the answers are too lengthy or too short not fulfilling the purpose. For those how are looking for Java or Kotlin code to Convert bitmap to File Object. Here is the detailed article I have written on the topic. Convert Bitmap to File in Android
public static File bitmapToFile(Context context,Bitmap bitmap, String fileNameToSave) { // File name like "image.png"
//create a file to write bitmap data
File file = null;
try {
file = new File(Environment.getExternalStorageDirectory() + File.separator + fileNameToSave);
file.createNewFile();
//Convert bitmap to byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0 , bos); // YOU can also save it in JPEG
byte[] bitmapdata = bos.toByteArray();
//write the bytes in file
FileOutputStream fos = new FileOutputStream(file);
fos.write(bitmapdata);
fos.flush();
fos.close();
return file;
}catch (Exception e){
e.printStackTrace();
return file; // it will return null
}
}
Hope this helps u
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Get the bitmap from assets and display into image view
val bitmap = assetsToBitmap("tulip.jpg")
// If bitmap is not null
bitmap?.let {
image_view_bitmap.setImageBitmap(bitmap)
}
// Click listener for button widget
button.setOnClickListener{
if(bitmap!=null){
// Save the bitmap to a file and display it into image view
val uri = bitmapToFile(bitmap)
image_view_file.setImageURI(uri)
// Display the saved bitmap's uri in text view
text_view.text = uri.toString()
// Show a toast message
toast("Bitmap saved in a file.")
}else{
toast("bitmap not found.")
}
}
}
// Method to get a bitmap from assets
private fun assetsToBitmap(fileName:String):Bitmap?{
return try{
val stream = assets.open(fileName)
BitmapFactory.decodeStream(stream)
}catch (e:IOException){
e.printStackTrace()
null
}
}
// Method to save an bitmap to a file
private fun bitmapToFile(bitmap:Bitmap): Uri {
// Get the context wrapper
val wrapper = ContextWrapper(applicationContext)
// Initialize a new file instance to save bitmap object
var file = wrapper.getDir("Images",Context.MODE_PRIVATE)
file = File(file,"${UUID.randomUUID()}.jpg")
try{
// Compress the bitmap and save in jpg format
val stream:OutputStream = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.JPEG,100,stream)
stream.flush()
stream.close()
}catch (e:IOException){
e.printStackTrace()
}
// Return the saved bitmap uri
return Uri.parse(file.absolutePath)
}
}

screen shot for the activity

i want to create a bitmap of whats being currently displayed of my app, one thing i went into is cant read FB buffer requires root, would like to know if it is possible to create a image file for the screen, please i want the help to code this, no 3rd party intents , thanks, answers would be much appreciated
From your Activity (pseudo-code):
Bitmap bm = Bitmap.create...
Canvas canvas = new Canvas(bm);
getWindow.getDecorView().draw(canvas);
You can use FFMPEG to capture the Screen
Try this.....
{
LinearLayout view = (LinearLayout) findViewById(R.id.imageLayout);
View v1 = view.getRootView();
v1.setDrawingCacheEnabled(true);
String dir="myimages";
Bitmap bm = v1.getDrawingCache();
saveBitmap(bm, dir, "capturedimage");
}
static String saveBitmap(Bitmap bitmap, String dir, String baseName) {
try {
File sdcard = Environment.getExternalStorageDirectory();
File pictureDir = new File(sdcard, dir);
pictureDir.mkdirs();
File f = null;
for (int i = 1; i < 200; ++i) {
String name = baseName + i + ".png";
f = new File(pictureDir, name);
if (!f.exists()) {
break;
}
}
System.out.println("Image size : "+bitmap.getHeight());
if (!f.exists()) {
String name = f.getAbsolutePath();
FileOutputStream fos = new FileOutputStream(name);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
System.out.println("After File Size : "+f.length());
fos.flush();
fos.close();
return name;
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Exception in saveBitmap: "+e.getMessage());
} finally {
}
return null;
}

Categories

Resources