Tuesday, April 21, 2015

Save Bitmap to storage

This example show how to save bitmap to storage (SD Card) as file, and insert to MediaStore.


As a example, the bitmap is retrieved from ImageView by calling ((BitmapDrawable)imageView.getDrawable()).getBitmap(), note that it's not always work, depends on how to load image to ImageVIew.

To save file to external storage, permission of "android.permission.WRITE_EXTERNAL_STORAGE" is needed in AndroidManifest.xml. Otherwise you cannot save the file, but no error reported.

In this example:
- The first button save the bitmap as file, with specified path. In this case, MediaStore may not know there are new image, such that may be you cannot view it in Android Gallery App or Photos App.
- The second button insert the bitmap to MediaStore by calling MediaStore.Images.Media.insertImage(ContentResolver cr, Bitmap source, String title, String description), to MediaStore path. Such that you can view it in Android Gallery App or Photos App.
- The third button save the bitmap as file, then insert the file to MediaStore by calling MediaStore.Images.Media.insertImage(ContentResolver cr, String imagePath, String name, String description). In this case, you save two files actually.


package com.example.androidsavebitmap;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import android.support.v7.app.ActionBarActivity;
import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

/*
 * "android.permission.WRITE_EXTERNAL_STORAGE" is needed
 * otherwise, cannot save but no error report
 */

public class MainActivity extends ActionBarActivity {
 
 ImageView imageView;
 Button btnSaveExternalStorageDirectory;
 Button btnSaveMediaStore;
 Button btnSaveFileAndMediaStore;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView)findViewById(R.id.image);
        
        btnSaveExternalStorageDirectory = (Button)findViewById(R.id.saveExternalStorageDirectory);
        btnSaveExternalStorageDirectory.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    /*
     * Save bitmap to ExternalStorageDirectory
     */
    
    //get bitmap from ImageVIew
    //not always valid, depends on your drawable
    Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();

    //always save as 
       String fileName = "test.jpg";
       
       ByteArrayOutputStream bytes = new ByteArrayOutputStream();
       bitmap.compress(Bitmap.CompressFormat.JPEG, 40, bytes);

    File ExternalStorageDirectory = Environment.getExternalStorageDirectory();
    File file = new File(ExternalStorageDirectory + File.separator + fileName);
    
    FileOutputStream fileOutputStream = null;
    try {
     file.createNewFile();
     fileOutputStream = new FileOutputStream(file);
     fileOutputStream.write(bytes.toByteArray());
     
     Toast.makeText(MainActivity.this, 
       file.getAbsolutePath(), 
       Toast.LENGTH_LONG).show();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    } finally {
     if(fileOutputStream != null){
      try {
       fileOutputStream.close();
      } catch (IOException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }
     }
    }

   }});
        
        btnSaveMediaStore = (Button)findViewById(R.id.saveMediaStore);
        btnSaveMediaStore.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    /*
     * Save bitmap to MediaStore
     */
    
    //get bitmap from ImageVIew
    //not always valid, depends on your drawable
    Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();

    ContentResolver cr = getContentResolver();
    String title = "myBitmap";
    String description = "My bitmap created by Android-er";
    String savedURL = MediaStore.Images.Media
      .insertImage(cr, bitmap, title, description);
    
    Toast.makeText(MainActivity.this, 
      savedURL, 
      Toast.LENGTH_LONG).show();
    
   }});
        
        btnSaveFileAndMediaStore = (Button)findViewById(R.id.saveExternalStorageDirectoryMediaStore);
        btnSaveFileAndMediaStore.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    /*
     * Save bitmap to ExternalStorageDirectory
     */
    
    //get bitmap from ImageVIew
    //not always valid, depends on your drawable
    Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();

    //always save as 
       String fileName = "test.jpg";
       
       ByteArrayOutputStream bytes = new ByteArrayOutputStream();
       bitmap.compress(Bitmap.CompressFormat.JPEG, 40, bytes);

    File ExternalStorageDirectory = Environment.getExternalStorageDirectory();
    File file = new File(ExternalStorageDirectory + File.separator + fileName);
    
    FileOutputStream fileOutputStream = null;
    try {
     file.createNewFile();
     fileOutputStream = new FileOutputStream(file);
     fileOutputStream.write(bytes.toByteArray());
     
     ContentResolver cr = getContentResolver();
     String imagePath = file.getAbsolutePath();
     String name = file.getName();
     String description = "My bitmap created by Android-er";
     String savedURL = MediaStore.Images.Media
       .insertImage(cr, imagePath, name, description);
     
     Toast.makeText(MainActivity.this, 
       savedURL, 
       Toast.LENGTH_LONG).show();
     
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    } finally {
     if(fileOutputStream != null){
      try {
       fileOutputStream.close();
      } catch (IOException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }
     }
    }

   }});
    }

}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androidsavebitmap.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher" />

    <Button
        android:id="@+id/saveExternalStorageDirectory"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Save to ExternalStorageDirectory" />

    <Button
        android:id="@+id/saveMediaStore"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Save to MediaStore" />

    <Button
        android:id="@+id/saveExternalStorageDirectoryMediaStore"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Save to ExternalStorageDirectory and insert to MediaStore" />

</LinearLayout>


download filesDownload the files.

more:
Insert the bitmap to MediaStore with title and List images title in MediaStore

6 comments:

Lara said...

Hi Eric,

Could you tell me the exact purpose of title and description in insertImage? Neither pieces of text in " " seem to be saved as file info once the image is saved to your device - what is the point of these two Strings?

"ContentResolver contentResolver = getContentResolver();
String title = "title";
String description = "description";
MediaStore.Images.Media.insertImage(contentResolver, bitmap, title, description);"

Thanks!

Lara.

Erik said...

hello Lara,

It's for MediaStore, refer http://developer.android.com/reference/android/provider/MediaStore.Images.Media.html#insertImage(android.content.ContentResolver, android.graphics.Bitmap, java.lang.String, java.lang.String)

Lara said...

Hi Eric,

I got that. :-).

I just can't find any other documentation about the usefulness of title and description - I was hoping you have might have some more knowledge on the subject.

Lara.

Erik said...

Hello Lara,

In my understanding, they are some extra info stored in MediaStore, not file name, not ID. Actually I can't find any apps use the info.

Here is my modified example show how to store the title and list the titles in MediaStore. Insert bitmap to MediaStore with title and List images title in MediaStore.

Lara said...

Hi Eric,

Good to know regarding other apps, just wanted someone's else opinion.

And cheers for the second link!

You aren't on Twitter are you?

Lara.

Unknown said...

Can some one explain me why third approach giving me out of memory exception.

#Stack Trace#
at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:752)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:728)
at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:477)
at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:515)
at android.provider.MediaStore$Images$Media.insertImage(MediaStore.java:886)
at com.example.myappsampleimagegallery.MainActivity.click3(MainActivity.java:127)