3

My old implementation to upload image to Firebase Storage in JPEG format without any compression

private fun sendToFirebase() {

        if (imgUri != null) {

            val fileRef = storageRef!!.child(username+ ".jpg")
    
            ....

            // code to upload and read image url
        }
    }

Decided to write a image compression technique to compress image and then upload to Firebase Storage

Result : Achieved image compression technique, see below

Newly added code to compress image

  1. URI to Bitmap

    val bitmap = MediaStore.Images.Media.getBitmap(activity?.contentResolver, imgUri)
    
  2. Method to compress Bitmap

     private fun compressBitmap(bitmap: Bitmap, quality:Int):Bitmap{
        val stream = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.WEBP, quality, stream)
        val byteArray = stream.toByteArray()
        return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
     }
    
  3. Bitmap compression Implementation

     compressBitmap(bitmap, 80)
    

Query: How to upload same compressed image to Firebase storage

 private fun sendToFirebase() {

    if (imgUri != null) {

        // code to convert uri to bitmap <start>
        val bitmap = MediaStore.Images.Media.getBitmap(activity?.contentResolver, imgUri)

        compressBitmap(bitmap, 80)
        // code to convert uri to bitmap <end>


        // old implementation
        .....

    }
}
Android
  • 1,529
  • 1
  • 12
  • 27
  • 1
    Why not to use [this extension](https://firebase.google.com/products/extensions/storage-resize-images)? – Alex Mamo Jul 15 '20 at 07:33

1 Answers1

3

You don't seem to be passing anything into your function for sendtoFirebase. i am posting code i have done to successfully upload.

you looking at compressing first so you would need this;

private fun compressBitmap(bitmap: Bitmap, quality: Int): Bitmap {

    val stream = ByteArrayOutputStream()

    bitmap.compress(Bitmap.CompressFormat.WEBP,quality,stream)

    val byteArray = stream.toByteArray()

    arrayByte = byteArray

    
                uploadFile(arrayByte)
         
 
    return BitmapFactory.decodeByteArray(byteArray,0,byteArray.size)


}

in the above, uploadFile is the call for the firebase upload. i am passing the compressed bitmap into the function. the functional for upload looks as follows:

in below mImageURI is a companion object which is part of the URI passed for compression. you can remove the if statement below if you dont want to do the check

 private fun uploadFile(data:ByteArray) {


    if (mImageUri != null){

        val storageref = imageref.child("put your image id here")

        storageref.putBytes(data).addOnSuccessListener {

                            Handler().postDelayed({

                                progressbar.setProgress(0)
                                Toast.makeText(activity, "Upload Successful", Toast.LENGTH_LONG).show()

                            }

                                , 1000)
               
        }.addOnFailureListener{e->

            Toast.makeText(activity,e.message,Toast.LENGTH_LONG).show()
        }.addOnProgressListener {taskSnapshot ->

            val progress = (100.0 * taskSnapshot.bytesTransferred/taskSnapshot.totalByteCount)

            progressbar.setProgress(progress.toInt())

        }

    }
    else if(mImageUri == null) {
        Toast.makeText(activity,"No File Selected",Toast.LENGTH_LONG).show()

    }
}

You do not need to have the progress bar above. its just a nice visual for the user to have to see the progress of the upload if the file is large.

your really only need to ensure that you passing data into .putbytes



Edit: For your onActivity result if your code is similar to mine then use;

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data)

    if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK
        && data != null && data.getData() != null) {

            mImageUri = data.getData()!!

        image1.setImageURI(data.getData())


   }
}

in the above image1 is a imageView on the current page to show the image selected.

Hope this helps

Waseem Ahmed
  • 379
  • 1
  • 5
  • 17
  • Thanks Waseem. I tried my best to implement same and almost done, but not getting what I have to write inside onActivityResult(....) > compressBitmap() please check my update section above – Android Jul 18 '20 at 08:22
  • @Android, see my edited post above, you DO NOT call `compressBitmap()` inside `onActivityResult`. Call it as part of the button your press when uploading e.g. have an upload button. when pressed, the first function should be compress image and then the compress function itself will call the upload after the compression is done. hope that makes sense – Waseem Ahmed Jul 19 '20 at 11:01
  • Why are you assigning arrayByte = byteArray? Why not just uploadFile(byteArray)? Am I missing something? – Luis Aug 11 '20 at 13:39
  • @Luis, i guess you are right. at this point, it works for me in my App so won't be changing it for now:) – Waseem Ahmed Aug 12 '20 at 14:04
  • Yup, I simplified that, also if anyone gets here aswell, I had to initiate the variable on the main function as var bitmap: Bitmap? = null, and inside onCreate I used "YouButtonNameHere.setOnClickListener { bitmap?.let { it1 -> compressBitmap(it1) } }", without the quality parameter as I found that to be easily setable inside the compress function. Anyway Thanks for the tip Waseem! – Luis Aug 12 '20 at 14:36
  • My Pleasure! i try to help where possible so that other do not have to go through the same pains i experienced as a part time developer:) – Waseem Ahmed Aug 13 '20 at 09:03