196

What I want to do, is to save an image to the internal memory of the phone (Not The SD Card).

How can I do it?

I have got the image directly from the camera to the image view in my app its all working fine.

Now what I want is to save this image from Image View to the Internal memory of my android device and also access it when required.

Can anyone please guide me how to do this?

I am a little new to android so please, I would appreciate if I can have a detailed procedure.

Swati Garg
  • 995
  • 1
  • 10
  • 21
usamazf
  • 3,195
  • 4
  • 22
  • 40
  • Hi, Where is`/data/data/yourapp/app_data/imageDir` located exactly? http://stackoverflow.com/questions/40323126/where-do-i-find-the-saved-image-in-android – Khalil Khalaf Oct 29 '16 at 20:17

8 Answers8

376

Use the below code to save the image to internal directory.

private String saveToInternalStorage(Bitmap bitmapImage){
        ContextWrapper cw = new ContextWrapper(getApplicationContext());
         // path to /data/data/yourapp/app_data/imageDir
        File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
        // Create imageDir
        File mypath=new File(directory,"profile.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.PNG, 100, fos);
        } catch (Exception e) {
              e.printStackTrace();
        } finally {
            try {
              fos.close();
            } catch (IOException e) {
              e.printStackTrace();
            }
        } 
        return directory.getAbsolutePath();
    }

Explanation :

1.The Directory will be created with the given name. Javadocs is for to tell where exactly it will create the directory.

2.You will have to give the image name by which you want to save it.

To Read the file from internal memory. Use below code

private void loadImageFromStorage(String path)
{

    try {
        File f=new File(path, "profile.jpg");
        Bitmap b = BitmapFactory.decodeStream(new FileInputStream(f));
            ImageView img=(ImageView)findViewById(R.id.imgPicker);
        img.setImageBitmap(b);
    } 
    catch (FileNotFoundException e) 
    {
        e.printStackTrace();
    }

}
Wilder Pereira
  • 2,249
  • 3
  • 21
  • 31
Brijesh Thakur
  • 6,768
  • 4
  • 24
  • 29
  • I notice you have placed certain comments can you guide me what are implying? Like the one about the path? Do I have to give a path or something? – usamazf Jul 16 '13 at 12:47
  • 1
    How can I access my image from the memory? – usamazf Jul 16 '13 at 15:33
  • I edited the answer. To access image from memory. How are you setting the image to your image ?? I believe its nothing but Bitmap , the same instance you can pass to the function. – Brijesh Thakur Jul 16 '13 at 16:56
  • Why not. See the function , it returns the filepath. which you can use to retrieve it and show it to imageview. I have put the code to retrieve the image as well – Brijesh Thakur Jul 17 '13 at 05:23
  • @BrijeshThakur : which path you have passed in `loadImageFromStorage` ?? & how to get it? – Uniruddh Mar 19 '14 at 09:22
  • @i-droid : Read the comment in saveToInternalSorage() method. The path is for Internal Storage which you can save it while saving. See the method returns directory.getAbsolutePath(). Its a path to directory in which the file is saved. – Brijesh Thakur Mar 20 '14 at 11:21
  • HI Brijesh..u r life saver dude..can u describe this.. bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos); i mean what is 100 there? will it affect to qaulity? – Kalpesh Lakhani Apr 15 '14 at 12:24
  • Actually i m using your code for uploading image..i am taking directly this path: return directory.getAbsolutePath(); to upload image. so will it affect to image quality? or the will return the same bitmap with original size(mean hieght and width at the time of saving image?) – Kalpesh Lakhani Apr 15 '14 at 12:27
  • 5
    You should really close the stream from a finally block, not from inside the try block. – Kenn Cal Nov 28 '15 at 02:57
  • @BrijeshThakur Any reason why you do `BitmapFactory.decodeStream(new FileInputStream(f))` instead of `BitmapFactory.decodeFile(f)`? – KaliMa Apr 11 '16 at 16:33
  • Thank you so much! I only wrote another implementation for the directorie selection – vanlooverenkoen May 22 '16 at 13:22
  • Thanks for the answer. How can I save that image to a sub-directory in the internal storage? I'd like to store it somewhere like: "imageDir/user2/gallery/" – Dominik Jul 24 '16 at 20:32
  • http://stackoverflow.com/questions/40209822/how-to-save-user-selected-image-to-sharedpreference-to-be-used-in-other-parts-of something like that for mine? – Si8 Oct 24 '16 at 02:34
  • path is set to your app's private directory. i.e. /data/data/yourapp/app_data/imageDir – Brijesh Thakur Oct 25 '16 at 08:51
  • 2
    Hi, Where is `/data/data/yourapp/app_data/imageDir` located exactly? http://stackoverflow.com/questions/40323126/where-do-i-find-the-saved-image-in-android – Khalil Khalaf Oct 29 '16 at 20:16
  • Its private directory, which every App gets. You can read more about it here https://developer.android.com/guide/topics/data/data-storage.html – Brijesh Thakur Nov 02 '16 at 05:30
  • @dharmx did you try directory.exists() ? – Brijesh Thakur Aug 22 '17 at 06:20
  • @Usama Zafar the Path comment you ask about _// path to /data/data/yourapp/app_data/imageDir_ is just to show you that the new 'imageDir' directory made with 'cw.getDir("imageDir", Context.MODE_PRIVATE);' will have that path to it – Kent Lauridsen Jun 15 '18 at 21:24
  • Does everyone get Error reading CPU usage: /proc/stat (Permission denied) when executing ContextWrapper cw = new ContextWrapper(context);? Seems having this issue on Android O – felixwcf Feb 17 '19 at 06:06
  • Worked for me. I dont know about android O – Denny Kurniawan Apr 11 '19 at 10:59
81
/**
 * Created by Ilya Gazman on 3/6/2016.
 */
public class ImageSaver {

    private String directoryName = "images";
    private String fileName = "image.png";
    private Context context;
    private boolean external;

    public ImageSaver(Context context) {
        this.context = context;
    }

    public ImageSaver setFileName(String fileName) {
        this.fileName = fileName;
        return this;
    }

    public ImageSaver setExternal(boolean external) {
        this.external = external;
        return this;
    }

    public ImageSaver setDirectoryName(String directoryName) {
        this.directoryName = directoryName;
        return this;
    }

    public void save(Bitmap bitmapImage) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(createFile());
            bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @NonNull
    private File createFile() {
        File directory;
        if(external){
            directory = getAlbumStorageDir(directoryName);
        }
        else {
            directory = context.getDir(directoryName, Context.MODE_PRIVATE);
        }
        if(!directory.exists() && !directory.mkdirs()){
            Log.e("ImageSaver","Error creating directory " + directory);
        }

        return new File(directory, fileName);
    }

    private File getAlbumStorageDir(String albumName) {
        return new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), albumName);
    }

    public static boolean isExternalStorageWritable() {
        String state = Environment.getExternalStorageState();
        return Environment.MEDIA_MOUNTED.equals(state);
    }

    public static boolean isExternalStorageReadable() {
        String state = Environment.getExternalStorageState();
        return Environment.MEDIA_MOUNTED.equals(state) ||
                Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);
    }

    public Bitmap load() {
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(createFile());
            return BitmapFactory.decodeStream(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

Usage

  • To save:

    new ImageSaver(context).
            setFileName("myImage.png").
            setDirectoryName("images").
            save(bitmap);
    
  • To load:

    Bitmap bitmap = new ImageSaver(context).
            setFileName("myImage.png").
            setDirectoryName("images").
            load();
    

Edit:

Added ImageSaver.setExternal(boolean) to support saving to external storage based on googles example.

Ismail
  • 725
  • 8
  • 23
Ilya Gazman
  • 31,250
  • 24
  • 137
  • 216
  • 14
    Here is another useful method to put in the class: `public boolean deleteFile(){ File file = createFile(); return file.delete(); }` – Micro Apr 11 '16 at 01:43
  • when I want to share the saved image, it returns "Directory not created" and the image is crashed. can you help me? – A. N Oct 09 '17 at 08:02
  • could you add a statement about the license this code is available under, to make it possible to include in a project? – Don Park Jan 13 '18 at 05:15
  • 3
    @DonPark No need, any code on stackoverflowis is under stackoverflow license, you can use this with no worries :) – Ilya Gazman Jan 13 '18 at 23:23
  • I am trying to use this, but running into issues. Any help on this question I posted? https://stackoverflow.com/questions/51276641/cannot-find-image-stored @IlyaGazman – Lion789 Jul 11 '18 at 03:20
  • I want to save animated gif file which is located in external storage and I have the path i.e. /storage/emulated/0/Android/data//files//xyz.gif. Now I want to Save/copy this file to Image Gallery and show there. How to do this. – Zia Ur Rahman Jul 18 '18 at 09:00
33

Came across this question today and this is how I do it. Just call this function with the required parameters

public void saveImage(Context context, Bitmap bitmap, String name, String extension){
    name = name + "." + extension;
    FileOutputStream fileOutputStream;
    try {
        fileOutputStream = context.openFileOutput(name, Context.MODE_PRIVATE);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fileOutputStream);
        fileOutputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Similarly, for reading the same, use this

public Bitmap loadImageBitmap(Context context,String name,String extension){
    name = name + "." + extension
    FileInputStream fileInputStream
    Bitmap bitmap = null;
    try{
        fileInputStream = context.openFileInput(name);
        bitmap = BitmapFactory.decodeStream(fileInputStream);
        fileInputStream.close();
    } catch(Exception e) {
        e.printStackTrace();
    }
     return bitmap;
}
Emad Razavi
  • 1,903
  • 2
  • 17
  • 24
Anurag
  • 1,521
  • 2
  • 17
  • 34
  • How do you pass the argument `b` to the function `saveImage`. I have put the images on my android device, but I can't get their path. If I can't get their path, I can't pass them as arguments to the function `saveImage`. – Autonomous Aug 05 '14 at 00:29
  • I have that photo on device. I can see it through file explorer apps as well as adb shell, but I was not able to get its address programmatically. So I though let me write it using code and then again read it. Reading is my ultimate aim but I always get `nil` when I try to read that photo. – Autonomous Aug 07 '14 at 21:45
  • 1
    ok so when you say that you write it again, i suppose you have that image data as a bitmap or raw data in the form of byte-array. If you have bitmap, you can directly utilize the above functions. If you have it in the form of byte array, use this to convert it to bitmap Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapdata , 0, bitmapdata .length); Or even if its in any other form, just convert it into bitmap and use the above functions. – Anurag Aug 08 '14 at 20:52
  • "Edited the answer" with extension, in my case issues were raised, so after all I found the issue that extension should be added as a parameter. – Naveed Ahmad Mar 25 '15 at 13:24
  • Thanks for the edit, I assumed extension to be part of the name itself. – Anurag Mar 25 '15 at 14:00
  • Thank you for the code buddy, but my question is where will it be stored ? Any default path ? – Rizwan Ahmed Aug 18 '15 at 16:48
  • It will be stored on device's internal storage which will be private to your application and it cannot be accessed directly from SD card. Go through this link to understand the storage options and their usage http://developer.android.com/guide/topics/data/data-storage.html#filesInternal – Anurag Aug 19 '15 at 05:14
  • If you try to do it with a circular image and a black square is added when calling getImageBitmap - change Bitmap.CompressFormat.JPEG to Bitmap.CompressFormat.PNG. – MorZa Oct 07 '15 at 09:38
  • @Anurag I am getting BitmapFactory.UnabletoDecodeStream Filenotfound Exception! how do I solve it? – MrAlpha_SU Mar 04 '17 at 03:42
15

For Kotlin users, I created a ImageStorageManager class which will handle save, get and delete actions for images easily:

class ImageStorageManager {
    companion object {
        fun saveToInternalStorage(context: Context, bitmapImage: Bitmap, imageFileName: String): String {
            context.openFileOutput(imageFileName, Context.MODE_PRIVATE).use { fos ->
                bitmapImage.compress(Bitmap.CompressFormat.PNG, 25, fos)
            }
            return context.filesDir.absolutePath
        }

        fun getImageFromInternalStorage(context: Context, imageFileName: String): Bitmap? {
            val directory = context.filesDir
            val file = File(directory, imageFileName)
            return BitmapFactory.decodeStream(FileInputStream(file))
        }

        fun deleteImageFromInternalStorage(context: Context, imageFileName: String): Boolean {
            val dir = context.filesDir
            val file = File(dir, imageFileName)
            return file.delete()
        }
    }
}

Read more here

Leo DroidCoder
  • 14,527
  • 4
  • 62
  • 54
Amiraslan
  • 794
  • 1
  • 8
  • 19
1

This code will support up Upto Android 11+.

Declare a permission result on Fragment / Activity I am using a fragment

private val askPermissions =
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        val isGranted = permissions.entries.all {
            it.value == true
        }

        if (isGranted) {
            viewModel.saveImageToGallery(requireContext().contentResolver,
                getString(R.string.my_deshi_qr_code),
                bitmap)
        } else {
            askForWritePermission()
        }
    }

Trigger event

bindingView.downloadQrButton.setOnClickListener {
        requestPermission()
    }
private fun requestPermission() {
    val minSDK = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
    val isWritePermissionGranted = (ContextCompat.checkSelfPermission(requireContext(),
        Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) || minSDK

    if (!isWritePermissionGranted) {
        askForWritePermission()
    } else {
        viewModel.saveImageToGallery(requireContext().contentResolver,
            getString(R.string.my_deshi_qr_code),
            bitmap)
    }
}


private fun askForWritePermission() {
    askPermissions.launch(listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE).toTypedArray())
}

Viewmodel

fun saveImageToGallery(contentResolver: ContentResolver, imageName: String, bitmap: Bitmap?) {
    val imageUri: Uri?
    val contentValues = ContentValues().apply {
        put(MediaStore.MediaColumns.DISPLAY_NAME, "$imageName.jpg")
        put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
        bitmap?.let {
            put(MediaStore.Images.Media.WIDTH, bitmap.width)
            put(MediaStore.Images.Media.HEIGHT, bitmap.height)
        }
    }

    imageUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH,
            Environment.DIRECTORY_PICTURES + File.separator.toString() + "YourFolderName")
        MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
    } else {
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    }

    try {
        val uri = contentResolver.insert(imageUri, contentValues)
        val fos = uri?.let { contentResolver.openOutputStream(it) }
        bitmap?.compress(Bitmap.CompressFormat.JPEG, 100, fos)
        Objects.requireNonNull(fos)
        _showMessage.postValue(Event("Image Saved"))
    } catch (e: Exception) {
        _showMessage.postValue(Event("Image Not Saved \n$e"))
    }
}
Amit Kundu
  • 119
  • 5
0

// mutiple image retrieve

 File folPath = new File(getIntent().getStringExtra("folder_path"));
 File[] imagep = folPath.listFiles();

 for (int i = 0; i < imagep.length ; i++) {
     imageModelList.add(new ImageModel(imagep[i].getAbsolutePath(), Uri.parse(imagep[i].getAbsolutePath())));
 }
 imagesAdapter.notifyDataSetChanged();
Matt Ke
  • 3,599
  • 12
  • 30
  • 49
Meet Bhavsar
  • 442
  • 6
  • 12
0

if you want to follow Android 10 practices to write in storage, check here and if you only want the images to be app specific, here for example if you want to store an image just to be used by your app:

viewModelScope.launch(Dispatchers.IO) {
            getApplication<Application>().openFileOutput(filename, Context.MODE_PRIVATE).use {
                bitmap.compress(Bitmap.CompressFormat.PNG, 50, it)
            }
        }

getApplication is a method to give you context for ViewModel and it's part of AndroidViewModel later if you want to read it:

viewModelScope.launch(Dispatchers.IO) {
            val savedBitmap = BitmapFactory.decodeStream(
                getApplication<App>().openFileInput(filename).readBytes().inputStream()
            )
        }
Amin Keshavarzian
  • 3,646
  • 1
  • 37
  • 38
0

Make sure to use WEBP as your media format to save more space with same quality:

fun saveImage(context: Context, bitmap: Bitmap, name: String): String {
        context.openFileOutput(name, Context.MODE_PRIVATE).use { fos ->
            bitmap.compress(Bitmap.CompressFormat.WEBP, 25, fos)
        }
    return context.filesDir.absolutePath
 }
Jim Ovejera
  • 739
  • 6
  • 10