Kotlin图像压缩实现

3

我之前的实现方式是将JPEG格式的图片上传到Firebase存储中,并且没有进行任何压缩。

private fun sendToFirebase() {

        if (imgUri != null) {

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

            // code to upload and read image url
        }
    }

决定编写一个图像压缩技术,用于压缩图像并上传到 Firebase 存储

结果:实现了图像压缩技术,请见下文

新增代码以压缩图像

  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)
    

问题:如何将同一压缩图像上传到Firebase存储

 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
        .....

    }
}

1
为什么不使用此扩展 - Alex Mamo
1个回答

3

您的函数 sendtoFirebase 似乎没有传入任何参数。我发布了我已经成功上传的代码。

如果您要压缩,请参照以下代码:

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)


}

在上述代码中,uploadFile 是调用 firebase 上传操作的函数。我将压缩后的位图传递给了该函数。上传功能的实现如下:
在下面的代码中,mImageURI 是与压缩操作相关的 URI 的伴生对象。如果不需要进行检查,可以删除下面的 if 语句。
 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()

    }
}

您不需要在上方添加进度条,这只是为了让用户看到上传的进度,如果文件很大,这是一个好的可视化方式。

您只需要确保将data传递给.putbytes即可。



编辑:对于您的onActivityResult,如果您的代码类似于我的,请使用:

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())


   }
}

在上面的图像中,image1是当前页面上用于显示所选图像的imageView。
希望这能有所帮助。

谢谢Waseem。我尽力实现了同样的功能,几乎完成了,但是我不知道在onActivityResult(....) > compressBitmap()中应该写什么,请检查上面的更新部分。 - Android
@Android,请查看我上面编辑过的帖子,你不应该在onActivityResult中调用compressBitmap()。应该在上传时作为按钮的一部分进行调用,例如有一个上传按钮。当按下按钮时,第一个函数应该是压缩图像,然后压缩函数本身将在压缩完成后调用上传。希望这样说得清楚。 - Waseem Ahmed
为什么要将arrayByte赋值为byteArray?为什么不直接使用uploadFile(byteArray)?我有什么遗漏吗? - Luis
@Luis,我想你是对的。目前来看,在我的应用程序中它能够正常工作,所以暂时不会更改它 :) - Waseem Ahmed
是的,我简化了代码。如果有人也遇到这个问题,我必须在主函数中初始化变量 var bitmap: Bitmap? = null,在 onCreate 函数中使用 "YouButtonNameHere.setOnClickListener { bitmap?.let { it1 -> compressBitmap(it1) } }",没有 quality 参数,因为我发现可以在压缩函数内轻松设置。无论如何,感谢 Waseem 的提示! - Luis
很高兴能帮忙!我会尽可能地提供帮助,这样其他人就不必像我这样作为兼职开发人员经历同样的痛苦 :) - Waseem Ahmed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接