SaDeGH_F
SaDeGH_F

Reputation: 481

How to save scaled bitmap in sharedpreferences?

I'm trying to save the bitmap in sharedpreferences, But when I'm trying to load that bitmap I give a "java.lang.OutOfMemoryError".

I guess I'm saving the unscaled version.

This is my scaling code:

public void decodeFile(String filePath) {

    // Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, o);

    // The new size we want to scale to
    final int REQUIRED_SIZE = 2048;

    int width_tmp = o.outWidth, height_tmp = o.outHeight;
    int scale = 1;
    while (true) {
        if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
            break;
        width_tmp /= 2;
        height_tmp /= 2;
        scale *= 2;
    }

    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize = scale;
    bmp = BitmapFactory.decodeFile(filePath, o2);

}

and this is how I'm saving the bitmap:

decodeFile(filePath);
img_logo.setImageBitmap(bmp);
settings = getSharedPreferences("pref", 0);
SharedPreferences.Editor prefsEditor = settings.edit();
prefsEditor.putString("photo1", filePath);
prefsEditor.commit();

what is wrong?

Edit:

this is my whole onActivityResult code:

    @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // TODO Auto-generated method stub
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == GALLERY_PICTURE) {
        if (resultCode == RESULT_OK) {


                Uri selectedImage = data.getData();
                String[] filePathColumn = {MediaStore.Images.Media.DATA};

                Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
                if (cursor != null) {
                cursor.moveToFirst();

                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                String filePath = cursor.getString(columnIndex);
                cursor.close();


               decodeFile(filePath);
               img_logo.setImageBitmap(bmp);
               settings = getSharedPreferences("pref", 0);
               SharedPreferences.Editor prefsEditor = settings.edit();
                    prefsEditor.putString("photo1", filePath);
                    prefsEditor.commit();
                }


            } else {
                Toast.makeText(getApplicationContext(), "Cancelled",
                        Toast.LENGTH_SHORT).show();
            }
        } else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        }
     else if (requestCode == CAMERA_REQUEST) {
        if (resultCode == RESULT_OK) {
            String[] projection = { MediaStore.Images.Media.DATA}; 
            Cursor cursor = getContentResolver().query(mCapturedImageURI2, projection, null, null, null); 
            int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 
            cursor.moveToFirst(); 
            String capturedImageFilePath = cursor.getString(column_index_data);
            Log.d("photos*******"," in camera take int  "+capturedImageFilePath);

            decodeFile(capturedImageFilePath);

            if(data != null)
            {
                img_logo.setImageBitmap(bmp);
                settings = getSharedPreferences("pref", 0);
                SharedPreferences.Editor prefsEditor = settings.edit();
                    prefsEditor.putString("photo1", capturedImageFilePath);
                    prefsEditor.commit();
            }
        }
}
}

Edit2:

my whole activity code:

public class MainActivity extends Activity {
ImageView img_logo;
protected static final int CAMERA_REQUEST = 0;
protected static final int GALLERY_PICTURE = 1;
Uri mCapturedImageURI2;
SharedPreferences settings;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    settings = getSharedPreferences("pref", 0);

    img_logo = (ImageView) findViewById(R.id.imageView1);
    Log.d("SHAREDimagezzzz", "**********SHAREDzzzzzzz suckes******");
    img_logo.setImageURI(Uri.parse(settings.getString("photo1", "android.resource://com.tiktak.babyalbum/" + R.drawable.ic_launcher)));
    Log.d("SHAREDimage", "**********SHARED suckes******");
    img_logo.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            startDialog();
        }
    });
}
protected void startDialog() {
    AlertDialog.Builder myAlertDialog = new AlertDialog.Builder(this);
    myAlertDialog.setTitle("Upload Pictures Option");
    myAlertDialog.setMessage("How do you want to set your picture?");

    myAlertDialog.setPositiveButton("Gallery",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface arg0, int arg1) {
                    Intent galleryintent = new Intent(Intent.ACTION_GET_CONTENT);
                    galleryintent.setType("image/*");
                    galleryintent.putExtra("return-data", true);
                    startActivityForResult(galleryintent, GALLERY_PICTURE);
                }
            });

    myAlertDialog.setNegativeButton("Camera",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface arg0, int arg1) {
                    ContentValues values = new ContentValues();  
                    values.put(MediaStore.Images.Media.TITLE, "fileName");  
                    mCapturedImageURI2 = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);  

                    Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");
                    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI2);  
                    startActivityForResult(cameraIntent, CAMERA_REQUEST);

                }
            });
    myAlertDialog.show();
}
Bitmap bmp;
public String decodeFile(String filePath) {

    // Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, o);

    // The new size we want to scale to
    final int REQUIRED_SIZE = 2048;

    int width_tmp = o.outWidth, height_tmp = o.outHeight;
    int scale = 1;
    while (true) {
        if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
            break;
        width_tmp /= 2;
        height_tmp /= 2;
        scale *= 2;
    }

    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize = scale;
    bmp = BitmapFactory.decodeFile(filePath, o2);
    return filePath;

}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    // TODO Auto-generated method stub
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == GALLERY_PICTURE) {
        if (resultCode == RESULT_OK) {

                Uri selectedImage = data.getData();
                String[] filePathColumn = {MediaStore.Images.Media.DATA};

                Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
                if (cursor != null) {
                cursor.moveToFirst();

                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                String filePath = cursor.getString(columnIndex);
                cursor.close();

               String bb = decodeFile(filePath);
               img_logo.setImageBitmap(bmp);
               Log.d("galleryimage", "**********gallery suckes******");
               settings = getSharedPreferences("pref", 0);
               SharedPreferences.Editor prefsEditor = settings.edit();
                    prefsEditor.putString("photo1", bb);
                    prefsEditor.commit();
                }

            } else {
                Toast.makeText(getApplicationContext(), "Cancelled",
                        Toast.LENGTH_SHORT).show();
            }
        } else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        }
     else if (requestCode == CAMERA_REQUEST) {
        if (resultCode == RESULT_OK) {
            String[] projection = { MediaStore.Images.Media.DATA}; 
            Cursor cursor = getContentResolver().query(mCapturedImageURI2, projection, null, null, null); 
            int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 
            cursor.moveToFirst(); 
            String capturedImageFilePath = cursor.getString(column_index_data);
            Log.d("photos*******"," in camera take int  "+capturedImageFilePath);

            String bbd = decodeFile(capturedImageFilePath);

            if(data != null)
            {
                img_logo.setImageBitmap(bmp);
                Log.d("cameraimage", "**********camera suckes******");
                settings = getSharedPreferences("pref", 0);
                SharedPreferences.Editor prefsEditor = settings.edit();
                    prefsEditor.putString("photo1", bbd);
                    prefsEditor.commit();
            }
        }
}
}
}

I think I didn't place the sharedPreferences and prefsEditor right.

Upvotes: 0

Views: 366

Answers (5)

SaDeGH_F
SaDeGH_F

Reputation: 481

I solved my problem somehow.

I know that this is not the best answer to my question but it's working and that's enough for me! :)

Just Should do the Scaling progress once again before loading sharedPrefrences:

public class MainActivity extends Activity {
ImageView img_logo;
protected static final int CAMERA_REQUEST = 0;
protected static final int GALLERY_PICTURE = 1;
Uri mCapturedImageURI2;
SharedPreferences settings;



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    settings = getSharedPreferences("pref", 0);
    Button b1 = (Button) findViewById(R.id.button1);
    Button b2 = (Button) findViewById(R.id.bto2);
    b2.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            startActivity(new Intent(MainActivity.this, A2.class));
        }
    });

    img_logo = (ImageView) findViewById(R.id.imageView1);
    Log.d("SHAREDimagezzzz", "**********SHAREDzzzzzzz suckes******");
    BitmapFactory.Options o3 = new BitmapFactory.Options();
    o3.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(settings.getString("photo1", "android.resource://com.tiktak.babyalbum/" + R.drawable.ic_launcher), o3);
    final int REQUIRED_SIZE = 2048;

    int width_tmp = o3.outWidth, height_tmp = o3.outHeight;
    int scale = 1;
    while (true) {
        if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
            break;
        width_tmp /= 2;
        height_tmp /= 2;
        scale *= 2;
    }
    BitmapFactory.Options o4 = new BitmapFactory.Options();
    o4.inSampleSize = scale;
    Bitmap bit1 = BitmapFactory.decodeFile(settings.getString("photo1", "android.resource://com.tiktak.babyalbum/" + R.drawable.ic_launcher), o4);

    img_logo.setImageBitmap(bit1);
    // img_logo.setImageURI(Uri.parse(settings.getString("photo1", "android.resource://com.tiktak.babyalbum/" + R.drawable.ic_launcher)));

    Log.d("SHAREDimage", "**********SHARED suckes******");
    b1.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            startDialog();
        }
    });

}
protected void startDialog() {
    AlertDialog.Builder myAlertDialog = new AlertDialog.Builder(this);
    myAlertDialog.setTitle("Upload Pictures Option");
    myAlertDialog.setMessage("How do you want to set your picture?");

    myAlertDialog.setPositiveButton("Gallery",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface arg0, int arg1) {
                    Intent galleryintent = new Intent(Intent.ACTION_GET_CONTENT);
                    galleryintent.setType("image/*");
                    galleryintent.putExtra("return-data", true);
                    startActivityForResult(galleryintent, GALLERY_PICTURE);
                }
            });

    myAlertDialog.setNegativeButton("Camera",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface arg0, int arg1) {
                    ContentValues values = new ContentValues();  
                    values.put(MediaStore.Images.Media.TITLE, "fileName");  
                    mCapturedImageURI2 = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);  

                    Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");
                    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI2);  
                    startActivityForResult(cameraIntent, CAMERA_REQUEST);

                }
            });
    myAlertDialog.show();

}


Bitmap bmp;
public void decodeFile(String filePath) {

    // Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, o);

    // The new size we want to scale to
    final int REQUIRED_SIZE = 2048;

    int width_tmp = o.outWidth, height_tmp = o.outHeight;
    int scale = 1;
    while (true) {
        if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
            break;
        width_tmp /= 2;
        height_tmp /= 2;
        scale *= 2;
    }

    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize = scale;
    bmp = BitmapFactory.decodeFile(filePath, o2);



}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    // TODO Auto-generated method stub
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == GALLERY_PICTURE) {
        if (resultCode == RESULT_OK) {


                Uri selectedImage = data.getData();
                String[] filePathColumn = {MediaStore.Images.Media.DATA};

                Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
                if (cursor != null) {
                cursor.moveToFirst();

                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                String filePath = cursor.getString(columnIndex);
                cursor.close();


               decodeFile(filePath);
               img_logo.setImageBitmap(bmp);
               Log.d("galleryimage", "**********gallery suckes******");
               settings = getSharedPreferences("pref", 0);
               Editor prefsEditor = settings.edit();
                    prefsEditor.putString("photo1", filePath);
                    prefsEditor.commit();
                }


            } else {
                Toast.makeText(getApplicationContext(), "Cancelled",
                        Toast.LENGTH_SHORT).show();
            }
        } else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        }
     else if (requestCode == CAMERA_REQUEST) {
        if (resultCode == RESULT_OK) {
            String[] projection = { MediaStore.Images.Media.DATA}; 
            Cursor cursor = getContentResolver().query(mCapturedImageURI2, projection, null, null, null); 
            int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 
            cursor.moveToFirst(); 
            String capturedImageFilePath = cursor.getString(column_index_data);
            Log.d("photos*******"," in camera take int  "+capturedImageFilePath);

            decodeFile(capturedImageFilePath);

            if(data != null)
            {
                img_logo.setImageBitmap(bmp);
                settings = getSharedPreferences("pref", 0);
                Editor prefsEditor = settings.edit();
                    prefsEditor.putString("photo1", capturedImageFilePath);
                    prefsEditor.commit();

            }

        }

}

}


}

Upvotes: 0

localhost
localhost

Reputation: 5598

Each Android application is limited with 16Mb of memory. Even if you want to scale a 20MB image to small dimensions - you gonna load it to memory and get OOM.

The best practice to save/load large images is to use options.inJustDecodeBounds = true; in BitmapFactory. This will not load your image to memory and will scale it just in file system.

That's how i do it in my app:

public static Bitmap getThumbnail(String path, int target_width, int target_height, int max_size) {

    try {
      BitmapFactory.Options options = new BitmapFactory.Options();
      options.inJustDecodeBounds = true;
      BitmapFactory.decodeFile(path, options);

      int scale = 1;
      while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) >
        max_size) {
        scale++;
      }
      Log.d("boom", "scale = " + scale + ", orig-width: " + options.outWidth + ", orig-height: " + options.outHeight);

      Bitmap pic = null;
      if (scale > 1) {
        scale--;
        options = new BitmapFactory.Options();
        options.inSampleSize = scale;
        pic = BitmapFactory.decodeFile(path, options);

        Log.d("boom", "1th scale operation dimenions - width: " + target_width + ", target_height: " + target_height);

        double y = Math.sqrt(max_size
          / (((double) target_width) / target_height));
        double x = (y / target_height) * target_width;

        Bitmap scaledBitmap = Bitmap.createScaledBitmap(pic, (int) x, (int) y, true);
        pic.recycle();
        pic = scaledBitmap;

        System.gc();
      } else {
        pic = BitmapFactory.decodeFile(path, options);
      }

      Log.d("boom", "bitmap size - width: " +pic.getWidth() + ", height: " + pic.getHeight());
      return pic;
    } catch (Exception e) {
      Log.e("boom", e.getMessage(),e);
      return null;
    }
  }

More info here

But seems you did it fine, but you save/load SharedPreferences wrong. You saving empty string and try to parse URI them.

String bb = decodeFile(filePath);
...
prefsEditor.putString("photo1", bb);

and on load you do:

img_logo.setImageURI(Uri.parse(settings.getString("photo1", "android.resource://com.tiktak.babyalbum/" + R.drawable.ic_launcher)));

will return empty string and will cause an error.

Upvotes: 2

user1586758
user1586758

Reputation:

Try converting bitmap into String and save it, instead of saving the file path. This will help. On the other hand, it's better you use SQLite for these kind of operations instead of Sharedpreference..

Upvotes: 1

Aman Agnihotri
Aman Agnihotri

Reputation: 3023

Don't save bitmaps in SharedPreference. Its only for storing small key-value pairs. It isn't good practice, and probably unusual to store Bitmaps in SharedPreference.

Instead, cache your image in a file and save its path.

Use Universal Image Downloader to cache images as it will make your task easier.

Upvotes: 1

Sayed Jalil Hassan
Sayed Jalil Hassan

Reputation: 2595

I dont think shared preference is causing the problem. you are only storing path to the bitmap in the sharedPreference. Out of memory error is most probably caused by

     img_logo.setImageBitmap(bmp); 

use some good Image loading library e.g picasso or universal image loader.

Upvotes: 2

Related Questions