Encoding and Saving Images as Strings in Preferences in SUSI Android App

In this blog post, I’ll be telling about how to store images in preferences by encoding them into Strings and also how to retrieve them back. Many a times, you need to store an image in preferences for various purposes and then need to retrieve it back when required. In SUSI Android App, we need to store an image in preference to set the chat background. We just simply select image from gallery, convert image to a byte array, then do a Base 64 encoding to string, store it in preferences and later decode it and set the chat background.

Base64 Encoding-Decoding in Java

You may already know what Base 64 is but still here is a link to Wikipedia article explaining it. So, how to do a Base64 encoding-decoding in java? For that java has a class with all such methods already present. https://docs.oracle.com/javase/8/docs/api/java/util/Base64.html

According to the docs:

This class consists exclusively of static methods for obtaining encoders and decoders for the Base64 encoding scheme. The implementation of this class supports the following types of Base64 as specified in RFC 4648 and RFC 2045.

  • Basic
  • URL and Filename safe
  • MIME

So, you may just use Base64.encode to encode a byte array and Base64.decode to decode a byte array.

Implementation

1. Selecting image from gallery

    

Start Image Picker Intent and pick an image from gallery. After selecting you may also start a Crop Intent to crop image also. After selecting and cropping image, you will get a URI of the image.

override fun openImagePickerActivity() {
   val i = Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
   startActivityForResult(i, SELECT_PICTURE)
}
val thePic = data.extras.getParcelable<Bitmap>("data")
val encodedImage = ImageUtils.Companion.cropImage(thePic)
chatPresenter.cropPicture(encodedImage)

2. Getting image from the URI using inputstream

Next step is to get the image from file using URI from the previous step and InputStream class and store it in a BitMap variable.

val imageStream: InputStream = context.contentResolver.openInputStream(selectedImageUri)
   val selectedImage: Bitmap
   val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
   val cursor = context.contentResolver.query(getImageUrl(context.applicationContext, selectedImageUri), filePathColumn, null, null, null)
   cursor?.moveToFirst()
   selectedImage = BitmapFactory.decodeStream(imageStream)

3. Converting the bitmap to ByteArray

Now, just convert the Bitmap thus obtained to a ByteArray using below code.

val baos = ByteArrayOutputStream()
   selectedImage.compress(Bitmap.CompressFormat.JPEG, 100, baos)
   val b = baos.toByteArray()

4. Base64 encode the ByteArray and store in preference

Encode the the byte array obtained in last step to a String and store it in preferences.

 val encodedImage = Base64.encodeToString(b, Base64.DEFAULT)
//now you have a string. You can store it in preferences

5. Decoding the String to image

Now whenever you want, you can just decode the stored Base64 encoded string to a byte array and then from byte array to a bitmap and use wherever you want.

fun decodeImage(context: Context, previouslyChatImage: String): Drawable {
   val b = Base64.decode(previouslyChatImage, Base64.DEFAULT)
   val bitmap = BitmapFactory.decodeByteArray(b, 0, b.size)
   return BitmapDrawable(context.resources, bitmap)
}

Summary

So, the main aim of this blog was to give an idea about how can you store images in preferences. There is no way to store them directly. So, you have to convert them to String by encoding them in Base64 format and then decoding it to use it. You also have other ways to store images like storing it in database etc but this one is simpler and fast.

Resources

  1. Stackoverflow answer to “How to save image as String” https://stackoverflow.com/questions/31502566/save-image-as-string-with-sharedpreferences
  2. Other Stackoverflow answer about “Saving Images in preferences” https://stackoverflow.com/questions/18072448/how-to-save-image-in-shared-preference-in-android-shared-preference-issue-in-a
  3. Official docs of Base64 class https://docs.oracle.com/javase/8/docs/api/java/util/Base64.html
  4. Wikipedia link for learning about Base64 https://en.wikipedia.org/wiki/Base64
  5. Stackoverflow answer for “What is Base64 encoding used for?” https://stackoverflow.com/questions/201479/what-is-base-64-encoding-used-for